krb5: always confirm PA-PKINIT-KX for anon PKINIT
[heimdal.git] / lib / asn1 / template.c
blobfe0dc6c2f773c9340ecce2ad0b69eab21e2782da
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 - 2010 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 struct asn1_type_func asn1_template_prim[A1T_NUM_ENTRY] = {
40 #define el(name, type) { \
41 (asn1_type_encode)der_put_##name, \
42 (asn1_type_decode)der_get_##name, \
43 (asn1_type_length)der_length_##name, \
44 (asn1_type_copy)der_copy_##name, \
45 (asn1_type_release)der_free_##name, \
46 sizeof(type) \
48 #define elber(name, type) { \
49 (asn1_type_encode)der_put_##name, \
50 (asn1_type_decode)der_get_##name##_ber, \
51 (asn1_type_length)der_length_##name, \
52 (asn1_type_copy)der_copy_##name, \
53 (asn1_type_release)der_free_##name, \
54 sizeof(type) \
56 el(integer, int),
57 el(heim_integer, heim_integer),
58 el(integer, int),
59 el(integer64, int64_t),
60 el(unsigned, unsigned),
61 el(unsigned64, uint64_t),
62 el(general_string, heim_general_string),
63 el(octet_string, heim_octet_string),
64 elber(octet_string, heim_octet_string),
65 el(ia5_string, heim_ia5_string),
66 el(bmp_string, heim_bmp_string),
67 el(universal_string, heim_universal_string),
68 el(printable_string, heim_printable_string),
69 el(visible_string, heim_visible_string),
70 el(utf8string, heim_utf8_string),
71 el(generalized_time, time_t),
72 el(utctime, time_t),
73 el(bit_string, heim_bit_string),
74 { (asn1_type_encode)der_put_boolean, (asn1_type_decode)der_get_boolean,
75 (asn1_type_length)der_length_boolean, (asn1_type_copy)der_copy_integer,
76 (asn1_type_release)der_free_integer, sizeof(int)
78 el(oid, heim_oid),
79 el(general_string, heim_general_string),
80 #undef el
81 #undef elber
84 size_t
85 _asn1_sizeofType(const struct asn1_template *t)
87 return t->offset;
91 * Here is abstraction to not so well evil fact of bit fields in C,
92 * they are endian dependent, so when getting and setting bits in the
93 * host local structure we need to know the endianness of the host.
95 * Its not the first time in Heimdal this have bitten us, and some day
96 * we'll grow up and use #defined constant, but bit fields are still
97 * so pretty and shiny.
100 static void
101 _asn1_bmember_get_bit(const unsigned char *p, void *data,
102 unsigned int bit, size_t size)
104 unsigned int localbit = bit % 8;
105 if ((*p >> (7 - localbit)) & 1) {
106 #ifdef WORDS_BIGENDIAN
107 *(unsigned int *)data |= (1 << ((size * 8) - bit - 1));
108 #else
109 *(unsigned int *)data |= (1 << bit);
110 #endif
115 _asn1_bmember_isset_bit(const void *data, unsigned int bit, size_t size)
117 #ifdef WORDS_BIGENDIAN
118 if ((*(unsigned int *)data) & (1 << ((size * 8) - bit - 1)))
119 return 1;
120 return 0;
121 #else
122 if ((*(unsigned int *)data) & (1 << bit))
123 return 1;
124 return 0;
125 #endif
128 void
129 _asn1_bmember_put_bit(unsigned char *p, const void *data, unsigned int bit,
130 size_t size, unsigned int *bitset)
132 unsigned int localbit = bit % 8;
134 if (_asn1_bmember_isset_bit(data, bit, size)) {
135 *p |= (1 << (7 - localbit));
136 if (*bitset == 0)
137 *bitset = (7 - localbit) + 1;
142 _asn1_decode(const struct asn1_template *t, unsigned flags,
143 const unsigned char *p, size_t len, void *data, size_t *size)
145 size_t elements = A1_HEADER_LEN(t);
146 size_t oldlen = len;
147 int ret = 0;
148 const unsigned char *startp = NULL;
149 unsigned int template_flags = t->tt;
151 /* skip over header */
152 t++;
154 if (template_flags & A1_HF_PRESERVE)
155 startp = p;
157 while (elements) {
158 switch (t->tt & A1_OP_MASK) {
159 case A1_OP_TYPE:
160 case A1_OP_TYPE_EXTERN: {
161 size_t newsize, elsize;
162 void *el = DPO(data, t->offset);
163 void **pel = (void **)el;
165 if ((t->tt & A1_OP_MASK) == A1_OP_TYPE) {
166 elsize = _asn1_sizeofType(t->ptr);
167 } else {
168 const struct asn1_type_func *f = t->ptr;
169 elsize = f->size;
172 if (t->tt & A1_FLAG_OPTIONAL) {
173 *pel = calloc(1, elsize);
174 if (*pel == NULL)
175 return ENOMEM;
176 el = *pel;
178 if ((t->tt & A1_OP_MASK) == A1_OP_TYPE) {
179 ret = _asn1_decode(t->ptr, flags, p, len, el, &newsize);
180 } else {
181 const struct asn1_type_func *f = t->ptr;
182 ret = (f->decode)(p, len, el, &newsize);
184 if (ret) {
185 if (t->tt & A1_FLAG_OPTIONAL) {
186 free(*pel);
187 *pel = NULL;
188 break;
190 return ret;
192 p += newsize; len -= newsize;
194 break;
196 case A1_OP_TAG: {
197 Der_type dertype;
198 size_t newsize;
199 size_t datalen, l;
200 void *olddata = data;
201 int is_indefinite = 0;
202 int subflags = flags;
204 ret = der_match_tag_and_length(p, len, A1_TAG_CLASS(t->tt),
205 &dertype, A1_TAG_TAG(t->tt),
206 &datalen, &l);
207 if (ret) {
208 if (t->tt & A1_FLAG_OPTIONAL)
209 break;
210 return ret;
213 p += l; len -= l;
216 * Only allow indefinite encoding for OCTET STRING and BER
217 * for now. Should handle BIT STRING too.
220 if (dertype != A1_TAG_TYPE(t->tt) && (flags & A1_PF_ALLOW_BER)) {
221 const struct asn1_template *subtype = t->ptr;
222 subtype++; /* skip header */
224 if (((subtype->tt & A1_OP_MASK) == A1_OP_PARSE) &&
225 A1_PARSE_TYPE(subtype->tt) == A1T_OCTET_STRING)
226 subflags |= A1_PF_INDEFINTE;
229 if (datalen == ASN1_INDEFINITE) {
230 if ((flags & A1_PF_ALLOW_BER) == 0)
231 return ASN1_GOT_BER;
232 is_indefinite = 1;
233 datalen = len;
234 if (datalen < 2)
235 return ASN1_OVERRUN;
236 /* hide EndOfContent for sub-decoder, catching it below */
237 datalen -= 2;
238 } else if (datalen > len)
239 return ASN1_OVERRUN;
241 data = DPO(data, t->offset);
243 if (t->tt & A1_FLAG_OPTIONAL) {
244 void **el = (void **)data;
245 size_t ellen = _asn1_sizeofType(t->ptr);
247 *el = calloc(1, ellen);
248 if (*el == NULL)
249 return ENOMEM;
250 data = *el;
253 ret = _asn1_decode(t->ptr, subflags, p, datalen, data, &newsize);
254 if (ret)
255 return ret;
257 if (is_indefinite) {
258 /* If we use indefinite encoding, the newsize is the datasize. */
259 datalen = newsize;
260 } else if (newsize != datalen) {
261 /* Check for hidden data that might be after the real tag */
262 return ASN1_EXTRA_DATA;
265 len -= datalen;
266 p += datalen;
269 * Indefinite encoding needs a trailing EndOfContent,
270 * check for that.
272 if (is_indefinite) {
273 ret = der_match_tag_and_length(p, len, ASN1_C_UNIV,
274 &dertype, UT_EndOfContent,
275 &datalen, &l);
276 if (ret)
277 return ret;
278 if (dertype != PRIM)
279 return ASN1_BAD_ID;
280 if (datalen != 0)
281 return ASN1_INDEF_EXTRA_DATA;
282 p += l; len -= l;
284 data = olddata;
286 break;
288 case A1_OP_PARSE: {
289 unsigned int type = A1_PARSE_TYPE(t->tt);
290 size_t newsize;
291 void *el = DPO(data, t->offset);
294 * INDEFINITE primitive types are one element after the
295 * same type but non-INDEFINITE version.
297 if (flags & A1_PF_INDEFINTE)
298 type++;
300 if (type >= sizeof(asn1_template_prim)/sizeof(asn1_template_prim[0])) {
301 ABORT_ON_ERROR();
302 return ASN1_PARSE_ERROR;
305 ret = (asn1_template_prim[type].decode)(p, len, el, &newsize);
306 if (ret)
307 return ret;
308 p += newsize; len -= newsize;
310 break;
312 case A1_OP_SETOF:
313 case A1_OP_SEQOF: {
314 struct template_of *el = DPO(data, t->offset);
315 size_t newsize;
316 size_t ellen = _asn1_sizeofType(t->ptr);
317 size_t vallength = 0;
319 while (len > 0) {
320 void *tmp;
321 size_t newlen = vallength + ellen;
322 if (vallength > newlen)
323 return ASN1_OVERFLOW;
325 tmp = realloc(el->val, newlen);
326 if (tmp == NULL)
327 return ENOMEM;
329 memset(DPO(tmp, vallength), 0, ellen);
330 el->val = tmp;
332 ret = _asn1_decode(t->ptr, flags & (~A1_PF_INDEFINTE), p, len,
333 DPO(el->val, vallength), &newsize);
334 if (ret)
335 return ret;
336 vallength = newlen;
337 el->len++;
338 p += newsize; len -= newsize;
341 break;
343 case A1_OP_BMEMBER: {
344 const struct asn1_template *bmember = t->ptr;
345 size_t bsize = bmember->offset;
346 size_t belements = A1_HEADER_LEN(bmember);
347 size_t pos = 0;
349 bmember++;
351 memset(data, 0, bsize);
353 if (len < 1)
354 return ASN1_OVERRUN;
355 p++; len--;
357 while (belements && len) {
358 while (bmember->offset / 8 > pos / 8) {
359 if (len < 1)
360 break;
361 p++; len--;
362 pos += 8;
364 if (len) {
365 _asn1_bmember_get_bit(p, data, bmember->offset, bsize);
366 belements--; bmember++;
369 len = 0;
370 break;
372 case A1_OP_CHOICE: {
373 const struct asn1_template *choice = t->ptr;
374 unsigned int *element = DPO(data, choice->offset);
375 size_t datalen;
376 unsigned int i;
378 /* provide a saner value as default, we should have a NO element value */
379 *element = 1;
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(asn1_template_prim)/sizeof(asn1_template_prim[0])) {
517 ABORT_ON_ERROR();
518 return ASN1_PARSE_ERROR;
521 ret = (asn1_template_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 = _asn1_sizeofType(t->ptr);
531 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 = calloc(el->len, sizeof(val[0]));
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 if (val[i].length) {
551 val[i].data = malloc(val[i].length);
552 if (val[i].data == NULL) {
553 ret = ENOMEM;
554 break;
558 ret = _asn1_encode(t->ptr, DPO(val[i].data, val[i].length - 1),
559 val[i].length, elptr, &l);
560 if (ret)
561 break;
563 next = elptr + ellen;
564 if (next < elptr) {
565 ret = ASN1_OVERFLOW;
566 break;
568 elptr = next;
569 totallen += val[i].length;
571 if (ret == 0 && totallen > len)
572 ret = ASN1_OVERFLOW;
573 if (ret) {
574 for (i = 0; i < el->len; i++)
575 free(val[i].data);
576 free(val);
577 return ret;
580 len -= totallen;
582 qsort(val, el->len, sizeof(val[0]), _heim_der_set_sort);
584 i = el->len - 1;
585 do {
586 p -= val[i].length;
587 memcpy(p + 1, val[i].data, val[i].length);
588 free(val[i].data);
589 } while(i-- > 0);
590 free(val);
592 break;
595 case A1_OP_SEQOF: {
596 struct template_of *el = DPO(data, t->offset);
597 size_t ellen = _asn1_sizeofType(t->ptr);
598 size_t newsize;
599 unsigned int i;
600 unsigned char *elptr = el->val;
602 if (el->len == 0)
603 break;
605 elptr += ellen * (el->len - 1);
607 for (i = 0; i < el->len; i++) {
608 ret = _asn1_encode(t->ptr, p, len,
609 elptr,
610 &newsize);
611 if (ret)
612 return ret;
613 p -= newsize; len -= newsize;
614 elptr -= ellen;
617 break;
619 case A1_OP_BMEMBER: {
620 const struct asn1_template *bmember = t->ptr;
621 size_t bsize = bmember->offset;
622 size_t belements = A1_HEADER_LEN(bmember);
623 size_t pos;
624 unsigned char c = 0;
625 unsigned int bitset = 0;
626 int rfc1510 = (bmember->tt & A1_HBF_RFC1510);
628 bmember += belements;
630 if (rfc1510)
631 pos = 31;
632 else
633 pos = bmember->offset;
635 while (belements && len) {
636 while (bmember->offset / 8 < pos / 8) {
637 if (rfc1510 || bitset || c) {
638 if (len < 1)
639 return ASN1_OVERFLOW;
640 *p-- = c; len--;
642 c = 0;
643 pos -= 8;
645 _asn1_bmember_put_bit(&c, data, bmember->offset, bsize, &bitset);
646 belements--; bmember--;
648 if (rfc1510 || bitset) {
649 if (len < 1)
650 return ASN1_OVERFLOW;
651 *p-- = c; len--;
654 if (len < 1)
655 return ASN1_OVERFLOW;
656 if (rfc1510 || bitset == 0)
657 *p-- = 0;
658 else
659 *p-- = bitset - 1;
661 len--;
663 break;
665 case A1_OP_CHOICE: {
666 const struct asn1_template *choice = t->ptr;
667 const unsigned int *element = DPOC(data, choice->offset);
668 size_t datalen;
669 const void *el;
671 if (*element > A1_HEADER_LEN(choice)) {
672 printf("element: %d\n", *element);
673 return ASN1_PARSE_ERROR;
676 if (*element == 0) {
677 ret += der_put_octet_string(p, len,
678 DPOC(data, choice->tt), &datalen);
679 } else {
680 choice += *element;
681 el = DPOC(data, choice->offset);
682 ret = _asn1_encode(choice->ptr, p, len, el, &datalen);
683 if (ret)
684 return ret;
686 len -= datalen; p -= datalen;
688 break;
690 default:
691 ABORT_ON_ERROR();
693 t--;
694 elements--;
696 if (size)
697 *size = oldlen - len;
699 return 0;
702 size_t
703 _asn1_length(const struct asn1_template *t, const void *data)
705 size_t elements = A1_HEADER_LEN(t);
706 size_t ret = 0;
708 t += A1_HEADER_LEN(t);
710 while (elements) {
711 switch (t->tt & A1_OP_MASK) {
712 case A1_OP_TYPE:
713 case A1_OP_TYPE_EXTERN: {
714 const void *el = DPOC(data, t->offset);
716 if (t->tt & A1_FLAG_OPTIONAL) {
717 void **pel = (void **)el;
718 if (*pel == NULL)
719 break;
720 el = *pel;
723 if ((t->tt & A1_OP_MASK) == A1_OP_TYPE) {
724 ret += _asn1_length(t->ptr, el);
725 } else {
726 const struct asn1_type_func *f = t->ptr;
727 ret += (f->length)(el);
729 break;
731 case A1_OP_TAG: {
732 size_t datalen;
733 const void *olddata = data;
735 data = DPO(data, t->offset);
737 if (t->tt & A1_FLAG_OPTIONAL) {
738 void **el = (void **)data;
739 if (*el == NULL) {
740 data = olddata;
741 break;
743 data = *el;
745 datalen = _asn1_length(t->ptr, data);
746 ret += der_length_tag(A1_TAG_TAG(t->tt)) + der_length_len(datalen);
747 ret += datalen;
748 data = olddata;
749 break;
751 case A1_OP_PARSE: {
752 unsigned int type = A1_PARSE_TYPE(t->tt);
753 const void *el = DPOC(data, t->offset);
755 if (type >= sizeof(asn1_template_prim)/sizeof(asn1_template_prim[0])) {
756 ABORT_ON_ERROR();
757 break;
759 ret += (asn1_template_prim[type].length)(el);
760 break;
762 case A1_OP_SETOF:
763 case A1_OP_SEQOF: {
764 const struct template_of *el = DPOC(data, t->offset);
765 size_t ellen = _asn1_sizeofType(t->ptr);
766 const unsigned char *element = el->val;
767 unsigned int i;
769 for (i = 0; i < el->len; i++) {
770 ret += _asn1_length(t->ptr, element);
771 element += ellen;
774 break;
776 case A1_OP_BMEMBER: {
777 const struct asn1_template *bmember = t->ptr;
778 size_t size = bmember->offset;
779 size_t belements = A1_HEADER_LEN(bmember);
780 int rfc1510 = (bmember->tt & A1_HBF_RFC1510);
782 if (rfc1510) {
783 ret += 5;
784 } else {
786 ret += 1;
788 bmember += belements;
790 while (belements) {
791 if (_asn1_bmember_isset_bit(data, bmember->offset, size)) {
792 ret += (bmember->offset / 8) + 1;
793 break;
795 belements--; bmember--;
798 break;
800 case A1_OP_CHOICE: {
801 const struct asn1_template *choice = t->ptr;
802 const unsigned int *element = DPOC(data, choice->offset);
804 if (*element > A1_HEADER_LEN(choice))
805 break;
807 if (*element == 0) {
808 ret += der_length_octet_string(DPOC(data, choice->tt));
809 } else {
810 choice += *element;
811 ret += _asn1_length(choice->ptr, DPOC(data, choice->offset));
813 break;
815 default:
816 ABORT_ON_ERROR();
817 break;
819 elements--;
820 t--;
822 return ret;
825 void
826 _asn1_free(const struct asn1_template *t, void *data)
828 size_t elements = A1_HEADER_LEN(t);
830 if (t->tt & A1_HF_PRESERVE)
831 der_free_octet_string(data);
833 t++;
835 while (elements) {
836 switch (t->tt & A1_OP_MASK) {
837 case A1_OP_TYPE:
838 case A1_OP_TYPE_EXTERN: {
839 void *el = DPO(data, t->offset);
841 if (t->tt & A1_FLAG_OPTIONAL) {
842 void **pel = (void **)el;
843 if (*pel == NULL)
844 break;
845 el = *pel;
848 if ((t->tt & A1_OP_MASK) == A1_OP_TYPE) {
849 _asn1_free(t->ptr, el);
850 } else {
851 const struct asn1_type_func *f = t->ptr;
852 (f->release)(el);
854 if (t->tt & A1_FLAG_OPTIONAL)
855 free(el);
857 break;
859 case A1_OP_PARSE: {
860 unsigned int type = A1_PARSE_TYPE(t->tt);
861 void *el = DPO(data, t->offset);
863 if (type >= sizeof(asn1_template_prim)/sizeof(asn1_template_prim[0])) {
864 ABORT_ON_ERROR();
865 break;
867 (asn1_template_prim[type].release)(el);
868 break;
870 case A1_OP_TAG: {
871 void *el = DPO(data, t->offset);
873 if (t->tt & A1_FLAG_OPTIONAL) {
874 void **pel = (void **)el;
875 if (*pel == NULL)
876 break;
877 el = *pel;
880 _asn1_free(t->ptr, el);
882 if (t->tt & A1_FLAG_OPTIONAL)
883 free(el);
885 break;
887 case A1_OP_SETOF:
888 case A1_OP_SEQOF: {
889 struct template_of *el = DPO(data, t->offset);
890 size_t ellen = _asn1_sizeofType(t->ptr);
891 unsigned char *element = el->val;
892 unsigned int i;
894 for (i = 0; i < el->len; i++) {
895 _asn1_free(t->ptr, element);
896 element += ellen;
898 free(el->val);
899 el->val = NULL;
900 el->len = 0;
902 break;
904 case A1_OP_BMEMBER:
905 break;
906 case A1_OP_CHOICE: {
907 const struct asn1_template *choice = t->ptr;
908 const unsigned int *element = DPOC(data, choice->offset);
910 if (*element > A1_HEADER_LEN(choice))
911 break;
913 if (*element == 0) {
914 der_free_octet_string(DPO(data, choice->tt));
915 } else {
916 choice += *element;
917 _asn1_free(choice->ptr, DPO(data, choice->offset));
919 break;
921 default:
922 ABORT_ON_ERROR();
923 break;
925 t++;
926 elements--;
931 _asn1_copy(const struct asn1_template *t, const void *from, void *to)
933 size_t elements = A1_HEADER_LEN(t);
934 int ret = 0;
935 int preserve = (t->tt & A1_HF_PRESERVE);
937 t++;
939 if (preserve) {
940 ret = der_copy_octet_string(from, to);
941 if (ret)
942 return ret;
945 while (elements) {
946 switch (t->tt & A1_OP_MASK) {
947 case A1_OP_TYPE:
948 case A1_OP_TYPE_EXTERN: {
949 const void *fel = DPOC(from, t->offset);
950 void *tel = DPO(to, t->offset);
951 void **ptel = (void **)tel;
952 size_t size;
954 if ((t->tt & A1_OP_MASK) == A1_OP_TYPE) {
955 size = _asn1_sizeofType(t->ptr);
956 } else {
957 const struct asn1_type_func *f = t->ptr;
958 size = f->size;
961 if (t->tt & A1_FLAG_OPTIONAL) {
962 void **pfel = (void **)fel;
963 if (*pfel == NULL)
964 break;
965 fel = *pfel;
967 tel = *ptel = calloc(1, size);
968 if (tel == NULL)
969 return ENOMEM;
972 if ((t->tt & A1_OP_MASK) == A1_OP_TYPE) {
973 ret = _asn1_copy(t->ptr, fel, tel);
974 } else {
975 const struct asn1_type_func *f = t->ptr;
976 ret = (f->copy)(fel, tel);
979 if (ret) {
980 if (t->tt & A1_FLAG_OPTIONAL) {
981 free(*ptel);
982 *ptel = NULL;
984 return ret;
986 break;
988 case A1_OP_PARSE: {
989 unsigned int type = A1_PARSE_TYPE(t->tt);
990 const void *fel = DPOC(from, t->offset);
991 void *tel = DPO(to, t->offset);
993 if (type >= sizeof(asn1_template_prim)/sizeof(asn1_template_prim[0])) {
994 ABORT_ON_ERROR();
995 return ASN1_PARSE_ERROR;
997 ret = (asn1_template_prim[type].copy)(fel, tel);
998 if (ret)
999 return ret;
1000 break;
1002 case A1_OP_TAG: {
1003 const void *oldfrom = from;
1004 void *oldto = to;
1005 void **tel = NULL;
1007 from = DPOC(from, t->offset);
1008 to = DPO(to, t->offset);
1010 if (t->tt & A1_FLAG_OPTIONAL) {
1011 void **fel = (void **)from;
1012 tel = (void **)to;
1013 if (*fel == NULL) {
1014 from = oldfrom;
1015 to = oldto;
1016 break;
1018 from = *fel;
1020 to = *tel = calloc(1, _asn1_sizeofType(t->ptr));
1021 if (to == NULL)
1022 return ENOMEM;
1025 ret = _asn1_copy(t->ptr, from, to);
1026 if (ret) {
1027 if (tel) {
1028 free(*tel);
1029 *tel = NULL;
1031 return ret;
1034 from = oldfrom;
1035 to = oldto;
1037 break;
1039 case A1_OP_SETOF:
1040 case A1_OP_SEQOF: {
1041 const struct template_of *fel = DPOC(from, t->offset);
1042 struct template_of *tel = DPO(to, t->offset);
1043 size_t ellen = _asn1_sizeofType(t->ptr);
1044 unsigned int i;
1046 tel->val = calloc(fel->len, ellen);
1047 if (tel->val == NULL)
1048 return ENOMEM;
1050 tel->len = fel->len;
1052 for (i = 0; i < fel->len; i++) {
1053 ret = _asn1_copy(t->ptr,
1054 DPOC(fel->val, (i * ellen)),
1055 DPO(tel->val, (i *ellen)));
1056 if (ret)
1057 return ret;
1059 break;
1061 case A1_OP_BMEMBER: {
1062 const struct asn1_template *bmember = t->ptr;
1063 size_t size = bmember->offset;
1064 memcpy(to, from, size);
1065 break;
1067 case A1_OP_CHOICE: {
1068 const struct asn1_template *choice = t->ptr;
1069 const unsigned int *felement = DPOC(from, choice->offset);
1070 unsigned int *telement = DPO(to, choice->offset);
1072 if (*felement > A1_HEADER_LEN(choice))
1073 return ASN1_PARSE_ERROR;
1075 *telement = *felement;
1077 if (*felement == 0) {
1078 ret = der_copy_octet_string(DPOC(from, choice->tt), DPO(to, choice->tt));
1079 } else {
1080 choice += *felement;
1081 ret = _asn1_copy(choice->ptr,
1082 DPOC(from, choice->offset),
1083 DPO(to, choice->offset));
1085 if (ret)
1086 return ret;
1087 break;
1089 default:
1090 ABORT_ON_ERROR();
1091 break;
1093 t++;
1094 elements--;
1096 return 0;
1100 _asn1_decode_top(const struct asn1_template *t, unsigned flags, const unsigned char *p, size_t len, void *data, size_t *size)
1102 int ret;
1103 memset(data, 0, t->offset);
1104 ret = _asn1_decode(t, flags, p, len, data, size);
1105 if (ret)
1106 _asn1_free_top(t, data);
1108 return ret;
1112 _asn1_copy_top(const struct asn1_template *t, const void *from, void *to)
1114 int ret;
1115 memset(to, 0, t->offset);
1116 ret = _asn1_copy(t, from, to);
1117 if (ret)
1118 _asn1_free_top(t, to);
1120 return ret;
1123 void
1124 _asn1_free_top(const struct asn1_template *t, void *data)
1126 _asn1_free(t, data);
1127 memset(data, 0, t->offset);