xref: /freebsd/crypto/heimdal/lib/asn1/template.c (revision c66ec88fed842fbaad62c30d510644ceb7bd2d71)
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 }
1120