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