]> CyberLeo.Net >> Repos - FreeBSD/releng/10.0.git/blob - crypto/heimdal/lib/asn1/template.c
- Copy stable/10 (r259064) to releng/10.0 as part of the
[FreeBSD/releng/10.0.git] / crypto / heimdal / lib / asn1 / template.c
1 /*
2  * Copyright (c) 2009 Kungliga Tekniska Högskolan
3  * (Royal Institute of Technology, Stockholm, Sweden).
4  * All rights reserved.
5  *
6  * Portions Copyright (c) 2009 Apple Inc. All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  *
12  * 1. Redistributions of source code must retain the above copyright
13  *    notice, this list of conditions and the following disclaimer.
14  *
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.
18  *
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.
22  *
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.
34  */
35
36 #include "der_locl.h"
37 #include <com_err.h>
38
39 #if 0
40 #define ABORT_ON_ERROR() abort()
41 #else
42 #define ABORT_ON_ERROR() do { } while(0)
43 #endif
44
45 #define DPOC(data,offset) ((const void *)(((const unsigned char *)data)  + offset))
46 #define DPO(data,offset) ((void *)(((unsigned char *)data)  + offset))
47
48
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)                                    \
57     }
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)                                    \
65     }
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)
85     },
86     el(oid, heim_oid),
87     el(general_string, heim_general_string),
88 #undef el
89 #undef elber
90 };
91
92 static size_t
93 sizeofType(const struct asn1_template *t)
94 {
95     return t->offset;
96 }
97
98 /*
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.
102  *
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.
106  */
107
108 static void
109 bmember_get_bit(const unsigned char *p, void *data,
110                 unsigned int bit, size_t size)
111 {
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
119     }
120 }
121
122 static int
123 bmember_isset_bit(const void *data, unsigned int bit, size_t size)
124 {
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
134 }
135
136 static void
137 bmember_put_bit(unsigned char *p, const void *data, unsigned int bit,
138                 size_t size, unsigned int *bitset)
139 {
140     unsigned int localbit = bit % 8;
141
142     if (bmember_isset_bit(data, bit, size)) {
143         *p |= (1 << (7 - localbit));
144         if (*bitset == 0)
145             *bitset = (7 - localbit) + 1;
146     }
147 }
148
149 int
150 _asn1_decode(const struct asn1_template *t, unsigned flags,
151              const unsigned char *p, size_t len, void *data, size_t *size)
152 {
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;
158
159     /* skip over header */
160     t++;
161
162     if (template_flags & A1_HF_PRESERVE)
163         startp = p;
164
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;
172
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;
178             }
179
180             if (t->tt & A1_FLAG_OPTIONAL) {
181                 *pel = calloc(1, size);
182                 if (*pel == NULL)
183                     return ENOMEM;
184                 el = *pel;
185             }
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);
191             }
192             if (ret) {
193                 if (t->tt & A1_FLAG_OPTIONAL) {
194                     free(*pel);
195                     *pel = NULL;
196                     break;
197                 }
198                 return ret;
199             }
200             p += newsize; len -= newsize;
201
202             break;
203         }
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;
211
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;
219             }
220
221             p += l; len -= l;
222
223             /*
224              * Only allow indefinite encoding for OCTET STRING and BER
225              * for now. Should handle BIT STRING too.
226              */
227
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 */
231
232                 if (((subtype->tt & A1_OP_MASK) == A1_OP_PARSE) &&
233                     A1_PARSE_TYPE(subtype->tt) == A1T_OCTET_STRING)
234                     subflags |= A1_PF_INDEFINTE;
235             }
236
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;
248
249             data = DPO(data, t->offset);
250
251             if (t->tt & A1_FLAG_OPTIONAL) {
252                 void **el = (void **)data;
253                 size_t ellen = sizeofType(t->ptr);
254
255                 *el = calloc(1, ellen);
256                 if (*el == NULL)
257                     return ENOMEM;
258                 data = *el;
259             }
260
261             ret = _asn1_decode(t->ptr, subflags, p, datalen, data, &newsize);
262             if (ret)
263                 return ret;
264
265             if (newsize != datalen)
266                 return ASN1_EXTRA_DATA;
267
268             len -= datalen;
269             p += datalen;
270
271             /*
272              * Indefinite encoding needs a trailing EndOfContent,
273              * check for that.
274              */
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;
286             }
287             data = olddata;
288
289             break;
290         }
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);
295
296             /*
297              * INDEFINITE primitive types are one element after the
298              * same type but non-INDEFINITE version.
299             */
300             if (flags & A1_PF_INDEFINTE)
301                 type++;
302
303             if (type >= sizeof(prim)/sizeof(prim[0])) {
304                 ABORT_ON_ERROR();
305                 return ASN1_PARSE_ERROR;
306             }
307
308             ret = (prim[type].decode)(p, len, el, &newsize);
309             if (ret)
310                 return ret;
311             p += newsize; len -= newsize;
312
313             break;
314         }
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;
321
322             while (len > 0) {
323                 void *tmp;
324                 size_t newlen = vallength + ellen;
325                 if (vallength > newlen)
326                     return ASN1_OVERFLOW;
327
328                 tmp = realloc(el->val, newlen);
329                 if (tmp == NULL)
330                     return ENOMEM;
331
332                 memset(DPO(tmp, vallength), 0, ellen);
333                 el->val = tmp;
334
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;
342             }
343
344             break;
345         }
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;
351
352             bmember++;
353
354             memset(data, 0, size);
355
356             if (len < 1)
357                 return ASN1_OVERRUN;
358             p++; len--;
359
360             while (elements && len) {
361                 while (bmember->offset / 8 > pos / 8) {
362                     if (len < 1)
363                         break;
364                     p++; len--;
365                     pos += 8;
366                 }
367                 if (len) {
368                     bmember_get_bit(p, data, bmember->offset, size);
369                     elements--; bmember++;
370                 }
371             }
372             len = 0;
373             break;
374         }
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;
380
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;
391                 }
392             }
393             if (i >= A1_HEADER_LEN(choice) + 1) {
394                 if (choice->tt == 0)
395                     return ASN1_BAD_ID;
396
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;
403             }
404
405             break;
406         }
407         default:
408             ABORT_ON_ERROR();
409             return ASN1_PARSE_ERROR;
410         }
411         t++;
412         elements--;
413     }
414     /* if we are using padding, eat up read of context */
415     if (template_flags & A1_HF_ELLIPSIS)
416         len = 0;
417
418     oldlen -= len;
419
420     if (size)
421         *size = oldlen;
422
423     /*
424      * saved the raw bits if asked for it, useful for signature
425      * verification.
426      */
427     if (startp) {
428         heim_octet_string *save = data;
429
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);
436         }
437     }
438     return 0;
439 }
440
441 int
442 _asn1_encode(const struct asn1_template *t, unsigned char *p, size_t len, const void *data, size_t *size)
443 {
444     size_t elements = A1_HEADER_LEN(t);
445     int ret = 0;
446     size_t oldlen = len;
447
448     t += A1_HEADER_LEN(t);
449
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);
456
457             if (t->tt & A1_FLAG_OPTIONAL) {
458                 void **pel = (void **)el;
459                 if (*pel == NULL)
460                     break;
461                 el = *pel;
462             }
463
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);
469             }
470
471             if (ret)
472                 return ret;
473             p -= newsize; len -= newsize;
474
475             break;
476         }
477         case A1_OP_TAG: {
478             const void *olddata = data;
479             size_t l, datalen;
480
481             data = DPOC(data, t->offset);
482
483             if (t->tt & A1_FLAG_OPTIONAL) {
484                 void **el = (void **)data;
485                 if (*el == NULL) {
486                     data = olddata;
487                     break;
488                 }
489                 data = *el;
490             }
491
492             ret = _asn1_encode(t->ptr, p, len, data, &datalen);
493             if (ret)
494                 return ret;
495
496             len -= datalen; p -= datalen;
497
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;
504
505             p -= l; len -= l;
506
507             data = olddata;
508
509             break;
510         }
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);
515
516             if (type > sizeof(prim)/sizeof(prim[0])) {
517                 ABORT_ON_ERROR();
518                 return ASN1_PARSE_ERROR;
519             }
520
521             ret = (prim[type].encode)(p, len, el, &newsize);
522             if (ret)
523                 return ret;
524             p -= newsize; len -= newsize;
525
526             break;
527         }
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;
534
535             if (el->len == 0)
536                 break;
537
538             if (el->len > UINT_MAX/sizeof(val[0]))
539                 return ERANGE;
540
541             val = malloc(sizeof(val[0]) * el->len);
542             if (val == NULL)
543                 return ENOMEM;
544
545             for(totallen = 0, i = 0; i < el->len; i++) {
546                 unsigned char *next;
547                 size_t l;
548
549                 val[i].length = _asn1_length(t->ptr, elptr);
550                 val[i].data = malloc(val[i].length);
551
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;
556
557                 next = elptr + ellen;
558                 if (next < elptr) {
559                     ret = ASN1_OVERFLOW;
560                     break;
561                 }
562                 elptr = next;
563                 totallen += val[i].length;
564             }
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;
573             }
574
575             len -= totallen;
576
577             qsort(val, el->len, sizeof(val[0]), _heim_der_set_sort);
578
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);
586
587             break;
588
589         }
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;
596
597             if (el->len == 0)
598                 break;
599
600             elptr += ellen * (el->len - 1);
601
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;
610             }
611
612             break;
613         }
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);
622
623             bmember += elements;
624
625             if (rfc1510)
626                 pos = 31;
627             else
628                 pos = bmember->offset;
629
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--;
636                     }
637                     c = 0;
638                     pos -= 8;
639                 }
640                 bmember_put_bit(&c, data, bmember->offset, size, &bitset);
641                 elements--; bmember--;
642             }
643             if (rfc1510 || bitset) {
644                 if (len < 1)
645                     return ASN1_OVERFLOW;
646                 *p-- = c; len--;
647             }
648
649             if (len < 1)
650                 return ASN1_OVERFLOW;
651             if (rfc1510 || bitset == 0)
652                 *p-- = 0;
653             else
654                 *p-- = bitset - 1;
655
656             len--;
657
658             break;
659         }
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;
665
666             if (*element > A1_HEADER_LEN(choice)) {
667                 printf("element: %d\n", *element);
668                 return ASN1_PARSE_ERROR;
669             }
670
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;
680             }
681             len -= datalen; p -= datalen;
682
683             break;
684         }
685         default:
686             ABORT_ON_ERROR();
687         }
688         t--;
689         elements--;
690     }
691     if (size)
692         *size = oldlen - len;
693
694     return 0;
695 }
696
697 size_t
698 _asn1_length(const struct asn1_template *t, const void *data)
699 {
700     size_t elements = A1_HEADER_LEN(t);
701     size_t ret = 0;
702
703     t += A1_HEADER_LEN(t);
704
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);
710
711             if (t->tt & A1_FLAG_OPTIONAL) {
712                 void **pel = (void **)el;
713                 if (*pel == NULL)
714                     break;
715                 el = *pel;
716             }
717
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);
723             }
724             break;
725         }
726         case A1_OP_TAG: {
727             size_t datalen;
728             const void *olddata = data;
729
730             data = DPO(data, t->offset);
731
732             if (t->tt & A1_FLAG_OPTIONAL) {
733                 void **el = (void **)data;
734                 if (*el == NULL) {
735                     data = olddata;
736                     break;
737                 }
738                 data = *el;
739             }
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;
745         }
746         case A1_OP_PARSE: {
747             unsigned int type = A1_PARSE_TYPE(t->tt);
748             const void *el = DPOC(data, t->offset);
749
750             if (type > sizeof(prim)/sizeof(prim[0])) {
751                 ABORT_ON_ERROR();
752                 break;
753             }
754             ret += (prim[type].length)(el);
755             break;
756         }
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;
763
764             for (i = 0; i < el->len; i++) {
765                 ret += _asn1_length(t->ptr, element);
766                 element += ellen;
767             }
768
769             break;
770         }
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);
776
777             if (rfc1510) {
778                 ret += 5;
779             } else {
780
781                 ret += 1;
782
783                 bmember += elements;
784
785                 while (elements) {
786                     if (bmember_isset_bit(data, bmember->offset, size)) {
787                         ret += (bmember->offset / 8) + 1;
788                         break;
789                     }
790                     elements--; bmember--;
791                 }
792             }
793             break;
794         }
795         case A1_OP_CHOICE: {
796             const struct asn1_template *choice = t->ptr;
797             const unsigned int *element = DPOC(data, choice->offset);
798
799             if (*element > A1_HEADER_LEN(choice))
800                 break;
801
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));
807             }
808             break;
809         }
810         default:
811             ABORT_ON_ERROR();
812             break;
813         }
814         elements--;
815         t--;
816     }
817     return ret;
818 }
819
820 void
821 _asn1_free(const struct asn1_template *t, void *data)
822 {
823     size_t elements = A1_HEADER_LEN(t);
824
825     if (t->tt & A1_HF_PRESERVE)
826         der_free_octet_string(data);
827
828     t++;
829
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);
835
836             if (t->tt & A1_FLAG_OPTIONAL) {
837                 void **pel = (void **)el;
838                 if (*pel == NULL)
839                     break;
840                 el = *pel;
841             }
842
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);
848             }
849             if (t->tt & A1_FLAG_OPTIONAL)
850                 free(el);
851
852             break;
853         }
854         case A1_OP_PARSE: {
855             unsigned int type = A1_PARSE_TYPE(t->tt);
856             void *el = DPO(data, t->offset);
857
858             if (type > sizeof(prim)/sizeof(prim[0])) {
859                 ABORT_ON_ERROR();
860                 break;
861             }
862             (prim[type].release)(el);
863             break;
864         }
865         case A1_OP_TAG: {
866             void *el = DPO(data, t->offset);
867
868             if (t->tt & A1_FLAG_OPTIONAL) {
869                 void **pel = (void **)el;
870                 if (*pel == NULL)
871                     break;
872                 el = *pel;
873             }
874
875             _asn1_free(t->ptr, el);
876
877             if (t->tt & A1_FLAG_OPTIONAL)
878                 free(el);
879
880             break;
881         }
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;
888
889             for (i = 0; i < el->len; i++) {
890                 _asn1_free(t->ptr, element);
891                 element += ellen;
892             }
893             free(el->val);
894             el->val = NULL;
895             el->len = 0;
896
897             break;
898         }
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);
904
905             if (*element > A1_HEADER_LEN(choice))
906                 break;
907
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));
913             }
914             break;
915         }
916         default:
917             ABORT_ON_ERROR();
918             break;
919         }
920         t++;
921         elements--;
922     }
923 }
924
925 int
926 _asn1_copy(const struct asn1_template *t, const void *from, void *to)
927 {
928     size_t elements = A1_HEADER_LEN(t);
929     int ret = 0;
930     int preserve = (t->tt & A1_HF_PRESERVE);
931
932     t++;
933
934     if (preserve) {
935         ret = der_copy_octet_string(from, to);
936         if (ret)
937             return ret;
938     }
939
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;
948
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;
954             }
955
956             if (t->tt & A1_FLAG_OPTIONAL) {
957                 void **pfel = (void **)fel;
958                 if (*pfel == NULL)
959                     break;
960                 fel = *pfel;
961
962                 tel = *ptel = calloc(1, size);
963                 if (tel == NULL)
964                     return ENOMEM;
965             }
966
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);
972             }
973
974             if (ret) {
975                 if (t->tt & A1_FLAG_OPTIONAL) {
976                     free(*ptel);
977                     *ptel = NULL;
978                 }
979                 return ret;
980             }
981             break;
982         }
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);
987
988             if (type > sizeof(prim)/sizeof(prim[0])) {
989                 ABORT_ON_ERROR();
990                 return ASN1_PARSE_ERROR;
991             }
992             ret = (prim[type].copy)(fel, tel);
993             if (ret)
994                 return ret;
995             break;
996         }
997         case A1_OP_TAG: {
998             const void *oldfrom = from;
999             void *oldto = to;
1000             void **tel = NULL;
1001
1002             from = DPOC(from, t->offset);
1003             to = DPO(to, t->offset);
1004
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;
1012                 }
1013                 from = *fel;
1014
1015                 to = *tel = calloc(1, sizeofType(t->ptr));
1016                 if (to == NULL)
1017                     return ENOMEM;
1018             }
1019
1020             ret = _asn1_copy(t->ptr, from, to);
1021             if (ret) {
1022                 if (t->tt & A1_FLAG_OPTIONAL) {
1023                     free(*tel);
1024                     *tel = NULL;
1025                 }
1026                 return ret;
1027             }
1028
1029             from = oldfrom;
1030             to = oldto;
1031
1032             break;
1033         }
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;
1040
1041             tel->val = calloc(fel->len, ellen);
1042             if (tel->val == NULL)
1043                 return ENOMEM;
1044
1045             tel->len = fel->len;
1046
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;
1053             }
1054             break;
1055         }
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;
1061         }
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);
1066
1067             if (*felement > A1_HEADER_LEN(choice))
1068                 return ASN1_PARSE_ERROR;
1069
1070             *telement = *felement;
1071
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));
1079             }
1080             if (ret)
1081                 return ret;
1082             break;
1083         }
1084         default:
1085             ABORT_ON_ERROR();
1086             break;
1087         }
1088         t++;
1089         elements--;
1090     }
1091     return 0;
1092 }
1093
1094 int
1095 _asn1_decode_top(const struct asn1_template *t, unsigned flags, const unsigned char *p, size_t len, void *data, size_t *size)
1096 {
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);
1103     }
1104
1105     return ret;
1106 }
1107
1108 int
1109 _asn1_copy_top(const struct asn1_template *t, const void *from, void *to)
1110 {
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);
1117     }
1118     return ret;
1119 }