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 - 2010 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
39struct asn1_type_func asn1_template_prim[A1T_NUM_ENTRY] = {
40#define el(name, type) {				\
41	(asn1_type_encode)der_put_##name,		\
42	(asn1_type_decode)der_get_##name,		\
43	(asn1_type_length)der_length_##name,		\
44	(asn1_type_copy)der_copy_##name,		\
45	(asn1_type_release)der_free_##name,		\
46	sizeof(type)					\
47    }
48#define elber(name, type) {				\
49	(asn1_type_encode)der_put_##name,		\
50	(asn1_type_decode)der_get_##name##_ber,		\
51	(asn1_type_length)der_length_##name,		\
52	(asn1_type_copy)der_copy_##name,		\
53	(asn1_type_release)der_free_##name,		\
54	sizeof(type)					\
55    }
56    el(integer, int),
57    el(heim_integer, heim_integer),
58    el(integer, int),
59    el(unsigned, unsigned),
60    el(general_string, heim_general_string),
61    el(octet_string, heim_octet_string),
62    elber(octet_string, heim_octet_string),
63    el(ia5_string, heim_ia5_string),
64    el(bmp_string, heim_bmp_string),
65    el(universal_string, heim_universal_string),
66    el(printable_string, heim_printable_string),
67    el(visible_string, heim_visible_string),
68    el(utf8string, heim_utf8_string),
69    el(generalized_time, time_t),
70    el(utctime, time_t),
71    el(bit_string, heim_bit_string),
72    { (asn1_type_encode)der_put_boolean, (asn1_type_decode)der_get_boolean,
73      (asn1_type_length)der_length_boolean, (asn1_type_copy)der_copy_integer,
74      (asn1_type_release)der_free_integer, sizeof(int)
75    },
76    el(oid, heim_oid),
77    el(general_string, heim_general_string),
78#undef el
79#undef elber
80};
81
82size_t
83_asn1_sizeofType(const struct asn1_template *t)
84{
85    return t->offset;
86}
87
88/*
89 * Here is abstraction to not so well evil fact of bit fields in C,
90 * they are endian dependent, so when getting and setting bits in the
91 * host local structure we need to know the endianness of the host.
92 *
93 * Its not the first time in Heimdal this have bitten us, and some day
94 * we'll grow up and use #defined constant, but bit fields are still
95 * so pretty and shiny.
96 */
97
98static void
99_asn1_bmember_get_bit(const unsigned char *p, void *data,
100		      unsigned int bit, size_t size)
101{
102    unsigned int localbit = bit % 8;
103    if ((*p >> (7 - localbit)) & 1) {
104#ifdef WORDS_BIGENDIAN
105	*(unsigned int *)data |= (1 << ((size * 8) - bit - 1));
106#else
107	*(unsigned int *)data |= (1 << bit);
108#endif
109    }
110}
111
112int
113_asn1_bmember_isset_bit(const void *data, unsigned int bit, size_t size)
114{
115#ifdef WORDS_BIGENDIAN
116    if ((*(unsigned int *)data) & (1 << ((size * 8) - bit - 1)))
117	return 1;
118    return 0;
119#else
120    if ((*(unsigned int *)data) & (1 << bit))
121	return 1;
122    return 0;
123#endif
124}
125
126void
127_asn1_bmember_put_bit(unsigned char *p, const void *data, unsigned int bit,
128		      size_t size, unsigned int *bitset)
129{
130    unsigned int localbit = bit % 8;
131
132    if (_asn1_bmember_isset_bit(data, bit, size)) {
133	*p |= (1 << (7 - localbit));
134	if (*bitset == 0)
135	    *bitset = (7 - localbit) + 1;
136    }
137}
138
139int
140_asn1_decode(const struct asn1_template *t, unsigned flags,
141	     const unsigned char *p, size_t len, void *data, size_t *size)
142{
143    size_t elements = A1_HEADER_LEN(t);
144    size_t oldlen = len;
145    int ret = 0;
146    const unsigned char *startp = NULL;
147    unsigned int template_flags = t->tt;
148
149    /* skip over header */
150    t++;
151
152    if (template_flags & A1_HF_PRESERVE)
153	startp = p;
154
155    while (elements) {
156	switch (t->tt & A1_OP_MASK) {
157	case A1_OP_TYPE:
158	case A1_OP_TYPE_EXTERN: {
159	    size_t newsize, elsize;
160	    void *el = DPO(data, t->offset);
161	    void **pel = (void **)el;
162
163	    if ((t->tt & A1_OP_MASK) == A1_OP_TYPE) {
164		elsize = _asn1_sizeofType(t->ptr);
165	    } else {
166		const struct asn1_type_func *f = t->ptr;
167		elsize = f->size;
168	    }
169
170	    if (t->tt & A1_FLAG_OPTIONAL) {
171		*pel = calloc(1, elsize);
172		if (*pel == NULL)
173		    return ENOMEM;
174		el = *pel;
175	    }
176	    if ((t->tt & A1_OP_MASK) == A1_OP_TYPE) {
177		ret = _asn1_decode(t->ptr, flags, p, len, el, &newsize);
178	    } else {
179		const struct asn1_type_func *f = t->ptr;
180		ret = (f->decode)(p, len, el, &newsize);
181	    }
182	    if (ret) {
183		if (t->tt & A1_FLAG_OPTIONAL) {
184		    free(*pel);
185		    *pel = NULL;
186		    break;
187		}
188		return ret;
189	    }
190	    p += newsize; len -= newsize;
191
192	    break;
193	}
194	case A1_OP_TAG: {
195	    Der_type dertype;
196	    size_t newsize;
197	    size_t datalen, l;
198	    void *olddata = data;
199	    int is_indefinite = 0;
200	    int subflags = flags;
201
202	    ret = der_match_tag_and_length(p, len, A1_TAG_CLASS(t->tt),
203					   &dertype, A1_TAG_TAG(t->tt),
204					   &datalen, &l);
205	    if (ret) {
206		if (t->tt & A1_FLAG_OPTIONAL)
207		    break;
208		return ret;
209	    }
210
211	    p += l; len -= l;
212
213	    /*
214	     * Only allow indefinite encoding for OCTET STRING and BER
215	     * for now. Should handle BIT STRING too.
216	     */
217
218	    if (dertype != A1_TAG_TYPE(t->tt) && (flags & A1_PF_ALLOW_BER)) {
219		const struct asn1_template *subtype = t->ptr;
220		subtype++; /* skip header */
221
222		if (((subtype->tt & A1_OP_MASK) == A1_OP_PARSE) &&
223		    A1_PARSE_TYPE(subtype->tt) == A1T_OCTET_STRING)
224		    subflags |= A1_PF_INDEFINTE;
225	    }
226
227	    if (datalen == ASN1_INDEFINITE) {
228		if ((flags & A1_PF_ALLOW_BER) == 0)
229		    return ASN1_GOT_BER;
230		is_indefinite = 1;
231		datalen = len;
232		if (datalen < 2)
233		    return ASN1_OVERRUN;
234		/* hide EndOfContent for sub-decoder, catching it below */
235		datalen -= 2;
236	    } else if (datalen > len)
237		return ASN1_OVERRUN;
238
239	    data = DPO(data, t->offset);
240
241	    if (t->tt & A1_FLAG_OPTIONAL) {
242		void **el = (void **)data;
243		size_t ellen = _asn1_sizeofType(t->ptr);
244
245		*el = calloc(1, ellen);
246		if (*el == NULL)
247		    return ENOMEM;
248		data = *el;
249	    }
250
251	    ret = _asn1_decode(t->ptr, subflags, p, datalen, data, &newsize);
252	    if (ret)
253		return ret;
254
255	    if (is_indefinite) {
256		/* If we use indefinite encoding, the newsize is the datasize. */
257		datalen = newsize;
258	    } else if (newsize != datalen) {
259		/* Check for hidden data that might be after the real tag */
260		return ASN1_EXTRA_DATA;
261	    }
262
263	    len -= datalen;
264	    p += datalen;
265
266	    /*
267	     * Indefinite encoding needs a trailing EndOfContent,
268	     * check for that.
269	     */
270	    if (is_indefinite) {
271		ret = der_match_tag_and_length(p, len, ASN1_C_UNIV,
272					       &dertype, UT_EndOfContent,
273					       &datalen, &l);
274		if (ret)
275		    return ret;
276		if (dertype != PRIM)
277		    return ASN1_BAD_ID;
278		if (datalen != 0)
279		    return ASN1_INDEF_EXTRA_DATA;
280		p += l; len -= l;
281	    }
282	    data = olddata;
283
284	    break;
285	}
286	case A1_OP_PARSE: {
287	    unsigned int type = A1_PARSE_TYPE(t->tt);
288	    size_t newsize;
289	    void *el = DPO(data, t->offset);
290
291	    /*
292	     * INDEFINITE primitive types are one element after the
293	     * same type but non-INDEFINITE version.
294	    */
295	    if (flags & A1_PF_INDEFINTE)
296		type++;
297
298	    if (type >= sizeof(asn1_template_prim)/sizeof(asn1_template_prim[0])) {
299		ABORT_ON_ERROR();
300		return ASN1_PARSE_ERROR;
301	    }
302
303	    ret = (asn1_template_prim[type].decode)(p, len, el, &newsize);
304	    if (ret)
305		return ret;
306	    p += newsize; len -= newsize;
307
308	    break;
309	}
310	case A1_OP_SETOF:
311	case A1_OP_SEQOF: {
312	    struct template_of *el = DPO(data, t->offset);
313	    size_t newsize;
314	    size_t ellen = _asn1_sizeofType(t->ptr);
315	    size_t vallength = 0;
316
317	    while (len > 0) {
318		void *tmp;
319		size_t newlen = vallength + ellen;
320		if (vallength > newlen)
321		    return ASN1_OVERFLOW;
322
323		tmp = realloc(el->val, newlen);
324		if (tmp == NULL)
325		    return ENOMEM;
326
327		memset(DPO(tmp, vallength), 0, ellen);
328		el->val = tmp;
329		el->len++;
330
331		ret = _asn1_decode(t->ptr, flags & (~A1_PF_INDEFINTE), p, len,
332				   DPO(el->val, vallength), &newsize);
333		if (ret)
334		    return ret;
335		vallength = newlen;
336		p += newsize; len -= newsize;
337	    }
338
339	    break;
340	}
341	case A1_OP_BMEMBER: {
342	    const struct asn1_template *bmember = t->ptr;
343	    size_t bsize = bmember->offset;
344	    size_t belements = A1_HEADER_LEN(bmember);
345	    size_t pos = 0;
346
347	    bmember++;
348
349	    memset(data, 0, bsize);
350
351	    if (len < 1)
352		return ASN1_OVERRUN;
353	    p++; len--;
354
355	    while (belements && len) {
356		while (bmember->offset / 8 > pos / 8) {
357		    if (len < 1)
358			break;
359		    p++; len--;
360		    pos += 8;
361		}
362		if (len) {
363		    _asn1_bmember_get_bit(p, data, bmember->offset, bsize);
364		    belements--; bmember++;
365		}
366	    }
367	    len = 0;
368	    break;
369	}
370	case A1_OP_CHOICE: {
371	    const struct asn1_template *choice = t->ptr;
372	    int *element = DPO(data, choice->offset);
373	    size_t datalen;
374	    unsigned int i;
375
376	    /* provide a invalid value as default (0, so same as memset) */
377	    *element = ASN1_CHOICE_INVALID;
378
379	    for (i = 1; i < A1_HEADER_LEN(choice) + 1; i++) {
380		/* should match first tag instead, store it in choice.tt */
381		ret = _asn1_decode(choice[i].ptr, 0, p, len,
382				   DPO(data, choice[i].offset), &datalen);
383		if (ret == 0) {
384		    *element = i;
385		    p += datalen; len -= datalen;
386		    break;
387		} else if (ret != ASN1_BAD_ID && ret != ASN1_MISPLACED_FIELD && ret != ASN1_MISSING_FIELD) {
388		    _asn1_free_top(choice[i].ptr, DPO(data, choice[i].offset));
389		    return ret;
390		}
391		_asn1_free_top(choice[i].ptr, DPO(data, choice[i].offset));
392	    }
393	    if (i >= A1_HEADER_LEN(choice) + 1) {
394		if (choice->tt == 0)
395		    return ASN1_BAD_ID;
396
397		*element = ASN1_CHOICE_ELLIPSIS;
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
441int
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(asn1_template_prim)/sizeof(asn1_template_prim[0])) {
517		ABORT_ON_ERROR();
518		return ASN1_PARSE_ERROR;
519	    }
520
521	    ret = (asn1_template_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 = _asn1_sizeofType(t->ptr);
531	    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 = calloc(el->len, sizeof(val[0]));
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		if (val[i].length) {
551		    val[i].data = malloc(val[i].length);
552		    if (val[i].data == NULL) {
553			ret = ENOMEM;
554			break;
555		    }
556		}
557
558		ret = _asn1_encode(t->ptr, DPO(val[i].data, val[i].length - 1),
559				   val[i].length, elptr, &l);
560		if (ret)
561		    break;
562
563		next = elptr + ellen;
564		if (next < elptr) {
565		    ret = ASN1_OVERFLOW;
566		    break;
567		}
568		elptr = next;
569		totallen += val[i].length;
570	    }
571	    if (ret == 0 && totallen > len)
572		ret = ASN1_OVERFLOW;
573	    if (ret) {
574		for (i = 0; i < el->len; i++)
575		    free(val[i].data);
576		free(val);
577		return ret;
578	    }
579
580	    len -= totallen;
581
582	    qsort(val, el->len, sizeof(val[0]), _heim_der_set_sort);
583
584	    i = el->len - 1;
585	    do {
586		p -= val[i].length;
587		memcpy(p + 1, val[i].data, val[i].length);
588		free(val[i].data);
589	    } while(i-- > 0);
590	    free(val);
591
592	    break;
593
594	}
595	case A1_OP_SEQOF: {
596	    struct template_of *el = DPO(data, t->offset);
597	    size_t ellen = _asn1_sizeofType(t->ptr);
598	    size_t newsize;
599	    unsigned int i;
600	    unsigned char *elptr = el->val;
601
602	    if (el->len == 0)
603		break;
604
605	    elptr += ellen * (el->len - 1);
606
607	    for (i = 0; i < el->len; i++) {
608		ret = _asn1_encode(t->ptr, p, len,
609				   elptr,
610				   &newsize);
611		if (ret)
612		    return ret;
613		p -= newsize; len -= newsize;
614		elptr -= ellen;
615	    }
616
617	    break;
618	}
619	case A1_OP_BMEMBER: {
620	    const struct asn1_template *bmember = t->ptr;
621	    size_t bsize = bmember->offset;
622	    size_t belements = A1_HEADER_LEN(bmember);
623	    size_t pos;
624	    unsigned char c = 0;
625	    unsigned int bitset = 0;
626	    int rfc1510 = (bmember->tt & A1_HBF_RFC1510);
627
628	    bmember += belements;
629
630	    if (rfc1510)
631		pos = 31;
632	    else
633		pos = bmember->offset;
634
635	    while (belements && len) {
636		while (bmember->offset / 8 < pos / 8) {
637		    if (rfc1510 || bitset || c) {
638			if (len < 1)
639			    return ASN1_OVERFLOW;
640			*p-- = c; len--;
641		    }
642		    c = 0;
643		    pos -= 8;
644		}
645		_asn1_bmember_put_bit(&c, data, bmember->offset, bsize, &bitset);
646		belements--; bmember--;
647	    }
648	    if (rfc1510 || bitset) {
649		if (len < 1)
650		    return ASN1_OVERFLOW;
651		*p-- = c; len--;
652	    }
653
654	    if (len < 1)
655		return ASN1_OVERFLOW;
656	    if (rfc1510 || bitset == 0)
657		*p-- = 0;
658	    else
659		*p-- = bitset - 1;
660
661	    len--;
662
663	    break;
664	}
665	case A1_OP_CHOICE: {
666	    const struct asn1_template *choice = t->ptr;
667	    const int *element = DPOC(data, choice->offset);
668	    size_t datalen;
669	    const void *el;
670
671	    if (*element == ASN1_CHOICE_INVALID || *element > (int)A1_HEADER_LEN(choice)) {
672		ABORT_ON_ERROR();
673		return ASN1_PARSE_ERROR;
674	    }
675
676	    if (*element == ASN1_CHOICE_ELLIPSIS) {
677		ret += der_put_octet_string(p, len,
678					    DPOC(data, choice->tt), &datalen);
679	    } else {
680		choice += *element;
681		el = DPOC(data, choice->offset);
682		ret = _asn1_encode(choice->ptr, p, len, el, &datalen);
683		if (ret)
684		    return ret;
685	    }
686	    len -= datalen; p -= datalen;
687
688	    break;
689	}
690	default:
691	    ABORT_ON_ERROR();
692	}
693	t--;
694	elements--;
695    }
696    if (size)
697	*size = oldlen - len;
698
699    return 0;
700}
701
702size_t
703_asn1_length(const struct asn1_template *t, const void *data)
704{
705    size_t elements = A1_HEADER_LEN(t);
706    size_t ret = 0;
707
708    t += A1_HEADER_LEN(t);
709
710    while (elements) {
711	switch (t->tt & A1_OP_MASK) {
712	case A1_OP_TYPE:
713	case A1_OP_TYPE_EXTERN: {
714	    const void *el = DPOC(data, t->offset);
715
716	    if (t->tt & A1_FLAG_OPTIONAL) {
717		void **pel = (void **)el;
718		if (*pel == NULL)
719		    break;
720		el = *pel;
721	    }
722
723	    if ((t->tt & A1_OP_MASK) == A1_OP_TYPE) {
724		ret += _asn1_length(t->ptr, el);
725	    } else {
726		const struct asn1_type_func *f = t->ptr;
727		ret += (f->length)(el);
728	    }
729	    break;
730	}
731	case A1_OP_TAG: {
732	    size_t datalen;
733	    const void *olddata = data;
734
735	    data = DPO(data, t->offset);
736
737	    if (t->tt & A1_FLAG_OPTIONAL) {
738		void **el = (void **)data;
739		if (*el == NULL) {
740		    data = olddata;
741		    break;
742		}
743		data = *el;
744	    }
745	    datalen = _asn1_length(t->ptr, data);
746	    ret += der_length_tag(A1_TAG_TAG(t->tt)) + der_length_len(datalen);
747	    ret += datalen;
748	    data = olddata;
749	    break;
750	}
751	case A1_OP_PARSE: {
752	    unsigned int type = A1_PARSE_TYPE(t->tt);
753	    const void *el = DPOC(data, t->offset);
754
755	    if (type > sizeof(asn1_template_prim)/sizeof(asn1_template_prim[0])) {
756		ABORT_ON_ERROR();
757		break;
758	    }
759	    ret += (asn1_template_prim[type].length)(el);
760	    break;
761	}
762	case A1_OP_SETOF:
763	case A1_OP_SEQOF: {
764	    const struct template_of *el = DPOC(data, t->offset);
765	    size_t ellen = _asn1_sizeofType(t->ptr);
766	    const unsigned char *element = el->val;
767	    unsigned int i;
768
769	    for (i = 0; i < el->len; i++) {
770		ret += _asn1_length(t->ptr, element);
771		element += ellen;
772	    }
773
774	    break;
775	}
776	case A1_OP_BMEMBER: {
777	    const struct asn1_template *bmember = t->ptr;
778	    size_t size = bmember->offset;
779	    size_t belements = A1_HEADER_LEN(bmember);
780	    int rfc1510 = (bmember->tt & A1_HBF_RFC1510);
781
782	    if (rfc1510) {
783		ret += 5;
784	    } else {
785
786		ret += 1;
787
788		bmember += belements;
789
790		while (belements) {
791		    if (_asn1_bmember_isset_bit(data, bmember->offset, size)) {
792			ret += (bmember->offset / 8) + 1;
793			break;
794		    }
795		    belements--; bmember--;
796		}
797	    }
798	    break;
799	}
800	case A1_OP_CHOICE: {
801	    const struct asn1_template *choice = t->ptr;
802	    const int *element = DPOC(data, choice->offset);
803
804	    if (*element == ASN1_CHOICE_INVALID || *element > (int)A1_HEADER_LEN(choice)) {
805		ABORT_ON_ERROR();
806		break;
807	    }
808
809	    if (*element == ASN1_CHOICE_ELLIPSIS) {
810		ret += der_length_octet_string(DPOC(data, choice->tt));
811	    } else {
812		choice += *element;
813		ret += _asn1_length(choice->ptr, DPOC(data, choice->offset));
814	    }
815	    break;
816	}
817	default:
818	    ABORT_ON_ERROR();
819	    break;
820	}
821	elements--;
822	t--;
823    }
824    return ret;
825}
826
827void
828_asn1_free(const struct asn1_template *t, void *data)
829{
830    size_t elements = A1_HEADER_LEN(t);
831
832    if (t->tt & A1_HF_PRESERVE)
833	der_free_octet_string(data);
834
835    t++;
836
837    while (elements) {
838	switch (t->tt & A1_OP_MASK) {
839	case A1_OP_TYPE:
840	case A1_OP_TYPE_EXTERN: {
841	    void *el = DPO(data, t->offset);
842
843	    if (t->tt & A1_FLAG_OPTIONAL) {
844		void **pel = (void **)el;
845		if (*pel == NULL)
846		    break;
847		el = *pel;
848	    }
849
850	    if ((t->tt & A1_OP_MASK) == A1_OP_TYPE) {
851		_asn1_free(t->ptr, el);
852	    } else {
853		const struct asn1_type_func *f = t->ptr;
854		(f->release)(el);
855	    }
856	    if (t->tt & A1_FLAG_OPTIONAL)
857		free(el);
858
859	    break;
860	}
861	case A1_OP_PARSE: {
862	    unsigned int type = A1_PARSE_TYPE(t->tt);
863	    void *el = DPO(data, t->offset);
864
865	    if (type > sizeof(asn1_template_prim)/sizeof(asn1_template_prim[0])) {
866		ABORT_ON_ERROR();
867		break;
868	    }
869	    (asn1_template_prim[type].release)(el);
870	    break;
871	}
872	case A1_OP_TAG: {
873	    void *el = DPO(data, t->offset);
874
875	    if (t->tt & A1_FLAG_OPTIONAL) {
876		void **pel = (void **)el;
877		if (*pel == NULL)
878		    break;
879		el = *pel;
880	    }
881
882	    _asn1_free(t->ptr, el);
883
884	    if (t->tt & A1_FLAG_OPTIONAL)
885		free(el);
886
887	    break;
888	}
889	case A1_OP_SETOF:
890	case A1_OP_SEQOF: {
891	    struct template_of *el = DPO(data, t->offset);
892	    size_t ellen = _asn1_sizeofType(t->ptr);
893	    unsigned char *element = el->val;
894	    unsigned int i;
895
896	    for (i = 0; i < el->len; i++) {
897		_asn1_free(t->ptr, element);
898		element += ellen;
899	    }
900	    free(el->val);
901	    el->val = NULL;
902	    el->len = 0;
903
904	    break;
905	}
906	case A1_OP_BMEMBER:
907	    break;
908	case A1_OP_CHOICE: {
909	    const struct asn1_template *choice = t->ptr;
910	    const int *element = DPOC(data, choice->offset);
911
912	    if (*element == ASN1_CHOICE_INVALID)
913		break;
914
915	    if (*element > (int)A1_HEADER_LEN(choice)) {
916		ABORT_ON_ERROR();
917		break;
918	    }
919
920	    if (*element == ASN1_CHOICE_ELLIPSIS) {
921		der_free_octet_string(DPO(data, choice->tt));
922	    } else {
923		choice += *element;
924		_asn1_free(choice->ptr, DPO(data, choice->offset));
925	    }
926	    break;
927	}
928	default:
929	    ABORT_ON_ERROR();
930	    break;
931	}
932	t++;
933	elements--;
934    }
935}
936
937int
938_asn1_copy(const struct asn1_template *t, const void *from, void *to)
939{
940    size_t elements = A1_HEADER_LEN(t);
941    int ret = 0;
942    int preserve = (t->tt & A1_HF_PRESERVE);
943
944    t++;
945
946    if (preserve) {
947	ret = der_copy_octet_string(from, to);
948	if (ret)
949	    return ret;
950    }
951
952    while (elements) {
953	switch (t->tt & A1_OP_MASK) {
954	case A1_OP_TYPE:
955	case A1_OP_TYPE_EXTERN: {
956	    const void *fel = DPOC(from, t->offset);
957	    void *tel = DPO(to, t->offset);
958	    void **ptel = (void **)tel;
959	    size_t size;
960
961	    if ((t->tt & A1_OP_MASK) == A1_OP_TYPE) {
962		size = _asn1_sizeofType(t->ptr);
963	    } else {
964		const struct asn1_type_func *f = t->ptr;
965		size = f->size;
966	    }
967
968	    if (t->tt & A1_FLAG_OPTIONAL) {
969		void **pfel = (void **)fel;
970		if (*pfel == NULL)
971		    break;
972		fel = *pfel;
973
974		tel = *ptel = calloc(1, size);
975		if (tel == NULL)
976		    return ENOMEM;
977	    }
978
979	    if ((t->tt & A1_OP_MASK) == A1_OP_TYPE) {
980		ret = _asn1_copy(t->ptr, fel, tel);
981	    } else {
982		const struct asn1_type_func *f = t->ptr;
983		ret = (f->copy)(fel, tel);
984	    }
985
986	    if (ret) {
987		if (t->tt & A1_FLAG_OPTIONAL) {
988		    free(*ptel);
989		    *ptel = NULL;
990		}
991		return ret;
992	    }
993	    break;
994	}
995	case A1_OP_PARSE: {
996	    unsigned int type = A1_PARSE_TYPE(t->tt);
997	    const void *fel = DPOC(from, t->offset);
998	    void *tel = DPO(to, t->offset);
999
1000	    if (type > sizeof(asn1_template_prim)/sizeof(asn1_template_prim[0])) {
1001		ABORT_ON_ERROR();
1002		return ASN1_PARSE_ERROR;
1003	    }
1004	    ret = (asn1_template_prim[type].copy)(fel, tel);
1005	    if (ret)
1006		return ret;
1007	    break;
1008	}
1009	case A1_OP_TAG: {
1010	    const void *oldfrom = from;
1011	    void *oldto = to;
1012	    void **tel = NULL;
1013
1014	    from = DPOC(from, t->offset);
1015	    to = DPO(to, t->offset);
1016
1017	    if (t->tt & A1_FLAG_OPTIONAL) {
1018		void **fel = (void **)from;
1019		tel = (void **)to;
1020		if (*fel == NULL) {
1021		    from = oldfrom;
1022		    to = oldto;
1023		    break;
1024		}
1025		from = *fel;
1026
1027		to = *tel = calloc(1, _asn1_sizeofType(t->ptr));
1028		if (to == NULL)
1029		    return ENOMEM;
1030	    }
1031
1032	    ret = _asn1_copy(t->ptr, from, to);
1033	    if (ret) {
1034		if (tel) {
1035		    free(*tel);
1036		    *tel = NULL;
1037		}
1038		return ret;
1039	    }
1040
1041	    from = oldfrom;
1042	    to = oldto;
1043
1044	    break;
1045	}
1046	case A1_OP_SETOF:
1047	case A1_OP_SEQOF: {
1048	    const struct template_of *fel = DPOC(from, t->offset);
1049	    struct template_of *tel = DPO(to, t->offset);
1050	    size_t ellen = _asn1_sizeofType(t->ptr);
1051	    unsigned int i;
1052
1053	    tel->val = calloc(fel->len, ellen);
1054	    if (tel->val == NULL)
1055		return ENOMEM;
1056
1057	    tel->len = fel->len;
1058
1059	    for (i = 0; i < fel->len; i++) {
1060		ret = _asn1_copy(t->ptr,
1061				 DPOC(fel->val, (i * ellen)),
1062				 DPO(tel->val, (i *ellen)));
1063		if (ret)
1064		    return ret;
1065	    }
1066	    break;
1067	}
1068	case A1_OP_BMEMBER: {
1069	    const struct asn1_template *bmember = t->ptr;
1070	    size_t size = bmember->offset;
1071	    memcpy(to, from, size);
1072	    break;
1073	}
1074	case A1_OP_CHOICE: {
1075	    const struct asn1_template *choice = t->ptr;
1076	    const int *felement = DPOC(from, choice->offset);
1077	    int *telement = DPO(to, choice->offset);
1078
1079	    if (*felement == ASN1_CHOICE_INVALID || *felement > (int)A1_HEADER_LEN(choice))
1080		return ASN1_INVALID_CHOICE;
1081
1082	    *telement = *felement;
1083
1084	    if (*felement == ASN1_CHOICE_ELLIPSIS) {
1085		ret = der_copy_octet_string(DPOC(from, choice->tt), DPO(to, choice->tt));
1086	    } else {
1087		choice += *felement;
1088		ret = _asn1_copy(choice->ptr,
1089				 DPOC(from, choice->offset),
1090				 DPO(to, choice->offset));
1091	    }
1092	    if (ret)
1093		return ret;
1094	    break;
1095	}
1096	default:
1097	    ABORT_ON_ERROR();
1098	    break;
1099	}
1100	t++;
1101	elements--;
1102    }
1103    return 0;
1104}
1105
1106int
1107_asn1_decode_top(const struct asn1_template *t, unsigned flags, const unsigned char *p, size_t len, void *data, size_t *size)
1108{
1109    int ret;
1110    memset(data, 0, t->offset);
1111    ret = _asn1_decode(t, flags, p, len, data, size);
1112    if (ret)
1113	_asn1_free_top(t, data);
1114
1115    return ret;
1116}
1117
1118int
1119_asn1_copy_top(const struct asn1_template *t, const void *from, void *to)
1120{
1121    int ret;
1122    memset(to, 0, t->offset);
1123    ret = _asn1_copy(t, from, to);
1124    if (ret)
1125	_asn1_free_top(t, to);
1126
1127    return ret;
1128}
1129
1130void
1131_asn1_free_top(const struct asn1_template *t, void *data)
1132{
1133    _asn1_free(t, data);
1134    memset(data, 0, t->offset);
1135}
1136
1137#ifdef ASN1_CAPTURE_DATA
1138
1139void
1140_asn1_capture_data(const char *type, const unsigned char *p, size_t len)
1141{
1142    static unsigned long count = 0;
1143    char *filename = NULL;
1144    int fd;
1145
1146    asprintf(&filename, "/tmp/asn1/heimdal-%s-%s-%d-%lu", getprogname(), type, getpid(), count++);
1147    if (filename == NULL)
1148	return;
1149
1150    fd = open(filename, O_WRONLY|O_TRUNC|O_CREAT, 0644);
1151    free(filename);
1152    if (fd < 0)
1153	return;
1154    write(fd, type, strlen(type) + 1);
1155    write(fd, p, len);
1156    close(fd);
1157}
1158
1159#endif
1160