add heim_ipc_async.defs
[heimdal.git] / lib / asn1 / template.c
blob1a39677c636b87abd3ac146ab67aedf99525b781
1 /*
2 * Copyright (c) 2009 Kungliga Tekniska Högskolan
3 * (Royal Institute of Technology, Stockholm, Sweden).
4 * All rights reserved.
6 * Portions Copyright (c) 2009 Apple Inc. All rights reserved.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
19 * 3. Neither the name of the Institute nor the names of its contributors
20 * may be used to endorse or promote products derived from this software
21 * without specific prior written permission.
23 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 * SUCH DAMAGE.
36 #include "der_locl.h"
37 #include <com_err.h>
39 #if 0
40 #define ABORT_ON_ERROR() abort()
41 #else
42 #define ABORT_ON_ERROR() do { } while(0)
43 #endif
45 #define DPOC(data,offset) ((const void *)(((const unsigned char *)data) + offset))
46 #define DPO(data,offset) ((void *)(((unsigned char *)data) + offset))
49 struct asn1_type_func prim[] = {
50 #define el(name, type) { \
51 (asn1_type_encode)der_put_##name, \
52 (asn1_type_decode)der_get_##name, \
53 (asn1_type_length)der_length_##name, \
54 (asn1_type_copy)der_copy_##name, \
55 (asn1_type_release)der_free_##name, \
56 sizeof(type) \
58 #define elber(name, type) { \
59 (asn1_type_encode)der_put_##name, \
60 (asn1_type_decode)der_get_##name##_ber, \
61 (asn1_type_length)der_length_##name, \
62 (asn1_type_copy)der_copy_##name, \
63 (asn1_type_release)der_free_##name, \
64 sizeof(type) \
66 el(integer, int),
67 el(heim_integer, heim_integer),
68 el(integer, int),
69 el(unsigned, unsigned),
70 el(general_string, heim_general_string),
71 el(octet_string, heim_octet_string),
72 elber(octet_string, heim_octet_string),
73 el(ia5_string, heim_ia5_string),
74 el(bmp_string, heim_bmp_string),
75 el(universal_string, heim_universal_string),
76 el(printable_string, heim_printable_string),
77 el(visible_string, heim_visible_string),
78 el(utf8string, heim_utf8_string),
79 el(generalized_time, time_t),
80 el(utctime, time_t),
81 el(bit_string, heim_bit_string),
82 { (asn1_type_encode)der_put_boolean, (asn1_type_decode)der_get_boolean,
83 (asn1_type_length)der_length_boolean, (asn1_type_copy)der_copy_integer,
84 (asn1_type_release)der_free_integer, sizeof(int)
86 el(oid, heim_oid),
87 el(general_string, heim_general_string),
88 #undef el
89 #undef elber
92 static size_t
93 sizeofType(const struct asn1_template *t)
95 return t->offset;
99 * Here is abstraction to not so well evil fact of bit fields in C,
100 * they are endian dependent, so when getting and setting bits in the
101 * host local structure we need to know the endianness of the host.
103 * Its not the first time in Heimdal this have bitten us, and some day
104 * we'll grow up and use #defined constant, but bit fields are still
105 * so pretty and shiny.
108 static void
109 bmember_get_bit(const unsigned char *p, void *data,
110 unsigned int bit, size_t size)
112 unsigned int localbit = bit % 8;
113 if ((*p >> (7 - localbit)) & 1) {
114 #ifdef WORDS_BIGENDIAN
115 *(unsigned int *)data |= (1 << ((size * 8) - bit - 1));
116 #else
117 *(unsigned int *)data |= (1 << bit);
118 #endif
122 static int
123 bmember_isset_bit(const void *data, unsigned int bit, size_t size)
125 #ifdef WORDS_BIGENDIAN
126 if ((*(unsigned int *)data) & (1 << ((size * 8) - bit - 1)))
127 return 1;
128 return 0;
129 #else
130 if ((*(unsigned int *)data) & (1 << bit))
131 return 1;
132 return 0;
133 #endif
136 static void
137 bmember_put_bit(unsigned char *p, const void *data, unsigned int bit,
138 size_t size, unsigned int *bitset)
140 unsigned int localbit = bit % 8;
142 if (bmember_isset_bit(data, bit, size)) {
143 *p |= (1 << (7 - localbit));
144 if (*bitset == 0)
145 *bitset = (7 - localbit) + 1;
150 _asn1_decode(const struct asn1_template *t, unsigned flags,
151 const unsigned char *p, size_t len, void *data, size_t *size)
153 size_t elements = A1_HEADER_LEN(t);
154 size_t oldlen = len;
155 int ret = 0;
156 const unsigned char *startp = NULL;
157 unsigned int template_flags = t->tt;
159 /* skip over header */
160 t++;
162 if (template_flags & A1_HF_PRESERVE)
163 startp = p;
165 while (elements) {
166 switch (t->tt & A1_OP_MASK) {
167 case A1_OP_TYPE:
168 case A1_OP_TYPE_EXTERN: {
169 size_t newsize, size;
170 void *el = DPO(data, t->offset);
171 void **pel = (void **)el;
173 if ((t->tt & A1_OP_MASK) == A1_OP_TYPE) {
174 size = sizeofType(t->ptr);
175 } else {
176 const struct asn1_type_func *f = t->ptr;
177 size = f->size;
180 if (t->tt & A1_FLAG_OPTIONAL) {
181 *pel = calloc(1, size);
182 if (*pel == NULL)
183 return ENOMEM;
184 el = *pel;
186 if ((t->tt & A1_OP_MASK) == A1_OP_TYPE) {
187 ret = _asn1_decode(t->ptr, flags, p, len, el, &newsize);
188 } else {
189 const struct asn1_type_func *f = t->ptr;
190 ret = (f->decode)(p, len, el, &newsize);
192 if (ret) {
193 if (t->tt & A1_FLAG_OPTIONAL) {
194 free(*pel);
195 *pel = NULL;
196 break;
198 return ret;
200 p += newsize; len -= newsize;
202 break;
204 case A1_OP_TAG: {
205 Der_type dertype;
206 size_t newsize;
207 size_t datalen, l;
208 void *olddata = data;
209 int is_indefinite = 0;
210 int subflags = flags;
212 ret = der_match_tag_and_length(p, len, A1_TAG_CLASS(t->tt),
213 &dertype, A1_TAG_TAG(t->tt),
214 &datalen, &l);
215 if (ret) {
216 if (t->tt & A1_FLAG_OPTIONAL)
217 break;
218 return ret;
221 p += l; len -= l;
224 * Only allow indefinite encoding for OCTET STRING and BER
225 * for now. Should handle BIT STRING too.
228 if (dertype != A1_TAG_TYPE(t->tt) && (flags & A1_PF_ALLOW_BER)) {
229 const struct asn1_template *subtype = t->ptr;
230 subtype++; /* skip header */
232 if (((subtype->tt & A1_OP_MASK) == A1_OP_PARSE) &&
233 A1_PARSE_TYPE(subtype->tt) == A1T_OCTET_STRING)
234 subflags |= A1_PF_INDEFINTE;
237 if (datalen == ASN1_INDEFINITE) {
238 if ((flags & A1_PF_ALLOW_BER) == 0)
239 return ASN1_GOT_BER;
240 is_indefinite = 1;
241 datalen = len;
242 if (datalen < 2)
243 return ASN1_OVERRUN;
244 /* hide EndOfContent for sub-decoder, catching it below */
245 datalen -= 2;
246 } else if (datalen > len)
247 return ASN1_OVERRUN;
249 data = DPO(data, t->offset);
251 if (t->tt & A1_FLAG_OPTIONAL) {
252 void **el = (void **)data;
253 size_t ellen = sizeofType(t->ptr);
255 *el = calloc(1, ellen);
256 if (*el == NULL)
257 return ENOMEM;
258 data = *el;
261 ret = _asn1_decode(t->ptr, subflags, p, datalen, data, &newsize);
262 if (ret)
263 return ret;
265 if (newsize != datalen)
266 return ASN1_EXTRA_DATA;
268 len -= datalen;
269 p += datalen;
272 * Indefinite encoding needs a trailing EndOfContent,
273 * check for that.
275 if (is_indefinite) {
276 ret = der_match_tag_and_length(p, len, ASN1_C_UNIV,
277 &dertype, UT_EndOfContent,
278 &datalen, &l);
279 if (ret)
280 return ret;
281 if (dertype != PRIM)
282 return ASN1_BAD_ID;
283 if (datalen != 0)
284 return ASN1_INDEF_EXTRA_DATA;
285 p += l; len -= l;
287 data = olddata;
289 break;
291 case A1_OP_PARSE: {
292 unsigned int type = A1_PARSE_TYPE(t->tt);
293 size_t newsize;
294 void *el = DPO(data, t->offset);
297 * INDEFINITE primitive types are one element after the
298 * same type but non-INDEFINITE version.
300 if (flags & A1_PF_INDEFINTE)
301 type++;
303 if (type >= sizeof(prim)/sizeof(prim[0])) {
304 ABORT_ON_ERROR();
305 return ASN1_PARSE_ERROR;
308 ret = (prim[type].decode)(p, len, el, &newsize);
309 if (ret)
310 return ret;
311 p += newsize; len -= newsize;
313 break;
315 case A1_OP_SETOF:
316 case A1_OP_SEQOF: {
317 struct template_of *el = DPO(data, t->offset);
318 size_t newsize;
319 size_t ellen = sizeofType(t->ptr);
320 size_t vallength = 0;
322 while (len > 0) {
323 void *tmp;
324 size_t newlen = vallength + ellen;
325 if (vallength > newlen)
326 return ASN1_OVERFLOW;
328 tmp = realloc(el->val, newlen);
329 if (tmp == NULL)
330 return ENOMEM;
332 memset(DPO(tmp, vallength), 0, ellen);
333 el->val = tmp;
335 ret = _asn1_decode(t->ptr, flags & (~A1_PF_INDEFINTE), p, len,
336 DPO(el->val, vallength), &newsize);
337 if (ret)
338 return ret;
339 vallength = newlen;
340 el->len++;
341 p += newsize; len -= newsize;
344 break;
346 case A1_OP_BMEMBER: {
347 const struct asn1_template *bmember = t->ptr;
348 size_t size = bmember->offset;
349 size_t elements = A1_HEADER_LEN(bmember);
350 size_t pos = 0;
352 bmember++;
354 memset(data, 0, size);
356 if (len < 1)
357 return ASN1_OVERRUN;
358 p++; len--;
360 while (elements && len) {
361 while (bmember->offset / 8 > pos / 8) {
362 if (len < 1)
363 break;
364 p++; len--;
365 pos += 8;
367 if (len) {
368 bmember_get_bit(p, data, bmember->offset, size);
369 elements--; bmember++;
372 len = 0;
373 break;
375 case A1_OP_CHOICE: {
376 const struct asn1_template *choice = t->ptr;
377 unsigned int *element = DPO(data, choice->offset);
378 size_t datalen;
379 unsigned int i;
381 for (i = 1; i < A1_HEADER_LEN(choice) + 1; i++) {
382 /* should match first tag instead, store it in choice.tt */
383 ret = _asn1_decode(choice[i].ptr, 0, p, len,
384 DPO(data, choice[i].offset), &datalen);
385 if (ret == 0) {
386 *element = i;
387 p += datalen; len -= datalen;
388 break;
389 } else if (ret != ASN1_BAD_ID && ret != ASN1_MISPLACED_FIELD && ret != ASN1_MISSING_FIELD) {
390 return ret;
393 if (i >= A1_HEADER_LEN(choice) + 1) {
394 if (choice->tt == 0)
395 return ASN1_BAD_ID;
397 *element = 0;
398 ret = der_get_octet_string(p, len,
399 DPO(data, choice->tt), &datalen);
400 if (ret)
401 return ret;
402 p += datalen; len -= datalen;
405 break;
407 default:
408 ABORT_ON_ERROR();
409 return ASN1_PARSE_ERROR;
411 t++;
412 elements--;
414 /* if we are using padding, eat up read of context */
415 if (template_flags & A1_HF_ELLIPSIS)
416 len = 0;
418 oldlen -= len;
420 if (size)
421 *size = oldlen;
424 * saved the raw bits if asked for it, useful for signature
425 * verification.
427 if (startp) {
428 heim_octet_string *save = data;
430 save->data = malloc(oldlen);
431 if (save->data == NULL)
432 return ENOMEM;
433 else {
434 save->length = oldlen;
435 memcpy(save->data, startp, oldlen);
438 return 0;
442 _asn1_encode(const struct asn1_template *t, unsigned char *p, size_t len, const void *data, size_t *size)
444 size_t elements = A1_HEADER_LEN(t);
445 int ret = 0;
446 size_t oldlen = len;
448 t += A1_HEADER_LEN(t);
450 while (elements) {
451 switch (t->tt & A1_OP_MASK) {
452 case A1_OP_TYPE:
453 case A1_OP_TYPE_EXTERN: {
454 size_t newsize;
455 const void *el = DPOC(data, t->offset);
457 if (t->tt & A1_FLAG_OPTIONAL) {
458 void **pel = (void **)el;
459 if (*pel == NULL)
460 break;
461 el = *pel;
464 if ((t->tt & A1_OP_MASK) == A1_OP_TYPE) {
465 ret = _asn1_encode(t->ptr, p, len, el, &newsize);
466 } else {
467 const struct asn1_type_func *f = t->ptr;
468 ret = (f->encode)(p, len, el, &newsize);
471 if (ret)
472 return ret;
473 p -= newsize; len -= newsize;
475 break;
477 case A1_OP_TAG: {
478 const void *olddata = data;
479 size_t l, datalen;
481 data = DPOC(data, t->offset);
483 if (t->tt & A1_FLAG_OPTIONAL) {
484 void **el = (void **)data;
485 if (*el == NULL) {
486 data = olddata;
487 break;
489 data = *el;
492 ret = _asn1_encode(t->ptr, p, len, data, &datalen);
493 if (ret)
494 return ret;
496 len -= datalen; p -= datalen;
498 ret = der_put_length_and_tag(p, len, datalen,
499 A1_TAG_CLASS(t->tt),
500 A1_TAG_TYPE(t->tt),
501 A1_TAG_TAG(t->tt), &l);
502 if (ret)
503 return ret;
505 p -= l; len -= l;
507 data = olddata;
509 break;
511 case A1_OP_PARSE: {
512 unsigned int type = A1_PARSE_TYPE(t->tt);
513 size_t newsize;
514 const void *el = DPOC(data, t->offset);
516 if (type > sizeof(prim)/sizeof(prim[0])) {
517 ABORT_ON_ERROR();
518 return ASN1_PARSE_ERROR;
521 ret = (prim[type].encode)(p, len, el, &newsize);
522 if (ret)
523 return ret;
524 p -= newsize; len -= newsize;
526 break;
528 case A1_OP_SETOF: {
529 const struct template_of *el = DPOC(data, t->offset);
530 size_t ellen = sizeofType(t->ptr);
531 struct heim_octet_string *val;
532 unsigned char *elptr = el->val;
533 size_t i, totallen;
535 if (el->len == 0)
536 break;
538 if (el->len > UINT_MAX/sizeof(val[0]))
539 return ERANGE;
541 val = malloc(sizeof(val[0]) * el->len);
542 if (val == NULL)
543 return ENOMEM;
545 for(totallen = 0, i = 0; i < el->len; i++) {
546 unsigned char *next;
547 size_t l;
549 val[i].length = _asn1_length(t->ptr, elptr);
550 val[i].data = malloc(val[i].length);
552 ret = _asn1_encode(t->ptr, DPO(val[i].data, val[i].length - 1),
553 val[i].length, elptr, &l);
554 if (ret)
555 break;
557 next = elptr + ellen;
558 if (next < elptr) {
559 ret = ASN1_OVERFLOW;
560 break;
562 elptr = next;
563 totallen += val[i].length;
565 if (ret == 0 && totallen > len)
566 ret = ASN1_OVERFLOW;
567 if (ret) {
568 do {
569 free(val[i].data);
570 } while(i-- > 0);
571 free(val);
572 return ret;
575 len -= totallen;
577 qsort(val, el->len, sizeof(val[0]), _heim_der_set_sort);
579 i = el->len - 1;
580 do {
581 p -= val[i].length;
582 memcpy(p + 1, val[i].data, val[i].length);
583 free(val[i].data);
584 } while(i-- > 0);
585 free(val);
587 break;
590 case A1_OP_SEQOF: {
591 struct template_of *el = DPO(data, t->offset);
592 size_t ellen = sizeofType(t->ptr);
593 size_t newsize;
594 unsigned int i;
595 unsigned char *elptr = el->val;
597 if (el->len == 0)
598 break;
600 elptr += ellen * (el->len - 1);
602 for (i = 0; i < el->len; i++) {
603 ret = _asn1_encode(t->ptr, p, len,
604 elptr,
605 &newsize);
606 if (ret)
607 return ret;
608 p -= newsize; len -= newsize;
609 elptr -= ellen;
612 break;
614 case A1_OP_BMEMBER: {
615 const struct asn1_template *bmember = t->ptr;
616 size_t size = bmember->offset;
617 size_t elements = A1_HEADER_LEN(bmember);
618 size_t pos;
619 unsigned char c = 0;
620 unsigned int bitset = 0;
621 int rfc1510 = (bmember->tt & A1_HBF_RFC1510);
623 bmember += elements;
625 if (rfc1510)
626 pos = 31;
627 else
628 pos = bmember->offset;
630 while (elements && len) {
631 while (bmember->offset / 8 < pos / 8) {
632 if (rfc1510 || bitset || c) {
633 if (len < 1)
634 return ASN1_OVERFLOW;
635 *p-- = c; len--;
637 c = 0;
638 pos -= 8;
640 bmember_put_bit(&c, data, bmember->offset, size, &bitset);
641 elements--; bmember--;
643 if (rfc1510 || bitset) {
644 if (len < 1)
645 return ASN1_OVERFLOW;
646 *p-- = c; len--;
649 if (len < 1)
650 return ASN1_OVERFLOW;
651 if (rfc1510 || bitset == 0)
652 *p-- = 0;
653 else
654 *p-- = bitset - 1;
656 len--;
658 break;
660 case A1_OP_CHOICE: {
661 const struct asn1_template *choice = t->ptr;
662 const unsigned int *element = DPOC(data, choice->offset);
663 size_t datalen;
664 const void *el;
666 if (*element > A1_HEADER_LEN(choice)) {
667 printf("element: %d\n", *element);
668 return ASN1_PARSE_ERROR;
671 if (*element == 0) {
672 ret += der_put_octet_string(p, len,
673 DPOC(data, choice->tt), &datalen);
674 } else {
675 choice += *element;
676 el = DPOC(data, choice->offset);
677 ret = _asn1_encode(choice->ptr, p, len, el, &datalen);
678 if (ret)
679 return ret;
681 len -= datalen; p -= datalen;
683 break;
685 default:
686 ABORT_ON_ERROR();
688 t--;
689 elements--;
691 if (size)
692 *size = oldlen - len;
694 return 0;
697 size_t
698 _asn1_length(const struct asn1_template *t, const void *data)
700 size_t elements = A1_HEADER_LEN(t);
701 size_t ret = 0;
703 t += A1_HEADER_LEN(t);
705 while (elements) {
706 switch (t->tt & A1_OP_MASK) {
707 case A1_OP_TYPE:
708 case A1_OP_TYPE_EXTERN: {
709 const void *el = DPOC(data, t->offset);
711 if (t->tt & A1_FLAG_OPTIONAL) {
712 void **pel = (void **)el;
713 if (*pel == NULL)
714 break;
715 el = *pel;
718 if ((t->tt & A1_OP_MASK) == A1_OP_TYPE) {
719 ret += _asn1_length(t->ptr, el);
720 } else {
721 const struct asn1_type_func *f = t->ptr;
722 ret += (f->length)(el);
724 break;
726 case A1_OP_TAG: {
727 size_t datalen;
728 const void *olddata = data;
730 data = DPO(data, t->offset);
732 if (t->tt & A1_FLAG_OPTIONAL) {
733 void **el = (void **)data;
734 if (*el == NULL) {
735 data = olddata;
736 break;
738 data = *el;
740 datalen = _asn1_length(t->ptr, data);
741 ret += der_length_tag(A1_TAG_TAG(t->tt)) + der_length_len(datalen);
742 ret += datalen;
743 data = olddata;
744 break;
746 case A1_OP_PARSE: {
747 unsigned int type = A1_PARSE_TYPE(t->tt);
748 const void *el = DPOC(data, t->offset);
750 if (type > sizeof(prim)/sizeof(prim[0])) {
751 ABORT_ON_ERROR();
752 break;
754 ret += (prim[type].length)(el);
755 break;
757 case A1_OP_SETOF:
758 case A1_OP_SEQOF: {
759 const struct template_of *el = DPOC(data, t->offset);
760 size_t ellen = sizeofType(t->ptr);
761 const unsigned char *element = el->val;
762 unsigned int i;
764 for (i = 0; i < el->len; i++) {
765 ret += _asn1_length(t->ptr, element);
766 element += ellen;
769 break;
771 case A1_OP_BMEMBER: {
772 const struct asn1_template *bmember = t->ptr;
773 size_t size = bmember->offset;
774 size_t elements = A1_HEADER_LEN(bmember);
775 int rfc1510 = (bmember->tt & A1_HBF_RFC1510);
777 if (rfc1510) {
778 ret += 5;
779 } else {
781 ret += 1;
783 bmember += elements;
785 while (elements) {
786 if (bmember_isset_bit(data, bmember->offset, size)) {
787 ret += (bmember->offset / 8) + 1;
788 break;
790 elements--; bmember--;
793 break;
795 case A1_OP_CHOICE: {
796 const struct asn1_template *choice = t->ptr;
797 const unsigned int *element = DPOC(data, choice->offset);
799 if (*element > A1_HEADER_LEN(choice))
800 break;
802 if (*element == 0) {
803 ret += der_length_octet_string(DPOC(data, choice->tt));
804 } else {
805 choice += *element;
806 ret += _asn1_length(choice->ptr, DPOC(data, choice->offset));
808 break;
810 default:
811 ABORT_ON_ERROR();
812 break;
814 elements--;
815 t--;
817 return ret;
820 void
821 _asn1_free(const struct asn1_template *t, void *data)
823 size_t elements = A1_HEADER_LEN(t);
825 if (t->tt & A1_HF_PRESERVE)
826 der_free_octet_string(data);
828 t++;
830 while (elements) {
831 switch (t->tt & A1_OP_MASK) {
832 case A1_OP_TYPE:
833 case A1_OP_TYPE_EXTERN: {
834 void *el = DPO(data, t->offset);
836 if (t->tt & A1_FLAG_OPTIONAL) {
837 void **pel = (void **)el;
838 if (*pel == NULL)
839 break;
840 el = *pel;
843 if ((t->tt & A1_OP_MASK) == A1_OP_TYPE) {
844 _asn1_free(t->ptr, el);
845 } else {
846 const struct asn1_type_func *f = t->ptr;
847 (f->release)(el);
849 if (t->tt & A1_FLAG_OPTIONAL)
850 free(el);
852 break;
854 case A1_OP_PARSE: {
855 unsigned int type = A1_PARSE_TYPE(t->tt);
856 void *el = DPO(data, t->offset);
858 if (type > sizeof(prim)/sizeof(prim[0])) {
859 ABORT_ON_ERROR();
860 break;
862 (prim[type].release)(el);
863 break;
865 case A1_OP_TAG: {
866 void *el = DPO(data, t->offset);
868 if (t->tt & A1_FLAG_OPTIONAL) {
869 void **pel = (void **)el;
870 if (*pel == NULL)
871 break;
872 el = *pel;
875 _asn1_free(t->ptr, el);
877 if (t->tt & A1_FLAG_OPTIONAL)
878 free(el);
880 break;
882 case A1_OP_SETOF:
883 case A1_OP_SEQOF: {
884 struct template_of *el = DPO(data, t->offset);
885 size_t ellen = sizeofType(t->ptr);
886 unsigned char *element = el->val;
887 unsigned int i;
889 for (i = 0; i < el->len; i++) {
890 _asn1_free(t->ptr, element);
891 element += ellen;
893 free(el->val);
894 el->val = NULL;
895 el->len = 0;
897 break;
899 case A1_OP_BMEMBER:
900 break;
901 case A1_OP_CHOICE: {
902 const struct asn1_template *choice = t->ptr;
903 const unsigned int *element = DPOC(data, choice->offset);
905 if (*element > A1_HEADER_LEN(choice))
906 break;
908 if (*element == 0) {
909 der_free_octet_string(DPO(data, choice->tt));
910 } else {
911 choice += *element;
912 _asn1_free(choice->ptr, DPO(data, choice->offset));
914 break;
916 default:
917 ABORT_ON_ERROR();
918 break;
920 t++;
921 elements--;
926 _asn1_copy(const struct asn1_template *t, const void *from, void *to)
928 size_t elements = A1_HEADER_LEN(t);
929 int ret = 0;
930 int preserve = (t->tt & A1_HF_PRESERVE);
932 t++;
934 if (preserve) {
935 ret = der_copy_octet_string(from, to);
936 if (ret)
937 return ret;
940 while (elements) {
941 switch (t->tt & A1_OP_MASK) {
942 case A1_OP_TYPE:
943 case A1_OP_TYPE_EXTERN: {
944 const void *fel = DPOC(from, t->offset);
945 void *tel = DPO(to, t->offset);
946 void **ptel = (void **)tel;
947 size_t size;
949 if ((t->tt & A1_OP_MASK) == A1_OP_TYPE) {
950 size = sizeofType(t->ptr);
951 } else {
952 const struct asn1_type_func *f = t->ptr;
953 size = f->size;
956 if (t->tt & A1_FLAG_OPTIONAL) {
957 void **pfel = (void **)fel;
958 if (*pfel == NULL)
959 break;
960 fel = *pfel;
962 tel = *ptel = calloc(1, size);
963 if (tel == NULL)
964 return ENOMEM;
967 if ((t->tt & A1_OP_MASK) == A1_OP_TYPE) {
968 ret = _asn1_copy(t->ptr, fel, tel);
969 } else {
970 const struct asn1_type_func *f = t->ptr;
971 ret = (f->copy)(fel, tel);
974 if (ret) {
975 if (t->tt & A1_FLAG_OPTIONAL) {
976 free(*ptel);
977 *ptel = NULL;
979 return ret;
981 break;
983 case A1_OP_PARSE: {
984 unsigned int type = A1_PARSE_TYPE(t->tt);
985 const void *fel = DPOC(from, t->offset);
986 void *tel = DPO(to, t->offset);
988 if (type > sizeof(prim)/sizeof(prim[0])) {
989 ABORT_ON_ERROR();
990 return ASN1_PARSE_ERROR;
992 ret = (prim[type].copy)(fel, tel);
993 if (ret)
994 return ret;
995 break;
997 case A1_OP_TAG: {
998 const void *oldfrom = from;
999 void *oldto = to;
1000 void **tel = NULL;
1002 from = DPOC(from, t->offset);
1003 to = DPO(to, t->offset);
1005 if (t->tt & A1_FLAG_OPTIONAL) {
1006 void **fel = (void **)from;
1007 tel = (void **)to;
1008 if (*fel == NULL) {
1009 from = oldfrom;
1010 to = oldto;
1011 break;
1013 from = *fel;
1015 to = *tel = calloc(1, sizeofType(t->ptr));
1016 if (to == NULL)
1017 return ENOMEM;
1020 ret = _asn1_copy(t->ptr, from, to);
1021 if (ret) {
1022 if (t->tt & A1_FLAG_OPTIONAL) {
1023 free(*tel);
1024 *tel = NULL;
1026 return ret;
1029 from = oldfrom;
1030 to = oldto;
1032 break;
1034 case A1_OP_SETOF:
1035 case A1_OP_SEQOF: {
1036 const struct template_of *fel = DPOC(from, t->offset);
1037 struct template_of *tel = DPO(to, t->offset);
1038 size_t ellen = sizeofType(t->ptr);
1039 unsigned int i;
1041 tel->val = calloc(fel->len, ellen);
1042 if (tel->val == NULL)
1043 return ENOMEM;
1045 tel->len = fel->len;
1047 for (i = 0; i < fel->len; i++) {
1048 ret = _asn1_copy(t->ptr,
1049 DPOC(fel->val, (i * ellen)),
1050 DPO(tel->val, (i *ellen)));
1051 if (ret)
1052 return ret;
1054 break;
1056 case A1_OP_BMEMBER: {
1057 const struct asn1_template *bmember = t->ptr;
1058 size_t size = bmember->offset;
1059 memcpy(to, from, size);
1060 break;
1062 case A1_OP_CHOICE: {
1063 const struct asn1_template *choice = t->ptr;
1064 const unsigned int *felement = DPOC(from, choice->offset);
1065 unsigned int *telement = DPO(to, choice->offset);
1067 if (*felement > A1_HEADER_LEN(choice))
1068 return ASN1_PARSE_ERROR;
1070 *telement = *felement;
1072 if (*felement == 0) {
1073 ret = der_copy_octet_string(DPOC(from, choice->tt), DPO(to, choice->tt));
1074 } else {
1075 choice += *felement;
1076 ret = _asn1_copy(choice->ptr,
1077 DPOC(from, choice->offset),
1078 DPO(to, choice->offset));
1080 if (ret)
1081 return ret;
1082 break;
1084 default:
1085 ABORT_ON_ERROR();
1086 break;
1088 t++;
1089 elements--;
1091 return 0;
1095 _asn1_decode_top(const struct asn1_template *t, unsigned flags, const unsigned char *p, size_t len, void *data, size_t *size)
1097 int ret;
1098 memset(data, 0, t->offset);
1099 ret = _asn1_decode(t, flags, p, len, data, size);
1100 if (ret) {
1101 _asn1_free(t, data);
1102 memset(data, 0, t->offset);
1105 return ret;
1109 _asn1_copy_top(const struct asn1_template *t, const void *from, void *to)
1111 int ret;
1112 memset(to, 0, t->offset);
1113 ret = _asn1_copy(t, from, to);
1114 if (ret) {
1115 _asn1_free(t, to);
1116 memset(to, 0, t->offset);
1118 return ret;