fix memset
[heimdal.git] / lib / asn1 / template.c
blobd3b2c07f0012da9dda1ef5465f0f0fc3c310d9d0
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 static 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(integer64, int64_t),
70 el(unsigned, unsigned),
71 el(unsigned64, uint64_t),
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 *retsize)
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 els = 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 (els && 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 els--; 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 (retsize)
423 *retsize = 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,
445 const void *data, size_t *retsize)
447 size_t elements = A1_HEADER_LEN(t);
448 int ret = 0;
449 size_t oldlen = len;
451 t += A1_HEADER_LEN(t);
453 while (elements) {
454 switch (t->tt & A1_OP_MASK) {
455 case A1_OP_TYPE:
456 case A1_OP_TYPE_EXTERN: {
457 size_t newsize;
458 const void *el = DPOC(data, t->offset);
460 if (t->tt & A1_FLAG_OPTIONAL) {
461 void **pel = (void **)el;
462 if (*pel == NULL)
463 break;
464 el = *pel;
467 if ((t->tt & A1_OP_MASK) == A1_OP_TYPE) {
468 ret = _asn1_encode(t->ptr, p, len, el, &newsize);
469 } else {
470 const struct asn1_type_func *f = t->ptr;
471 ret = (f->encode)(p, len, el, &newsize);
474 if (ret)
475 return ret;
476 p -= newsize; len -= newsize;
478 break;
480 case A1_OP_TAG: {
481 const void *olddata = data;
482 size_t l, datalen;
484 data = DPOC(data, t->offset);
486 if (t->tt & A1_FLAG_OPTIONAL) {
487 void **el = (void **)data;
488 if (*el == NULL) {
489 data = olddata;
490 break;
492 data = *el;
495 ret = _asn1_encode(t->ptr, p, len, data, &datalen);
496 if (ret)
497 return ret;
499 len -= datalen; p -= datalen;
501 ret = der_put_length_and_tag(p, len, datalen,
502 A1_TAG_CLASS(t->tt),
503 A1_TAG_TYPE(t->tt),
504 A1_TAG_TAG(t->tt), &l);
505 if (ret)
506 return ret;
508 p -= l; len -= l;
510 data = olddata;
512 break;
514 case A1_OP_PARSE: {
515 unsigned int type = A1_PARSE_TYPE(t->tt);
516 size_t newsize;
517 const void *el = DPOC(data, t->offset);
519 if (type > sizeof(prim)/sizeof(prim[0])) {
520 ABORT_ON_ERROR();
521 return ASN1_PARSE_ERROR;
524 ret = (prim[type].encode)(p, len, el, &newsize);
525 if (ret)
526 return ret;
527 p -= newsize; len -= newsize;
529 break;
531 case A1_OP_SETOF: {
532 const struct template_of *el = DPOC(data, t->offset);
533 size_t ellen = sizeofType(t->ptr);
534 struct heim_octet_string *val;
535 unsigned char *elptr = el->val;
536 size_t i, totallen;
538 if (el->len == 0)
539 break;
541 if (el->len > UINT_MAX/sizeof(val[0]))
542 return ERANGE;
544 val = malloc(sizeof(val[0]) * el->len);
545 if (val == NULL)
546 return ENOMEM;
548 for(totallen = 0, i = 0; i < el->len; i++) {
549 unsigned char *next;
550 size_t l;
552 val[i].length = _asn1_length(t->ptr, elptr);
553 val[i].data = malloc(val[i].length);
555 ret = _asn1_encode(t->ptr, DPO(val[i].data, val[i].length - 1),
556 val[i].length, elptr, &l);
557 if (ret)
558 break;
560 next = elptr + ellen;
561 if (next < elptr) {
562 ret = ASN1_OVERFLOW;
563 break;
565 elptr = next;
566 totallen += val[i].length;
568 if (ret == 0 && totallen > len)
569 ret = ASN1_OVERFLOW;
570 if (ret) {
571 do {
572 free(val[i].data);
573 } while(i-- > 0);
574 free(val);
575 return ret;
578 len -= totallen;
580 qsort(val, el->len, sizeof(val[0]), _heim_der_set_sort);
582 i = el->len - 1;
583 do {
584 p -= val[i].length;
585 memcpy(p + 1, val[i].data, val[i].length);
586 free(val[i].data);
587 } while(i-- > 0);
588 free(val);
590 break;
593 case A1_OP_SEQOF: {
594 struct template_of *el = DPO(data, t->offset);
595 size_t ellen = sizeofType(t->ptr);
596 size_t newsize;
597 unsigned int i;
598 unsigned char *elptr = el->val;
600 if (el->len == 0)
601 break;
603 elptr += ellen * (el->len - 1);
605 for (i = 0; i < el->len; i++) {
606 ret = _asn1_encode(t->ptr, p, len,
607 elptr,
608 &newsize);
609 if (ret)
610 return ret;
611 p -= newsize; len -= newsize;
612 elptr -= ellen;
615 break;
617 case A1_OP_BMEMBER: {
618 const struct asn1_template *bmember = t->ptr;
619 size_t size = bmember->offset;
620 size_t els = A1_HEADER_LEN(bmember);
621 size_t pos;
622 unsigned char c = 0;
623 unsigned int bitset = 0;
624 int rfc1510 = (bmember->tt & A1_HBF_RFC1510);
626 bmember += els;
628 if (rfc1510)
629 pos = 31;
630 else
631 pos = bmember->offset;
633 while (els && len) {
634 while (bmember->offset / 8 < pos / 8) {
635 if (rfc1510 || bitset || c) {
636 if (len < 1)
637 return ASN1_OVERFLOW;
638 *p-- = c; len--;
640 c = 0;
641 pos -= 8;
643 bmember_put_bit(&c, data, bmember->offset, size, &bitset);
644 els--; bmember--;
646 if (rfc1510 || bitset) {
647 if (len < 1)
648 return ASN1_OVERFLOW;
649 *p-- = c; len--;
652 if (len < 1)
653 return ASN1_OVERFLOW;
654 if (rfc1510 || bitset == 0)
655 *p-- = 0;
656 else
657 *p-- = bitset - 1;
659 len--;
661 break;
663 case A1_OP_CHOICE: {
664 const struct asn1_template *choice = t->ptr;
665 const unsigned int *element = DPOC(data, choice->offset);
666 size_t datalen;
667 const void *el;
669 if (*element > A1_HEADER_LEN(choice)) {
670 printf("element: %d\n", *element);
671 return ASN1_PARSE_ERROR;
674 if (*element == 0) {
675 ret += der_put_octet_string(p, len,
676 DPOC(data, choice->tt), &datalen);
677 } else {
678 choice += *element;
679 el = DPOC(data, choice->offset);
680 ret = _asn1_encode(choice->ptr, p, len, el, &datalen);
681 if (ret)
682 return ret;
684 len -= datalen; p -= datalen;
686 break;
688 default:
689 ABORT_ON_ERROR();
691 t--;
692 elements--;
694 if (retsize)
695 *retsize = oldlen - len;
697 return 0;
700 size_t
701 _asn1_length(const struct asn1_template *t, const void *data)
703 size_t elements = A1_HEADER_LEN(t);
704 size_t ret = 0;
706 t += A1_HEADER_LEN(t);
708 while (elements) {
709 switch (t->tt & A1_OP_MASK) {
710 case A1_OP_TYPE:
711 case A1_OP_TYPE_EXTERN: {
712 const void *el = DPOC(data, t->offset);
714 if (t->tt & A1_FLAG_OPTIONAL) {
715 void **pel = (void **)el;
716 if (*pel == NULL)
717 break;
718 el = *pel;
721 if ((t->tt & A1_OP_MASK) == A1_OP_TYPE) {
722 ret += _asn1_length(t->ptr, el);
723 } else {
724 const struct asn1_type_func *f = t->ptr;
725 ret += (f->length)(el);
727 break;
729 case A1_OP_TAG: {
730 size_t datalen;
731 const void *olddata = data;
733 data = DPO(data, t->offset);
735 if (t->tt & A1_FLAG_OPTIONAL) {
736 void **el = (void **)data;
737 if (*el == NULL) {
738 data = olddata;
739 break;
741 data = *el;
743 datalen = _asn1_length(t->ptr, data);
744 ret += der_length_tag(A1_TAG_TAG(t->tt)) + der_length_len(datalen);
745 ret += datalen;
746 data = olddata;
747 break;
749 case A1_OP_PARSE: {
750 unsigned int type = A1_PARSE_TYPE(t->tt);
751 const void *el = DPOC(data, t->offset);
753 if (type > sizeof(prim)/sizeof(prim[0])) {
754 ABORT_ON_ERROR();
755 break;
757 ret += (prim[type].length)(el);
758 break;
760 case A1_OP_SETOF:
761 case A1_OP_SEQOF: {
762 const struct template_of *el = DPOC(data, t->offset);
763 size_t ellen = sizeofType(t->ptr);
764 const unsigned char *element = el->val;
765 unsigned int i;
767 for (i = 0; i < el->len; i++) {
768 ret += _asn1_length(t->ptr, element);
769 element += ellen;
772 break;
774 case A1_OP_BMEMBER: {
775 const struct asn1_template *bmember = t->ptr;
776 size_t size = bmember->offset;
777 size_t els = A1_HEADER_LEN(bmember);
778 int rfc1510 = (bmember->tt & A1_HBF_RFC1510);
780 if (rfc1510) {
781 ret += 5;
782 } else {
784 ret += 1;
786 bmember += els;
788 while (els) {
789 if (bmember_isset_bit(data, bmember->offset, size)) {
790 ret += (bmember->offset / 8) + 1;
791 break;
793 els--; bmember--;
796 break;
798 case A1_OP_CHOICE: {
799 const struct asn1_template *choice = t->ptr;
800 const unsigned int *element = DPOC(data, choice->offset);
802 if (*element > A1_HEADER_LEN(choice))
803 break;
805 if (*element == 0) {
806 ret += der_length_octet_string(DPOC(data, choice->tt));
807 } else {
808 choice += *element;
809 ret += _asn1_length(choice->ptr, DPOC(data, choice->offset));
811 break;
813 default:
814 ABORT_ON_ERROR();
815 break;
817 elements--;
818 t--;
820 return ret;
823 void
824 _asn1_free(const struct asn1_template *t, void *data)
826 size_t elements = A1_HEADER_LEN(t);
828 if (t->tt & A1_HF_PRESERVE)
829 der_free_octet_string(data);
831 t++;
833 while (elements) {
834 switch (t->tt & A1_OP_MASK) {
835 case A1_OP_TYPE:
836 case A1_OP_TYPE_EXTERN: {
837 void *el = DPO(data, t->offset);
839 if (t->tt & A1_FLAG_OPTIONAL) {
840 void **pel = (void **)el;
841 if (*pel == NULL)
842 break;
843 el = *pel;
846 if ((t->tt & A1_OP_MASK) == A1_OP_TYPE) {
847 _asn1_free(t->ptr, el);
848 } else {
849 const struct asn1_type_func *f = t->ptr;
850 (f->release)(el);
852 if (t->tt & A1_FLAG_OPTIONAL)
853 free(el);
855 break;
857 case A1_OP_PARSE: {
858 unsigned int type = A1_PARSE_TYPE(t->tt);
859 void *el = DPO(data, t->offset);
861 if (type > sizeof(prim)/sizeof(prim[0])) {
862 ABORT_ON_ERROR();
863 break;
865 (prim[type].release)(el);
866 break;
868 case A1_OP_TAG: {
869 void *el = DPO(data, t->offset);
871 if (t->tt & A1_FLAG_OPTIONAL) {
872 void **pel = (void **)el;
873 if (*pel == NULL)
874 break;
875 el = *pel;
878 _asn1_free(t->ptr, el);
880 if (t->tt & A1_FLAG_OPTIONAL)
881 free(el);
883 break;
885 case A1_OP_SETOF:
886 case A1_OP_SEQOF: {
887 struct template_of *el = DPO(data, t->offset);
888 size_t ellen = sizeofType(t->ptr);
889 unsigned char *element = el->val;
890 unsigned int i;
892 for (i = 0; i < el->len; i++) {
893 _asn1_free(t->ptr, element);
894 element += ellen;
896 free(el->val);
897 el->val = NULL;
898 el->len = 0;
900 break;
902 case A1_OP_BMEMBER:
903 break;
904 case A1_OP_CHOICE: {
905 const struct asn1_template *choice = t->ptr;
906 const unsigned int *element = DPOC(data, choice->offset);
908 if (*element > A1_HEADER_LEN(choice))
909 break;
911 if (*element == 0) {
912 der_free_octet_string(DPO(data, choice->tt));
913 } else {
914 choice += *element;
915 _asn1_free(choice->ptr, DPO(data, choice->offset));
917 break;
919 default:
920 ABORT_ON_ERROR();
921 break;
923 t++;
924 elements--;
929 _asn1_copy(const struct asn1_template *t, const void *from, void *to)
931 size_t elements = A1_HEADER_LEN(t);
932 int ret = 0;
933 int preserve = (t->tt & A1_HF_PRESERVE);
935 t++;
937 if (preserve) {
938 ret = der_copy_octet_string(from, to);
939 if (ret)
940 return ret;
943 while (elements) {
944 switch (t->tt & A1_OP_MASK) {
945 case A1_OP_TYPE:
946 case A1_OP_TYPE_EXTERN: {
947 const void *fel = DPOC(from, t->offset);
948 void *tel = DPO(to, t->offset);
949 void **ptel = (void **)tel;
950 size_t size;
952 if ((t->tt & A1_OP_MASK) == A1_OP_TYPE) {
953 size = sizeofType(t->ptr);
954 } else {
955 const struct asn1_type_func *f = t->ptr;
956 size = f->size;
959 if (t->tt & A1_FLAG_OPTIONAL) {
960 void **pfel = (void **)fel;
961 if (*pfel == NULL)
962 break;
963 fel = *pfel;
965 tel = *ptel = calloc(1, size);
966 if (tel == NULL)
967 return ENOMEM;
970 if ((t->tt & A1_OP_MASK) == A1_OP_TYPE) {
971 ret = _asn1_copy(t->ptr, fel, tel);
972 } else {
973 const struct asn1_type_func *f = t->ptr;
974 ret = (f->copy)(fel, tel);
977 if (ret) {
978 if (t->tt & A1_FLAG_OPTIONAL) {
979 free(*ptel);
980 *ptel = NULL;
982 return ret;
984 break;
986 case A1_OP_PARSE: {
987 unsigned int type = A1_PARSE_TYPE(t->tt);
988 const void *fel = DPOC(from, t->offset);
989 void *tel = DPO(to, t->offset);
991 if (type > sizeof(prim)/sizeof(prim[0])) {
992 ABORT_ON_ERROR();
993 return ASN1_PARSE_ERROR;
995 ret = (prim[type].copy)(fel, tel);
996 if (ret)
997 return ret;
998 break;
1000 case A1_OP_TAG: {
1001 const void *oldfrom = from;
1002 void *oldto = to;
1003 void **tel = NULL;
1005 from = DPOC(from, t->offset);
1006 to = DPO(to, t->offset);
1008 if (t->tt & A1_FLAG_OPTIONAL) {
1009 void **fel = (void **)from;
1010 tel = (void **)to;
1011 if (*fel == NULL) {
1012 from = oldfrom;
1013 to = oldto;
1014 break;
1016 from = *fel;
1018 to = *tel = calloc(1, sizeofType(t->ptr));
1019 if (to == NULL)
1020 return ENOMEM;
1023 ret = _asn1_copy(t->ptr, from, to);
1024 if (ret) {
1025 if (t->tt & A1_FLAG_OPTIONAL) {
1026 free(*tel);
1027 *tel = NULL;
1029 return ret;
1032 from = oldfrom;
1033 to = oldto;
1035 break;
1037 case A1_OP_SETOF:
1038 case A1_OP_SEQOF: {
1039 const struct template_of *fel = DPOC(from, t->offset);
1040 struct template_of *tel = DPO(to, t->offset);
1041 size_t ellen = sizeofType(t->ptr);
1042 unsigned int i;
1044 tel->val = calloc(fel->len, ellen);
1045 if (tel->val == NULL)
1046 return ENOMEM;
1048 tel->len = fel->len;
1050 for (i = 0; i < fel->len; i++) {
1051 ret = _asn1_copy(t->ptr,
1052 DPOC(fel->val, (i * ellen)),
1053 DPO(tel->val, (i *ellen)));
1054 if (ret)
1055 return ret;
1057 break;
1059 case A1_OP_BMEMBER: {
1060 const struct asn1_template *bmember = t->ptr;
1061 size_t size = bmember->offset;
1062 memcpy(to, from, size);
1063 break;
1065 case A1_OP_CHOICE: {
1066 const struct asn1_template *choice = t->ptr;
1067 const unsigned int *felement = DPOC(from, choice->offset);
1068 unsigned int *telement = DPO(to, choice->offset);
1070 if (*felement > A1_HEADER_LEN(choice))
1071 return ASN1_PARSE_ERROR;
1073 *telement = *felement;
1075 if (*felement == 0) {
1076 ret = der_copy_octet_string(DPOC(from, choice->tt), DPO(to, choice->tt));
1077 } else {
1078 choice += *felement;
1079 ret = _asn1_copy(choice->ptr,
1080 DPOC(from, choice->offset),
1081 DPO(to, choice->offset));
1083 if (ret)
1084 return ret;
1085 break;
1087 default:
1088 ABORT_ON_ERROR();
1089 break;
1091 t++;
1092 elements--;
1094 return 0;
1098 _asn1_decode_top(const struct asn1_template *t, unsigned flags, const unsigned char *p, size_t len, void *data, size_t *size)
1100 int ret;
1101 memset(data, 0, t->offset);
1102 ret = _asn1_decode(t, flags, p, len, data, size);
1103 if (ret) {
1104 _asn1_free(t, data);
1105 memset(data, 0, t->offset);
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(t, to);
1119 memset(to, 0, t->offset);
1121 return ret;