xref: /freebsd/crypto/heimdal/lib/asn1/template.c (revision 1b7487592987c91020063a311a14dc15b6e58075)
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(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)
87     },
88     el(oid, heim_oid),
89     el(general_string, heim_general_string),
90 #undef el
91 #undef elber
92 };
93 
94 static size_t
95 sizeofType(const struct asn1_template *t)
96 {
97     return t->offset;
98 }
99 
100 /*
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.
104  *
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.
108  */
109 
110 static void
111 bmember_get_bit(const unsigned char *p, void *data,
112 		unsigned int bit, size_t size)
113 {
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
121     }
122 }
123 
124 static int
125 bmember_isset_bit(const void *data, unsigned int bit, size_t size)
126 {
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
136 }
137 
138 static void
139 bmember_put_bit(unsigned char *p, const void *data, unsigned int bit,
140 		size_t size, unsigned int *bitset)
141 {
142     unsigned int localbit = bit % 8;
143 
144     if (bmember_isset_bit(data, bit, size)) {
145 	*p |= (1 << (7 - localbit));
146 	if (*bitset == 0)
147 	    *bitset = (7 - localbit) + 1;
148     }
149 }
150 
151 int
152 _asn1_decode(const struct asn1_template *t, unsigned flags,
153 	     const unsigned char *p, size_t len, void *data, size_t *size)
154 {
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;
160 
161     /* skip over header */
162     t++;
163 
164     if (template_flags & A1_HF_PRESERVE)
165 	startp = p;
166 
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;
174 
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;
180 	    }
181 
182 	    if (t->tt & A1_FLAG_OPTIONAL) {
183 		*pel = calloc(1, size);
184 		if (*pel == NULL)
185 		    return ENOMEM;
186 		el = *pel;
187 	    }
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);
193 	    }
194 	    if (ret) {
195 		if (t->tt & A1_FLAG_OPTIONAL) {
196 		    free(*pel);
197 		    *pel = NULL;
198 		    break;
199 		}
200 		return ret;
201 	    }
202 	    p += newsize; len -= newsize;
203 
204 	    break;
205 	}
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;
213 
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;
221 	    }
222 
223 	    p += l; len -= l;
224 
225 	    /*
226 	     * Only allow indefinite encoding for OCTET STRING and BER
227 	     * for now. Should handle BIT STRING too.
228 	     */
229 
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 */
233 
234 		if (((subtype->tt & A1_OP_MASK) == A1_OP_PARSE) &&
235 		    A1_PARSE_TYPE(subtype->tt) == A1T_OCTET_STRING)
236 		    subflags |= A1_PF_INDEFINTE;
237 	    }
238 
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;
250 
251 	    data = DPO(data, t->offset);
252 
253 	    if (t->tt & A1_FLAG_OPTIONAL) {
254 		void **el = (void **)data;
255 		size_t ellen = sizeofType(t->ptr);
256 
257 		*el = calloc(1, ellen);
258 		if (*el == NULL)
259 		    return ENOMEM;
260 		data = *el;
261 	    }
262 
263 	    ret = _asn1_decode(t->ptr, subflags, p, datalen, data, &newsize);
264 	    if (ret)
265 		return ret;
266 
267 	    if (newsize != datalen)
268 		return ASN1_EXTRA_DATA;
269 
270 	    len -= datalen;
271 	    p += datalen;
272 
273 	    /*
274 	     * Indefinite encoding needs a trailing EndOfContent,
275 	     * check for that.
276 	     */
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;
288 	    }
289 	    data = olddata;
290 
291 	    break;
292 	}
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);
297 
298 	    /*
299 	     * INDEFINITE primitive types are one element after the
300 	     * same type but non-INDEFINITE version.
301 	    */
302 	    if (flags & A1_PF_INDEFINTE)
303 		type++;
304 
305 	    if (type >= sizeof(prim)/sizeof(prim[0])) {
306 		ABORT_ON_ERROR();
307 		return ASN1_PARSE_ERROR;
308 	    }
309 
310 	    ret = (prim[type].decode)(p, len, el, &newsize);
311 	    if (ret)
312 		return ret;
313 	    p += newsize; len -= newsize;
314 
315 	    break;
316 	}
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;
323 
324 	    while (len > 0) {
325 		void *tmp;
326 		size_t newlen = vallength + ellen;
327 		if (vallength > newlen)
328 		    return ASN1_OVERFLOW;
329 
330 		tmp = realloc(el->val, newlen);
331 		if (tmp == NULL)
332 		    return ENOMEM;
333 
334 		memset(DPO(tmp, vallength), 0, ellen);
335 		el->val = tmp;
336 
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;
344 	    }
345 
346 	    break;
347 	}
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;
353 
354 	    bmember++;
355 
356 	    memset(data, 0, size);
357 
358 	    if (len < 1)
359 		return ASN1_OVERRUN;
360 	    p++; len--;
361 
362 	    while (elements && len) {
363 		while (bmember->offset / 8 > pos / 8) {
364 		    if (len < 1)
365 			break;
366 		    p++; len--;
367 		    pos += 8;
368 		}
369 		if (len) {
370 		    bmember_get_bit(p, data, bmember->offset, size);
371 		    elements--; bmember++;
372 		}
373 	    }
374 	    len = 0;
375 	    break;
376 	}
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;
382 
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;
393 		}
394 	    }
395 	    if (i >= A1_HEADER_LEN(choice) + 1) {
396 		if (choice->tt == 0)
397 		    return ASN1_BAD_ID;
398 
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;
405 	    }
406 
407 	    break;
408 	}
409 	default:
410 	    ABORT_ON_ERROR();
411 	    return ASN1_PARSE_ERROR;
412 	}
413 	t++;
414 	elements--;
415     }
416     /* if we are using padding, eat up read of context */
417     if (template_flags & A1_HF_ELLIPSIS)
418 	len = 0;
419 
420     oldlen -= len;
421 
422     if (size)
423 	*size = oldlen;
424 
425     /*
426      * saved the raw bits if asked for it, useful for signature
427      * verification.
428      */
429     if (startp) {
430 	heim_octet_string *save = data;
431 
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);
438 	}
439     }
440     return 0;
441 }
442 
443 int
444 _asn1_encode(const struct asn1_template *t, unsigned char *p, size_t len, const void *data, size_t *size)
445 {
446     size_t elements = A1_HEADER_LEN(t);
447     int ret = 0;
448     size_t oldlen = len;
449 
450     t += A1_HEADER_LEN(t);
451 
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);
458 
459 	    if (t->tt & A1_FLAG_OPTIONAL) {
460 		void **pel = (void **)el;
461 		if (*pel == NULL)
462 		    break;
463 		el = *pel;
464 	    }
465 
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);
471 	    }
472 
473 	    if (ret)
474 		return ret;
475 	    p -= newsize; len -= newsize;
476 
477 	    break;
478 	}
479 	case A1_OP_TAG: {
480 	    const void *olddata = data;
481 	    size_t l, datalen;
482 
483 	    data = DPOC(data, t->offset);
484 
485 	    if (t->tt & A1_FLAG_OPTIONAL) {
486 		void **el = (void **)data;
487 		if (*el == NULL) {
488 		    data = olddata;
489 		    break;
490 		}
491 		data = *el;
492 	    }
493 
494 	    ret = _asn1_encode(t->ptr, p, len, data, &datalen);
495 	    if (ret)
496 		return ret;
497 
498 	    len -= datalen; p -= datalen;
499 
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;
506 
507 	    p -= l; len -= l;
508 
509 	    data = olddata;
510 
511 	    break;
512 	}
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);
517 
518 	    if (type > sizeof(prim)/sizeof(prim[0])) {
519 		ABORT_ON_ERROR();
520 		return ASN1_PARSE_ERROR;
521 	    }
522 
523 	    ret = (prim[type].encode)(p, len, el, &newsize);
524 	    if (ret)
525 		return ret;
526 	    p -= newsize; len -= newsize;
527 
528 	    break;
529 	}
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;
536 
537 	    if (el->len == 0)
538 		break;
539 
540 	    if (el->len > UINT_MAX/sizeof(val[0]))
541 		return ERANGE;
542 
543 	    val = malloc(sizeof(val[0]) * el->len);
544 	    if (val == NULL)
545 		return ENOMEM;
546 
547 	    for(totallen = 0, i = 0; i < el->len; i++) {
548 		unsigned char *next;
549 		size_t l;
550 
551 		val[i].length = _asn1_length(t->ptr, elptr);
552 		val[i].data = malloc(val[i].length);
553 
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;
558 
559 		next = elptr + ellen;
560 		if (next < elptr) {
561 		    ret = ASN1_OVERFLOW;
562 		    break;
563 		}
564 		elptr = next;
565 		totallen += val[i].length;
566 	    }
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;
575 	    }
576 
577 	    len -= totallen;
578 
579 	    qsort(val, el->len, sizeof(val[0]), _heim_der_set_sort);
580 
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);
588 
589 	    break;
590 
591 	}
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;
598 
599 	    if (el->len == 0)
600 		break;
601 
602 	    elptr += ellen * (el->len - 1);
603 
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;
612 	    }
613 
614 	    break;
615 	}
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);
624 
625 	    bmember += elements;
626 
627 	    if (rfc1510)
628 		pos = 31;
629 	    else
630 		pos = bmember->offset;
631 
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--;
638 		    }
639 		    c = 0;
640 		    pos -= 8;
641 		}
642 		bmember_put_bit(&c, data, bmember->offset, size, &bitset);
643 		elements--; bmember--;
644 	    }
645 	    if (rfc1510 || bitset) {
646 		if (len < 1)
647 		    return ASN1_OVERFLOW;
648 		*p-- = c; len--;
649 	    }
650 
651 	    if (len < 1)
652 		return ASN1_OVERFLOW;
653 	    if (rfc1510 || bitset == 0)
654 		*p-- = 0;
655 	    else
656 		*p-- = bitset - 1;
657 
658 	    len--;
659 
660 	    break;
661 	}
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;
667 
668 	    if (*element > A1_HEADER_LEN(choice)) {
669 		printf("element: %d\n", *element);
670 		return ASN1_PARSE_ERROR;
671 	    }
672 
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;
682 	    }
683 	    len -= datalen; p -= datalen;
684 
685 	    break;
686 	}
687 	default:
688 	    ABORT_ON_ERROR();
689 	}
690 	t--;
691 	elements--;
692     }
693     if (size)
694 	*size = oldlen - len;
695 
696     return 0;
697 }
698 
699 size_t
700 _asn1_length(const struct asn1_template *t, const void *data)
701 {
702     size_t elements = A1_HEADER_LEN(t);
703     size_t ret = 0;
704 
705     t += A1_HEADER_LEN(t);
706 
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);
712 
713 	    if (t->tt & A1_FLAG_OPTIONAL) {
714 		void **pel = (void **)el;
715 		if (*pel == NULL)
716 		    break;
717 		el = *pel;
718 	    }
719 
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);
725 	    }
726 	    break;
727 	}
728 	case A1_OP_TAG: {
729 	    size_t datalen;
730 	    const void *olddata = data;
731 
732 	    data = DPO(data, t->offset);
733 
734 	    if (t->tt & A1_FLAG_OPTIONAL) {
735 		void **el = (void **)data;
736 		if (*el == NULL) {
737 		    data = olddata;
738 		    break;
739 		}
740 		data = *el;
741 	    }
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;
747 	}
748 	case A1_OP_PARSE: {
749 	    unsigned int type = A1_PARSE_TYPE(t->tt);
750 	    const void *el = DPOC(data, t->offset);
751 
752 	    if (type > sizeof(prim)/sizeof(prim[0])) {
753 		ABORT_ON_ERROR();
754 		break;
755 	    }
756 	    ret += (prim[type].length)(el);
757 	    break;
758 	}
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;
765 
766 	    for (i = 0; i < el->len; i++) {
767 		ret += _asn1_length(t->ptr, element);
768 		element += ellen;
769 	    }
770 
771 	    break;
772 	}
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);
778 
779 	    if (rfc1510) {
780 		ret += 5;
781 	    } else {
782 
783 		ret += 1;
784 
785 		bmember += elements;
786 
787 		while (elements) {
788 		    if (bmember_isset_bit(data, bmember->offset, size)) {
789 			ret += (bmember->offset / 8) + 1;
790 			break;
791 		    }
792 		    elements--; bmember--;
793 		}
794 	    }
795 	    break;
796 	}
797 	case A1_OP_CHOICE: {
798 	    const struct asn1_template *choice = t->ptr;
799 	    const unsigned int *element = DPOC(data, choice->offset);
800 
801 	    if (*element > A1_HEADER_LEN(choice))
802 		break;
803 
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));
809 	    }
810 	    break;
811 	}
812 	default:
813 	    ABORT_ON_ERROR();
814 	    break;
815 	}
816 	elements--;
817 	t--;
818     }
819     return ret;
820 }
821 
822 void
823 _asn1_free(const struct asn1_template *t, void *data)
824 {
825     size_t elements = A1_HEADER_LEN(t);
826 
827     if (t->tt & A1_HF_PRESERVE)
828 	der_free_octet_string(data);
829 
830     t++;
831 
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);
837 
838 	    if (t->tt & A1_FLAG_OPTIONAL) {
839 		void **pel = (void **)el;
840 		if (*pel == NULL)
841 		    break;
842 		el = *pel;
843 	    }
844 
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);
850 	    }
851 	    if (t->tt & A1_FLAG_OPTIONAL)
852 		free(el);
853 
854 	    break;
855 	}
856 	case A1_OP_PARSE: {
857 	    unsigned int type = A1_PARSE_TYPE(t->tt);
858 	    void *el = DPO(data, t->offset);
859 
860 	    if (type > sizeof(prim)/sizeof(prim[0])) {
861 		ABORT_ON_ERROR();
862 		break;
863 	    }
864 	    (prim[type].release)(el);
865 	    break;
866 	}
867 	case A1_OP_TAG: {
868 	    void *el = DPO(data, t->offset);
869 
870 	    if (t->tt & A1_FLAG_OPTIONAL) {
871 		void **pel = (void **)el;
872 		if (*pel == NULL)
873 		    break;
874 		el = *pel;
875 	    }
876 
877 	    _asn1_free(t->ptr, el);
878 
879 	    if (t->tt & A1_FLAG_OPTIONAL)
880 		free(el);
881 
882 	    break;
883 	}
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;
890 
891 	    for (i = 0; i < el->len; i++) {
892 		_asn1_free(t->ptr, element);
893 		element += ellen;
894 	    }
895 	    free(el->val);
896 	    el->val = NULL;
897 	    el->len = 0;
898 
899 	    break;
900 	}
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);
906 
907 	    if (*element > A1_HEADER_LEN(choice))
908 		break;
909 
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));
915 	    }
916 	    break;
917 	}
918 	default:
919 	    ABORT_ON_ERROR();
920 	    break;
921 	}
922 	t++;
923 	elements--;
924     }
925 }
926 
927 int
928 _asn1_copy(const struct asn1_template *t, const void *from, void *to)
929 {
930     size_t elements = A1_HEADER_LEN(t);
931     int ret = 0;
932     int preserve = (t->tt & A1_HF_PRESERVE);
933 
934     t++;
935 
936     if (preserve) {
937 	ret = der_copy_octet_string(from, to);
938 	if (ret)
939 	    return ret;
940     }
941 
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;
950 
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;
956 	    }
957 
958 	    if (t->tt & A1_FLAG_OPTIONAL) {
959 		void **pfel = (void **)fel;
960 		if (*pfel == NULL)
961 		    break;
962 		fel = *pfel;
963 
964 		tel = *ptel = calloc(1, size);
965 		if (tel == NULL)
966 		    return ENOMEM;
967 	    }
968 
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);
974 	    }
975 
976 	    if (ret) {
977 		if (t->tt & A1_FLAG_OPTIONAL) {
978 		    free(*ptel);
979 		    *ptel = NULL;
980 		}
981 		return ret;
982 	    }
983 	    break;
984 	}
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);
989 
990 	    if (type > sizeof(prim)/sizeof(prim[0])) {
991 		ABORT_ON_ERROR();
992 		return ASN1_PARSE_ERROR;
993 	    }
994 	    ret = (prim[type].copy)(fel, tel);
995 	    if (ret)
996 		return ret;
997 	    break;
998 	}
999 	case A1_OP_TAG: {
1000 	    const void *oldfrom = from;
1001 	    void *oldto = to;
1002 	    void **tel = NULL;
1003 
1004 	    from = DPOC(from, t->offset);
1005 	    to = DPO(to, t->offset);
1006 
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;
1014 		}
1015 		from = *fel;
1016 
1017 		to = *tel = calloc(1, sizeofType(t->ptr));
1018 		if (to == NULL)
1019 		    return ENOMEM;
1020 	    }
1021 
1022 	    ret = _asn1_copy(t->ptr, from, to);
1023 	    if (ret) {
1024 		if (t->tt & A1_FLAG_OPTIONAL) {
1025 		    free(*tel);
1026 		    *tel = NULL;
1027 		}
1028 		return ret;
1029 	    }
1030 
1031 	    from = oldfrom;
1032 	    to = oldto;
1033 
1034 	    break;
1035 	}
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;
1042 
1043 	    tel->val = calloc(fel->len, ellen);
1044 	    if (tel->val == NULL)
1045 		return ENOMEM;
1046 
1047 	    tel->len = fel->len;
1048 
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;
1055 	    }
1056 	    break;
1057 	}
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;
1063 	}
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);
1068 
1069 	    if (*felement > A1_HEADER_LEN(choice))
1070 		return ASN1_PARSE_ERROR;
1071 
1072 	    *telement = *felement;
1073 
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));
1081 	    }
1082 	    if (ret)
1083 		return ret;
1084 	    break;
1085 	}
1086 	default:
1087 	    ABORT_ON_ERROR();
1088 	    break;
1089 	}
1090 	t++;
1091 	elements--;
1092     }
1093     return 0;
1094 }
1095 
1096 int
1097 _asn1_decode_top(const struct asn1_template *t, unsigned flags, const unsigned char *p, size_t len, void *data, size_t *size)
1098 {
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);
1105     }
1106 
1107     return ret;
1108 }
1109 
1110 int
1111 _asn1_copy_top(const struct asn1_template *t, const void *from, void *to)
1112 {
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);
1119     }
1120     return ret;
1121 }
1122