Remove building with NOCRYPTO option
[minix.git] / crypto / external / bsd / heimdal / dist / lib / asn1 / template.c
blob3922b092abb46ec272650db88b5ac4a4c53752e7
1 /* $NetBSD: template.c,v 1.1.1.2 2014/04/24 12:45:28 pettai Exp $ */
3 /*
4 * Copyright (c) 2009 Kungliga Tekniska Högskolan
5 * (Royal Institute of Technology, Stockholm, Sweden).
6 * All rights reserved.
8 * Portions Copyright (c) 2009 Apple Inc. All rights reserved.
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
17 * 2. Redistributions in binary form must reproduce the above copyright
18 * notice, this list of conditions and the following disclaimer in the
19 * documentation and/or other materials provided with the distribution.
21 * 3. Neither the name of the Institute nor the names of its contributors
22 * may be used to endorse or promote products derived from this software
23 * without specific prior written permission.
25 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
26 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
28 * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
29 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
30 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
31 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
32 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
33 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
34 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35 * SUCH DAMAGE.
38 #include "der_locl.h"
39 #include <krb5/com_err.h>
41 #if 0
42 #define ABORT_ON_ERROR() abort()
43 #else
44 #define ABORT_ON_ERROR() do { } while(0)
45 #endif
47 #define DPOC(data,offset) ((const void *)(((const unsigned char *)data) + offset))
48 #define DPO(data,offset) ((void *)(((unsigned char *)data) + offset))
51 static struct asn1_type_func prim[] = {
52 #define el(name, type) { \
53 (asn1_type_encode)der_put_##name, \
54 (asn1_type_decode)der_get_##name, \
55 (asn1_type_length)der_length_##name, \
56 (asn1_type_copy)der_copy_##name, \
57 (asn1_type_release)der_free_##name, \
58 sizeof(type) \
60 #define elber(name, type) { \
61 (asn1_type_encode)der_put_##name, \
62 (asn1_type_decode)der_get_##name##_ber, \
63 (asn1_type_length)der_length_##name, \
64 (asn1_type_copy)der_copy_##name, \
65 (asn1_type_release)der_free_##name, \
66 sizeof(type) \
68 el(integer, int),
69 el(heim_integer, heim_integer),
70 el(integer, int),
71 el(unsigned, unsigned),
72 el(general_string, heim_general_string),
73 el(octet_string, heim_octet_string),
74 elber(octet_string, heim_octet_string),
75 el(ia5_string, heim_ia5_string),
76 el(bmp_string, heim_bmp_string),
77 el(universal_string, heim_universal_string),
78 el(printable_string, heim_printable_string),
79 el(visible_string, heim_visible_string),
80 el(utf8string, heim_utf8_string),
81 el(generalized_time, time_t),
82 el(utctime, time_t),
83 el(bit_string, heim_bit_string),
84 { (asn1_type_encode)der_put_boolean, (asn1_type_decode)der_get_boolean,
85 (asn1_type_length)der_length_boolean, (asn1_type_copy)der_copy_integer,
86 (asn1_type_release)der_free_integer, sizeof(int)
88 el(oid, heim_oid),
89 el(general_string, heim_general_string),
90 #undef el
91 #undef elber
94 static size_t
95 sizeofType(const struct asn1_template *t)
97 return t->offset;
101 * Here is abstraction to not so well evil fact of bit fields in C,
102 * they are endian dependent, so when getting and setting bits in the
103 * host local structure we need to know the endianness of the host.
105 * Its not the first time in Heimdal this have bitten us, and some day
106 * we'll grow up and use #defined constant, but bit fields are still
107 * so pretty and shiny.
110 static void
111 bmember_get_bit(const unsigned char *p, void *data,
112 unsigned int bit, size_t size)
114 unsigned int localbit = bit % 8;
115 if ((*p >> (7 - localbit)) & 1) {
116 #ifdef WORDS_BIGENDIAN
117 *(unsigned int *)data |= (1 << ((size * 8) - bit - 1));
118 #else
119 *(unsigned int *)data |= (1 << bit);
120 #endif
124 static int
125 bmember_isset_bit(const void *data, unsigned int bit, size_t size)
127 #ifdef WORDS_BIGENDIAN
128 if ((*(unsigned int *)data) & (1 << ((size * 8) - bit - 1)))
129 return 1;
130 return 0;
131 #else
132 if ((*(unsigned int *)data) & (1 << bit))
133 return 1;
134 return 0;
135 #endif
138 static void
139 bmember_put_bit(unsigned char *p, const void *data, unsigned int bit,
140 size_t size, unsigned int *bitset)
142 unsigned int localbit = bit % 8;
144 if (bmember_isset_bit(data, bit, size)) {
145 *p |= (1 << (7 - localbit));
146 if (*bitset == 0)
147 *bitset = (7 - localbit) + 1;
152 _asn1_decode(const struct asn1_template *t, unsigned flags,
153 const unsigned char *p, size_t len, void *data, size_t *size)
155 size_t elements = A1_HEADER_LEN(t);
156 size_t oldlen = len;
157 int ret = 0;
158 const unsigned char *startp = NULL;
159 unsigned int template_flags = t->tt;
161 /* skip over header */
162 t++;
164 if (template_flags & A1_HF_PRESERVE)
165 startp = p;
167 while (elements) {
168 switch (t->tt & A1_OP_MASK) {
169 case A1_OP_TYPE:
170 case A1_OP_TYPE_EXTERN: {
171 size_t newsize, size;
172 void *el = DPO(data, t->offset);
173 void **pel = (void **)el;
175 if ((t->tt & A1_OP_MASK) == A1_OP_TYPE) {
176 size = sizeofType(t->ptr);
177 } else {
178 const struct asn1_type_func *f = t->ptr;
179 size = f->size;
182 if (t->tt & A1_FLAG_OPTIONAL) {
183 *pel = calloc(1, size);
184 if (*pel == NULL)
185 return ENOMEM;
186 el = *pel;
188 if ((t->tt & A1_OP_MASK) == A1_OP_TYPE) {
189 ret = _asn1_decode(t->ptr, flags, p, len, el, &newsize);
190 } else {
191 const struct asn1_type_func *f = t->ptr;
192 ret = (f->decode)(p, len, el, &newsize);
194 if (ret) {
195 if (t->tt & A1_FLAG_OPTIONAL) {
196 free(*pel);
197 *pel = NULL;
198 break;
200 return ret;
202 p += newsize; len -= newsize;
204 break;
206 case A1_OP_TAG: {
207 Der_type dertype;
208 size_t newsize;
209 size_t datalen, l;
210 void *olddata = data;
211 int is_indefinite = 0;
212 int subflags = flags;
214 ret = der_match_tag_and_length(p, len, A1_TAG_CLASS(t->tt),
215 &dertype, A1_TAG_TAG(t->tt),
216 &datalen, &l);
217 if (ret) {
218 if (t->tt & A1_FLAG_OPTIONAL)
219 break;
220 return ret;
223 p += l; len -= l;
226 * Only allow indefinite encoding for OCTET STRING and BER
227 * for now. Should handle BIT STRING too.
230 if (dertype != A1_TAG_TYPE(t->tt) && (flags & A1_PF_ALLOW_BER)) {
231 const struct asn1_template *subtype = t->ptr;
232 subtype++; /* skip header */
234 if (((subtype->tt & A1_OP_MASK) == A1_OP_PARSE) &&
235 A1_PARSE_TYPE(subtype->tt) == A1T_OCTET_STRING)
236 subflags |= A1_PF_INDEFINTE;
239 if (datalen == ASN1_INDEFINITE) {
240 if ((flags & A1_PF_ALLOW_BER) == 0)
241 return ASN1_GOT_BER;
242 is_indefinite = 1;
243 datalen = len;
244 if (datalen < 2)
245 return ASN1_OVERRUN;
246 /* hide EndOfContent for sub-decoder, catching it below */
247 datalen -= 2;
248 } else if (datalen > len)
249 return ASN1_OVERRUN;
251 data = DPO(data, t->offset);
253 if (t->tt & A1_FLAG_OPTIONAL) {
254 void **el = (void **)data;
255 size_t ellen = sizeofType(t->ptr);
257 *el = calloc(1, ellen);
258 if (*el == NULL)
259 return ENOMEM;
260 data = *el;
263 ret = _asn1_decode(t->ptr, subflags, p, datalen, data, &newsize);
264 if (ret)
265 return ret;
267 if (newsize != datalen)
268 return ASN1_EXTRA_DATA;
270 len -= datalen;
271 p += datalen;
274 * Indefinite encoding needs a trailing EndOfContent,
275 * check for that.
277 if (is_indefinite) {
278 ret = der_match_tag_and_length(p, len, ASN1_C_UNIV,
279 &dertype, UT_EndOfContent,
280 &datalen, &l);
281 if (ret)
282 return ret;
283 if (dertype != PRIM)
284 return ASN1_BAD_ID;
285 if (datalen != 0)
286 return ASN1_INDEF_EXTRA_DATA;
287 p += l; len -= l;
289 data = olddata;
291 break;
293 case A1_OP_PARSE: {
294 unsigned int type = A1_PARSE_TYPE(t->tt);
295 size_t newsize;
296 void *el = DPO(data, t->offset);
299 * INDEFINITE primitive types are one element after the
300 * same type but non-INDEFINITE version.
302 if (flags & A1_PF_INDEFINTE)
303 type++;
305 if (type >= sizeof(prim)/sizeof(prim[0])) {
306 ABORT_ON_ERROR();
307 return ASN1_PARSE_ERROR;
310 ret = (prim[type].decode)(p, len, el, &newsize);
311 if (ret)
312 return ret;
313 p += newsize; len -= newsize;
315 break;
317 case A1_OP_SETOF:
318 case A1_OP_SEQOF: {
319 struct template_of *el = DPO(data, t->offset);
320 size_t newsize;
321 size_t ellen = sizeofType(t->ptr);
322 size_t vallength = 0;
324 while (len > 0) {
325 void *tmp;
326 size_t newlen = vallength + ellen;
327 if (vallength > newlen)
328 return ASN1_OVERFLOW;
330 tmp = realloc(el->val, newlen);
331 if (tmp == NULL)
332 return ENOMEM;
334 memset(DPO(tmp, vallength), 0, ellen);
335 el->val = tmp;
337 ret = _asn1_decode(t->ptr, flags & (~A1_PF_INDEFINTE), p, len,
338 DPO(el->val, vallength), &newsize);
339 if (ret)
340 return ret;
341 vallength = newlen;
342 el->len++;
343 p += newsize; len -= newsize;
346 break;
348 case A1_OP_BMEMBER: {
349 const struct asn1_template *bmember = t->ptr;
350 size_t size = bmember->offset;
351 size_t elements = A1_HEADER_LEN(bmember);
352 size_t pos = 0;
354 bmember++;
356 memset(data, 0, size);
358 if (len < 1)
359 return ASN1_OVERRUN;
360 p++; len--;
362 while (elements && len) {
363 while (bmember->offset / 8 > pos / 8) {
364 if (len < 1)
365 break;
366 p++; len--;
367 pos += 8;
369 if (len) {
370 bmember_get_bit(p, data, bmember->offset, size);
371 elements--; bmember++;
374 len = 0;
375 break;
377 case A1_OP_CHOICE: {
378 const struct asn1_template *choice = t->ptr;
379 unsigned int *element = DPO(data, choice->offset);
380 size_t datalen;
381 unsigned int i;
383 for (i = 1; i < A1_HEADER_LEN(choice) + 1; i++) {
384 /* should match first tag instead, store it in choice.tt */
385 ret = _asn1_decode(choice[i].ptr, 0, p, len,
386 DPO(data, choice[i].offset), &datalen);
387 if (ret == 0) {
388 *element = i;
389 p += datalen; len -= datalen;
390 break;
391 } else if (ret != ASN1_BAD_ID && ret != ASN1_MISPLACED_FIELD && ret != ASN1_MISSING_FIELD) {
392 return ret;
395 if (i >= A1_HEADER_LEN(choice) + 1) {
396 if (choice->tt == 0)
397 return ASN1_BAD_ID;
399 *element = 0;
400 ret = der_get_octet_string(p, len,
401 DPO(data, choice->tt), &datalen);
402 if (ret)
403 return ret;
404 p += datalen; len -= datalen;
407 break;
409 default:
410 ABORT_ON_ERROR();
411 return ASN1_PARSE_ERROR;
413 t++;
414 elements--;
416 /* if we are using padding, eat up read of context */
417 if (template_flags & A1_HF_ELLIPSIS)
418 len = 0;
420 oldlen -= len;
422 if (size)
423 *size = oldlen;
426 * saved the raw bits if asked for it, useful for signature
427 * verification.
429 if (startp) {
430 heim_octet_string *save = data;
432 save->data = malloc(oldlen);
433 if (save->data == NULL)
434 return ENOMEM;
435 else {
436 save->length = oldlen;
437 memcpy(save->data, startp, oldlen);
440 return 0;
444 _asn1_encode(const struct asn1_template *t, unsigned char *p, size_t len, const void *data, size_t *size)
446 size_t elements = A1_HEADER_LEN(t);
447 int ret = 0;
448 size_t oldlen = len;
450 t += A1_HEADER_LEN(t);
452 while (elements) {
453 switch (t->tt & A1_OP_MASK) {
454 case A1_OP_TYPE:
455 case A1_OP_TYPE_EXTERN: {
456 size_t newsize;
457 const void *el = DPOC(data, t->offset);
459 if (t->tt & A1_FLAG_OPTIONAL) {
460 void **pel = (void **)el;
461 if (*pel == NULL)
462 break;
463 el = *pel;
466 if ((t->tt & A1_OP_MASK) == A1_OP_TYPE) {
467 ret = _asn1_encode(t->ptr, p, len, el, &newsize);
468 } else {
469 const struct asn1_type_func *f = t->ptr;
470 ret = (f->encode)(p, len, el, &newsize);
473 if (ret)
474 return ret;
475 p -= newsize; len -= newsize;
477 break;
479 case A1_OP_TAG: {
480 const void *olddata = data;
481 size_t l, datalen;
483 data = DPOC(data, t->offset);
485 if (t->tt & A1_FLAG_OPTIONAL) {
486 void **el = (void **)data;
487 if (*el == NULL) {
488 data = olddata;
489 break;
491 data = *el;
494 ret = _asn1_encode(t->ptr, p, len, data, &datalen);
495 if (ret)
496 return ret;
498 len -= datalen; p -= datalen;
500 ret = der_put_length_and_tag(p, len, datalen,
501 A1_TAG_CLASS(t->tt),
502 A1_TAG_TYPE(t->tt),
503 A1_TAG_TAG(t->tt), &l);
504 if (ret)
505 return ret;
507 p -= l; len -= l;
509 data = olddata;
511 break;
513 case A1_OP_PARSE: {
514 unsigned int type = A1_PARSE_TYPE(t->tt);
515 size_t newsize;
516 const void *el = DPOC(data, t->offset);
518 if (type > sizeof(prim)/sizeof(prim[0])) {
519 ABORT_ON_ERROR();
520 return ASN1_PARSE_ERROR;
523 ret = (prim[type].encode)(p, len, el, &newsize);
524 if (ret)
525 return ret;
526 p -= newsize; len -= newsize;
528 break;
530 case A1_OP_SETOF: {
531 const struct template_of *el = DPOC(data, t->offset);
532 size_t ellen = sizeofType(t->ptr);
533 struct heim_octet_string *val;
534 unsigned char *elptr = el->val;
535 size_t i, totallen;
537 if (el->len == 0)
538 break;
540 if (el->len > UINT_MAX/sizeof(val[0]))
541 return ERANGE;
543 val = malloc(sizeof(val[0]) * el->len);
544 if (val == NULL)
545 return ENOMEM;
547 for(totallen = 0, i = 0; i < el->len; i++) {
548 unsigned char *next;
549 size_t l;
551 val[i].length = _asn1_length(t->ptr, elptr);
552 val[i].data = malloc(val[i].length);
554 ret = _asn1_encode(t->ptr, DPO(val[i].data, val[i].length - 1),
555 val[i].length, elptr, &l);
556 if (ret)
557 break;
559 next = elptr + ellen;
560 if (next < elptr) {
561 ret = ASN1_OVERFLOW;
562 break;
564 elptr = next;
565 totallen += val[i].length;
567 if (ret == 0 && totallen > len)
568 ret = ASN1_OVERFLOW;
569 if (ret) {
570 do {
571 free(val[i].data);
572 } while(i-- > 0);
573 free(val);
574 return ret;
577 len -= totallen;
579 qsort(val, el->len, sizeof(val[0]), _heim_der_set_sort);
581 i = el->len - 1;
582 do {
583 p -= val[i].length;
584 memcpy(p + 1, val[i].data, val[i].length);
585 free(val[i].data);
586 } while(i-- > 0);
587 free(val);
589 break;
592 case A1_OP_SEQOF: {
593 struct template_of *el = DPO(data, t->offset);
594 size_t ellen = sizeofType(t->ptr);
595 size_t newsize;
596 unsigned int i;
597 unsigned char *elptr = el->val;
599 if (el->len == 0)
600 break;
602 elptr += ellen * (el->len - 1);
604 for (i = 0; i < el->len; i++) {
605 ret = _asn1_encode(t->ptr, p, len,
606 elptr,
607 &newsize);
608 if (ret)
609 return ret;
610 p -= newsize; len -= newsize;
611 elptr -= ellen;
614 break;
616 case A1_OP_BMEMBER: {
617 const struct asn1_template *bmember = t->ptr;
618 size_t size = bmember->offset;
619 size_t elements = A1_HEADER_LEN(bmember);
620 size_t pos;
621 unsigned char c = 0;
622 unsigned int bitset = 0;
623 int rfc1510 = (bmember->tt & A1_HBF_RFC1510);
625 bmember += elements;
627 if (rfc1510)
628 pos = 31;
629 else
630 pos = bmember->offset;
632 while (elements && len) {
633 while (bmember->offset / 8 < pos / 8) {
634 if (rfc1510 || bitset || c) {
635 if (len < 1)
636 return ASN1_OVERFLOW;
637 *p-- = c; len--;
639 c = 0;
640 pos -= 8;
642 bmember_put_bit(&c, data, bmember->offset, size, &bitset);
643 elements--; bmember--;
645 if (rfc1510 || bitset) {
646 if (len < 1)
647 return ASN1_OVERFLOW;
648 *p-- = c; len--;
651 if (len < 1)
652 return ASN1_OVERFLOW;
653 if (rfc1510 || bitset == 0)
654 *p-- = 0;
655 else
656 *p-- = bitset - 1;
658 len--;
660 break;
662 case A1_OP_CHOICE: {
663 const struct asn1_template *choice = t->ptr;
664 const unsigned int *element = DPOC(data, choice->offset);
665 size_t datalen;
666 const void *el;
668 if (*element > A1_HEADER_LEN(choice)) {
669 printf("element: %d\n", *element);
670 return ASN1_PARSE_ERROR;
673 if (*element == 0) {
674 ret += der_put_octet_string(p, len,
675 DPOC(data, choice->tt), &datalen);
676 } else {
677 choice += *element;
678 el = DPOC(data, choice->offset);
679 ret = _asn1_encode(choice->ptr, p, len, el, &datalen);
680 if (ret)
681 return ret;
683 len -= datalen; p -= datalen;
685 break;
687 default:
688 ABORT_ON_ERROR();
690 t--;
691 elements--;
693 if (size)
694 *size = oldlen - len;
696 return 0;
699 size_t
700 _asn1_length(const struct asn1_template *t, const void *data)
702 size_t elements = A1_HEADER_LEN(t);
703 size_t ret = 0;
705 t += A1_HEADER_LEN(t);
707 while (elements) {
708 switch (t->tt & A1_OP_MASK) {
709 case A1_OP_TYPE:
710 case A1_OP_TYPE_EXTERN: {
711 const void *el = DPOC(data, t->offset);
713 if (t->tt & A1_FLAG_OPTIONAL) {
714 void **pel = (void **)el;
715 if (*pel == NULL)
716 break;
717 el = *pel;
720 if ((t->tt & A1_OP_MASK) == A1_OP_TYPE) {
721 ret += _asn1_length(t->ptr, el);
722 } else {
723 const struct asn1_type_func *f = t->ptr;
724 ret += (f->length)(el);
726 break;
728 case A1_OP_TAG: {
729 size_t datalen;
730 const void *olddata = data;
732 data = DPO(data, t->offset);
734 if (t->tt & A1_FLAG_OPTIONAL) {
735 void **el = (void **)data;
736 if (*el == NULL) {
737 data = olddata;
738 break;
740 data = *el;
742 datalen = _asn1_length(t->ptr, data);
743 ret += der_length_tag(A1_TAG_TAG(t->tt)) + der_length_len(datalen);
744 ret += datalen;
745 data = olddata;
746 break;
748 case A1_OP_PARSE: {
749 unsigned int type = A1_PARSE_TYPE(t->tt);
750 const void *el = DPOC(data, t->offset);
752 if (type > sizeof(prim)/sizeof(prim[0])) {
753 ABORT_ON_ERROR();
754 break;
756 ret += (prim[type].length)(el);
757 break;
759 case A1_OP_SETOF:
760 case A1_OP_SEQOF: {
761 const struct template_of *el = DPOC(data, t->offset);
762 size_t ellen = sizeofType(t->ptr);
763 const unsigned char *element = el->val;
764 unsigned int i;
766 for (i = 0; i < el->len; i++) {
767 ret += _asn1_length(t->ptr, element);
768 element += ellen;
771 break;
773 case A1_OP_BMEMBER: {
774 const struct asn1_template *bmember = t->ptr;
775 size_t size = bmember->offset;
776 size_t elements = A1_HEADER_LEN(bmember);
777 int rfc1510 = (bmember->tt & A1_HBF_RFC1510);
779 if (rfc1510) {
780 ret += 5;
781 } else {
783 ret += 1;
785 bmember += elements;
787 while (elements) {
788 if (bmember_isset_bit(data, bmember->offset, size)) {
789 ret += (bmember->offset / 8) + 1;
790 break;
792 elements--; bmember--;
795 break;
797 case A1_OP_CHOICE: {
798 const struct asn1_template *choice = t->ptr;
799 const unsigned int *element = DPOC(data, choice->offset);
801 if (*element > A1_HEADER_LEN(choice))
802 break;
804 if (*element == 0) {
805 ret += der_length_octet_string(DPOC(data, choice->tt));
806 } else {
807 choice += *element;
808 ret += _asn1_length(choice->ptr, DPOC(data, choice->offset));
810 break;
812 default:
813 ABORT_ON_ERROR();
814 break;
816 elements--;
817 t--;
819 return ret;
822 void
823 _asn1_free(const struct asn1_template *t, void *data)
825 size_t elements = A1_HEADER_LEN(t);
827 if (t->tt & A1_HF_PRESERVE)
828 der_free_octet_string(data);
830 t++;
832 while (elements) {
833 switch (t->tt & A1_OP_MASK) {
834 case A1_OP_TYPE:
835 case A1_OP_TYPE_EXTERN: {
836 void *el = DPO(data, t->offset);
838 if (t->tt & A1_FLAG_OPTIONAL) {
839 void **pel = (void **)el;
840 if (*pel == NULL)
841 break;
842 el = *pel;
845 if ((t->tt & A1_OP_MASK) == A1_OP_TYPE) {
846 _asn1_free(t->ptr, el);
847 } else {
848 const struct asn1_type_func *f = t->ptr;
849 (f->release)(el);
851 if (t->tt & A1_FLAG_OPTIONAL)
852 free(el);
854 break;
856 case A1_OP_PARSE: {
857 unsigned int type = A1_PARSE_TYPE(t->tt);
858 void *el = DPO(data, t->offset);
860 if (type > sizeof(prim)/sizeof(prim[0])) {
861 ABORT_ON_ERROR();
862 break;
864 (prim[type].release)(el);
865 break;
867 case A1_OP_TAG: {
868 void *el = DPO(data, t->offset);
870 if (t->tt & A1_FLAG_OPTIONAL) {
871 void **pel = (void **)el;
872 if (*pel == NULL)
873 break;
874 el = *pel;
877 _asn1_free(t->ptr, el);
879 if (t->tt & A1_FLAG_OPTIONAL)
880 free(el);
882 break;
884 case A1_OP_SETOF:
885 case A1_OP_SEQOF: {
886 struct template_of *el = DPO(data, t->offset);
887 size_t ellen = sizeofType(t->ptr);
888 unsigned char *element = el->val;
889 unsigned int i;
891 for (i = 0; i < el->len; i++) {
892 _asn1_free(t->ptr, element);
893 element += ellen;
895 free(el->val);
896 el->val = NULL;
897 el->len = 0;
899 break;
901 case A1_OP_BMEMBER:
902 break;
903 case A1_OP_CHOICE: {
904 const struct asn1_template *choice = t->ptr;
905 const unsigned int *element = DPOC(data, choice->offset);
907 if (*element > A1_HEADER_LEN(choice))
908 break;
910 if (*element == 0) {
911 der_free_octet_string(DPO(data, choice->tt));
912 } else {
913 choice += *element;
914 _asn1_free(choice->ptr, DPO(data, choice->offset));
916 break;
918 default:
919 ABORT_ON_ERROR();
920 break;
922 t++;
923 elements--;
928 _asn1_copy(const struct asn1_template *t, const void *from, void *to)
930 size_t elements = A1_HEADER_LEN(t);
931 int ret = 0;
932 int preserve = (t->tt & A1_HF_PRESERVE);
934 t++;
936 if (preserve) {
937 ret = der_copy_octet_string(from, to);
938 if (ret)
939 return ret;
942 while (elements) {
943 switch (t->tt & A1_OP_MASK) {
944 case A1_OP_TYPE:
945 case A1_OP_TYPE_EXTERN: {
946 const void *fel = DPOC(from, t->offset);
947 void *tel = DPO(to, t->offset);
948 void **ptel = (void **)tel;
949 size_t size;
951 if ((t->tt & A1_OP_MASK) == A1_OP_TYPE) {
952 size = sizeofType(t->ptr);
953 } else {
954 const struct asn1_type_func *f = t->ptr;
955 size = f->size;
958 if (t->tt & A1_FLAG_OPTIONAL) {
959 void **pfel = (void **)fel;
960 if (*pfel == NULL)
961 break;
962 fel = *pfel;
964 tel = *ptel = calloc(1, size);
965 if (tel == NULL)
966 return ENOMEM;
969 if ((t->tt & A1_OP_MASK) == A1_OP_TYPE) {
970 ret = _asn1_copy(t->ptr, fel, tel);
971 } else {
972 const struct asn1_type_func *f = t->ptr;
973 ret = (f->copy)(fel, tel);
976 if (ret) {
977 if (t->tt & A1_FLAG_OPTIONAL) {
978 free(*ptel);
979 *ptel = NULL;
981 return ret;
983 break;
985 case A1_OP_PARSE: {
986 unsigned int type = A1_PARSE_TYPE(t->tt);
987 const void *fel = DPOC(from, t->offset);
988 void *tel = DPO(to, t->offset);
990 if (type > sizeof(prim)/sizeof(prim[0])) {
991 ABORT_ON_ERROR();
992 return ASN1_PARSE_ERROR;
994 ret = (prim[type].copy)(fel, tel);
995 if (ret)
996 return ret;
997 break;
999 case A1_OP_TAG: {
1000 const void *oldfrom = from;
1001 void *oldto = to;
1002 void **tel = NULL;
1004 from = DPOC(from, t->offset);
1005 to = DPO(to, t->offset);
1007 if (t->tt & A1_FLAG_OPTIONAL) {
1008 void **fel = (void **)from;
1009 tel = (void **)to;
1010 if (*fel == NULL) {
1011 from = oldfrom;
1012 to = oldto;
1013 break;
1015 from = *fel;
1017 to = *tel = calloc(1, sizeofType(t->ptr));
1018 if (to == NULL)
1019 return ENOMEM;
1022 ret = _asn1_copy(t->ptr, from, to);
1023 if (ret) {
1024 if (t->tt & A1_FLAG_OPTIONAL) {
1025 free(*tel);
1026 *tel = NULL;
1028 return ret;
1031 from = oldfrom;
1032 to = oldto;
1034 break;
1036 case A1_OP_SETOF:
1037 case A1_OP_SEQOF: {
1038 const struct template_of *fel = DPOC(from, t->offset);
1039 struct template_of *tel = DPO(to, t->offset);
1040 size_t ellen = sizeofType(t->ptr);
1041 unsigned int i;
1043 tel->val = calloc(fel->len, ellen);
1044 if (tel->val == NULL)
1045 return ENOMEM;
1047 tel->len = fel->len;
1049 for (i = 0; i < fel->len; i++) {
1050 ret = _asn1_copy(t->ptr,
1051 DPOC(fel->val, (i * ellen)),
1052 DPO(tel->val, (i *ellen)));
1053 if (ret)
1054 return ret;
1056 break;
1058 case A1_OP_BMEMBER: {
1059 const struct asn1_template *bmember = t->ptr;
1060 size_t size = bmember->offset;
1061 memcpy(to, from, size);
1062 break;
1064 case A1_OP_CHOICE: {
1065 const struct asn1_template *choice = t->ptr;
1066 const unsigned int *felement = DPOC(from, choice->offset);
1067 unsigned int *telement = DPO(to, choice->offset);
1069 if (*felement > A1_HEADER_LEN(choice))
1070 return ASN1_PARSE_ERROR;
1072 *telement = *felement;
1074 if (*felement == 0) {
1075 ret = der_copy_octet_string(DPOC(from, choice->tt), DPO(to, choice->tt));
1076 } else {
1077 choice += *felement;
1078 ret = _asn1_copy(choice->ptr,
1079 DPOC(from, choice->offset),
1080 DPO(to, choice->offset));
1082 if (ret)
1083 return ret;
1084 break;
1086 default:
1087 ABORT_ON_ERROR();
1088 break;
1090 t++;
1091 elements--;
1093 return 0;
1097 _asn1_decode_top(const struct asn1_template *t, unsigned flags, const unsigned char *p, size_t len, void *data, size_t *size)
1099 int ret;
1100 memset(data, 0, t->offset);
1101 ret = _asn1_decode(t, flags, p, len, data, size);
1102 if (ret) {
1103 _asn1_free(t, data);
1104 memset(data, 0, t->offset);
1107 return ret;
1111 _asn1_copy_top(const struct asn1_template *t, const void *from, void *to)
1113 int ret;
1114 memset(to, 0, t->offset);
1115 ret = _asn1_copy(t, from, to);
1116 if (ret) {
1117 _asn1_free(t, to);
1118 memset(to, 0, t->offset);
1120 return ret;