1 /*
2  * %CopyrightBegin%
3  *
4  * Copyright Ericsson AB 2002-2018. All Rights Reserved.
5  *
6  * Licensed under the Apache License, Version 2.0 (the "License");
7  * you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at
9  *
10  *     http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  *
18  * %CopyrightEnd%
19  *
20  */
21 #include <stdlib.h>
22 #include <stdio.h>
23 #include <string.h>
24 #include <erl_nif.h>
25 
26 /* #define ASN1_DEBUG 1 */
27 
28 #define ASN1_OK 0
29 #define ASN1_ERROR -1
30 #define ASN1_COMPL_ERROR 1
31 #define ASN1_DECODE_ERROR 2
32 #define ASN1_TAG_ERROR -3
33 #define ASN1_LEN_ERROR -4
34 #define ASN1_INDEF_LEN_ERROR -5
35 #define ASN1_VALUE_ERROR -6
36 
37 #define ASN1_CLASS 0xc0
38 #define ASN1_FORM 0x20
39 #define ASN1_CLASSFORM (ASN1_CLASS | ASN1_FORM)
40 #define ASN1_TAG 0x1f
41 #define ASN1_LONG_TAG 0x7f
42 
43 #define ASN1_INDEFINITE_LENGTH 0x80
44 #define ASN1_SHORT_DEFINITE_LENGTH 0
45 
46 #define ASN1_PRIMITIVE 0
47 #define ASN1_CONSTRUCTED 0x20
48 
49 #define ASN1_NOVALUE 0
50 
51 #define ASN1_SKIPPED 0
52 #define ASN1_OPTIONAL 1
53 #define ASN1_CHOOSEN 2
54 
55 #define CEIL(X,Y) ((X-1) / Y + 1)
56 
57 #define INVMASK(X,M) (X & (M ^ 0xff))
58 #define MASK(X,M) (X & M)
59 
60 /* PER COMPLETE */
61 static int per_complete(ErlNifBinary *, unsigned char *, int);
62 
63 static int per_insert_octets(int, unsigned char **, unsigned char **, int *);
64 
65 static int per_insert_octets_except_unused(int, unsigned char **, unsigned char **,
66 	int *, int);
67 
68 static int per_insert_octets_as_bits_exact_len(int, int, unsigned char **,
69 	unsigned char **, int *);
70 
71 static int per_insert_octets_as_bits(int, unsigned char **, unsigned char **, int *);
72 
73 static int per_pad_bits(int, unsigned char **, int *);
74 
75 static int per_insert_least_sign_bits(int, unsigned char, unsigned char **, int *);
76 
77 static int per_insert_most_sign_bits(int, unsigned char, unsigned char **, int *);
78 
79 static int per_insert_bits_as_bits(int, int, unsigned char **, unsigned char **, int *);
80 
81 static int per_insert_octets_unaligned(int, unsigned char **, unsigned char **, int);
82 
83 static int per_realloc_memory(ErlNifBinary *, int, unsigned char **);
84 
85 /* BER DECODE */
86 static int ber_decode_begin(ErlNifEnv *, ERL_NIF_TERM *, unsigned char *, int,
87 	unsigned int *);
88 
89 static int ber_decode(ErlNifEnv *, ERL_NIF_TERM *, unsigned char *, int *, int);
90 
91 static int ber_decode_tag(ErlNifEnv *, ERL_NIF_TERM *, unsigned char *, int, int *);
92 
93 static int ber_decode_value(ErlNifEnv*, ERL_NIF_TERM *, unsigned char *, int *, int,
94 	int);
95 
96 /* BER ENCODE */
97 typedef struct ber_encode_mem_chunk mem_chunk_t;
98 
99 static int ber_encode(ErlNifEnv *, ERL_NIF_TERM , mem_chunk_t **, unsigned int *);
100 
101 static void ber_free_chunks(mem_chunk_t *chunk);
102 static mem_chunk_t *ber_new_chunk(unsigned int length);
103 static int ber_check_memory(mem_chunk_t **curr, unsigned int needed);
104 
105 static int ber_encode_tag(ErlNifEnv *, ERL_NIF_TERM , unsigned int ,
106 	mem_chunk_t **, unsigned int *);
107 
108 static int ber_encode_length(size_t , mem_chunk_t **, unsigned int *);
109 
110 /*
111  *
112  * This section defines functionality for the complete encode of a
113  * PER encoded message
114  *
115  */
116 
per_complete(ErlNifBinary * out_binary,unsigned char * in_buf,int in_buf_len)117 static int per_complete(ErlNifBinary *out_binary, unsigned char *in_buf,
118 	int in_buf_len) {
119     int counter = in_buf_len;
120     /* counter keeps track of number of bytes left in the
121      input buffer */
122 
123     int buf_space = in_buf_len;
124     /* This is the amount of allocated space left of the out_binary. It
125      is possible when padding is applied that more space is needed than
126      was originally allocated. */
127 
128     int buf_size = in_buf_len;
129     /* Size of the buffer. May become reallocated and thus other than
130      in_buf_len */
131 
132     unsigned char *in_ptr, *ptr;
133     /* in_ptr points at the next byte in in_buf to be moved to
134      complete_buf.
135      ptr points into the new completed buffer, complete_buf, at the
136      position of the next byte that will be set */
137     int unused = 8;
138     /* unused = [1,...,8] indicates how many of the rigthmost bits of
139      the byte that ptr points at that are unassigned */
140 
141     int no_bits, no_bytes, in_unused, desired_len, ret, saved_mem, needed,
142 	    pad_bits;
143 
144     unsigned char val;
145 
146     in_ptr = in_buf;
147     ptr = out_binary->data;
148     *ptr = 0x00;
149     while (counter > 0) {
150 	counter--;
151 	switch (*in_ptr) {
152 	case 0:
153 	    /* just one zero-bit should be added to the buffer */
154 	    if (unused == 1) {
155 		unused = 8;
156 		*++ptr = 0x00;
157 		buf_space--;
158 	    } else
159 		unused--;
160 	    break;
161 
162 	case 1:
163 	    /* one one-bit should be added to the buffer */
164 	    if (unused == 1) {
165 		*ptr = *ptr | 1;
166 		unused = 8;
167 		*++ptr = 0x00;
168 		buf_space--;
169 	    } else {
170 		*ptr = *ptr | (1 << (unused - 1));
171 		unused--;
172 	    }
173 	    break;
174 
175 	case 2:
176 	    /* align buffer to end of byte */
177 	    if (unused != 8) {
178 		*++ptr = 0x00;
179 		buf_space--;
180 		unused = 8;
181 	    }
182 	    break;
183 
184 	case 10:
185 	    /* next byte in in_buf tells how many bits in the second next
186 	     byte that will be used */
187 	    /* The leftmost unused bits in the value byte are supposed to be
188 	     zero bits */
189 	    no_bits = (int) *(++in_ptr);
190 	    val = *(++in_ptr);
191 	    counter -= 2;
192 	    if ((ret = per_insert_least_sign_bits(no_bits, val, &ptr, &unused))
193 		    == ASN1_ERROR
194 		    )
195 		return ASN1_ERROR;
196 	    buf_space -= ret;
197 	    break;
198 
199 	case 20:
200 	    /* in this case the next value in_ptr points at holds the number
201 	     of following bytes that holds the value that will be inserted
202 	     in the completed buffer */
203 	    no_bytes = (int) *(++in_ptr);
204 	    counter -= (no_bytes + 1);
205 	    if ((counter < 0)
206 		    || (ret = per_insert_octets(no_bytes, &in_ptr, &ptr,
207 			    &unused)) == ASN1_ERROR
208 		    )
209 		return ASN1_ERROR;
210 	    buf_space -= ret;
211 	    break;
212 
213 	case 21:
214 	    /* in this case the next two bytes in_ptr points at holds the number
215 	     of following bytes that holds the value that will be inserted
216 	     in the completed buffer */
217 	    no_bytes = (int) *(++in_ptr);
218 	    no_bytes = no_bytes << 8;
219 	    no_bytes = no_bytes | (int) *(++in_ptr);
220 	    counter -= (2 + no_bytes);
221 	    if ((counter < 0)
222 		    || (ret = per_insert_octets(no_bytes, &in_ptr, &ptr,
223 			    &unused)) == ASN1_ERROR
224 		    )
225 		return ASN1_ERROR;
226 	    buf_space -= ret;
227 	    break;
228 
229 	case 30:
230 	    /* If we call the following bytes, in the buffer in_ptr points at,
231 	     By1,By2,Rest then Rest is the value that will be transfered to
232 	     the completed buffer. By1 tells how many of the rightmost bits in
233 	     Rest that should not be used. By2 is the length of Rest in bytes.*/
234 	    in_unused = (int) *(++in_ptr);
235 	    no_bytes = (int) *(++in_ptr);
236 	    counter -= (2 + no_bytes);
237 	    ret = -4711;
238 	    if ((counter < 0)
239 		    || (ret = per_insert_octets_except_unused(no_bytes, &in_ptr,
240 			    &ptr, &unused, in_unused)) == ASN1_ERROR
241 		    )
242 		return ASN1_ERROR;
243 	    buf_space -= ret;
244 	    break;
245 
246 	case 31:
247 	    /* If we call the following bytes, in the buffer in_ptr points at,
248 	     By1,By2,By3,Rest then Rest is the value that will be transfered to
249 	     the completed buffer. By1 tells how many of the rightmost bits in
250 	     Rest that should not be used. By2 and By3 is the length of
251 	     Rest in bytes.*/
252 	    in_unused = (int) *(++in_ptr);
253 	    no_bytes = (int) *(++in_ptr);
254 	    no_bytes = no_bytes << 8;
255 	    no_bytes = no_bytes | (int) *(++in_ptr);
256 	    counter -= (3 + no_bytes);
257 	    if ((counter < 0)
258 		    || (ret = per_insert_octets_except_unused(no_bytes, &in_ptr,
259 			    &ptr, &unused, in_unused)) == ASN1_ERROR
260 		    )
261 		return ASN1_ERROR;
262 	    buf_space -= ret;
263 	    break;
264 
265 	case 40:
266 	    /* This case implies that next byte,By1,(..,By1,By2,Bin,...)
267 	     is the desired length of the completed value, maybe needs
268 	     padding zero bits or removal of trailing zero bits from Bin.
269 	     By2 is the length of Bin and Bin is the value that will be
270 	     put into the completed buffer. Each byte in Bin has the value
271 	     1 or 0.*/
272 	    desired_len = (int) *(++in_ptr);
273 	    no_bytes = (int) *(++in_ptr);
274 
275 	    /* This is the algorithm for need of memory reallocation:
276 	     Only when padding (cases 40 - 43,45 - 47) more memory may be
277 	     used than allocated. Therefore one has to keep track of how
278 	     much of the allocated memory that has been saved, i.e. the
279 	     difference between the number of parsed bytes of the input buffer
280 	     and the number of used bytes of the output buffer.
281 	     If saved memory is less than needed for the padding then we
282 	     need more memory. */
283 	    saved_mem = buf_space - counter;
284 	    pad_bits = desired_len - no_bytes - unused;
285 	    needed = (pad_bits > 0) ? CEIL(pad_bits,8) : 0;
286 	    if (saved_mem < needed) {
287 		/* Have to allocate more memory */
288 		buf_size += needed;
289 		buf_space += needed;
290 		if (per_realloc_memory(out_binary, buf_size, &ptr) == ASN1_ERROR
291 		)
292 		    return ASN1_ERROR;
293 	    }
294 
295 	    counter -= (2 + no_bytes);
296 	    if ((counter < 0)
297 		    || (ret = per_insert_octets_as_bits_exact_len(desired_len,
298 			    no_bytes, &in_ptr, &ptr, &unused)) == ASN1_ERROR
299 		    )
300 		return ASN1_ERROR;
301 	    buf_space -= ret;
302 	    break;
303 
304 	case 41:
305 	    /* Same as case 40 apart from By2, the length of Bin, which is in
306 	     two bytes*/
307 	    desired_len = (int) *(++in_ptr);
308 	    no_bytes = (int) *(++in_ptr);
309 	    no_bytes = no_bytes << 8;
310 	    no_bytes = no_bytes | (int) *(++in_ptr);
311 
312 	    saved_mem = buf_space - counter;
313 	    needed = CEIL((desired_len-unused),8) - no_bytes;
314 	    if (saved_mem < needed) {
315 		/* Have to allocate more memory */
316 		buf_size += needed;
317 		buf_space += needed;
318 		if (per_realloc_memory(out_binary, buf_size, &ptr) == ASN1_ERROR
319 		)
320 		    return ASN1_ERROR;
321 	    }
322 
323 	    counter -= (3 + no_bytes);
324 	    if ((counter < 0)
325 		    || (ret = per_insert_octets_as_bits_exact_len(desired_len,
326 			    no_bytes, &in_ptr, &ptr, &unused)) == ASN1_ERROR
327 		    )
328 		return ASN1_ERROR;
329 	    buf_space -= ret;
330 	    break;
331 
332 	case 42:
333 	    /* Same as case 40 apart from By1, the desired length, which is in
334 	     two bytes*/
335 	    desired_len = (int) *(++in_ptr);
336 	    desired_len = desired_len << 8;
337 	    desired_len = desired_len | (int) *(++in_ptr);
338 	    no_bytes = (int) *(++in_ptr);
339 
340 	    saved_mem = buf_space - counter;
341 	    needed = CEIL((desired_len-unused),8) - no_bytes;
342 	    if (saved_mem < needed) {
343 		/* Have to allocate more memory */
344 		buf_size += needed;
345 		buf_space += needed;
346 		if (per_realloc_memory(out_binary, buf_size, &ptr) == ASN1_ERROR
347 		)
348 		    return ASN1_ERROR;
349 	    }
350 
351 	    counter -= (3 + no_bytes);
352 	    if ((counter < 0)
353 		    || (ret = per_insert_octets_as_bits_exact_len(desired_len,
354 			    no_bytes, &in_ptr, &ptr, &unused)) == ASN1_ERROR
355 		    )
356 		return ASN1_ERROR;
357 	    buf_space -= ret;
358 	    break;
359 
360 	case 43:
361 	    /* Same as case 40 apart from By1 and By2, the desired length and
362 	     the length of Bin, which are in two bytes each. */
363 	    desired_len = (int) *(++in_ptr);
364 	    desired_len = desired_len << 8;
365 	    desired_len = desired_len | (int) *(++in_ptr);
366 	    no_bytes = (int) *(++in_ptr);
367 	    no_bytes = no_bytes << 8;
368 	    no_bytes = no_bytes | (int) *(++in_ptr);
369 
370 	    saved_mem = buf_space - counter;
371 	    needed = CEIL((desired_len-unused),8) - no_bytes;
372 	    if (saved_mem < needed) {
373 		/* Have to allocate more memory */
374 		buf_size += needed;
375 		buf_space += needed;
376 		if (per_realloc_memory(out_binary, buf_size, &ptr) == ASN1_ERROR
377 		)
378 		    return ASN1_ERROR;
379 	    }
380 
381 	    counter -= (4 + no_bytes);
382 	    if ((counter < 0)
383 		    || (ret = per_insert_octets_as_bits_exact_len(desired_len,
384 			    no_bytes, &in_ptr, &ptr, &unused)) == ASN1_ERROR
385 		    )
386 		return ASN1_ERROR;
387 	    buf_space -= ret;
388 	    break;
389 
390 	case 45:
391 	    /* This case assumes that the following bytes in the incoming buffer
392 	     (called By1,By2,Bin) is By1, which is the number of bits (n) that
393 	     will be inserted in the completed buffer. By2 is the number of
394 	     bytes in Bin. Each bit in the buffer Bin should be inserted from
395 	     the leftmost until the nth.*/
396 	    desired_len = (int) *(++in_ptr);
397 	    no_bytes = (int) *(++in_ptr);
398 
399 	    saved_mem = buf_space - counter;
400 	    needed = CEIL((desired_len-unused),8) - no_bytes;
401 	    if (saved_mem < needed) {
402 		/* Have to allocate more memory */
403 		buf_size += needed;
404 		buf_space += needed;
405 		if (per_realloc_memory(out_binary, buf_size, &ptr) == ASN1_ERROR
406 		)
407 		    return ASN1_ERROR;
408 	    }
409 
410 	    counter -= (2 + no_bytes);
411 
412 	    if ((counter < 0)
413 		    || (ret = per_insert_bits_as_bits(desired_len, no_bytes,
414 			    &in_ptr, &ptr, &unused)) == ASN1_ERROR
415 		    )
416 		return ASN1_ERROR;
417 	    buf_space -= ret;
418 	    break;
419 
420 	case 46:
421 	    /* Same as case 45 apart from By1, the desired length, which is
422 	     in two bytes. */
423 	    desired_len = (int) *(++in_ptr);
424 	    desired_len = desired_len << 8;
425 	    desired_len = desired_len | (int) *(++in_ptr);
426 	    no_bytes = (int) *(++in_ptr);
427 
428 	    saved_mem = buf_space - counter;
429 	    needed = CEIL((desired_len-unused),8) - no_bytes;
430 	    if (saved_mem < needed) {
431 		/* Have to allocate more memory */
432 		buf_size += needed;
433 		buf_space += needed;
434 		if (per_realloc_memory(out_binary, buf_size, &ptr) == ASN1_ERROR
435 		)
436 		    return ASN1_ERROR;
437 	    }
438 
439 	    counter -= (3 + no_bytes);
440 	    if ((counter < 0)
441 		    || (ret = per_insert_bits_as_bits(desired_len, no_bytes,
442 			    &in_ptr, &ptr, &unused)) == ASN1_ERROR
443 		    )
444 		return ASN1_ERROR;
445 	    buf_space -= ret;
446 	    break;
447 
448 	case 47:
449 	    /* Same as case 45 apart from By1 and By2, the desired length
450 	     and the length of Bin, which are in two bytes each. */
451 	    desired_len = (int) *(++in_ptr);
452 	    desired_len = desired_len << 8;
453 	    desired_len = desired_len | (int) *(++in_ptr);
454 	    no_bytes = (int) *(++in_ptr);
455 	    no_bytes = no_bytes << 8;
456 	    no_bytes = no_bytes | (int) *(++in_ptr);
457 
458 	    saved_mem = buf_space - counter;
459 	    needed = CEIL((desired_len-unused),8) - no_bytes;
460 	    if (saved_mem < needed) {
461 		/* Have to allocate more memory */
462 		buf_size += needed;
463 		buf_space += needed;
464 		if (per_realloc_memory(out_binary, buf_size, &ptr) == ASN1_ERROR
465 		)
466 		    return ASN1_ERROR;
467 	    }
468 
469 	    counter -= (4 + no_bytes);
470 	    if ((counter < 0)
471 		    || (ret = per_insert_bits_as_bits(desired_len, no_bytes,
472 			    &in_ptr, &ptr, &unused)) == ASN1_ERROR
473 		    )
474 		return ASN1_ERROR;
475 	    buf_space -= ret;
476 	    break;
477 
478 	default:
479 	    return ASN1_ERROR;
480 	}
481 	in_ptr++;
482     }
483     /* The returned buffer must be at least one byte and
484      it must be octet aligned */
485     if ((unused == 8) && (ptr != out_binary->data))
486 	return (ptr - out_binary->data);
487     else {
488 	ptr++; /* octet align buffer */
489 	return (ptr - out_binary->data);
490     }
491 }
492 
per_realloc_memory(ErlNifBinary * binary,int amount,unsigned char ** ptr)493 static int per_realloc_memory(ErlNifBinary *binary, int amount, unsigned char **ptr) {
494 
495     int i = *ptr - binary->data;
496 
497     if (!enif_realloc_binary(binary, amount)) {
498 	/*error handling due to memory allocation failure */
499 	return ASN1_ERROR;
500     } else {
501 	*ptr = binary->data + i;
502     }
503     return ASN1_OK;
504 }
505 
per_insert_most_sign_bits(int no_bits,unsigned char val,unsigned char ** output_ptr,int * unused)506 static int per_insert_most_sign_bits(int no_bits, unsigned char val,
507 	unsigned char **output_ptr, int *unused) {
508     unsigned char *ptr = *output_ptr;
509 
510     if (no_bits < *unused) {
511 	*ptr = *ptr | (val >> (8 - *unused));
512 	*unused -= no_bits;
513     } else if (no_bits == *unused) {
514 	*ptr = *ptr | (val >> (8 - *unused));
515 	*unused = 8;
516 	*++ptr = 0x00;
517     } else {
518 	*ptr = *ptr | (val >> (8 - *unused));
519 	*++ptr = 0x00;
520 	*ptr = *ptr | (val << *unused);
521 	*unused = 8 - (no_bits - *unused);
522     }
523     *output_ptr = ptr;
524     return ASN1_OK;
525 }
526 
per_insert_least_sign_bits(int no_bits,unsigned char val,unsigned char ** output_ptr,int * unused)527 static int per_insert_least_sign_bits(int no_bits, unsigned char val,
528 	unsigned char **output_ptr, int *unused) {
529     unsigned char *ptr = *output_ptr;
530     int ret = 0;
531 
532     if (no_bits < *unused) {
533 	*ptr = *ptr | (val << (*unused - no_bits));
534 	*unused -= no_bits;
535     } else if (no_bits == *unused) {
536 	*ptr = *ptr | val;
537 	*unused = 8;
538 	*++ptr = 0x00;
539 	ret++;
540     } else {
541 	/* first in the begun byte in the completed buffer insert
542 	 so many bits that fit, then insert the rest in next byte.*/
543 	*ptr = *ptr | (val >> (no_bits - *unused));
544 	*++ptr = 0x00;
545 	ret++;
546 	*ptr = *ptr | (val << (8 - (no_bits - *unused)));
547 	*unused = 8 - (no_bits - *unused);
548     }
549     *output_ptr = ptr;
550     return ret;
551 }
552 
553 /* per_pad_bits adds no_bits bits in the buffer that output_ptr
554  points at.
555  */
per_pad_bits(int no_bits,unsigned char ** output_ptr,int * unused)556 static int per_pad_bits(int no_bits, unsigned char **output_ptr, int *unused) {
557     unsigned char *ptr = *output_ptr;
558     int ret = 0;
559 
560     while (no_bits > 0) {
561 	if (*unused == 1) {
562 	    *unused = 8;
563 	    *++ptr = 0x00;
564 	    ret++;
565 	} else
566 	    (*unused)--;
567 	no_bits--;
568     }
569     *output_ptr = ptr;
570     return ret;
571 }
572 
573 /* insert_bits_as_bits removes no_bytes bytes from the buffer that in_ptr
574  points at and takes the desired_no leftmost bits from those removed
575  bytes and inserts them in the buffer(output buffer) that ptr points at.
576  The unused parameter tells how many bits that are not set in the
577  actual byte in the output buffer. If desired_no is more bits than the
578  input buffer has in no_bytes bytes, then zero bits is padded.*/
per_insert_bits_as_bits(int desired_no,int no_bytes,unsigned char ** input_ptr,unsigned char ** output_ptr,int * unused)579 static int per_insert_bits_as_bits(int desired_no, int no_bytes,
580 	unsigned char **input_ptr, unsigned char **output_ptr, int *unused) {
581     unsigned char *in_ptr = *input_ptr;
582     unsigned char val;
583     int no_bits, ret;
584 
585     if (desired_no == (no_bytes * 8)) {
586 	if (per_insert_octets_unaligned(no_bytes, &in_ptr, output_ptr, *unused)
587 		== ASN1_ERROR
588 		)
589 	    return ASN1_ERROR;
590 	ret = no_bytes;
591     } else if (desired_no < (no_bytes * 8)) {
592 	/*     printf("per_insert_bits_as_bits 1\n\r"); */
593 	if (per_insert_octets_unaligned(desired_no / 8, &in_ptr, output_ptr,
594 		*unused) == ASN1_ERROR
595 	)
596 	    return ASN1_ERROR;
597 	/*     printf("per_insert_bits_as_bits 2\n\r"); */
598 	val = *++in_ptr;
599 	/*     printf("val = %d\n\r",(int)val); */
600 	no_bits = desired_no % 8;
601 	/*     printf("no_bits = %d\n\r",no_bits); */
602 	per_insert_most_sign_bits(no_bits, val, output_ptr, unused);
603 	ret = CEIL(desired_no,8);
604     } else {
605 	if (per_insert_octets_unaligned(no_bytes, &in_ptr, output_ptr, *unused)
606 		== ASN1_ERROR
607 		)
608 	    return ASN1_ERROR;
609 	per_pad_bits(desired_no - (no_bytes * 8), output_ptr, unused);
610 	ret = CEIL(desired_no,8);
611 	/*     printf("ret = %d\n\r",ret); */
612     }
613     /*   printf("*unused = %d\n\r",*unused); */
614     *input_ptr = in_ptr;
615     return ret;
616 }
617 
618 /* per_insert_octets_as_bits_exact_len */
per_insert_octets_as_bits_exact_len(int desired_len,int in_buff_len,unsigned char ** in_ptr,unsigned char ** ptr,int * unused)619 static int per_insert_octets_as_bits_exact_len(int desired_len, int in_buff_len,
620 	unsigned char **in_ptr, unsigned char **ptr, int *unused) {
621     int ret = 0;
622     int ret2 = 0;
623 
624     if (desired_len == in_buff_len) {
625 	if ((ret = per_insert_octets_as_bits(in_buff_len, in_ptr, ptr, unused))
626 		== ASN1_ERROR
627 		)
628 	    return ASN1_ERROR;
629     } else if (desired_len > in_buff_len) {
630 	if ((ret = per_insert_octets_as_bits(in_buff_len, in_ptr, ptr, unused))
631 		== ASN1_ERROR
632 		)
633 	    return ASN1_ERROR;
634 	/* now pad with zero bits */
635 	/*     printf("~npad_bits: called with %d bits padding~n~n~r",desired_len - in_buff_len); */
636 	if ((ret2 = per_pad_bits(desired_len - in_buff_len, ptr, unused))
637 		== ASN1_ERROR
638 		)
639 	    return ASN1_ERROR;
640     } else {/* desired_len < no_bits */
641 	if ((ret = per_insert_octets_as_bits(desired_len, in_ptr, ptr, unused))
642 		== ASN1_ERROR
643 		)
644 	    return ASN1_ERROR;
645 	/* now remove no_bits - desired_len bytes from in buffer */
646 	*in_ptr += (in_buff_len - desired_len);
647     }
648     return (ret + ret2);
649 }
650 
651 /* insert_octets_as_bits takes no_bytes bytes from the buffer that input_ptr
652  points at and inserts the least significant bit of it in the buffer that
653  output_ptr points at. Each byte in the input buffer must be 1 or 0
654  otherwise the function returns ASN1_ERROR. The output buffer is concatenated
655  without alignment.
656  */
per_insert_octets_as_bits(int no_bytes,unsigned char ** input_ptr,unsigned char ** output_ptr,int * unused)657 static int per_insert_octets_as_bits(int no_bytes, unsigned char **input_ptr,
658 	unsigned char **output_ptr, int *unused) {
659     unsigned char *in_ptr = *input_ptr;
660     unsigned char *ptr = *output_ptr;
661     int used_bits = 8 - *unused;
662 
663     while (no_bytes > 0) {
664 	switch (*++in_ptr) {
665 	case 0:
666 	    if (*unused == 1) {
667 		*unused = 8;
668 		*++ptr = 0x00;
669 	    } else
670 		(*unused)--;
671 	    break;
672 	case 1:
673 	    if (*unused == 1) {
674 		*ptr = *ptr | 1;
675 		*unused = 8;
676 		*++ptr = 0x00;
677 	    } else {
678 		*ptr = *ptr | (1 << (*unused - 1));
679 		(*unused)--;
680 	    }
681 	    break;
682 	default:
683 	    return ASN1_ERROR;
684 	}
685 	no_bytes--;
686     }
687     *input_ptr = in_ptr;
688     *output_ptr = ptr;
689     return ((used_bits + no_bytes) / 8); /*return number of new bytes
690      in completed buffer */
691 }
692 
693 /* insert_octets inserts bytes from the input buffer, *input_ptr,
694  into the output buffer, *output_ptr. Before the first byte is
695  inserted the input buffer is aligned.
696  */
per_insert_octets(int no_bytes,unsigned char ** input_ptr,unsigned char ** output_ptr,int * unused)697 static int per_insert_octets(int no_bytes, unsigned char **input_ptr,
698 	unsigned char **output_ptr, int *unused) {
699     unsigned char *in_ptr = *input_ptr;
700     unsigned char *ptr = *output_ptr;
701     int ret = 0;
702 
703     if (*unused != 8) {/* must align before octets are added */
704 	*++ptr = 0x00;
705 	ret++;
706 	*unused = 8;
707     }
708     while (no_bytes > 0) {
709 	*ptr = *(++in_ptr);
710 	*++ptr = 0x00;
711 	/*      *unused = *unused - 1; */
712 	no_bytes--;
713     }
714     *input_ptr = in_ptr;
715     *output_ptr = ptr;
716     return (ret + no_bytes);
717 }
718 
719 /* per_insert_octets_unaligned inserts bytes from the input buffer, *input_ptr,
720  into the output buffer, *output_ptr.No alignment is done.
721  */
per_insert_octets_unaligned(int no_bytes,unsigned char ** input_ptr,unsigned char ** output_ptr,int unused)722 static int per_insert_octets_unaligned(int no_bytes, unsigned char **input_ptr,
723 	unsigned char **output_ptr, int unused) {
724     unsigned char *in_ptr = *input_ptr;
725     unsigned char *ptr = *output_ptr;
726     int n = no_bytes;
727     unsigned char val;
728 
729     while (n > 0) {
730 	if (unused == 8) {
731 	    *ptr = *++in_ptr;
732 	    *++ptr = 0x00;
733 	} else {
734 	    val = *++in_ptr;
735 	    *ptr = *ptr | val >> (8 - unused);
736 	    *++ptr = 0x00;
737 	    *ptr = val << unused;
738 	}
739 	n--;
740     }
741     *input_ptr = in_ptr;
742     *output_ptr = ptr;
743     return no_bytes;
744 }
745 
per_insert_octets_except_unused(int no_bytes,unsigned char ** input_ptr,unsigned char ** output_ptr,int * unused,int in_unused)746 static int per_insert_octets_except_unused(int no_bytes, unsigned char **input_ptr,
747 	unsigned char **output_ptr, int *unused, int in_unused) {
748     unsigned char *in_ptr = *input_ptr;
749     unsigned char *ptr = *output_ptr;
750     int val, no_bits;
751     int ret = 0;
752 
753     if (in_unused == 0) {
754 	if ((ret = per_insert_octets_unaligned(no_bytes, &in_ptr, &ptr, *unused))
755 		== ASN1_ERROR
756 		)
757 	    return ASN1_ERROR;
758     } else {
759 	if ((ret = per_insert_octets_unaligned(no_bytes - 1, &in_ptr, &ptr, *unused))
760 		!= ASN1_ERROR) {
761 	    val = (int) *(++in_ptr);
762 	    no_bits = 8 - in_unused;
763 	    /* no_bits is always less than *unused since the buffer is
764 	     octet aligned after insert:octets call, so the following
765 	     if clasuse is obsolete I think */
766 	    if (no_bits < *unused) {
767 		*ptr = *ptr | (val >> (8 - *unused));
768 		*unused = *unused - no_bits;
769 	    } else if (no_bits == *unused) {
770 		*ptr = *ptr | (val >> (8 - *unused));
771 		*++ptr = 0x00;
772 		ret++;
773 		*unused = 8;
774 	    } else {
775 		*ptr = *ptr | (val >> (8 - *unused));
776 		*++ptr = 0x00;
777 		ret++;
778 		*ptr = *ptr | (val << *unused);
779 		*unused = 8 - (no_bits - *unused);
780 	    }
781 	} else
782 	    return ASN1_ERROR;
783     }
784     *input_ptr = in_ptr;
785     *output_ptr = ptr;
786     return ret;
787 }
788 
789 /*
790  *
791  * This section defines functionality for the partial decode of a
792  * BER encoded message
793  *
794  */
795 
796 /*
797  * int decode(ErlNifEnv* env, ERL_NIF_TERM *term, unsigned char *in_buf,
798  int in_buf_len, unsigned int *err_pos)
799  * term is a pointer to the term which is to be returned to erlang
800  * in_buf is a pointer into the buffer of incoming bytes.
801  * in_buf_len is the length of the incoming buffer.
802  * The function reads the bytes in the incoming buffer and structures
803  * it in a nested way as Erlang terms. The buffer contains data in the
804  * order tag - length - value. Tag, length and value has the following
805  * format:
806  * A tag is normally one byte but may be of any length, if the tag number
807  * is greater than 30. +----------+
808  *		       |CL|C|NNNNN|
809  * 		       +----------+
810  * If NNNNN is 31 then will the 7 l.s.b of each of the following tag number
811  * bytes contain the tag number. Each tag number byte that is not the last one
812  * has the m.s.b. set to 1.
813  * The length can be short definite length (sdl), long definite length (ldl)
814  * or indefinite length (il).
815  * sdl: +---------+ the L bits is the length
816  *	|0|LLLLLLL|
817  *	+---------+
818  * ldl:	+---------+ +---------+ +---------+     +-----------+
819  *	|1|lllllll| |first len| |	  |     |the Nth len|
820  *	+---------+ +---------+ +---------+ ... +-----------+
821  *    	The first byte tells how many len octets will follow, max 127
822  * il:  +---------+ +----------------------+ +--------+ +--------+
823  *	|1|0000000| |content octets (Value)| |00000000| |00000000|
824  *	+---------+ +----------------------+ +--------+ +--------+
825  *	The value octets are preceded by one octet and followed by two
826  *	exactly as above. The value must be some tag-length-value encoding.
827  *
828  * The function returns a value in Erlang nif term format:
829  * {{TagNo,Value},Rest}
830  * TagNo is an integer ((CL bsl 16) + tag number) which limits the tag number
831  * to 65535.
832  * Value is a binary if the C bit in tag was unset, otherwise (if tag was
833  * constructed) Value is a list, List.
834  * List is like: [{TagNo,Value},{TagNo,Value},...]
835  * Rest is a binary, i.e. the undecoded part of the buffer. Most often Rest
836  * is the empty binary.
837  * If some error occured during the decoding of the in_buf an error is returned.
838  */
ber_decode_begin(ErlNifEnv * env,ERL_NIF_TERM * term,unsigned char * in_buf,int in_buf_len,unsigned int * err_pos)839 static int ber_decode_begin(ErlNifEnv* env, ERL_NIF_TERM *term, unsigned char *in_buf,
840 	int in_buf_len, unsigned int *err_pos) {
841     int maybe_ret;
842     int ib_index = 0;
843     unsigned char *rest_data;
844     ERL_NIF_TERM decoded_term, rest;
845 
846     if ((maybe_ret = ber_decode(env, &decoded_term, in_buf, &ib_index,
847 	    in_buf_len)) <= ASN1_ERROR)
848     {
849 	*err_pos = ib_index;
850 	return maybe_ret;
851     };
852 
853     // The remaining binary after one ASN1 segment has been decoded
854     rest_data = enif_make_new_binary(env, in_buf_len - ib_index, &rest);
855     memcpy(rest_data, in_buf+ib_index, in_buf_len - ib_index);
856 
857     *term = enif_make_tuple2(env, decoded_term, rest);
858     return ASN1_OK;
859 }
860 
ber_decode(ErlNifEnv * env,ERL_NIF_TERM * term,unsigned char * in_buf,int * ib_index,int in_buf_len)861 static int ber_decode(ErlNifEnv* env, ERL_NIF_TERM *term, unsigned char *in_buf,
862 	int *ib_index, int in_buf_len) {
863     int maybe_ret;
864     int form;
865     ERL_NIF_TERM tag, value;
866 
867     /*buffer must hold at least two bytes*/
868     if ((*ib_index + 2) > in_buf_len)
869 	return ASN1_VALUE_ERROR;
870     /* "{{TagNo," */
871     if ((form = ber_decode_tag(env, &tag, in_buf, in_buf_len, ib_index))
872 	    <= ASN1_ERROR
873 	    )
874 	return form; /* 5 bytes */
875     if (*ib_index >= in_buf_len) {
876 	return ASN1_TAG_ERROR;
877     }
878     /* buffer must hold at least one byte (0 as length and nothing as
879      value) */
880     /* "{{TagNo,Value}," */
881     if ((maybe_ret = ber_decode_value(env, &value, in_buf, ib_index, form,
882 	    in_buf_len)) <= ASN1_ERROR
883     )
884 	return maybe_ret; /* at least 5 bytes */
885     *term = enif_make_tuple2(env, tag, value);
886     return ASN1_OK;
887 }
888 
889 /*
890  * decode_tag decodes the BER encoded tag in in_buf and creates an
891  * nif term tag
892  */
ber_decode_tag(ErlNifEnv * env,ERL_NIF_TERM * tag,unsigned char * in_buf,int in_buf_len,int * ib_index)893 static int ber_decode_tag(ErlNifEnv* env, ERL_NIF_TERM *tag, unsigned char *in_buf,
894 	int in_buf_len, int *ib_index) {
895     int tag_no, tmp_tag, form;
896 
897     /* first get the class of tag and bit shift left 16*/
898     tag_no = ((MASK(in_buf[*ib_index],ASN1_CLASS)) << 10);
899 
900     form = (MASK(in_buf[*ib_index],ASN1_FORM));
901 
902     /* then get the tag number */
903     if ((tmp_tag = (int) INVMASK(in_buf[*ib_index],ASN1_CLASSFORM)) < 31) {
904 	*tag = enif_make_uint(env, tag_no | tmp_tag);
905 	(*ib_index)++;
906     } else {
907 	/* should check that at least three bytes are left in
908 	 in-buffer,at least two tag byte and at least one length byte */
909 	if ((*ib_index + 3) > in_buf_len)
910 	    return ASN1_VALUE_ERROR;
911 	(*ib_index)++;
912 	/*
913          * The tag is in the following bytes in in_buf as:
914          *
915          *  1ttttttt 0ttttttt
916          *
917          * or
918          *
919          *  0ttttttt
920          *
921          * where the t-bits is the tag number. If the tag does not
922          * fit in two tag bytes (16K), return an error.
923          */
924 	if ((tmp_tag = (int) in_buf[*ib_index]) >= 128) {
925 	    tag_no = tag_no | (MASK(tmp_tag,ASN1_LONG_TAG) << 7);
926 	    (*ib_index)++;
927 	}
928         tmp_tag = (int) in_buf[*ib_index];
929 	if (tmp_tag >= 128) {
930 	    return ASN1_TAG_ERROR; /* tag number > 16K */
931         }
932 	tag_no = tag_no | tmp_tag;
933 	(*ib_index)++;
934 	*tag = enif_make_uint(env, tag_no);
935     }
936     return form;
937 }
938 
939 /*
940  * ber_decode_value decodes the BER encoded length and value fields in the
941  * in_buf and puts the value part in the decode_buf as an Erlang
942  * nif term into value
943  */
ber_decode_value(ErlNifEnv * env,ERL_NIF_TERM * value,unsigned char * in_buf,int * ib_index,int form,int in_buf_len)944 static int ber_decode_value(ErlNifEnv* env, ERL_NIF_TERM *value, unsigned char *in_buf,
945 	int *ib_index, int form, int in_buf_len) {
946     int maybe_ret;
947     unsigned int len = 0;
948     unsigned int lenoflen = 0;
949     unsigned char *tmp_out_buff;
950     ERL_NIF_TERM term = 0, curr_head = 0;
951 
952     /* Recursion depth limitation, borrow a signed int: maybe_ret */
953     maybe_ret = (int) (ErlNifSInt) ((char *)value - (char *)ib_index);
954     maybe_ret = maybe_ret < 0 ? -maybe_ret : maybe_ret;
955     if (maybe_ret >= sizeof(void *) * 8192) /* 8 k pointer words */
956         return ASN1_ERROR;
957 
958     if (((in_buf[*ib_index]) & 0x80) == ASN1_SHORT_DEFINITE_LENGTH) {
959 	len = in_buf[*ib_index];
960     } else if (in_buf[*ib_index] == ASN1_INDEFINITE_LENGTH) {
961 	(*ib_index)++;
962 	curr_head = enif_make_list(env, 0);
963 	if (*ib_index+1 >= in_buf_len || form == ASN1_PRIMITIVE) {
964 	    return ASN1_INDEF_LEN_ERROR;
965 	}
966 	while (!(in_buf[*ib_index] == 0 && in_buf[*ib_index + 1] == 0)) {
967 	    maybe_ret = ber_decode(env, &term, in_buf, ib_index, in_buf_len);
968 	    if (maybe_ret <= ASN1_ERROR) {
969 		return maybe_ret;
970 	    }
971 	    curr_head = enif_make_list_cell(env, term, curr_head);
972 	    if (*ib_index+1 >= in_buf_len) {
973 		return ASN1_INDEF_LEN_ERROR;
974 	    }
975 	}
976 	enif_make_reverse_list(env, curr_head, value);
977 	(*ib_index) += 2; /* skip the indefinite length end bytes */
978 	return ASN1_OK;
979     } else /* long definite length */{
980 	lenoflen = (in_buf[*ib_index] & 0x7f); /*length of length */
981 	if (lenoflen > (in_buf_len - (*ib_index + 1)))
982 	    return ASN1_LEN_ERROR;
983 	len = 0;
984 	while (lenoflen--) {
985 	    (*ib_index)++;
986 	    if (!(len < (1 << (sizeof(len) - 1) * 8)))
987 		return ASN1_LEN_ERROR; /* length does not fit in 32 bits */
988 	    len = (len << 8) + in_buf[*ib_index];
989 	}
990     }
991     if (len > (in_buf_len - (*ib_index + 1)))
992 	return ASN1_VALUE_ERROR;
993     (*ib_index)++;
994     if (form == ASN1_CONSTRUCTED) {
995 	int end_index = *ib_index + len;
996 	if (end_index > in_buf_len)
997 	    return ASN1_LEN_ERROR;
998 	curr_head = enif_make_list(env, 0);
999 	while (*ib_index < end_index) {
1000 
1001 	    if ((maybe_ret = ber_decode(env, &term, in_buf, ib_index,
1002                    end_index )) <= ASN1_ERROR
1003 	    )
1004 		return maybe_ret;
1005 	    curr_head = enif_make_list_cell(env, term, curr_head);
1006 	}
1007 	enif_make_reverse_list(env, curr_head, value);
1008     } else {
1009 	if ((*ib_index + len) > in_buf_len)
1010 	    return ASN1_LEN_ERROR;
1011 	tmp_out_buff = enif_make_new_binary(env, len, value);
1012 	memcpy(tmp_out_buff, in_buf + *ib_index, len);
1013 	*ib_index = *ib_index + len;
1014     }
1015     return ASN1_OK;
1016 }
1017 
1018 struct ber_encode_mem_chunk {
1019     mem_chunk_t *next;
1020     int length;
1021     char *top;
1022     char *curr;
1023 };
1024 
ber_encode(ErlNifEnv * env,ERL_NIF_TERM term,mem_chunk_t ** curr,unsigned int * count)1025 static int ber_encode(ErlNifEnv *env, ERL_NIF_TERM term, mem_chunk_t **curr, unsigned int *count) {
1026 
1027     const ERL_NIF_TERM *tv;
1028     unsigned int form;
1029     int arity;
1030 
1031     if (!enif_get_tuple(env, term, &arity, &tv))
1032 	return ASN1_ERROR;
1033 
1034     form = enif_is_list(env, tv[1]) ? ASN1_CONSTRUCTED : ASN1_PRIMITIVE;
1035 
1036     switch (form) {
1037     case ASN1_PRIMITIVE: {
1038 	ErlNifBinary value;
1039 	if (!enif_inspect_binary(env, tv[1], &value))
1040 	    return ASN1_ERROR;
1041 
1042 	if (ber_check_memory(curr, value.size))
1043 	    return ASN1_ERROR;
1044 	memcpy((*curr)->curr - value.size + 1, value.data, value.size);
1045 	(*curr)->curr -= value.size;
1046 	*count += value.size;
1047 
1048 	if (ber_encode_length(value.size, curr, count))
1049 	    return ASN1_ERROR;
1050 
1051 	break;
1052     }
1053     case ASN1_CONSTRUCTED: {
1054 	ERL_NIF_TERM head, tail;
1055 	unsigned int tmp_cnt;
1056 
1057 	if(!enif_make_reverse_list(env, tv[1], &head))
1058 	    return ASN1_ERROR;
1059 
1060 	if (!enif_get_list_cell(env, head, &head, &tail)) {
1061 	    if (enif_is_empty_list(env, tv[1])) {
1062 		*((*curr)->curr) = 0;
1063 		(*curr)->curr -= 1;
1064 		(*count)++;
1065 		break;
1066 	    } else
1067 		return ASN1_ERROR;
1068 	}
1069 
1070 	do {
1071 	    tmp_cnt = 0;
1072 	    if (ber_encode(env, head, curr, &tmp_cnt)) {
1073 		return ASN1_ERROR;
1074 	    }
1075 	    *count += tmp_cnt;
1076 	} while (enif_get_list_cell(env, tail, &head, &tail));
1077 
1078 	if (ber_check_memory(curr, *count)) {
1079 	    return ASN1_ERROR;
1080 	}
1081 
1082 	if (ber_encode_length(*count, curr, count)) {
1083 	    return ASN1_ERROR;
1084 	}
1085 
1086 	break;
1087     }
1088     }
1089 
1090     // We need atleast 5 bytes to encode the next tlv
1091     if (ber_check_memory(curr, 3))
1092 	return ASN1_ERROR;
1093 
1094     if (ber_encode_tag(env, tv[0], form, curr, count))
1095 	return ASN1_ERROR;
1096 
1097     return ASN1_OK;
1098 }
1099 
ber_encode_tag(ErlNifEnv * env,ERL_NIF_TERM tag,unsigned int form,mem_chunk_t ** curr,unsigned int * count)1100 static int ber_encode_tag(ErlNifEnv *env, ERL_NIF_TERM tag, unsigned int form,
1101 	mem_chunk_t **curr, unsigned int *count) {
1102     unsigned int class_tag_no, head_tag;
1103     if (!enif_get_uint(env, tag, &class_tag_no))
1104 	return ASN1_ERROR;
1105 
1106     head_tag = form | ((class_tag_no & 0x30000) >> 10);
1107     class_tag_no = class_tag_no & 0xFFFF;
1108 
1109     if (class_tag_no <= 30) {
1110 	*(*curr)->curr = head_tag | class_tag_no;
1111 	(*curr)->curr -= 1;
1112 	(*count)++;
1113 	return ASN1_OK;
1114     } else {
1115 	*(*curr)->curr = class_tag_no & 127;
1116 	class_tag_no = class_tag_no >> 7;
1117 	(*curr)->curr -= 1;
1118 	(*count)++;
1119 
1120 	while (class_tag_no > 0) {
1121 	    *(*curr)->curr = (class_tag_no & 127) | 0x80;
1122 	    class_tag_no >>= 7;
1123 	    (*curr)->curr -= 1;
1124 	    (*count)++;
1125 	}
1126 
1127 	*(*curr)->curr = head_tag | 0x1F;
1128 	(*curr)->curr -= 1;
1129 	(*count)++;
1130 
1131 	return ASN1_OK;
1132     }
1133 }
1134 
ber_encode_length(size_t size,mem_chunk_t ** curr,unsigned int * count)1135 static int ber_encode_length(size_t size, mem_chunk_t **curr, unsigned int *count) {
1136     if (size < 128) {
1137 	if (ber_check_memory(curr, 1u))
1138 	    return ASN1_ERROR;
1139 	*(*curr)->curr = size;
1140 	(*curr)->curr -= 1;
1141 	(*count)++;
1142     } else {
1143 	int chunks = 0;
1144 	if (ber_check_memory(curr, 8))
1145 	    return ASN1_ERROR;
1146 
1147 	while (size > 0)
1148 	{
1149 	    *(*curr)->curr = size & 0xFF;
1150 	    size >>= 8;
1151 	    (*curr)->curr -= 1;
1152 	    (*count)++;
1153 	    chunks++;
1154 	}
1155 
1156 	*(*curr)->curr = chunks | 0x80;
1157 	(*curr)->curr -= 1;
1158 	(*count)++;
1159     }
1160     return ASN1_OK;
1161 }
1162 
ber_new_chunk(unsigned int length)1163 static mem_chunk_t *ber_new_chunk(unsigned int length) {
1164     mem_chunk_t *new = enif_alloc(sizeof(mem_chunk_t));
1165     if (new == NULL)
1166 	return NULL;
1167     new->next = NULL;
1168     new->top = enif_alloc(sizeof(char) * length);
1169     if (new->top == NULL) {
1170 	free(new);
1171 	return NULL;
1172     }
1173     new->curr = new->top + length - 1;
1174     new->length = length;
1175     return new;
1176 }
1177 
ber_free_chunks(mem_chunk_t * chunk)1178 static void ber_free_chunks(mem_chunk_t *chunk) {
1179     mem_chunk_t *curr, *next = chunk;
1180     while (next != NULL) {
1181 	curr = next;
1182 	next = curr->next;
1183 	enif_free(curr->top);
1184 	enif_free(curr);
1185     }
1186 }
1187 
ber_check_memory(mem_chunk_t ** curr,unsigned int needed)1188 static int ber_check_memory(mem_chunk_t **curr, unsigned int needed) {
1189     mem_chunk_t *new;
1190     if ((*curr)->curr-needed >= (*curr)->top)
1191 	return ASN1_OK;
1192 
1193     if ((new = ber_new_chunk((*curr)->length > needed ? (*curr)->length * 2 : (*curr)->length + needed)) == NULL)
1194 	return ASN1_ERROR;
1195     new->next = *curr;
1196     *curr = new;
1197     return ASN1_OK;
1198 }
1199 
encode_per_complete(ErlNifEnv * env,int argc,const ERL_NIF_TERM argv[])1200 static ERL_NIF_TERM encode_per_complete(ErlNifEnv* env, int argc,
1201 	const ERL_NIF_TERM argv[]) {
1202     ERL_NIF_TERM err_code;
1203     ErlNifBinary in_binary;
1204     ErlNifBinary out_binary;
1205     int complete_len;
1206     if (!enif_inspect_iolist_as_binary(env, argv[0], &in_binary))
1207 	return enif_make_badarg(env);
1208 
1209     if (!enif_alloc_binary(in_binary.size, &out_binary))
1210 	return enif_make_atom(env, "alloc_binary_failed");
1211 
1212     if (in_binary.size == 0)
1213 	return enif_make_binary(env, &out_binary);
1214 
1215     if ((complete_len = per_complete(&out_binary, in_binary.data,
1216 	    in_binary.size)) <= ASN1_ERROR) {
1217 	enif_release_binary(&out_binary);
1218 	if (complete_len == ASN1_ERROR
1219 	)
1220 	    err_code = enif_make_uint(env, '1');
1221 	else
1222 	    err_code = enif_make_uint(env, 0);
1223 	return enif_make_tuple2(env, enif_make_atom(env, "error"), err_code);
1224     }
1225     if (complete_len < out_binary.size)
1226 	enif_realloc_binary(&out_binary, complete_len);
1227 
1228     return enif_make_binary(env, &out_binary);
1229 }
1230 
1231 static ERL_NIF_TERM
make_ber_error_term(ErlNifEnv * env,unsigned int return_code,unsigned int err_pos)1232 make_ber_error_term(ErlNifEnv* env, unsigned int return_code,
1233 		    unsigned int err_pos)
1234 {
1235     ERL_NIF_TERM reason;
1236     ERL_NIF_TERM t;
1237 
1238     switch (return_code) {
1239     case ASN1_TAG_ERROR:
1240 	reason = enif_make_atom(env, "invalid_tag");
1241 	break;
1242     case ASN1_LEN_ERROR:
1243     case ASN1_INDEF_LEN_ERROR:
1244 	reason = enif_make_atom(env, "invalid_length");
1245 	break;
1246     case ASN1_VALUE_ERROR:
1247 	reason = enif_make_atom(env, "invalid_value");
1248 	break;
1249     default:
1250 	reason = enif_make_atom(env, "unknown");
1251 	break;
1252     }
1253     t = enif_make_tuple2(env, reason, enif_make_int(env, err_pos));
1254     return enif_make_tuple2(env, enif_make_atom(env, "error"), t);
1255 }
1256 
decode_ber_tlv_raw(ErlNifEnv * env,int argc,const ERL_NIF_TERM argv[])1257 static ERL_NIF_TERM decode_ber_tlv_raw(ErlNifEnv* env, int argc,
1258 	const ERL_NIF_TERM argv[]) {
1259     ErlNifBinary in_binary;
1260     ERL_NIF_TERM return_term;
1261     unsigned int err_pos = 0, return_code;
1262 
1263     if (!enif_inspect_iolist_as_binary(env, argv[0], &in_binary))
1264 	return enif_make_badarg(env);
1265 
1266     return_code = ber_decode_begin(env, &return_term, in_binary.data,
1267 				   in_binary.size, &err_pos);
1268     if (return_code != ASN1_OK) {
1269 	return make_ber_error_term(env, return_code, err_pos);
1270     }
1271     return return_term;
1272 }
1273 
encode_ber_tlv(ErlNifEnv * env,int argc,const ERL_NIF_TERM argv[])1274 static ERL_NIF_TERM encode_ber_tlv(ErlNifEnv* env, int argc,
1275 	const ERL_NIF_TERM argv[]) {
1276     ErlNifBinary out_binary;
1277     unsigned int length = 0, pos = 0;
1278     int encode_err;
1279     mem_chunk_t *curr, *top;
1280     ERL_NIF_TERM err_code;
1281 
1282     curr = ber_new_chunk(40);
1283     if (!curr) {
1284         err_code = enif_make_atom(env,"oom");
1285         goto err;
1286     }
1287 
1288     encode_err = ber_encode(env, argv[0], &curr, &length);
1289     if (encode_err <= ASN1_ERROR) {
1290 	err_code = enif_make_int(env, encode_err);
1291 	goto err;
1292     }
1293 
1294     if (!enif_alloc_binary(length, &out_binary)) {
1295         err_code = enif_make_atom(env,"oom");
1296         goto err;
1297     }
1298 
1299     top = curr;
1300 
1301     while (curr != NULL) {
1302 	length = curr->length - (curr->curr-curr->top) -1;
1303 	if (length > 0)
1304 	    memcpy(out_binary.data + pos, curr->curr+1, length);
1305 	pos += length;
1306 	curr = curr->next;
1307     }
1308 
1309     ber_free_chunks(top);
1310 
1311     return enif_make_binary(env, &out_binary);
1312 
1313  err:
1314     ber_free_chunks(curr);
1315     return enif_make_tuple2(env, enif_make_atom(env, "error"), err_code);
1316 }
1317 
is_ok_load_info(ErlNifEnv * env,ERL_NIF_TERM load_info)1318 static int is_ok_load_info(ErlNifEnv* env, ERL_NIF_TERM load_info) {
1319     int i;
1320     return enif_get_int(env, load_info, &i) && i == 1;
1321 }
1322 
load(ErlNifEnv * env,void ** priv_data,ERL_NIF_TERM load_info)1323 static int load(ErlNifEnv* env, void** priv_data, ERL_NIF_TERM load_info) {
1324     if (!is_ok_load_info(env, load_info))
1325 	return -1;
1326     return 0;
1327 }
1328 
upgrade(ErlNifEnv * env,void ** priv_data,void ** old_priv_data,ERL_NIF_TERM load_info)1329 static int upgrade(ErlNifEnv* env, void** priv_data, void** old_priv_data,
1330 	ERL_NIF_TERM load_info) {
1331     if (!is_ok_load_info(env, load_info))
1332 	return -1;
1333     return 0;
1334 }
1335 
unload(ErlNifEnv * env,void * priv_data)1336 static void unload(ErlNifEnv* env, void* priv_data) {
1337 
1338 }
1339 
1340 
1341 static ErlNifFunc nif_funcs[] =  {
1342     { "encode_per_complete", 1, encode_per_complete },
1343     { "decode_ber_tlv_raw", 1, decode_ber_tlv_raw },
1344     { "encode_ber_tlv", 1, encode_ber_tlv },
1345 };
1346 
1347 ERL_NIF_INIT(asn1rt_nif, nif_funcs, load, NULL, upgrade, unload)
1348