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