1226031Sstas/*
2226031Sstas * Copyright (c) 2009 Kungliga Tekniska H��gskolan
3226031Sstas * (Royal Institute of Technology, Stockholm, Sweden).
4226031Sstas * All rights reserved.
5226031Sstas *
6226031Sstas * Portions Copyright (c) 2009 Apple Inc. All rights reserved.
7226031Sstas *
8226031Sstas * Redistribution and use in source and binary forms, with or without
9226031Sstas * modification, are permitted provided that the following conditions
10226031Sstas * are met:
11226031Sstas *
12226031Sstas * 1. Redistributions of source code must retain the above copyright
13226031Sstas *    notice, this list of conditions and the following disclaimer.
14226031Sstas *
15226031Sstas * 2. Redistributions in binary form must reproduce the above copyright
16226031Sstas *    notice, this list of conditions and the following disclaimer in the
17226031Sstas *    documentation and/or other materials provided with the distribution.
18226031Sstas *
19226031Sstas * 3. Neither the name of the Institute nor the names of its contributors
20226031Sstas *    may be used to endorse or promote products derived from this software
21226031Sstas *    without specific prior written permission.
22226031Sstas *
23226031Sstas * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
24226031Sstas * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25226031Sstas * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26226031Sstas * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
27226031Sstas * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28226031Sstas * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29226031Sstas * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30226031Sstas * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31226031Sstas * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32226031Sstas * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33226031Sstas * SUCH DAMAGE.
34226031Sstas */
35226031Sstas
36226031Sstas#include "der_locl.h"
37226031Sstas#include <com_err.h>
38226031Sstas
39226031Sstas#if 0
40226031Sstas#define ABORT_ON_ERROR() abort()
41226031Sstas#else
42226031Sstas#define ABORT_ON_ERROR() do { } while(0)
43226031Sstas#endif
44226031Sstas
45226031Sstas#define DPOC(data,offset) ((const void *)(((const unsigned char *)data)  + offset))
46226031Sstas#define DPO(data,offset) ((void *)(((unsigned char *)data)  + offset))
47226031Sstas
48226031Sstas
49226031Sstasstatic struct asn1_type_func prim[] = {
50226031Sstas#define el(name, type) {				\
51226031Sstas	(asn1_type_encode)der_put_##name,		\
52226031Sstas	(asn1_type_decode)der_get_##name,		\
53226031Sstas	(asn1_type_length)der_length_##name,		\
54226031Sstas	(asn1_type_copy)der_copy_##name,		\
55226031Sstas	(asn1_type_release)der_free_##name,		\
56226031Sstas	sizeof(type)					\
57226031Sstas    }
58226031Sstas#define elber(name, type) {				\
59226031Sstas	(asn1_type_encode)der_put_##name,		\
60226031Sstas	(asn1_type_decode)der_get_##name##_ber,		\
61226031Sstas	(asn1_type_length)der_length_##name,		\
62226031Sstas	(asn1_type_copy)der_copy_##name,		\
63226031Sstas	(asn1_type_release)der_free_##name,		\
64226031Sstas	sizeof(type)					\
65226031Sstas    }
66226031Sstas    el(integer, int),
67226031Sstas    el(heim_integer, heim_integer),
68226031Sstas    el(integer, int),
69226031Sstas    el(unsigned, unsigned),
70226031Sstas    el(general_string, heim_general_string),
71226031Sstas    el(octet_string, heim_octet_string),
72226031Sstas    elber(octet_string, heim_octet_string),
73226031Sstas    el(ia5_string, heim_ia5_string),
74226031Sstas    el(bmp_string, heim_bmp_string),
75226031Sstas    el(universal_string, heim_universal_string),
76226031Sstas    el(printable_string, heim_printable_string),
77226031Sstas    el(visible_string, heim_visible_string),
78226031Sstas    el(utf8string, heim_utf8_string),
79226031Sstas    el(generalized_time, time_t),
80226031Sstas    el(utctime, time_t),
81226031Sstas    el(bit_string, heim_bit_string),
82226031Sstas    { (asn1_type_encode)der_put_boolean, (asn1_type_decode)der_get_boolean,
83226031Sstas      (asn1_type_length)der_length_boolean, (asn1_type_copy)der_copy_integer,
84226031Sstas      (asn1_type_release)der_free_integer, sizeof(int)
85226031Sstas    },
86226031Sstas    el(oid, heim_oid),
87226031Sstas    el(general_string, heim_general_string),
88226031Sstas#undef el
89226031Sstas#undef elber
90226031Sstas};
91226031Sstas
92226031Sstasstatic size_t
93226031SstassizeofType(const struct asn1_template *t)
94226031Sstas{
95226031Sstas    return t->offset;
96226031Sstas}
97226031Sstas
98226031Sstas/*
99226031Sstas * Here is abstraction to not so well evil fact of bit fields in C,
100226031Sstas * they are endian dependent, so when getting and setting bits in the
101226031Sstas * host local structure we need to know the endianness of the host.
102226031Sstas *
103226031Sstas * Its not the first time in Heimdal this have bitten us, and some day
104226031Sstas * we'll grow up and use #defined constant, but bit fields are still
105226031Sstas * so pretty and shiny.
106226031Sstas */
107226031Sstas
108226031Sstasstatic void
109226031Sstasbmember_get_bit(const unsigned char *p, void *data,
110226031Sstas		unsigned int bit, size_t size)
111226031Sstas{
112226031Sstas    unsigned int localbit = bit % 8;
113226031Sstas    if ((*p >> (7 - localbit)) & 1) {
114226031Sstas#ifdef WORDS_BIGENDIAN
115226031Sstas	*(unsigned int *)data |= (1 << ((size * 8) - bit - 1));
116226031Sstas#else
117226031Sstas	*(unsigned int *)data |= (1 << bit);
118226031Sstas#endif
119226031Sstas    }
120226031Sstas}
121226031Sstas
122226031Sstasstatic int
123226031Sstasbmember_isset_bit(const void *data, unsigned int bit, size_t size)
124226031Sstas{
125226031Sstas#ifdef WORDS_BIGENDIAN
126226031Sstas    if ((*(unsigned int *)data) & (1 << ((size * 8) - bit - 1)))
127226031Sstas	return 1;
128226031Sstas    return 0;
129226031Sstas#else
130226031Sstas    if ((*(unsigned int *)data) & (1 << bit))
131226031Sstas	return 1;
132226031Sstas    return 0;
133226031Sstas#endif
134226031Sstas}
135226031Sstas
136226031Sstasstatic void
137226031Sstasbmember_put_bit(unsigned char *p, const void *data, unsigned int bit,
138226031Sstas		size_t size, unsigned int *bitset)
139226031Sstas{
140226031Sstas    unsigned int localbit = bit % 8;
141226031Sstas
142226031Sstas    if (bmember_isset_bit(data, bit, size)) {
143226031Sstas	*p |= (1 << (7 - localbit));
144226031Sstas	if (*bitset == 0)
145226031Sstas	    *bitset = (7 - localbit) + 1;
146226031Sstas    }
147226031Sstas}
148226031Sstas
149226031Sstasint
150226031Sstas_asn1_decode(const struct asn1_template *t, unsigned flags,
151226031Sstas	     const unsigned char *p, size_t len, void *data, size_t *size)
152226031Sstas{
153226031Sstas    size_t elements = A1_HEADER_LEN(t);
154226031Sstas    size_t oldlen = len;
155226031Sstas    int ret = 0;
156226031Sstas    const unsigned char *startp = NULL;
157226031Sstas    unsigned int template_flags = t->tt;
158226031Sstas
159226031Sstas    /* skip over header */
160226031Sstas    t++;
161226031Sstas
162226031Sstas    if (template_flags & A1_HF_PRESERVE)
163226031Sstas	startp = p;
164226031Sstas
165226031Sstas    while (elements) {
166226031Sstas	switch (t->tt & A1_OP_MASK) {
167226031Sstas	case A1_OP_TYPE:
168226031Sstas	case A1_OP_TYPE_EXTERN: {
169226031Sstas	    size_t newsize, size;
170226031Sstas	    void *el = DPO(data, t->offset);
171226031Sstas	    void **pel = (void **)el;
172226031Sstas
173226031Sstas	    if ((t->tt & A1_OP_MASK) == A1_OP_TYPE) {
174226031Sstas		size = sizeofType(t->ptr);
175226031Sstas	    } else {
176226031Sstas		const struct asn1_type_func *f = t->ptr;
177226031Sstas		size = f->size;
178226031Sstas	    }
179226031Sstas
180226031Sstas	    if (t->tt & A1_FLAG_OPTIONAL) {
181226031Sstas		*pel = calloc(1, size);
182226031Sstas		if (*pel == NULL)
183226031Sstas		    return ENOMEM;
184226031Sstas		el = *pel;
185226031Sstas	    }
186226031Sstas	    if ((t->tt & A1_OP_MASK) == A1_OP_TYPE) {
187226031Sstas		ret = _asn1_decode(t->ptr, flags, p, len, el, &newsize);
188226031Sstas	    } else {
189226031Sstas		const struct asn1_type_func *f = t->ptr;
190226031Sstas		ret = (f->decode)(p, len, el, &newsize);
191226031Sstas	    }
192226031Sstas	    if (ret) {
193226031Sstas		if (t->tt & A1_FLAG_OPTIONAL) {
194226031Sstas		    free(*pel);
195226031Sstas		    *pel = NULL;
196226031Sstas		    break;
197226031Sstas		}
198226031Sstas		return ret;
199226031Sstas	    }
200226031Sstas	    p += newsize; len -= newsize;
201226031Sstas
202226031Sstas	    break;
203226031Sstas	}
204226031Sstas	case A1_OP_TAG: {
205226031Sstas	    Der_type dertype;
206226031Sstas	    size_t newsize;
207226031Sstas	    size_t datalen, l;
208226031Sstas	    void *olddata = data;
209226031Sstas	    int is_indefinite = 0;
210226031Sstas	    int subflags = flags;
211226031Sstas
212226031Sstas	    ret = der_match_tag_and_length(p, len, A1_TAG_CLASS(t->tt),
213226031Sstas					   &dertype, A1_TAG_TAG(t->tt),
214226031Sstas					   &datalen, &l);
215226031Sstas	    if (ret) {
216226031Sstas		if (t->tt & A1_FLAG_OPTIONAL)
217226031Sstas		    break;
218226031Sstas		return ret;
219226031Sstas	    }
220226031Sstas
221226031Sstas	    p += l; len -= l;
222226031Sstas
223226031Sstas	    /*
224226031Sstas	     * Only allow indefinite encoding for OCTET STRING and BER
225226031Sstas	     * for now. Should handle BIT STRING too.
226226031Sstas	     */
227226031Sstas
228226031Sstas	    if (dertype != A1_TAG_TYPE(t->tt) && (flags & A1_PF_ALLOW_BER)) {
229226031Sstas		const struct asn1_template *subtype = t->ptr;
230226031Sstas		subtype++; /* skip header */
231226031Sstas
232226031Sstas		if (((subtype->tt & A1_OP_MASK) == A1_OP_PARSE) &&
233226031Sstas		    A1_PARSE_TYPE(subtype->tt) == A1T_OCTET_STRING)
234226031Sstas		    subflags |= A1_PF_INDEFINTE;
235226031Sstas	    }
236226031Sstas
237226031Sstas	    if (datalen == ASN1_INDEFINITE) {
238226031Sstas		if ((flags & A1_PF_ALLOW_BER) == 0)
239226031Sstas		    return ASN1_GOT_BER;
240226031Sstas		is_indefinite = 1;
241226031Sstas		datalen = len;
242226031Sstas		if (datalen < 2)
243226031Sstas		    return ASN1_OVERRUN;
244226031Sstas		/* hide EndOfContent for sub-decoder, catching it below */
245226031Sstas		datalen -= 2;
246226031Sstas	    } else if (datalen > len)
247226031Sstas		return ASN1_OVERRUN;
248226031Sstas
249226031Sstas	    data = DPO(data, t->offset);
250226031Sstas
251226031Sstas	    if (t->tt & A1_FLAG_OPTIONAL) {
252226031Sstas		void **el = (void **)data;
253226031Sstas		size_t ellen = sizeofType(t->ptr);
254226031Sstas
255226031Sstas		*el = calloc(1, ellen);
256226031Sstas		if (*el == NULL)
257226031Sstas		    return ENOMEM;
258226031Sstas		data = *el;
259226031Sstas	    }
260226031Sstas
261226031Sstas	    ret = _asn1_decode(t->ptr, subflags, p, datalen, data, &newsize);
262226031Sstas	    if (ret)
263226031Sstas		return ret;
264226031Sstas
265226031Sstas	    if (newsize != datalen)
266226031Sstas		return ASN1_EXTRA_DATA;
267226031Sstas
268226031Sstas	    len -= datalen;
269226031Sstas	    p += datalen;
270226031Sstas
271226031Sstas	    /*
272226031Sstas	     * Indefinite encoding needs a trailing EndOfContent,
273226031Sstas	     * check for that.
274226031Sstas	     */
275226031Sstas	    if (is_indefinite) {
276226031Sstas		ret = der_match_tag_and_length(p, len, ASN1_C_UNIV,
277226031Sstas					       &dertype, UT_EndOfContent,
278226031Sstas					       &datalen, &l);
279226031Sstas		if (ret)
280226031Sstas		    return ret;
281226031Sstas		if (dertype != PRIM)
282226031Sstas		    return ASN1_BAD_ID;
283226031Sstas		if (datalen != 0)
284226031Sstas		    return ASN1_INDEF_EXTRA_DATA;
285226031Sstas		p += l; len -= l;
286226031Sstas	    }
287226031Sstas	    data = olddata;
288226031Sstas
289226031Sstas	    break;
290226031Sstas	}
291226031Sstas	case A1_OP_PARSE: {
292226031Sstas	    unsigned int type = A1_PARSE_TYPE(t->tt);
293226031Sstas	    size_t newsize;
294226031Sstas	    void *el = DPO(data, t->offset);
295226031Sstas
296226031Sstas	    /*
297226031Sstas	     * INDEFINITE primitive types are one element after the
298226031Sstas	     * same type but non-INDEFINITE version.
299226031Sstas	    */
300226031Sstas	    if (flags & A1_PF_INDEFINTE)
301226031Sstas		type++;
302226031Sstas
303226031Sstas	    if (type >= sizeof(prim)/sizeof(prim[0])) {
304226031Sstas		ABORT_ON_ERROR();
305226031Sstas		return ASN1_PARSE_ERROR;
306226031Sstas	    }
307226031Sstas
308226031Sstas	    ret = (prim[type].decode)(p, len, el, &newsize);
309226031Sstas	    if (ret)
310226031Sstas		return ret;
311226031Sstas	    p += newsize; len -= newsize;
312226031Sstas
313226031Sstas	    break;
314226031Sstas	}
315226031Sstas	case A1_OP_SETOF:
316226031Sstas	case A1_OP_SEQOF: {
317226031Sstas	    struct template_of *el = DPO(data, t->offset);
318226031Sstas	    size_t newsize;
319226031Sstas	    size_t ellen = sizeofType(t->ptr);
320226031Sstas	    size_t vallength = 0;
321226031Sstas
322226031Sstas	    while (len > 0) {
323226031Sstas		void *tmp;
324226031Sstas		size_t newlen = vallength + ellen;
325226031Sstas		if (vallength > newlen)
326226031Sstas		    return ASN1_OVERFLOW;
327226031Sstas
328226031Sstas		tmp = realloc(el->val, newlen);
329226031Sstas		if (tmp == NULL)
330226031Sstas		    return ENOMEM;
331226031Sstas
332226031Sstas		memset(DPO(tmp, vallength), 0, ellen);
333226031Sstas		el->val = tmp;
334226031Sstas
335226031Sstas		ret = _asn1_decode(t->ptr, flags & (~A1_PF_INDEFINTE), p, len,
336226031Sstas				   DPO(el->val, vallength), &newsize);
337226031Sstas		if (ret)
338226031Sstas		    return ret;
339226031Sstas		vallength = newlen;
340226031Sstas		el->len++;
341226031Sstas		p += newsize; len -= newsize;
342226031Sstas	    }
343226031Sstas
344226031Sstas	    break;
345226031Sstas	}
346226031Sstas	case A1_OP_BMEMBER: {
347226031Sstas	    const struct asn1_template *bmember = t->ptr;
348226031Sstas	    size_t size = bmember->offset;
349226031Sstas	    size_t elements = A1_HEADER_LEN(bmember);
350226031Sstas	    size_t pos = 0;
351226031Sstas
352226031Sstas	    bmember++;
353226031Sstas
354226031Sstas	    memset(data, 0, size);
355226031Sstas
356226031Sstas	    if (len < 1)
357226031Sstas		return ASN1_OVERRUN;
358226031Sstas	    p++; len--;
359226031Sstas
360226031Sstas	    while (elements && len) {
361226031Sstas		while (bmember->offset / 8 > pos / 8) {
362226031Sstas		    if (len < 1)
363226031Sstas			break;
364226031Sstas		    p++; len--;
365226031Sstas		    pos += 8;
366226031Sstas		}
367226031Sstas		if (len) {
368226031Sstas		    bmember_get_bit(p, data, bmember->offset, size);
369226031Sstas		    elements--; bmember++;
370226031Sstas		}
371226031Sstas	    }
372226031Sstas	    len = 0;
373226031Sstas	    break;
374226031Sstas	}
375226031Sstas	case A1_OP_CHOICE: {
376226031Sstas	    const struct asn1_template *choice = t->ptr;
377226031Sstas	    unsigned int *element = DPO(data, choice->offset);
378226031Sstas	    size_t datalen;
379226031Sstas	    unsigned int i;
380226031Sstas
381226031Sstas	    for (i = 1; i < A1_HEADER_LEN(choice) + 1; i++) {
382226031Sstas		/* should match first tag instead, store it in choice.tt */
383226031Sstas		ret = _asn1_decode(choice[i].ptr, 0, p, len,
384226031Sstas				   DPO(data, choice[i].offset), &datalen);
385226031Sstas		if (ret == 0) {
386226031Sstas		    *element = i;
387226031Sstas		    p += datalen; len -= datalen;
388226031Sstas		    break;
389226031Sstas		} else if (ret != ASN1_BAD_ID && ret != ASN1_MISPLACED_FIELD && ret != ASN1_MISSING_FIELD) {
390226031Sstas		    return ret;
391226031Sstas		}
392226031Sstas	    }
393226031Sstas	    if (i >= A1_HEADER_LEN(choice) + 1) {
394226031Sstas		if (choice->tt == 0)
395226031Sstas		    return ASN1_BAD_ID;
396226031Sstas
397226031Sstas		*element = 0;
398226031Sstas		ret = der_get_octet_string(p, len,
399226031Sstas					   DPO(data, choice->tt), &datalen);
400226031Sstas		if (ret)
401226031Sstas		    return ret;
402226031Sstas		p += datalen; len -= datalen;
403226031Sstas	    }
404226031Sstas
405226031Sstas	    break;
406226031Sstas	}
407226031Sstas	default:
408226031Sstas	    ABORT_ON_ERROR();
409226031Sstas	    return ASN1_PARSE_ERROR;
410226031Sstas	}
411226031Sstas	t++;
412226031Sstas	elements--;
413226031Sstas    }
414226031Sstas    /* if we are using padding, eat up read of context */
415226031Sstas    if (template_flags & A1_HF_ELLIPSIS)
416226031Sstas	len = 0;
417226031Sstas
418226031Sstas    oldlen -= len;
419226031Sstas
420226031Sstas    if (size)
421226031Sstas	*size = oldlen;
422226031Sstas
423226031Sstas    /*
424226031Sstas     * saved the raw bits if asked for it, useful for signature
425226031Sstas     * verification.
426226031Sstas     */
427226031Sstas    if (startp) {
428226031Sstas	heim_octet_string *save = data;
429226031Sstas
430226031Sstas	save->data = malloc(oldlen);
431226031Sstas	if (save->data == NULL)
432226031Sstas	    return ENOMEM;
433226031Sstas	else {
434226031Sstas	    save->length = oldlen;
435226031Sstas	    memcpy(save->data, startp, oldlen);
436226031Sstas	}
437226031Sstas    }
438226031Sstas    return 0;
439226031Sstas}
440226031Sstas
441226031Sstasint
442226031Sstas_asn1_encode(const struct asn1_template *t, unsigned char *p, size_t len, const void *data, size_t *size)
443226031Sstas{
444226031Sstas    size_t elements = A1_HEADER_LEN(t);
445226031Sstas    int ret = 0;
446226031Sstas    size_t oldlen = len;
447226031Sstas
448226031Sstas    t += A1_HEADER_LEN(t);
449226031Sstas
450226031Sstas    while (elements) {
451226031Sstas	switch (t->tt & A1_OP_MASK) {
452226031Sstas	case A1_OP_TYPE:
453226031Sstas	case A1_OP_TYPE_EXTERN: {
454226031Sstas	    size_t newsize;
455226031Sstas	    const void *el = DPOC(data, t->offset);
456226031Sstas
457226031Sstas	    if (t->tt & A1_FLAG_OPTIONAL) {
458226031Sstas		void **pel = (void **)el;
459226031Sstas		if (*pel == NULL)
460226031Sstas		    break;
461226031Sstas		el = *pel;
462226031Sstas	    }
463226031Sstas
464226031Sstas	    if ((t->tt & A1_OP_MASK) == A1_OP_TYPE) {
465226031Sstas		ret = _asn1_encode(t->ptr, p, len, el, &newsize);
466226031Sstas	    } else {
467226031Sstas		const struct asn1_type_func *f = t->ptr;
468226031Sstas		ret = (f->encode)(p, len, el, &newsize);
469226031Sstas	    }
470226031Sstas
471226031Sstas	    if (ret)
472226031Sstas		return ret;
473226031Sstas	    p -= newsize; len -= newsize;
474226031Sstas
475226031Sstas	    break;
476226031Sstas	}
477226031Sstas	case A1_OP_TAG: {
478226031Sstas	    const void *olddata = data;
479226031Sstas	    size_t l, datalen;
480226031Sstas
481226031Sstas	    data = DPOC(data, t->offset);
482226031Sstas
483226031Sstas	    if (t->tt & A1_FLAG_OPTIONAL) {
484226031Sstas		void **el = (void **)data;
485226031Sstas		if (*el == NULL) {
486226031Sstas		    data = olddata;
487226031Sstas		    break;
488226031Sstas		}
489226031Sstas		data = *el;
490226031Sstas	    }
491226031Sstas
492226031Sstas	    ret = _asn1_encode(t->ptr, p, len, data, &datalen);
493226031Sstas	    if (ret)
494226031Sstas		return ret;
495226031Sstas
496226031Sstas	    len -= datalen; p -= datalen;
497226031Sstas
498226031Sstas	    ret = der_put_length_and_tag(p, len, datalen,
499226031Sstas					 A1_TAG_CLASS(t->tt),
500226031Sstas					 A1_TAG_TYPE(t->tt),
501226031Sstas					 A1_TAG_TAG(t->tt), &l);
502226031Sstas	    if (ret)
503226031Sstas		return ret;
504226031Sstas
505226031Sstas	    p -= l; len -= l;
506226031Sstas
507226031Sstas	    data = olddata;
508226031Sstas
509226031Sstas	    break;
510226031Sstas	}
511226031Sstas	case A1_OP_PARSE: {
512226031Sstas	    unsigned int type = A1_PARSE_TYPE(t->tt);
513226031Sstas	    size_t newsize;
514226031Sstas	    const void *el = DPOC(data, t->offset);
515226031Sstas
516226031Sstas	    if (type > sizeof(prim)/sizeof(prim[0])) {
517226031Sstas		ABORT_ON_ERROR();
518226031Sstas		return ASN1_PARSE_ERROR;
519226031Sstas	    }
520226031Sstas
521226031Sstas	    ret = (prim[type].encode)(p, len, el, &newsize);
522226031Sstas	    if (ret)
523226031Sstas		return ret;
524226031Sstas	    p -= newsize; len -= newsize;
525226031Sstas
526226031Sstas	    break;
527226031Sstas	}
528226031Sstas	case A1_OP_SETOF: {
529226031Sstas	    const struct template_of *el = DPOC(data, t->offset);
530226031Sstas	    size_t ellen = sizeofType(t->ptr);
531226031Sstas	    struct heim_octet_string *val;
532226031Sstas	    unsigned char *elptr = el->val;
533226031Sstas	    size_t i, totallen;
534226031Sstas
535226031Sstas	    if (el->len == 0)
536226031Sstas		break;
537226031Sstas
538226031Sstas	    if (el->len > UINT_MAX/sizeof(val[0]))
539226031Sstas		return ERANGE;
540226031Sstas
541226031Sstas	    val = malloc(sizeof(val[0]) * el->len);
542226031Sstas	    if (val == NULL)
543226031Sstas		return ENOMEM;
544226031Sstas
545226031Sstas	    for(totallen = 0, i = 0; i < el->len; i++) {
546226031Sstas		unsigned char *next;
547226031Sstas		size_t l;
548226031Sstas
549226031Sstas		val[i].length = _asn1_length(t->ptr, elptr);
550226031Sstas		val[i].data = malloc(val[i].length);
551226031Sstas
552226031Sstas		ret = _asn1_encode(t->ptr, DPO(val[i].data, val[i].length - 1),
553226031Sstas				   val[i].length, elptr, &l);
554226031Sstas		if (ret)
555226031Sstas		    break;
556226031Sstas
557226031Sstas		next = elptr + ellen;
558226031Sstas		if (next < elptr) {
559226031Sstas		    ret = ASN1_OVERFLOW;
560226031Sstas		    break;
561226031Sstas		}
562226031Sstas		elptr = next;
563226031Sstas		totallen += val[i].length;
564226031Sstas	    }
565226031Sstas	    if (ret == 0 && totallen > len)
566226031Sstas		ret = ASN1_OVERFLOW;
567226031Sstas	    if (ret) {
568226031Sstas		do {
569226031Sstas		    free(val[i].data);
570226031Sstas		} while(i-- > 0);
571226031Sstas		free(val);
572226031Sstas		return ret;
573226031Sstas	    }
574226031Sstas
575226031Sstas	    len -= totallen;
576226031Sstas
577226031Sstas	    qsort(val, el->len, sizeof(val[0]), _heim_der_set_sort);
578226031Sstas
579226031Sstas	    i = el->len - 1;
580226031Sstas	    do {
581226031Sstas		p -= val[i].length;
582226031Sstas		memcpy(p + 1, val[i].data, val[i].length);
583226031Sstas		free(val[i].data);
584226031Sstas	    } while(i-- > 0);
585226031Sstas	    free(val);
586226031Sstas
587226031Sstas	    break;
588226031Sstas
589226031Sstas	}
590226031Sstas	case A1_OP_SEQOF: {
591226031Sstas	    struct template_of *el = DPO(data, t->offset);
592226031Sstas	    size_t ellen = sizeofType(t->ptr);
593226031Sstas	    size_t newsize;
594226031Sstas	    unsigned int i;
595226031Sstas	    unsigned char *elptr = el->val;
596226031Sstas
597226031Sstas	    if (el->len == 0)
598226031Sstas		break;
599226031Sstas
600226031Sstas	    elptr += ellen * (el->len - 1);
601226031Sstas
602226031Sstas	    for (i = 0; i < el->len; i++) {
603226031Sstas		ret = _asn1_encode(t->ptr, p, len,
604226031Sstas				   elptr,
605226031Sstas				   &newsize);
606226031Sstas		if (ret)
607226031Sstas		    return ret;
608226031Sstas		p -= newsize; len -= newsize;
609226031Sstas		elptr -= ellen;
610226031Sstas	    }
611226031Sstas
612226031Sstas	    break;
613226031Sstas	}
614226031Sstas	case A1_OP_BMEMBER: {
615226031Sstas	    const struct asn1_template *bmember = t->ptr;
616226031Sstas	    size_t size = bmember->offset;
617226031Sstas	    size_t elements = A1_HEADER_LEN(bmember);
618226031Sstas	    size_t pos;
619226031Sstas	    unsigned char c = 0;
620226031Sstas	    unsigned int bitset = 0;
621226031Sstas	    int rfc1510 = (bmember->tt & A1_HBF_RFC1510);
622226031Sstas
623226031Sstas	    bmember += elements;
624226031Sstas
625226031Sstas	    if (rfc1510)
626226031Sstas		pos = 31;
627226031Sstas	    else
628226031Sstas		pos = bmember->offset;
629226031Sstas
630226031Sstas	    while (elements && len) {
631226031Sstas		while (bmember->offset / 8 < pos / 8) {
632226031Sstas		    if (rfc1510 || bitset || c) {
633226031Sstas			if (len < 1)
634226031Sstas			    return ASN1_OVERFLOW;
635226031Sstas			*p-- = c; len--;
636226031Sstas		    }
637226031Sstas		    c = 0;
638226031Sstas		    pos -= 8;
639226031Sstas		}
640226031Sstas		bmember_put_bit(&c, data, bmember->offset, size, &bitset);
641226031Sstas		elements--; bmember--;
642226031Sstas	    }
643226031Sstas	    if (rfc1510 || bitset) {
644226031Sstas		if (len < 1)
645226031Sstas		    return ASN1_OVERFLOW;
646226031Sstas		*p-- = c; len--;
647226031Sstas	    }
648226031Sstas
649226031Sstas	    if (len < 1)
650226031Sstas		return ASN1_OVERFLOW;
651226031Sstas	    if (rfc1510 || bitset == 0)
652226031Sstas		*p-- = 0;
653226031Sstas	    else
654226031Sstas		*p-- = bitset - 1;
655226031Sstas
656226031Sstas	    len--;
657226031Sstas
658226031Sstas	    break;
659226031Sstas	}
660226031Sstas	case A1_OP_CHOICE: {
661226031Sstas	    const struct asn1_template *choice = t->ptr;
662226031Sstas	    const unsigned int *element = DPOC(data, choice->offset);
663226031Sstas	    size_t datalen;
664226031Sstas	    const void *el;
665226031Sstas
666226031Sstas	    if (*element > A1_HEADER_LEN(choice)) {
667226031Sstas		printf("element: %d\n", *element);
668226031Sstas		return ASN1_PARSE_ERROR;
669226031Sstas	    }
670226031Sstas
671226031Sstas	    if (*element == 0) {
672226031Sstas		ret += der_put_octet_string(p, len,
673226031Sstas					    DPOC(data, choice->tt), &datalen);
674226031Sstas	    } else {
675226031Sstas		choice += *element;
676226031Sstas		el = DPOC(data, choice->offset);
677226031Sstas		ret = _asn1_encode(choice->ptr, p, len, el, &datalen);
678226031Sstas		if (ret)
679226031Sstas		    return ret;
680226031Sstas	    }
681226031Sstas	    len -= datalen; p -= datalen;
682226031Sstas
683226031Sstas	    break;
684226031Sstas	}
685226031Sstas	default:
686226031Sstas	    ABORT_ON_ERROR();
687226031Sstas	}
688226031Sstas	t--;
689226031Sstas	elements--;
690226031Sstas    }
691226031Sstas    if (size)
692226031Sstas	*size = oldlen - len;
693226031Sstas
694226031Sstas    return 0;
695226031Sstas}
696226031Sstas
697226031Sstassize_t
698226031Sstas_asn1_length(const struct asn1_template *t, const void *data)
699226031Sstas{
700226031Sstas    size_t elements = A1_HEADER_LEN(t);
701226031Sstas    size_t ret = 0;
702226031Sstas
703226031Sstas    t += A1_HEADER_LEN(t);
704226031Sstas
705226031Sstas    while (elements) {
706226031Sstas	switch (t->tt & A1_OP_MASK) {
707226031Sstas	case A1_OP_TYPE:
708226031Sstas	case A1_OP_TYPE_EXTERN: {
709226031Sstas	    const void *el = DPOC(data, t->offset);
710226031Sstas
711226031Sstas	    if (t->tt & A1_FLAG_OPTIONAL) {
712226031Sstas		void **pel = (void **)el;
713226031Sstas		if (*pel == NULL)
714226031Sstas		    break;
715226031Sstas		el = *pel;
716226031Sstas	    }
717226031Sstas
718226031Sstas	    if ((t->tt & A1_OP_MASK) == A1_OP_TYPE) {
719226031Sstas		ret += _asn1_length(t->ptr, el);
720226031Sstas	    } else {
721226031Sstas		const struct asn1_type_func *f = t->ptr;
722226031Sstas		ret += (f->length)(el);
723226031Sstas	    }
724226031Sstas	    break;
725226031Sstas	}
726226031Sstas	case A1_OP_TAG: {
727226031Sstas	    size_t datalen;
728226031Sstas	    const void *olddata = data;
729226031Sstas
730226031Sstas	    data = DPO(data, t->offset);
731226031Sstas
732226031Sstas	    if (t->tt & A1_FLAG_OPTIONAL) {
733226031Sstas		void **el = (void **)data;
734226031Sstas		if (*el == NULL) {
735226031Sstas		    data = olddata;
736226031Sstas		    break;
737226031Sstas		}
738226031Sstas		data = *el;
739226031Sstas	    }
740226031Sstas	    datalen = _asn1_length(t->ptr, data);
741226031Sstas	    ret += der_length_tag(A1_TAG_TAG(t->tt)) + der_length_len(datalen);
742226031Sstas	    ret += datalen;
743226031Sstas	    data = olddata;
744226031Sstas	    break;
745226031Sstas	}
746226031Sstas	case A1_OP_PARSE: {
747226031Sstas	    unsigned int type = A1_PARSE_TYPE(t->tt);
748226031Sstas	    const void *el = DPOC(data, t->offset);
749226031Sstas
750226031Sstas	    if (type > sizeof(prim)/sizeof(prim[0])) {
751226031Sstas		ABORT_ON_ERROR();
752226031Sstas		break;
753226031Sstas	    }
754226031Sstas	    ret += (prim[type].length)(el);
755226031Sstas	    break;
756226031Sstas	}
757226031Sstas	case A1_OP_SETOF:
758226031Sstas	case A1_OP_SEQOF: {
759226031Sstas	    const struct template_of *el = DPOC(data, t->offset);
760226031Sstas	    size_t ellen = sizeofType(t->ptr);
761226031Sstas	    const unsigned char *element = el->val;
762226031Sstas	    unsigned int i;
763226031Sstas
764226031Sstas	    for (i = 0; i < el->len; i++) {
765226031Sstas		ret += _asn1_length(t->ptr, element);
766226031Sstas		element += ellen;
767226031Sstas	    }
768226031Sstas
769226031Sstas	    break;
770226031Sstas	}
771226031Sstas	case A1_OP_BMEMBER: {
772226031Sstas	    const struct asn1_template *bmember = t->ptr;
773226031Sstas	    size_t size = bmember->offset;
774226031Sstas	    size_t elements = A1_HEADER_LEN(bmember);
775226031Sstas	    int rfc1510 = (bmember->tt & A1_HBF_RFC1510);
776226031Sstas
777226031Sstas	    if (rfc1510) {
778226031Sstas		ret += 5;
779226031Sstas	    } else {
780226031Sstas
781226031Sstas		ret += 1;
782226031Sstas
783226031Sstas		bmember += elements;
784226031Sstas
785226031Sstas		while (elements) {
786226031Sstas		    if (bmember_isset_bit(data, bmember->offset, size)) {
787226031Sstas			ret += (bmember->offset / 8) + 1;
788226031Sstas			break;
789226031Sstas		    }
790226031Sstas		    elements--; bmember--;
791226031Sstas		}
792226031Sstas	    }
793226031Sstas	    break;
794226031Sstas	}
795226031Sstas	case A1_OP_CHOICE: {
796226031Sstas	    const struct asn1_template *choice = t->ptr;
797226031Sstas	    const unsigned int *element = DPOC(data, choice->offset);
798226031Sstas
799226031Sstas	    if (*element > A1_HEADER_LEN(choice))
800226031Sstas		break;
801226031Sstas
802226031Sstas	    if (*element == 0) {
803226031Sstas		ret += der_length_octet_string(DPOC(data, choice->tt));
804226031Sstas	    } else {
805226031Sstas		choice += *element;
806226031Sstas		ret += _asn1_length(choice->ptr, DPOC(data, choice->offset));
807226031Sstas	    }
808226031Sstas	    break;
809226031Sstas	}
810226031Sstas	default:
811226031Sstas	    ABORT_ON_ERROR();
812226031Sstas	    break;
813226031Sstas	}
814226031Sstas	elements--;
815226031Sstas	t--;
816226031Sstas    }
817226031Sstas    return ret;
818226031Sstas}
819226031Sstas
820226031Sstasvoid
821226031Sstas_asn1_free(const struct asn1_template *t, void *data)
822226031Sstas{
823226031Sstas    size_t elements = A1_HEADER_LEN(t);
824226031Sstas
825226031Sstas    if (t->tt & A1_HF_PRESERVE)
826226031Sstas	der_free_octet_string(data);
827226031Sstas
828226031Sstas    t++;
829226031Sstas
830226031Sstas    while (elements) {
831226031Sstas	switch (t->tt & A1_OP_MASK) {
832226031Sstas	case A1_OP_TYPE:
833226031Sstas	case A1_OP_TYPE_EXTERN: {
834226031Sstas	    void *el = DPO(data, t->offset);
835226031Sstas
836226031Sstas	    if (t->tt & A1_FLAG_OPTIONAL) {
837226031Sstas		void **pel = (void **)el;
838226031Sstas		if (*pel == NULL)
839226031Sstas		    break;
840226031Sstas		el = *pel;
841226031Sstas	    }
842226031Sstas
843226031Sstas	    if ((t->tt & A1_OP_MASK) == A1_OP_TYPE) {
844226031Sstas		_asn1_free(t->ptr, el);
845226031Sstas	    } else {
846226031Sstas		const struct asn1_type_func *f = t->ptr;
847226031Sstas		(f->release)(el);
848226031Sstas	    }
849226031Sstas	    if (t->tt & A1_FLAG_OPTIONAL)
850226031Sstas		free(el);
851226031Sstas
852226031Sstas	    break;
853226031Sstas	}
854226031Sstas	case A1_OP_PARSE: {
855226031Sstas	    unsigned int type = A1_PARSE_TYPE(t->tt);
856226031Sstas	    void *el = DPO(data, t->offset);
857226031Sstas
858226031Sstas	    if (type > sizeof(prim)/sizeof(prim[0])) {
859226031Sstas		ABORT_ON_ERROR();
860226031Sstas		break;
861226031Sstas	    }
862226031Sstas	    (prim[type].release)(el);
863226031Sstas	    break;
864226031Sstas	}
865226031Sstas	case A1_OP_TAG: {
866226031Sstas	    void *el = DPO(data, t->offset);
867226031Sstas
868226031Sstas	    if (t->tt & A1_FLAG_OPTIONAL) {
869226031Sstas		void **pel = (void **)el;
870226031Sstas		if (*pel == NULL)
871226031Sstas		    break;
872226031Sstas		el = *pel;
873226031Sstas	    }
874226031Sstas
875226031Sstas	    _asn1_free(t->ptr, el);
876226031Sstas
877226031Sstas	    if (t->tt & A1_FLAG_OPTIONAL)
878226031Sstas		free(el);
879226031Sstas
880226031Sstas	    break;
881226031Sstas	}
882226031Sstas	case A1_OP_SETOF:
883226031Sstas	case A1_OP_SEQOF: {
884226031Sstas	    struct template_of *el = DPO(data, t->offset);
885226031Sstas	    size_t ellen = sizeofType(t->ptr);
886226031Sstas	    unsigned char *element = el->val;
887226031Sstas	    unsigned int i;
888226031Sstas
889226031Sstas	    for (i = 0; i < el->len; i++) {
890226031Sstas		_asn1_free(t->ptr, element);
891226031Sstas		element += ellen;
892226031Sstas	    }
893226031Sstas	    free(el->val);
894226031Sstas	    el->val = NULL;
895226031Sstas	    el->len = 0;
896226031Sstas
897226031Sstas	    break;
898226031Sstas	}
899226031Sstas	case A1_OP_BMEMBER:
900226031Sstas	    break;
901226031Sstas	case A1_OP_CHOICE: {
902226031Sstas	    const struct asn1_template *choice = t->ptr;
903226031Sstas	    const unsigned int *element = DPOC(data, choice->offset);
904226031Sstas
905226031Sstas	    if (*element > A1_HEADER_LEN(choice))
906226031Sstas		break;
907226031Sstas
908226031Sstas	    if (*element == 0) {
909226031Sstas		der_free_octet_string(DPO(data, choice->tt));
910226031Sstas	    } else {
911226031Sstas		choice += *element;
912226031Sstas		_asn1_free(choice->ptr, DPO(data, choice->offset));
913226031Sstas	    }
914226031Sstas	    break;
915226031Sstas	}
916226031Sstas	default:
917226031Sstas	    ABORT_ON_ERROR();
918226031Sstas	    break;
919226031Sstas	}
920226031Sstas	t++;
921226031Sstas	elements--;
922226031Sstas    }
923226031Sstas}
924226031Sstas
925226031Sstasint
926226031Sstas_asn1_copy(const struct asn1_template *t, const void *from, void *to)
927226031Sstas{
928226031Sstas    size_t elements = A1_HEADER_LEN(t);
929226031Sstas    int ret = 0;
930226031Sstas    int preserve = (t->tt & A1_HF_PRESERVE);
931226031Sstas
932226031Sstas    t++;
933226031Sstas
934226031Sstas    if (preserve) {
935226031Sstas	ret = der_copy_octet_string(from, to);
936226031Sstas	if (ret)
937226031Sstas	    return ret;
938226031Sstas    }
939226031Sstas
940226031Sstas    while (elements) {
941226031Sstas	switch (t->tt & A1_OP_MASK) {
942226031Sstas	case A1_OP_TYPE:
943226031Sstas	case A1_OP_TYPE_EXTERN: {
944226031Sstas	    const void *fel = DPOC(from, t->offset);
945226031Sstas	    void *tel = DPO(to, t->offset);
946226031Sstas	    void **ptel = (void **)tel;
947226031Sstas	    size_t size;
948226031Sstas
949226031Sstas	    if ((t->tt & A1_OP_MASK) == A1_OP_TYPE) {
950226031Sstas		size = sizeofType(t->ptr);
951226031Sstas	    } else {
952226031Sstas		const struct asn1_type_func *f = t->ptr;
953226031Sstas		size = f->size;
954226031Sstas	    }
955226031Sstas
956226031Sstas	    if (t->tt & A1_FLAG_OPTIONAL) {
957226031Sstas		void **pfel = (void **)fel;
958226031Sstas		if (*pfel == NULL)
959226031Sstas		    break;
960226031Sstas		fel = *pfel;
961226031Sstas
962226031Sstas		tel = *ptel = calloc(1, size);
963226031Sstas		if (tel == NULL)
964226031Sstas		    return ENOMEM;
965226031Sstas	    }
966226031Sstas
967226031Sstas	    if ((t->tt & A1_OP_MASK) == A1_OP_TYPE) {
968226031Sstas		ret = _asn1_copy(t->ptr, fel, tel);
969226031Sstas	    } else {
970226031Sstas		const struct asn1_type_func *f = t->ptr;
971226031Sstas		ret = (f->copy)(fel, tel);
972226031Sstas	    }
973226031Sstas
974226031Sstas	    if (ret) {
975226031Sstas		if (t->tt & A1_FLAG_OPTIONAL) {
976226031Sstas		    free(*ptel);
977226031Sstas		    *ptel = NULL;
978226031Sstas		}
979226031Sstas		return ret;
980226031Sstas	    }
981226031Sstas	    break;
982226031Sstas	}
983226031Sstas	case A1_OP_PARSE: {
984226031Sstas	    unsigned int type = A1_PARSE_TYPE(t->tt);
985226031Sstas	    const void *fel = DPOC(from, t->offset);
986226031Sstas	    void *tel = DPO(to, t->offset);
987226031Sstas
988226031Sstas	    if (type > sizeof(prim)/sizeof(prim[0])) {
989226031Sstas		ABORT_ON_ERROR();
990226031Sstas		return ASN1_PARSE_ERROR;
991226031Sstas	    }
992226031Sstas	    ret = (prim[type].copy)(fel, tel);
993226031Sstas	    if (ret)
994226031Sstas		return ret;
995226031Sstas	    break;
996226031Sstas	}
997226031Sstas	case A1_OP_TAG: {
998226031Sstas	    const void *oldfrom = from;
999226031Sstas	    void *oldto = to;
1000226031Sstas	    void **tel = NULL;
1001226031Sstas
1002226031Sstas	    from = DPOC(from, t->offset);
1003226031Sstas	    to = DPO(to, t->offset);
1004226031Sstas
1005226031Sstas	    if (t->tt & A1_FLAG_OPTIONAL) {
1006226031Sstas		void **fel = (void **)from;
1007226031Sstas		tel = (void **)to;
1008226031Sstas		if (*fel == NULL) {
1009226031Sstas		    from = oldfrom;
1010226031Sstas		    to = oldto;
1011226031Sstas		    break;
1012226031Sstas		}
1013226031Sstas		from = *fel;
1014226031Sstas
1015226031Sstas		to = *tel = calloc(1, sizeofType(t->ptr));
1016226031Sstas		if (to == NULL)
1017226031Sstas		    return ENOMEM;
1018226031Sstas	    }
1019226031Sstas
1020226031Sstas	    ret = _asn1_copy(t->ptr, from, to);
1021226031Sstas	    if (ret) {
1022226031Sstas		if (t->tt & A1_FLAG_OPTIONAL) {
1023226031Sstas		    free(*tel);
1024226031Sstas		    *tel = NULL;
1025226031Sstas		}
1026226031Sstas		return ret;
1027226031Sstas	    }
1028226031Sstas
1029226031Sstas	    from = oldfrom;
1030226031Sstas	    to = oldto;
1031226031Sstas
1032226031Sstas	    break;
1033226031Sstas	}
1034226031Sstas	case A1_OP_SETOF:
1035226031Sstas	case A1_OP_SEQOF: {
1036226031Sstas	    const struct template_of *fel = DPOC(from, t->offset);
1037226031Sstas	    struct template_of *tel = DPO(to, t->offset);
1038226031Sstas	    size_t ellen = sizeofType(t->ptr);
1039226031Sstas	    unsigned int i;
1040226031Sstas
1041226031Sstas	    tel->val = calloc(fel->len, ellen);
1042226031Sstas	    if (tel->val == NULL)
1043226031Sstas		return ENOMEM;
1044226031Sstas
1045226031Sstas	    tel->len = fel->len;
1046226031Sstas
1047226031Sstas	    for (i = 0; i < fel->len; i++) {
1048226031Sstas		ret = _asn1_copy(t->ptr,
1049226031Sstas				 DPOC(fel->val, (i * ellen)),
1050226031Sstas				 DPO(tel->val, (i *ellen)));
1051226031Sstas		if (ret)
1052226031Sstas		    return ret;
1053226031Sstas	    }
1054226031Sstas	    break;
1055226031Sstas	}
1056226031Sstas	case A1_OP_BMEMBER: {
1057226031Sstas	    const struct asn1_template *bmember = t->ptr;
1058226031Sstas	    size_t size = bmember->offset;
1059226031Sstas	    memcpy(to, from, size);
1060226031Sstas	    break;
1061226031Sstas	}
1062226031Sstas	case A1_OP_CHOICE: {
1063226031Sstas	    const struct asn1_template *choice = t->ptr;
1064226031Sstas	    const unsigned int *felement = DPOC(from, choice->offset);
1065226031Sstas	    unsigned int *telement = DPO(to, choice->offset);
1066226031Sstas
1067226031Sstas	    if (*felement > A1_HEADER_LEN(choice))
1068226031Sstas		return ASN1_PARSE_ERROR;
1069226031Sstas
1070226031Sstas	    *telement = *felement;
1071226031Sstas
1072226031Sstas	    if (*felement == 0) {
1073226031Sstas		ret = der_copy_octet_string(DPOC(from, choice->tt), DPO(to, choice->tt));
1074226031Sstas	    } else {
1075226031Sstas		choice += *felement;
1076226031Sstas		ret = _asn1_copy(choice->ptr,
1077226031Sstas				 DPOC(from, choice->offset),
1078226031Sstas				 DPO(to, choice->offset));
1079226031Sstas	    }
1080226031Sstas	    if (ret)
1081226031Sstas		return ret;
1082226031Sstas	    break;
1083226031Sstas	}
1084226031Sstas	default:
1085226031Sstas	    ABORT_ON_ERROR();
1086226031Sstas	    break;
1087226031Sstas	}
1088226031Sstas	t++;
1089226031Sstas	elements--;
1090226031Sstas    }
1091226031Sstas    return 0;
1092226031Sstas}
1093226031Sstas
1094226031Sstasint
1095226031Sstas_asn1_decode_top(const struct asn1_template *t, unsigned flags, const unsigned char *p, size_t len, void *data, size_t *size)
1096226031Sstas{
1097226031Sstas    int ret;
1098226031Sstas    memset(data, 0, t->offset);
1099226031Sstas    ret = _asn1_decode(t, flags, p, len, data, size);
1100226031Sstas    if (ret) {
1101226031Sstas	_asn1_free(t, data);
1102226031Sstas	memset(data, 0, t->offset);
1103226031Sstas    }
1104226031Sstas
1105226031Sstas    return ret;
1106226031Sstas}
1107226031Sstas
1108226031Sstasint
1109226031Sstas_asn1_copy_top(const struct asn1_template *t, const void *from, void *to)
1110226031Sstas{
1111226031Sstas    int ret;
1112226031Sstas    memset(to, 0, t->offset);
1113226031Sstas    ret = _asn1_copy(t, from, to);
1114226031Sstas    if (ret) {
1115226031Sstas	_asn1_free(t, to);
1116226031Sstas	memset(to, 0, t->offset);
1117226031Sstas    }
1118226031Sstas    return ret;
1119226031Sstas}
1120