s4:torture: Adapt KDC canon test to Heimdal upstream changes
[Samba.git] / source4 / heimdal / lib / asn1 / template.c
blob7f5670f3456fc30dcbda37c15b4753aee7664939
1 /*
2 * Copyright (c) 2009 Kungliga Tekniska Högskolan
3 * (Royal Institute of Technology, Stockholm, Sweden).
4 * All rights reserved.
6 * Portions Copyright (c) 2009 - 2010 Apple Inc. All rights reserved.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
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.
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.
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.
36 #include "der_locl.h"
37 #include <com_err.h>
38 #include <vis.h>
39 #include <vis-extras.h>
41 #ifndef ENOTSUP
42 /* Very old MSVC CRTs don't have ENOTSUP */
43 #define ENOTSUP EINVAL
44 #endif
46 struct asn1_type_func asn1_template_prim[A1T_NUM_ENTRY] = {
47 #define el(name, type) { \
48 (asn1_type_encode)der_put_##name, \
49 (asn1_type_decode)der_get_##name, \
50 (asn1_type_length)der_length_##name, \
51 (asn1_type_copy)der_copy_##name, \
52 (asn1_type_release)der_free_##name, \
53 (asn1_type_print)der_print_##name, \
54 sizeof(type) \
56 #define elber(name, type) { \
57 (asn1_type_encode)der_put_##name, \
58 (asn1_type_decode)der_get_##name##_ber, \
59 (asn1_type_length)der_length_##name, \
60 (asn1_type_copy)der_copy_##name, \
61 (asn1_type_release)der_free_##name, \
62 (asn1_type_print)der_print_##name, \
63 sizeof(type) \
65 el(integer, int),
66 el(heim_integer, heim_integer),
67 el(integer, int),
68 el(integer64, int64_t),
69 el(unsigned, unsigned),
70 el(unsigned64, uint64_t),
71 el(general_string, heim_general_string),
72 el(octet_string, heim_octet_string),
73 elber(octet_string, heim_octet_string),
74 el(ia5_string, heim_ia5_string),
75 el(bmp_string, heim_bmp_string),
76 el(universal_string, heim_universal_string),
77 el(printable_string, heim_printable_string),
78 el(visible_string, heim_visible_string),
79 el(utf8string, heim_utf8_string),
80 el(generalized_time, time_t),
81 el(utctime, time_t),
82 el(bit_string, heim_bit_string),
83 { (asn1_type_encode)der_put_boolean, (asn1_type_decode)der_get_boolean,
84 (asn1_type_length)der_length_boolean, (asn1_type_copy)der_copy_integer,
85 (asn1_type_release)der_free_integer, (asn1_type_print)der_print_boolean,
86 sizeof(int)
88 el(oid, heim_oid),
89 el(general_string, heim_general_string),
90 #undef el
91 #undef elber
94 size_t
95 _asn1_sizeofType(const struct asn1_template *t)
97 return t->offset;
101 * Here is abstraction to not so well evil fact of bit fields in C,
102 * they are endian dependent, so when getting and setting bits in the
103 * host local structure we need to know the endianness of the host.
105 * Its not the first time in Heimdal this have bitten us, and some day
106 * we'll grow up and use #defined constant, but bit fields are still
107 * so pretty and shiny.
110 static void
111 _asn1_bmember_get_bit(const unsigned char *p, void *data,
112 unsigned int bit, size_t size)
114 unsigned int localbit = bit % 8;
115 if ((*p >> (7 - localbit)) & 1) {
116 #ifdef WORDS_BIGENDIAN
117 *(unsigned int *)data |= (1u << ((size * 8) - bit - 1));
118 #else
119 *(unsigned int *)data |= (1u << bit);
120 #endif
125 _asn1_bmember_isset_bit(const void *data, unsigned int bit, size_t size)
127 #ifdef WORDS_BIGENDIAN
128 if ((*(unsigned int *)data) & (1u << ((size * 8) - bit - 1)))
129 return 1;
130 return 0;
131 #else
132 if ((*(unsigned int *)data) & (1u << bit))
133 return 1;
134 return 0;
135 #endif
138 void
139 _asn1_bmember_put_bit(unsigned char *p, const void *data, unsigned int bit,
140 size_t size, unsigned int *bitset)
142 unsigned int localbit = bit % 8;
144 if (_asn1_bmember_isset_bit(data, bit, size)) {
145 *p |= (1u << (7 - localbit));
146 if (*bitset == 0)
147 *bitset = (7 - localbit) + 1;
152 * Utility function to tell us if the encoding of some type per its template
153 * will have an outer tag. This is needed when the caller wants to slap on an
154 * IMPLICIT tag: if the inner type has a tag then we need to replace it.
156 static int
157 is_tagged(const struct asn1_template *t)
159 size_t elements = A1_HEADER_LEN(t);
161 t += A1_HEADER_LEN(t);
162 if (elements != 1)
163 return 0;
164 switch (t->tt & A1_OP_MASK) {
165 case A1_OP_SEQOF: return 0;
166 case A1_OP_SETOF: return 0;
167 case A1_OP_BMEMBER: return 0;
168 case A1_OP_PARSE: return 0;
169 case A1_OP_TAG: return 1;
170 case A1_OP_CHOICE: return 1;
171 case A1_OP_TYPE: return 1;
172 case A1_OP_TYPE_EXTERN: {
173 const struct asn1_type_func *f = t->ptr;
176 * XXX Add a boolean to struct asn1_type_func to tell us if the type is
177 * tagged or not. Basically, it's not tagged if it's primitive.
179 if (f->encode == (asn1_type_encode)encode_heim_any ||
180 f->encode == (asn1_type_encode)encode_HEIM_ANY)
181 return 0;
182 abort(); /* XXX */
184 default: abort();
188 static size_t
189 inner_type_taglen(const struct asn1_template *t)
191 size_t elements = A1_HEADER_LEN(t);
193 t += A1_HEADER_LEN(t);
194 if (elements != 1)
195 return 0;
196 switch (t->tt & A1_OP_MASK) {
197 case A1_OP_SEQOF: return 0;
198 case A1_OP_SETOF: return 0;
199 case A1_OP_BMEMBER: return 0;
200 case A1_OP_PARSE: return 0;
201 case A1_OP_CHOICE: return 1;
202 case A1_OP_TYPE: return inner_type_taglen(t->ptr);
203 case A1_OP_TAG: return der_length_tag(A1_TAG_TAG(t->tt));
204 case A1_OP_TYPE_EXTERN: {
205 const struct asn1_type_func *f = t->ptr;
208 * XXX Add a boolean to struct asn1_type_func to tell us if the type is
209 * tagged or not. Basically, it's not tagged if it's primitive.
211 if (f->encode == (asn1_type_encode)encode_heim_any ||
212 f->encode == (asn1_type_encode)encode_HEIM_ANY)
213 return 0;
214 abort(); /* XXX */
216 default: abort();
217 #ifdef WIN32
218 _exit(0); /* Quiet VC */
219 #endif
224 * Compare some int of unknown size in a type ID field to the int value in
225 * some IOS object's type ID template entry.
227 * This should be called with a `A1_TAG_T(ASN1_C_UNIV, PRIM, UT_Integer)'
228 * template as the `ttypeid'.
230 static int
231 typeid_int_cmp(const void *intp,
232 int64_t i,
233 const struct asn1_template *ttypeid)
235 const struct asn1_template *tint = ttypeid->ptr;
237 if ((tint[1].tt & A1_OP_MASK) != A1_OP_PARSE)
238 return -1;
239 if (A1_PARSE_TYPE(tint[1].tt) != A1T_INTEGER &&
240 A1_PARSE_TYPE(tint[1].tt) != A1T_UNSIGNED &&
241 A1_PARSE_TYPE(tint[1].tt) != A1T_INTEGER64 &&
242 A1_PARSE_TYPE(tint[1].tt) != A1T_UNSIGNED64 &&
243 A1_PARSE_TYPE(tint[1].tt) != A1T_IMEMBER)
244 return -1;
245 switch (tint[0].offset) {
246 case 8: return i - *(const int64_t *)intp;
247 case 4: return i - *(const int32_t *)intp;
248 default: return -1;
253 * Map a logical SET/SEQUENCE member to a template entry.
255 * This should really have been done by the compiler, but clearly it wasn't.
257 * The point is that a struct type's template may be littered with entries that
258 * don't directly correspond to a struct field (SET/SEQUENCE member), so we
259 * have to count just the ones that do to get to the one we want.
261 static const struct asn1_template *
262 template4member(const struct asn1_template *t, size_t f)
264 size_t n = (uintptr_t)t->ptr;
265 size_t i;
267 for (i = 0, t++; i < n; t++, i++) {
268 switch (t->tt & A1_OP_MASK) {
269 case A1_OP_TAG:
270 case A1_OP_TYPE:
271 case A1_OP_TYPE_EXTERN:
272 if (f-- == 0)
273 return t;
274 continue;
275 case A1_OP_OPENTYPE_OBJSET:
276 case A1_OP_NAME:
277 return NULL;
278 default:
279 continue;
282 return NULL;
286 * Attempt to decode known open type alternatives into a CHOICE-like
287 * discriminated union.
289 * Arguments:
291 * - object set template
292 * - decoder flags
293 * - pointer to memory object (C struct) to decode into
294 * - template for type ID field of `data'
295 * - template for open type field of `data' (an octet string or HEIM_ANY)
297 * Returns:
299 * - 0
300 * - ENOMEM
302 * Other errors in decoding open type values are ignored, but applications can
303 * note that an error must have occurred. (Perhaps we should generate a `ret'
304 * field for the discriminated union we decode into that we could use to
305 * indicate what went wrong with decoding an open type value? The application
306 * can always try to decode itself to find out what the error was, but the
307 * whole point is to save the developer the bother of writing code to decode
308 * open type values. Then again, the specific cause of any one decode failure
309 * is not usually very important to users, so it's not very important to
310 * applications either.)
312 * Here `data' is something like this:
314 * typedef struct SingleAttribute {
315 * heim_oid type; // <--- decoded already
316 * HEIM_ANY value; // <--- decoded already
317 * // We must set this:
318 * // vvvvvvvv
319 * struct {
320 * enum {
321 * choice_SingleAttribute_iosnumunknown = 0,
322 * choice_SingleAttribute_iosnum_id_at_name,
323 * ..
324 * choice_SingleAttribute_iosnum_id_at_emailAddress,
325 * } element; // <--- map type ID to enum
326 * union {
327 * X520name* at_name;
328 * X520name* at_surname;
329 * ..
330 * AliasIA5String* at_emailAddress;
331 * } u; // <--- alloc and decode val above into this
332 * } _ioschoice_value;
333 * } SingleAttribute;
335 * or
337 * typedef struct AttributeSet {
338 * heim_oid type; // <--- decoded already
339 * struct AttributeSet_values {
340 * unsigned int len; // <--- decoded already
341 * HEIM_ANY *val; // <--- decoded already
342 * } values;
343 * // We must set this:
344 * // vvvvvvvv
345 * struct {
346 * enum { choice_AttributeSet_iosnumunknown = 0,
347 * choice_AttributeSet_iosnum_id_at_name,
348 * choice_AttributeSet_iosnum_id_at_surname,
349 * ..
350 * choice_AttributeSet_iosnum_id_at_emailAddress,
351 * } element; // <--- map type ID to enum
352 * unsigned int len; // <--- set len to len as above
353 * union {
354 * X520name *at_name;
355 * X520name *at_surname;
356 * ..
357 * AliasIA5String *at_emailAddress;
358 * } *val; // <--- alloc and decode vals above into this
359 * } _ioschoice_values;
360 * } AttributeSet;
362 static int
363 _asn1_decode_open_type(const struct asn1_template *t,
364 unsigned flags,
365 void *data,
366 const struct asn1_template *ttypeid,
367 const struct asn1_template *topentype)
369 const struct asn1_template *ttypeid_univ = ttypeid;
370 const struct asn1_template *tactual_type;
371 const struct asn1_template *tos = t->ptr;
372 size_t sz, n;
373 size_t i = 0;
374 unsigned int *lenp = NULL; /* Pointer to array length field */
375 unsigned int len = 1; /* Array length */
376 void **dp = NULL; /* Decoded open type struct pointer */
377 int *elementp; /* Choice enum pointer */
378 int typeid_is_oid = 0;
379 int typeid_is_int = 0;
380 int ret = 0;
383 * NOTE: Here expressions like `DPO(data, t->offset + ...)' refer to parts
384 * of a _ioschoice_<fieldName> struct field of `data'.
386 * Expressions like `DPO(data, topentype->offset + ...)' refer to
387 * the open type field in `data', which is either a `heim_any', a
388 * `heim_octet_string', or an array of one of those.
390 * Expressions like `DPO(data, ttypeid->offset)' refer to the open
391 * type's type ID field in `data'.
395 * Minimal setup:
397 * - set type choice to choice_<type>_iosnumunknown (zero).
398 * - set union value to zero
400 * We need a pointer to the choice ID:
402 * typedef struct AttributeSet {
403 * heim_oid type; // <--- decoded already
404 * struct AttributeSet_values {
405 * unsigned int len; // <--- decoded already
406 * HEIM_ANY *val; // <--- decoded already
407 * } values;
408 * struct {
409 * enum { choice_AttributeSet_iosnumunknown = 0,
410 * -----------> ...
411 * } element; // HERE
412 * ...
413 * } ...
416 * XXX NOTE: We're assuming that sizeof(enum) == sizeof(int)!
418 elementp = DPO(data, t->offset);
419 *elementp = 0; /* Set the choice to choice_<type>_iosnumunknown */
420 if (t->tt & A1_OS_OT_IS_ARRAY) {
422 * The open type is a SET OF / SEQUENCE OF -- an array.
424 * Get the number of elements to decode from:
426 * typedef struct AttributeSet {
427 * heim_oid type;
428 * struct AttributeSet_values {
429 * ------------>unsigned int len; // HERE
430 * HEIM_ANY *val;
431 * } values;
432 * ...
435 len = *((unsigned int *)DPO(data, topentype->offset));
438 * Set the number of decoded elements to zero for now:
440 * typedef struct AttributeSet {
441 * heim_oid type;
442 * struct AttributeSet_values {
443 * unsigned int len;
444 * HEIM_ANY *val;
445 * } values;
446 * struct {
447 * enum { ... } element;
448 * ------------>unsigned int len; // HERE
449 * ...
450 * } _ioschoice_values;
453 lenp = DPO(data, t->offset + sizeof(*elementp));
454 *lenp = 0;
456 * Get a pointer to the place where we must put the decoded value:
458 * typedef struct AttributeSet {
459 * heim_oid type;
460 * struct AttributeSet_values {
461 * unsigned int len;
462 * HEIM_ANY *val;
463 * } values;
464 * struct {
465 * enum { ... } element;
466 * unsigned int len;
467 * struct {
468 * union { SomeType *some_choice; ... } u;
469 * ------------>} *val; // HERE
470 * } _ioschoice_values;
471 * } AttributeSet;
473 dp = DPO(data, t->offset + sizeof(*elementp) + sizeof(*lenp));
474 } else {
476 * Get a pointer to the place where we must put the decoded value:
478 * typedef struct SingleAttribute {
479 * heim_oid type;
480 * HEIM_ANY value;
481 * struct {
482 * enum { ... } element;
483 * ------------>union { SomeType *some_choice; ... } u; // HERE
484 * } _ioschoice_value;
485 * } SingleAttribute;
487 dp = DPO(data, t->offset + sizeof(*elementp));
490 /* Align `dp' */
491 while (sizeof(void *) != sizeof(*elementp) &&
492 ((uintptr_t)dp) % sizeof(void *) != 0)
493 dp = (void *)(((char *)dp) + sizeof(*elementp));
494 *dp = NULL;
497 * Find out the type of the type ID member. We currently support only
498 * integers and OIDs.
500 * Chase through any tags to get to the type.
502 while (((ttypeid_univ->tt & A1_OP_MASK) == A1_OP_TAG &&
503 A1_TAG_CLASS(ttypeid_univ->tt) == ASN1_C_CONTEXT) ||
504 ((ttypeid_univ->tt & A1_OP_MASK) == A1_OP_TYPE)) {
505 ttypeid_univ = ttypeid_univ->ptr;
506 ttypeid_univ++;
508 switch (ttypeid_univ->tt & A1_OP_MASK) {
509 case A1_OP_TAG:
510 if (A1_TAG_CLASS(ttypeid_univ->tt) != ASN1_C_UNIV)
511 return 0; /* Do nothing, silently */
512 switch (A1_TAG_TAG(ttypeid_univ->tt)) {
513 case UT_OID:
514 typeid_is_oid = 1;
515 break;
516 case UT_Integer: {
517 const struct asn1_template *tint = ttypeid_univ->ptr;
519 tint++;
521 if ((tint->tt & A1_OP_MASK) != A1_OP_PARSE)
522 return 0; /* Do nothing, silently */
523 if (A1_PARSE_TYPE(tint->tt) != A1T_INTEGER &&
524 A1_PARSE_TYPE(tint->tt) != A1T_UNSIGNED &&
525 A1_PARSE_TYPE(tint->tt) != A1T_INTEGER64 &&
526 A1_PARSE_TYPE(tint->tt) != A1T_UNSIGNED64 &&
527 A1_PARSE_TYPE(tint->tt) != A1T_IMEMBER)
528 return 0; /* Do nothing, silently (maybe a large int) */
529 typeid_is_int = 1;
530 break;
532 /* It might be cool to support string types as type ID types */
533 default: return 0; /* Do nothing, silently */
535 break;
536 default: return 0; /* Do nothing, silently */
540 * Find the type of the open type.
542 * An object set template looks like:
544 * const struct asn1_template asn1_ObjectSetName[] = {
545 * // Header entry (in this case it says there's 17 objects):
546 * { 0, 0, ((void*)17) },
548 * // here's the name of the object set:
549 * { A1_OP_NAME, 0, "ObjectSetName" },
551 * // then three entries per object: object name, object type ID,
552 * // object type:
553 * { A1_OP_NAME, 0, "ext-AuthorityInfoAccess" },
554 * { A1_OP_OPENTYPE_ID, 0, (const void*)&asn1_oid_oidName },
555 * { A1_OP_OPENTYPE, sizeof(SomeType), (const void*)&asn1_SomeType },
556 * ...
557 * };
559 * `i' being a logical object offset, i*3+3 would be the index of the
560 * A1_OP_OPENTYPE_ID entry for the current object, and i*3+4 the index of
561 * the A1_OP_OPENTYPE entry for the current object.
563 if (t->tt & A1_OS_IS_SORTED) {
564 size_t left = 0;
565 size_t right = A1_HEADER_LEN(tos);
566 const void *vp = DPO(data, ttypeid->offset);
567 int c = -1;
569 while (left < right) {
570 size_t mid = (left + right) >> 1;
572 if ((tos[3 + mid * 3].tt & A1_OP_MASK) != A1_OP_OPENTYPE_ID)
573 return 0;
574 if (typeid_is_int)
575 c = typeid_int_cmp(vp, (intptr_t)tos[3 + mid * 3].ptr,
576 ttypeid_univ);
577 else if (typeid_is_oid)
578 c = der_heim_oid_cmp(vp, tos[3 + mid * 3].ptr);
579 if (c < 0) {
580 right = mid;
581 } else if (c > 0) {
582 left = mid + 1;
583 } else {
584 i = mid;
585 break;
588 if (c)
589 return 0; /* No match */
590 } else {
591 for (i = 0, n = A1_HEADER_LEN(tos); i < n; i++) {
592 /* We add 1 to `i' because we're skipping the header */
593 if ((tos[3 + i*3].tt & A1_OP_MASK) != A1_OP_OPENTYPE_ID)
594 return 0;
595 if (typeid_is_int &&
596 typeid_int_cmp(DPO(data, ttypeid->offset),
597 (intptr_t)tos[3 + i*3].ptr,
598 ttypeid_univ))
599 continue;
600 if (typeid_is_oid &&
601 der_heim_oid_cmp(DPO(data, ttypeid->offset), tos[3 + i*3].ptr))
602 continue;
603 break;
605 if (i == n)
606 return 0; /* No match */
609 /* Match! */
610 *elementp = i+1; /* Zero is the "unknown" choice, so add 1 */
613 * We want the A1_OP_OPENTYPE template entry. Its `offset' is the sizeof
614 * the object we'll be decoding into, and its `ptr' is the pointer to the
615 * template for decoding that type.
617 tactual_type = &tos[i*3 + 4];
619 /* Decode the encoded open type value(s) */
620 if (!(t->tt & A1_OS_OT_IS_ARRAY)) {
622 * Not a SET OF/SEQUENCE OF open type, just singular.
624 * We need the address of the octet string / ANY field containing the
625 * encoded open type value:
627 * typedef struct SingleAttribute {
628 * heim_oid type;
629 * -------->HEIM_ANY value; // HERE
630 * struct {
631 * ...
632 * } ...
635 const struct heim_base_data *d = DPOC(data, topentype->offset);
636 void *o;
638 if (d->data && d->length) {
639 if ((o = calloc(1, tactual_type->offset)) == NULL)
640 return ENOMEM;
642 /* Re-enter to decode the encoded open type value */
643 ret = _asn1_decode(tactual_type->ptr, flags, d->data, d->length, o, &sz);
645 * Store the decoded object in the union:
647 * typedef struct SingleAttribute {
648 * heim_oid type;
649 * HEIM_ANY value;
650 * struct {
651 * enum { ... } element;
652 * ------------>union { SomeType *some_choice; ... } u; // HERE
653 * } _ioschoice_value;
654 * } SingleAttribute;
656 * All the union arms are pointers.
658 if (ret) {
659 _asn1_free(tactual_type->ptr, o);
660 free(o);
662 * So we failed to decode the open type -- that should not be fatal
663 * to decoding the rest of the input. Only ENOMEM should be fatal.
665 ret = 0;
666 } else {
667 *dp = o;
670 return ret;
671 } else {
672 const struct heim_base_data * const *d;
673 void **val; /* Array of pointers */
676 * A SET OF/SEQUENCE OF open type, plural.
678 * We need the address of the octet string / ANY array pointer field
679 * containing the encoded open type values:
681 * typedef struct AttributeSet {
682 * heim_oid type;
683 * struct AttributeSet_values {
684 * unsigned int len;
685 * ------------>HEIM_ANY *val; // HERE
686 * } values;
687 * ...
690 * We already know the value of the `len' field.
692 d = DPOC(data, topentype->offset + sizeof(unsigned int));
693 while (sizeof(void *) != sizeof(len) &&
694 ((uintptr_t)d) % sizeof(void *) != 0)
695 d = (const void *)(((const char *)d) + sizeof(len));
697 if ((val = calloc(len, sizeof(*val))) == NULL)
698 ret = ENOMEM;
700 /* Increment the count of decoded values as we decode */
701 *lenp = len;
702 for (i = 0; ret != ENOMEM && i < len; i++) {
703 if ((val[i] = calloc(1, tactual_type->offset)) == NULL)
704 ret = ENOMEM;
705 if (ret == 0)
706 /* Re-enter to decode the encoded open type value */
707 ret = _asn1_decode(tactual_type->ptr, flags, d[0][i].data,
708 d[0][i].length, val[i], &sz);
709 if (ret) {
710 _asn1_free(tactual_type->ptr, val[i]);
711 free(val[i]);
712 val[i] = NULL;
715 if (ret != ENOMEM)
716 ret = 0; /* See above */
717 *dp = val;
718 return ret;
723 _asn1_decode(const struct asn1_template *t, unsigned flags,
724 const unsigned char *p, size_t len, void *data, size_t *size)
726 const struct asn1_template *tbase = t;
727 const struct asn1_template *tdefval = NULL;
728 size_t elements = A1_HEADER_LEN(t);
729 size_t oldlen = len;
730 int ret = 0;
731 const unsigned char *startp = NULL;
732 unsigned int template_flags = t->tt;
735 * Important notes:
737 * - by and large we don't call _asn1_free() on error, except when we're
738 * decoding optional things or choices, then we do call _asn1_free()
739 * here
741 * instead we leave it to _asn1_decode_top() to call _asn1_free() on
742 * error
744 * - on error all fields of whatever we didn't _asn1_free() must have been
745 * initialized to sane values because _asn1_decode_top() will call
746 * _asn1_free() on error, so we must have left everything initialized
747 * that _asn1_free() could possibly look at
749 * - so we must initialize everything
751 * FIXME? but we mostly rely on calloc() to do this...
753 * - we don't use malloc() unless we're going to write over the whole
754 * thing with memcpy() or whatever
757 /* skip over header */
758 t++;
760 if (template_flags & A1_HF_PRESERVE)
761 startp = p;
763 while (elements) {
764 switch (t->tt & A1_OP_MASK) {
765 case A1_OP_OPENTYPE_OBJSET: {
766 size_t opentypeid = t->tt & ((1<<10)-1);
767 size_t opentype = (t->tt >> 10) & ((1<<10)-1);
769 /* Note that the only error returned here would be ENOMEM */
770 ret = _asn1_decode_open_type(t, flags, data,
771 template4member(tbase, opentypeid),
772 template4member(tbase, opentype));
773 if (ret)
774 return ret;
775 break;
777 case A1_OP_TYPE_DECORATE: break;
778 case A1_OP_NAME: break;
779 case A1_OP_DEFVAL:
780 tdefval = t;
781 break;
782 case A1_OP_TYPE:
783 case A1_OP_TYPE_EXTERN: {
784 size_t newsize, elsize;
785 void *el = DPO(data, t->offset);
786 void **pel = (void **)el;
788 if ((t->tt & A1_OP_MASK) == A1_OP_TYPE) {
789 elsize = _asn1_sizeofType(t->ptr);
790 } else {
791 const struct asn1_type_func *f = t->ptr;
792 elsize = f->size;
795 if (t->tt & A1_FLAG_OPTIONAL) {
796 *pel = calloc(1, elsize);
797 if (*pel == NULL)
798 return ENOMEM;
799 el = *pel;
800 if ((t->tt & A1_OP_MASK) == A1_OP_TYPE) {
801 ret = _asn1_decode(t->ptr, flags, p, len, el, &newsize);
802 } else {
803 const struct asn1_type_func *f = t->ptr;
804 ret = (f->decode)(p, len, el, &newsize);
806 if (ret) {
808 * Optional field not present in encoding, presumably,
809 * though we should really look more carefully at `ret'.
811 if ((t->tt & A1_OP_MASK) == A1_OP_TYPE) {
812 _asn1_free(t->ptr, el);
813 } else {
814 const struct asn1_type_func *f = t->ptr;
815 f->release(el);
817 free(*pel);
818 *pel = NULL;
819 break;
821 } else {
822 if ((t->tt & A1_OP_MASK) == A1_OP_TYPE) {
823 ret = _asn1_decode(t->ptr, flags, p, len, el, &newsize);
824 } else {
825 const struct asn1_type_func *f = t->ptr;
826 ret = (f->decode)(p, len, el, &newsize);
829 if (ret) {
830 if (t->tt & A1_FLAG_OPTIONAL) {
831 } else if (t->tt & A1_FLAG_DEFAULT) {
833 * Defaulted field not present in encoding, presumably,
834 * though we should really look more carefully at `ret'.
836 if (tdefval->tt & A1_DV_BOOLEAN) {
837 int *i = (void *)(char *)el;
839 *i = tdefval->ptr ? 1 : 0;
840 } else if (tdefval->tt & A1_DV_INTEGER64) {
841 int64_t *i = (void *)(char *)el;
843 *i = (int64_t)(intptr_t)tdefval->ptr;
844 } else if (tdefval->tt & A1_DV_INTEGER32) {
845 int32_t *i = (void *)(char *)el;
847 *i = (int32_t)(intptr_t)tdefval->ptr;
848 } else if (tdefval->tt & A1_DV_INTEGER) {
849 struct heim_integer *i = (void *)(char *)el;
851 if ((ret = der_copy_heim_integer(tdefval->ptr, i)))
852 return ret;
853 } else if (tdefval->tt & A1_DV_UTF8STRING) {
854 char **s = el;
856 if ((*s = strdup(tdefval->ptr)) == NULL)
857 return ENOMEM;
858 } else {
859 abort();
861 break;
863 return ret; /* Error decoding required field */
865 p += newsize; len -= newsize;
867 break;
869 case A1_OP_TAG: {
870 Der_type dertype;
871 size_t newsize = 0;
872 size_t datalen, l = 0;
873 void *olddata = data;
874 int is_indefinite = 0;
875 int subflags = flags;
876 int replace_tag = (t->tt & A1_FLAG_IMPLICIT) && is_tagged(t->ptr);
877 void *el = data = DPO(data, t->offset);
878 void **pel = (void **)el;
881 * XXX If this type (chasing t->ptr through IMPLICIT tags, if this
882 * one is too, till we find a non-TTag) is a [UNIVERSAL SET] type,
883 * then we have to accept fields out of order. For each field tag
884 * we see we'd have to do a linear search of the SET's template
885 * because it won't be sorted (or we could sort a copy and do a
886 * binary search on that, but these SETs will always be small so it
887 * won't be worthwhile). We'll need a utility function to do all
888 * of this.
890 ret = der_match_tag_and_length(p, len, A1_TAG_CLASS(t->tt),
891 &dertype, A1_TAG_TAG(t->tt),
892 &datalen, &l);
893 if (ret) {
894 if (t->tt & A1_FLAG_OPTIONAL) {
895 data = olddata;
896 break;
897 } else if (t->tt & A1_FLAG_DEFAULT) {
899 * Defaulted field not present in encoding, presumably,
900 * though we should really look more carefully at `ret'.
902 if (tdefval->tt & A1_DV_BOOLEAN) {
903 int *i = (void *)(char *)data;
905 *i = tdefval->ptr ? 1 : 0;
906 } else if (tdefval->tt & A1_DV_INTEGER64) {
907 int64_t *i = (void *)(char *)data;
909 *i = (int64_t)(intptr_t)tdefval->ptr;
910 } else if (tdefval->tt & A1_DV_INTEGER32) {
911 int32_t *i = (void *)(char *)data;
913 *i = (int32_t)(intptr_t)tdefval->ptr;
914 } else if (tdefval->tt & A1_DV_INTEGER) {
915 struct heim_integer *i = (void *)(char *)data;
917 if ((ret = der_copy_heim_integer(tdefval->ptr, i)))
918 return ret;
919 } else if (tdefval->tt & A1_DV_UTF8STRING) {
920 char **s = data;
922 if ((*s = strdup(tdefval->ptr)) == NULL)
923 return ENOMEM;
924 } else {
925 abort();
927 data = olddata;
928 break;
930 return ret; /* Error decoding required field */
933 p += l; len -= l;
936 * Only allow indefinite encoding for OCTET STRING and BER
937 * for now. Should handle BIT STRING too.
940 if (dertype != A1_TAG_TYPE(t->tt) && (flags & A1_PF_ALLOW_BER)) {
941 const struct asn1_template *subtype = t->ptr;
942 subtype++; /* skip header */
944 if (((subtype->tt & A1_OP_MASK) == A1_OP_PARSE) &&
945 A1_PARSE_TYPE(subtype->tt) == A1T_OCTET_STRING)
946 subflags |= A1_PF_INDEFINTE;
949 if (datalen == ASN1_INDEFINITE) {
950 if ((flags & A1_PF_ALLOW_BER) == 0)
951 return ASN1_GOT_BER;
952 is_indefinite = 1;
953 datalen = len;
954 if (datalen < 2)
955 return ASN1_OVERRUN;
956 /* hide EndOfContent for sub-decoder, catching it below */
957 datalen -= 2;
958 } else if (datalen > len)
959 return ASN1_OVERRUN;
961 if (t->tt & A1_FLAG_OPTIONAL) {
962 size_t ellen = _asn1_sizeofType(t->ptr);
964 *pel = calloc(1, ellen);
965 if (*pel == NULL)
966 return ENOMEM;
967 data = *pel;
970 if (replace_tag) {
971 const struct asn1_template *subtype = t->ptr;
972 int have_tag = 0;
975 * So, we have an IMPLICIT tag. What we want to do is find the
976 * template for the body of the type so-tagged. That's going
977 * to be a template that has a tag that isn't itself IMPLICIT.
979 * So we chase the pointer in the template until we find such a
980 * thing, then decode using that template.
982 while (!have_tag) {
983 subtype++;
984 if ((subtype->tt & A1_OP_MASK) == A1_OP_TAG)
985 replace_tag = (subtype->tt & A1_FLAG_IMPLICIT) && is_tagged(t->ptr);
986 if (replace_tag) {
987 subtype = subtype->ptr;
988 continue;
990 if ((subtype->tt & A1_OP_MASK) == A1_OP_TAG) {
991 ret = _asn1_decode(subtype->ptr, subflags, p, datalen, data, &newsize);
992 have_tag = 1;
993 } else {
994 subtype = subtype->ptr;
997 } else {
998 ret = _asn1_decode(t->ptr, subflags, p, datalen, data, &newsize);
1000 if (ret == 0 && !is_indefinite && newsize != datalen)
1001 /* Hidden data */
1002 ret = ASN1_EXTRA_DATA;
1004 if (ret == 0) {
1005 if (is_indefinite) {
1006 /* If we use indefinite encoding, the newsize is the datasize. */
1007 datalen = newsize;
1010 len -= datalen;
1011 p += datalen;
1014 * Indefinite encoding needs a trailing EndOfContent,
1015 * check for that.
1017 if (is_indefinite) {
1018 ret = der_match_tag_and_length(p, len, ASN1_C_UNIV,
1019 &dertype, UT_EndOfContent,
1020 &datalen, &l);
1021 if (ret == 0 && dertype != PRIM)
1022 ret = ASN1_BAD_ID;
1023 else if (ret == 0 && datalen != 0)
1024 ret = ASN1_INDEF_EXTRA_DATA;
1025 if (ret == 0) {
1026 p += l; len -= l;
1030 if (ret) {
1031 if (!(t->tt & A1_FLAG_OPTIONAL))
1032 return ret;
1034 _asn1_free(t->ptr, data);
1035 free(data);
1036 *pel = NULL;
1037 return ret;
1039 data = olddata;
1041 break;
1043 case A1_OP_PARSE: {
1044 unsigned int type = A1_PARSE_TYPE(t->tt);
1045 size_t newsize;
1046 void *el = DPO(data, t->offset);
1049 * INDEFINITE primitive types are one element after the
1050 * same type but non-INDEFINITE version.
1052 if (flags & A1_PF_INDEFINTE)
1053 type++;
1055 if (type >= sizeof(asn1_template_prim)/sizeof(asn1_template_prim[0])) {
1056 ABORT_ON_ERROR();
1057 return ASN1_PARSE_ERROR;
1060 ret = (asn1_template_prim[type].decode)(p, len, el, &newsize);
1061 if (ret)
1062 return ret;
1063 p += newsize; len -= newsize;
1065 break;
1067 case A1_OP_SETOF:
1068 case A1_OP_SEQOF: {
1069 struct template_of *el = DPO(data, t->offset);
1070 size_t newsize;
1071 size_t ellen = _asn1_sizeofType(t->ptr);
1072 size_t vallength = 0;
1074 while (len > 0) {
1075 void *tmp;
1076 size_t newlen = vallength + ellen;
1077 if (vallength > newlen)
1078 return ASN1_OVERFLOW;
1080 /* XXX Slow */
1081 tmp = realloc(el->val, newlen);
1082 if (tmp == NULL)
1083 return ENOMEM;
1085 memset(DPO(tmp, vallength), 0, ellen);
1086 el->val = tmp;
1088 el->len++;
1089 ret = _asn1_decode(t->ptr, flags & (~A1_PF_INDEFINTE), p, len,
1090 DPO(el->val, vallength), &newsize);
1091 if (ret)
1092 return ret;
1093 vallength = newlen;
1094 p += newsize; len -= newsize;
1097 break;
1099 case A1_OP_BMEMBER: {
1100 const struct asn1_template *bmember = t->ptr;
1101 size_t bsize = bmember->offset;
1102 size_t belements = A1_HEADER_LEN(bmember);
1103 size_t pos = 0;
1105 bmember++;
1107 memset(data, 0, bsize);
1109 if (len < 1)
1110 return ASN1_OVERRUN;
1111 p++; len--;
1113 while (belements && len) {
1114 while (bmember->offset / 8 > pos / 8) {
1115 if (len < 1)
1116 break;
1117 p++; len--;
1118 pos += 8;
1120 if (len) {
1121 _asn1_bmember_get_bit(p, data, bmember->offset, bsize);
1122 belements--; bmember++;
1125 len = 0;
1126 break;
1128 case A1_OP_CHOICE: {
1129 const struct asn1_template *choice = t->ptr;
1130 unsigned int *element = DPO(data, choice->offset);
1131 size_t datalen;
1132 unsigned int i;
1135 * CHOICE element IDs are assigned in monotonically increasing
1136 * fashion. Therefore any unrealistic value is a suitable invalid
1137 * CHOICE value. The largest binary value (or -1 if treating the
1138 * enum as signed on a twos-complement system, or...) will do.
1140 *element = ~0;
1142 for (i = 1; i < A1_HEADER_LEN(choice) + 1 && choice[i].tt; i++) {
1144 * This is more permissive than is required. CHOICE
1145 * alternatives must have different outer tags, so in principle
1146 * we should just match the tag at `p' and `len' in sequence to
1147 * the choice alternatives.
1149 * Trying every alternative instead happens to do this anyways
1150 * because each one will first match the tag at `p' and `len',
1151 * but if there are CHOICE altnernatives with the same outer
1152 * tag, then we'll allow it, and they had better be unambiguous
1153 * in their internal details, otherwise there would be some
1154 * aliasing.
1156 * Arguably the *compiler* should detect ambiguous CHOICE types
1157 * and raise an error, then we don't have to be concerned here
1158 * at all.
1160 ret = _asn1_decode(choice[i].ptr, 0, p, len,
1161 DPO(data, choice[i].offset), &datalen);
1162 if (ret == 0) {
1163 *element = i;
1164 p += datalen; len -= datalen;
1165 break;
1167 _asn1_free(choice[i].ptr, DPO(data, choice[i].offset));
1168 if (ret != ASN1_BAD_ID && ret != ASN1_MISPLACED_FIELD &&
1169 ret != ASN1_MISSING_FIELD)
1170 return ret;
1172 if (i >= A1_HEADER_LEN(choice) + 1 || !choice[i].tt) {
1173 if (choice->tt == 0)
1174 return ASN1_BAD_ID;
1176 /* This is the ellipsis case */
1177 *element = 0;
1178 ret = der_get_octet_string(p, len,
1179 DPO(data, choice->tt), &datalen);
1180 if (ret)
1181 return ret;
1182 p += datalen; len -= datalen;
1185 break;
1187 default:
1188 ABORT_ON_ERROR();
1189 return ASN1_PARSE_ERROR;
1191 t++;
1192 elements--;
1194 /* if we are using padding, eat up read of context */
1195 if (template_flags & A1_HF_ELLIPSIS)
1196 len = 0;
1198 oldlen -= len;
1200 if (size)
1201 *size = oldlen;
1204 * saved the raw bits if asked for it, useful for signature
1205 * verification.
1207 if (startp) {
1208 heim_octet_string *save = data;
1210 save->data = malloc(oldlen);
1211 if (save->data == NULL)
1212 return ENOMEM;
1213 else {
1214 save->length = oldlen;
1215 memcpy(save->data, startp, oldlen);
1218 return 0;
1222 * This should be called with a `A1_TAG_T(ASN1_C_UNIV, PRIM, UT_Integer)'
1223 * template as the `ttypeid'.
1225 static int
1226 typeid_int_copy(void *intp,
1227 int64_t i,
1228 const struct asn1_template *ttypeid)
1230 const struct asn1_template *tint = ttypeid->ptr;
1232 if ((tint[1].tt & A1_OP_MASK) != A1_OP_PARSE)
1233 return -1;
1234 if (A1_PARSE_TYPE(tint[1].tt) != A1T_INTEGER)
1235 return -1;
1236 switch (tint[0].offset) {
1237 case 8: *((int64_t *)intp) = i; return 0;
1238 case 4: *((int32_t *)intp) = i; return 0;
1239 default: memset(intp, 0, tint[0].offset); return 0;
1243 /* See commentary in _asn1_decode_open_type() */
1244 static int
1245 _asn1_encode_open_type(const struct asn1_template *t,
1246 const void *data, /* NOTE: Not really const */
1247 const struct asn1_template *ttypeid,
1248 const struct asn1_template *topentype)
1250 const struct asn1_template *ttypeid_univ = ttypeid;
1251 const struct asn1_template *tactual_type;
1252 const struct asn1_template *tos = t->ptr;
1253 size_t sz, i;
1254 unsigned int *lenp = NULL;
1255 unsigned int len = 1;
1256 int element = *(const int *)DPOC(data, t->offset);
1257 int typeid_is_oid = 0;
1258 int typeid_is_int = 0;
1259 int enotsup = 0;
1260 int ret = 0;
1262 if (element == 0 || element >= A1_HEADER_LEN(tos) + 1)
1263 return 0;
1265 if (t->tt & A1_OS_OT_IS_ARRAY) {
1266 /* The actual `len' is from the decoded open type field */
1267 len = *(const unsigned int *)DPOC(data, t->offset + sizeof(element));
1269 if (!len)
1270 return 0; /* The app may be encoding the open type by itself */
1273 /* Work out the type ID field's type */
1274 while (((ttypeid_univ->tt & A1_OP_MASK) == A1_OP_TAG &&
1275 A1_TAG_CLASS(ttypeid_univ->tt) == ASN1_C_CONTEXT) ||
1276 ((ttypeid_univ->tt & A1_OP_MASK) == A1_OP_TYPE)) {
1277 ttypeid_univ = ttypeid_univ->ptr;
1278 ttypeid_univ++;
1280 switch (ttypeid_univ->tt & A1_OP_MASK) {
1281 case A1_OP_TAG:
1282 if (A1_TAG_CLASS(ttypeid_univ->tt) != ASN1_C_UNIV) {
1283 enotsup = 1;
1284 break;
1286 switch (A1_TAG_TAG(ttypeid_univ->tt)) {
1287 case UT_OID:
1288 typeid_is_oid = 1;
1289 break;
1290 case UT_Integer: {
1291 const struct asn1_template *tint = ttypeid_univ->ptr;
1293 tint++;
1294 if ((tint->tt & A1_OP_MASK) != A1_OP_PARSE ||
1295 A1_PARSE_TYPE(tint->tt) != A1T_INTEGER) {
1296 enotsup = 1;
1297 break;
1299 typeid_is_int = 1;
1300 break;
1302 default: enotsup = 1; break;
1304 break;
1305 default: enotsup = 1; break;
1309 * The app may not be aware of our automatic open type handling, so if the
1310 * open type already appears to have been encoded, then ignore the decoded
1311 * values.
1313 if (!(t->tt & A1_OS_OT_IS_ARRAY)) {
1314 struct heim_base_data *os = DPO(data, topentype->offset);
1316 if (os->length && os->data)
1317 return 0;
1318 } else {
1319 struct heim_base_data **os = DPO(data, topentype->offset + sizeof(len));
1321 while (sizeof(void *) != sizeof(unsigned int) &&
1322 ((uintptr_t)os) % sizeof(void *) != 0)
1323 os = (void *)(((char *)os) + sizeof(unsigned int));
1325 lenp = DPO(data, topentype->offset);
1326 if (*lenp == len && os[0]->length && os[0]->data)
1327 return 0;
1330 if (typeid_is_int) {
1332 * Copy the int from the type ID object field to the type ID struct
1333 * field.
1335 ret = typeid_int_copy(DPO(data, ttypeid->offset),
1336 (intptr_t)tos[3 + (element-1)*3].ptr, ttypeid_univ);
1337 } else if (typeid_is_oid) {
1339 * Copy the OID from the type ID object field to the type ID struct
1340 * field.
1342 ret = der_copy_oid(tos[3 + (element-1)*3].ptr, DPO(data, ttypeid->offset));
1343 } else
1344 enotsup = 1;
1347 * If the app did not already encode the open type, we can't help it if we
1348 * don't know what it is.
1350 if (enotsup)
1351 return ENOTSUP;
1353 tactual_type = &tos[(element-1)*3 + 4];
1355 if (!(t->tt & A1_OS_OT_IS_ARRAY)) {
1356 struct heim_base_data *os = DPO(data, topentype->offset);
1357 const void * const *d = DPOC(data, t->offset + sizeof(element));
1359 while (sizeof(void *) != sizeof(element) &&
1360 ((uintptr_t)d) % sizeof(void *) != 0) {
1361 d = (void *)(((char *)d) + sizeof(element));
1364 os->length = _asn1_length(tactual_type->ptr, *d);
1365 if ((os->data = malloc(os->length)) == NULL)
1366 return ENOMEM;
1367 ret = _asn1_encode(tactual_type->ptr, (os->length - 1) + (unsigned char *)os->data, os->length, *d, &sz);
1368 } else {
1369 struct heim_base_data *os;
1370 const void * const *val =
1371 DPOC(data, t->offset + sizeof(element) + sizeof(*lenp));
1373 if ((os = calloc(len, sizeof(*os))) == NULL)
1374 return ENOMEM;
1376 *lenp = len;
1377 for (i = 0; ret == 0 && i < len; i++) {
1378 os[i].length = _asn1_length(tactual_type->ptr, val[i]);
1379 if ((os[i].data = malloc(os[i].length)) == NULL)
1380 ret = ENOMEM;
1381 if (ret == 0)
1382 ret = _asn1_encode(tactual_type->ptr, (os[i].length - 1) + (unsigned char *)os[i].data, os[i].length,
1383 val[i], &sz);
1385 if (ret) {
1386 for (i = 0; i < (*lenp); i++)
1387 free(os[i].data);
1388 free(os);
1389 *lenp = 0;
1390 return ret;
1392 *(struct heim_base_data **)DPO(data, topentype->offset + sizeof(len)) = os;
1394 return ret;
1398 _asn1_encode(const struct asn1_template *t, unsigned char *p, size_t len, const void *data, size_t *size)
1400 const struct asn1_template *tbase = t;
1401 size_t elements = A1_HEADER_LEN(t);
1402 int ret = 0;
1403 size_t oldlen = len;
1405 t += A1_HEADER_LEN(t);
1407 while (elements) {
1408 switch (t->tt & A1_OP_MASK) {
1409 case A1_OP_OPENTYPE_OBJSET: {
1410 size_t opentypeid = t->tt & ((1<<10)-1);
1411 size_t opentype = (t->tt >> 10) & ((1<<10)-1);
1412 ret = _asn1_encode_open_type(t, data,
1413 template4member(tbase, opentypeid),
1414 template4member(tbase, opentype));
1415 if (ret)
1416 return ret;
1417 break;
1419 case A1_OP_NAME: break;
1420 case A1_OP_DEFVAL: break;
1421 case A1_OP_TYPE_DECORATE: break;
1422 case A1_OP_TYPE:
1423 case A1_OP_TYPE_EXTERN: {
1424 size_t newsize;
1425 const void *el = DPOC(data, t->offset);
1427 if (t->tt & A1_FLAG_OPTIONAL) {
1428 void **pel = (void **)el;
1429 if (*pel == NULL)
1430 break;
1431 el = *pel;
1432 } else if ((t->tt & A1_FLAG_DEFAULT) && elements > 1) {
1433 const struct asn1_template *tdefval = t - 1;
1434 /* Compare tdefval to whatever's at `el' */
1435 if (tdefval->tt & A1_DV_BOOLEAN) {
1436 const int *i = (void *)(char *)el;
1438 if ((*i && tdefval->ptr) || (!*i && !tdefval->ptr))
1439 break;
1440 } else if (tdefval->tt & A1_DV_INTEGER64) {
1441 const int64_t *i = (void *)(char *)el;
1443 if (*i == (int64_t)(intptr_t)tdefval->ptr)
1444 break;
1445 } else if (tdefval->tt & A1_DV_INTEGER32) {
1446 const int32_t *i = (void *)(char *)el;
1448 if ((int64_t)(intptr_t)tdefval->ptr <= INT_MAX &&
1449 (int64_t)(intptr_t)tdefval->ptr >= INT_MIN &&
1450 *i == (int32_t)(intptr_t)tdefval->ptr)
1451 break;
1452 } else if (tdefval->tt & A1_DV_INTEGER) {
1453 const struct heim_integer *i = (void *)(char *)el;
1455 if (der_heim_integer_cmp(i, tdefval->ptr) == 0)
1456 break;
1457 } else if (tdefval->tt & A1_DV_UTF8STRING) {
1458 const char * const *s = el;
1460 if (*s && strcmp(*s, tdefval->ptr) == 0)
1461 break;
1462 } else {
1463 abort();
1467 if ((t->tt & A1_OP_MASK) == A1_OP_TYPE) {
1468 ret = _asn1_encode(t->ptr, p, len, el, &newsize);
1469 } else {
1470 const struct asn1_type_func *f = t->ptr;
1471 ret = (f->encode)(p, len, el, &newsize);
1474 if (ret)
1475 return ret;
1476 p -= newsize; len -= newsize;
1478 break;
1480 case A1_OP_TAG: {
1481 const void *olddata = data;
1482 size_t l, datalen = 0;
1483 int replace_tag = 0;
1486 * XXX If this type (chasing t->ptr through IMPLICIT tags, if this
1487 * one is too) till we find a non-TTag) is a [UNIVERSAL SET] type,
1488 * then we have to sort [a copy of] its template by tag, then
1489 * encode the SET using that sorted template. These SETs will
1490 * generally be small, so when they are we might want to allocate
1491 * the copy on the stack and insertion sort it. We'll need a
1492 * utility function to do all of this.
1495 data = DPOC(data, t->offset);
1497 if (t->tt & A1_FLAG_OPTIONAL) {
1498 void **el = (void **)data;
1499 if (*el == NULL) {
1500 data = olddata;
1501 break;
1503 data = *el;
1504 } else if ((t->tt & A1_FLAG_DEFAULT) && elements > 1) {
1505 const struct asn1_template *tdefval = t - 1;
1506 int exclude = 0;
1508 /* Compare tdefval to whatever's at `data' */
1509 if (tdefval->tt & A1_DV_BOOLEAN) {
1510 const int *i = (void *)(char *)data;
1512 if ((*i && tdefval->ptr) || (!*i && !tdefval->ptr))
1513 exclude = 1;
1514 } else if (tdefval->tt & A1_DV_INTEGER64) {
1515 const int64_t *i = (void *)(char *)data;
1517 if (*i == (int64_t)(intptr_t)tdefval->ptr)
1518 exclude = 1;
1519 } else if (tdefval->tt & A1_DV_INTEGER32) {
1520 const int32_t *i = (void *)(char *)data;
1522 if ((int64_t)(intptr_t)tdefval->ptr <= INT_MAX &&
1523 (int64_t)(intptr_t)tdefval->ptr >= INT_MIN &&
1524 *i == (int32_t)(intptr_t)tdefval->ptr)
1525 exclude = 1;
1526 } else if (tdefval->tt & A1_DV_INTEGER) {
1527 const struct heim_integer *i = (void *)(char *)data;
1529 if (der_heim_integer_cmp(i, tdefval->ptr) == 0)
1530 break;
1531 } else if (tdefval->tt & A1_DV_UTF8STRING) {
1532 const char * const *s = data;
1534 if (*s && strcmp(*s, tdefval->ptr) == 0)
1535 exclude = 1;
1536 } else {
1537 abort();
1539 if (exclude) {
1540 data = olddata;
1541 break;
1545 replace_tag = (t->tt & A1_FLAG_IMPLICIT) && is_tagged(t->ptr);
1547 /* IMPLICIT tags need special handling (see gen_encode.c) */
1548 if (replace_tag) {
1549 unsigned char *pfree, *psave = p;
1550 Der_class found_class;
1551 Der_type found_type = 0;
1552 unsigned int found_tag;
1553 size_t lensave = len;
1554 size_t oldtaglen = 0;
1555 size_t taglen = der_length_tag(A1_TAG_TAG(t->tt));;
1557 /* Allocate a buffer at least as big as we need */
1558 len = _asn1_length(t->ptr, data) + taglen;
1559 if ((p = pfree = malloc(len)) == NULL) {
1560 ret = ENOMEM;
1561 } else {
1563 * Encode into it (with the wrong tag, which we'll replace
1564 * below).
1566 p += len - 1;
1567 ret = _asn1_encode(t->ptr, p, len, data, &datalen);
1569 if (ret == 0) {
1570 /* Get the old tag and, critically, its length */
1571 len -= datalen; p -= datalen;
1572 ret = der_get_tag(p + 1, datalen, &found_class, &found_type,
1573 &found_tag, &oldtaglen);
1575 if (ret == 0) {
1576 /* Drop the old tag */
1577 len += oldtaglen; p += oldtaglen;
1578 /* Put the new tag */
1579 ret = der_put_tag(p, len,
1580 A1_TAG_CLASS(t->tt),
1581 found_type,
1582 A1_TAG_TAG(t->tt), &l);
1584 if (ret == 0) {
1585 /* Copy the encoding where it belongs */
1586 len -= l; p -= l;
1587 psave -= (datalen + l - oldtaglen);
1588 lensave -= (datalen + l - oldtaglen);
1589 memcpy(psave + 1, p + 1, datalen + l - oldtaglen);
1590 p = psave;
1591 len = lensave;
1593 free(pfree);
1594 } else {
1595 /* Easy case */
1596 ret = _asn1_encode(t->ptr, p, len, data, &datalen);
1597 if (ret)
1598 return ret;
1600 len -= datalen; p -= datalen;
1602 ret = der_put_length_and_tag(p, len, datalen,
1603 A1_TAG_CLASS(t->tt),
1604 A1_TAG_TYPE(t->tt),
1605 A1_TAG_TAG(t->tt), &l);
1606 if (ret == 0) {
1607 p -= l; len -= l;
1610 if (ret)
1611 return ret;
1613 data = olddata;
1615 break;
1617 case A1_OP_PARSE: {
1618 unsigned int type = A1_PARSE_TYPE(t->tt);
1619 size_t newsize;
1620 const void *el = DPOC(data, t->offset);
1622 if (type >= sizeof(asn1_template_prim)/sizeof(asn1_template_prim[0])) {
1623 ABORT_ON_ERROR();
1624 return ASN1_PARSE_ERROR;
1627 ret = (asn1_template_prim[type].encode)(p, len, el, &newsize);
1628 if (ret)
1629 return ret;
1630 p -= newsize; len -= newsize;
1632 break;
1634 case A1_OP_SETOF: {
1635 const struct template_of *el = DPOC(data, t->offset);
1636 size_t ellen = _asn1_sizeofType(t->ptr);
1637 heim_octet_string *val;
1638 unsigned char *elptr = el->val;
1639 size_t i, totallen;
1641 if (el->len == 0)
1642 break;
1644 if (el->len > UINT_MAX/sizeof(val[0]))
1645 return ERANGE;
1647 val = calloc(el->len, sizeof(val[0]));
1648 if (val == NULL)
1649 return ENOMEM;
1651 for(totallen = 0, i = 0; i < el->len; i++) {
1652 unsigned char *next;
1653 size_t l;
1655 val[i].length = _asn1_length(t->ptr, elptr);
1656 if (val[i].length) {
1657 val[i].data = malloc(val[i].length);
1658 if (val[i].data == NULL) {
1659 ret = ENOMEM;
1660 break;
1664 ret = _asn1_encode(t->ptr, DPO(val[i].data, val[i].length - 1),
1665 val[i].length, elptr, &l);
1666 if (ret)
1667 break;
1669 next = elptr + ellen;
1670 if (next < elptr) {
1671 ret = ASN1_OVERFLOW;
1672 break;
1674 elptr = next;
1675 totallen += val[i].length;
1677 if (ret == 0 && totallen > len)
1678 ret = ASN1_OVERFLOW;
1679 if (ret) {
1680 for (i = 0; i < el->len; i++)
1681 free(val[i].data);
1682 free(val);
1683 return ret;
1686 len -= totallen;
1688 qsort(val, el->len, sizeof(val[0]), _heim_der_set_sort);
1690 i = el->len - 1;
1691 do {
1692 p -= val[i].length;
1693 memcpy(p + 1, val[i].data, val[i].length);
1694 free(val[i].data);
1695 } while(i-- > 0);
1696 free(val);
1698 break;
1701 case A1_OP_SEQOF: {
1702 struct template_of *el = DPO(data, t->offset);
1703 size_t ellen = _asn1_sizeofType(t->ptr);
1704 size_t newsize;
1705 unsigned int i;
1706 unsigned char *elptr = el->val;
1708 if (el->len == 0)
1709 break;
1711 elptr += ellen * (el->len - 1);
1713 for (i = 0; i < el->len; i++) {
1714 ret = _asn1_encode(t->ptr, p, len,
1715 elptr,
1716 &newsize);
1717 if (ret)
1718 return ret;
1719 p -= newsize; len -= newsize;
1720 elptr -= ellen;
1723 break;
1725 case A1_OP_BMEMBER: {
1726 const struct asn1_template *bmember = t->ptr;
1727 size_t bsize = bmember->offset;
1728 size_t belements = A1_HEADER_LEN(bmember);
1729 size_t pos;
1730 unsigned char c = 0;
1731 unsigned int bitset = 0;
1732 int rfc1510 = (bmember->tt & A1_HBF_RFC1510);
1734 bmember += belements;
1736 if (rfc1510)
1737 pos = 31;
1738 else
1739 pos = bmember->offset;
1741 while (belements && len) {
1742 while (bmember->offset / 8 < pos / 8) {
1743 if (rfc1510 || bitset || c) {
1744 if (len < 1)
1745 return ASN1_OVERFLOW;
1746 *p-- = c; len--;
1748 c = 0;
1749 pos -= 8;
1751 _asn1_bmember_put_bit(&c, data, bmember->offset, bsize, &bitset);
1752 belements--; bmember--;
1754 if (rfc1510 || bitset) {
1755 if (len < 1)
1756 return ASN1_OVERFLOW;
1757 *p-- = c; len--;
1760 if (len < 1)
1761 return ASN1_OVERFLOW;
1762 if (rfc1510 || bitset == 0)
1763 *p-- = 0;
1764 else
1765 *p-- = bitset - 1;
1767 len--;
1769 break;
1771 case A1_OP_CHOICE: {
1772 const struct asn1_template *choice = t->ptr;
1773 const unsigned int *element = DPOC(data, choice->offset);
1774 size_t datalen;
1775 const void *el;
1777 if (*element > A1_HEADER_LEN(choice)) {
1778 printf("element: %d\n", *element);
1779 return ASN1_PARSE_ERROR;
1782 if (*element == 0) {
1783 ret += der_put_octet_string(p, len,
1784 DPOC(data, choice->tt), &datalen);
1785 } else {
1786 choice += *element;
1787 el = DPOC(data, choice->offset);
1788 ret = _asn1_encode(choice->ptr, p, len, el, &datalen);
1789 if (ret)
1790 return ret;
1792 len -= datalen; p -= datalen;
1794 break;
1796 default:
1797 ABORT_ON_ERROR();
1799 t--;
1800 elements--;
1802 if (size)
1803 *size = oldlen - len;
1805 return 0;
1808 static size_t
1809 _asn1_length_open_type_helper(const struct asn1_template *t,
1810 size_t sz)
1812 const struct asn1_template *tinner = t->ptr;
1814 switch (t->tt & A1_OP_MASK) {
1815 case A1_OP_TAG:
1816 /* XXX Not tail-recursive :( */
1817 sz = _asn1_length_open_type_helper(tinner, sz);
1818 sz += der_length_len(sz);
1819 sz += der_length_tag(A1_TAG_TAG(t->tt));
1820 return sz;
1821 default:
1822 return sz;
1826 static size_t
1827 _asn1_length_open_type_id(const struct asn1_template *t,
1828 const void *data)
1830 struct asn1_template pretend[2] = {
1831 { 0, 0, ((void*)1) },
1833 pretend[1] = *t;
1834 while ((t->tt & A1_OP_MASK) == A1_OP_TAG)
1835 t = t->ptr;
1836 pretend[0].offset = t->offset;
1837 return _asn1_length(pretend, data);
1840 /* See commentary in _asn1_encode_open_type() */
1841 static size_t
1842 _asn1_length_open_type(const struct asn1_template *tbase,
1843 const struct asn1_template *t,
1844 const void *data,
1845 const struct asn1_template *ttypeid,
1846 const struct asn1_template *topentype)
1848 const struct asn1_template *ttypeid_univ = ttypeid;
1849 const struct asn1_template *tactual_type;
1850 const struct asn1_template *tos = t->ptr;
1851 const unsigned int *lenp = NULL;
1852 unsigned int len = 1;
1853 size_t sz = 0;
1854 size_t i;
1855 int element = *(const int *)DPOC(data, t->offset);
1856 int typeid_is_oid = 0;
1857 int typeid_is_int = 0;
1859 /* If nothing to encode, we add nothing to the length */
1860 if (element == 0 || element >= A1_HEADER_LEN(tos) + 1)
1861 return 0;
1862 if (t->tt & A1_OS_OT_IS_ARRAY) {
1863 len = *(const unsigned int *)DPOC(data, t->offset + sizeof(element));
1864 if (!len)
1865 return 0;
1868 /* Work out the type ID field's type */
1869 while (((ttypeid_univ->tt & A1_OP_MASK) == A1_OP_TAG &&
1870 A1_TAG_CLASS(ttypeid_univ->tt) == ASN1_C_CONTEXT) ||
1871 ((ttypeid_univ->tt & A1_OP_MASK) == A1_OP_TYPE)) {
1872 ttypeid_univ = ttypeid_univ->ptr;
1873 ttypeid_univ++;
1875 switch (ttypeid_univ->tt & A1_OP_MASK) {
1876 case A1_OP_TAG:
1877 if (A1_TAG_CLASS(ttypeid_univ->tt) != ASN1_C_UNIV)
1878 return 0;
1879 switch (A1_TAG_TAG(ttypeid_univ->tt)) {
1880 case UT_OID:
1881 typeid_is_oid = 1;
1882 break;
1883 case UT_Integer: {
1884 const struct asn1_template *tint = ttypeid_univ->ptr;
1886 tint++;
1887 if ((tint->tt & A1_OP_MASK) != A1_OP_PARSE ||
1888 A1_PARSE_TYPE(tint->tt) != A1T_INTEGER)
1889 return 0;
1890 typeid_is_int = 1;
1891 break;
1893 default: return 0;
1895 break;
1896 default: return 0;
1898 if (!typeid_is_int && !typeid_is_oid)
1899 return 0;
1900 if (!(t->tt & A1_OS_OT_IS_ARRAY)) {
1901 struct heim_base_data *os = DPO(data, topentype->offset);
1903 if (os->length && os->data)
1904 return 0;
1905 } else {
1906 struct heim_base_data **os = DPO(data, topentype->offset + sizeof(len));
1908 while (sizeof(void *) != sizeof(unsigned int) &&
1909 ((uintptr_t)os) % sizeof(void *) != 0)
1910 os = (void *)(((char *)os) + sizeof(unsigned int));
1912 lenp = DPOC(data, topentype->offset);
1913 if (*lenp == len && os[0]->length && os[0]->data)
1914 return 0;
1917 /* Compute the size of the type ID field */
1918 if (typeid_is_int) {
1919 int64_t i8;
1920 int32_t i4;
1922 switch (ttypeid_univ->offset) {
1923 case 8:
1924 i8 = (intptr_t)t->ptr;
1925 sz = _asn1_length_open_type_id(ttypeid, &i8);
1926 i8 = 0;
1927 sz -= _asn1_length_open_type_id(ttypeid, &i8);
1928 break;
1929 case 4:
1930 i4 = (intptr_t)t->ptr;
1931 sz = _asn1_length_open_type_id(ttypeid, &i4);
1932 i4 = 0;
1933 sz -= _asn1_length_open_type_id(ttypeid, &i8);
1934 break;
1935 default:
1936 return 0;
1938 } else if (typeid_is_oid) {
1939 heim_oid no_oid = { 0, 0 };
1941 sz = _asn1_length_open_type_id(ttypeid, tos[3 + (element - 1)*3].ptr);
1942 sz -= _asn1_length_open_type_id(ttypeid, &no_oid);
1945 tactual_type = &tos[(element-1)*3 + 4];
1947 /* Compute the size of the encoded value(s) */
1948 if (!(t->tt & A1_OS_OT_IS_ARRAY)) {
1949 const void * const *d = DPOC(data, t->offset + sizeof(element));
1951 while (sizeof(void *) != sizeof(element) &&
1952 ((uintptr_t)d) % sizeof(void *) != 0)
1953 d = (void *)(((char *)d) + sizeof(element));
1954 if (*d)
1955 sz += _asn1_length(tactual_type->ptr, *d);
1956 } else {
1957 size_t bodysz;
1958 const void * const * val =
1959 DPOC(data, t->offset + sizeof(element) + sizeof(*lenp));
1961 /* Compute the size of the encoded SET OF / SEQUENCE OF body */
1962 for (i = 0, bodysz = 0; i < len; i++) {
1963 if (val[i])
1964 bodysz += _asn1_length(tactual_type->ptr, val[i]);
1968 * We now know the size of the body of the SET OF or SEQUENCE OF. Now
1969 * we just need to count the length of all the TLs on the outside.
1971 sz += _asn1_length_open_type_helper(topentype, bodysz);
1973 return sz;
1976 size_t
1977 _asn1_length(const struct asn1_template *t, const void *data)
1979 const struct asn1_template *tbase = t;
1980 size_t elements = A1_HEADER_LEN(t);
1981 size_t ret = 0;
1983 t += A1_HEADER_LEN(t);
1985 while (elements) {
1986 switch (t->tt & A1_OP_MASK) {
1987 case A1_OP_OPENTYPE_OBJSET: {
1988 size_t opentypeid = t->tt & ((1<<10)-1);
1989 size_t opentype = (t->tt >> 10) & ((1<<10)-1);
1990 ret += _asn1_length_open_type(tbase, t, data,
1991 template4member(tbase, opentypeid),
1992 template4member(tbase, opentype));
1993 break;
1995 case A1_OP_NAME: break;
1996 case A1_OP_DEFVAL: break;
1997 case A1_OP_TYPE_DECORATE: break;
1998 case A1_OP_TYPE:
1999 case A1_OP_TYPE_EXTERN: {
2000 const void *el = DPOC(data, t->offset);
2002 if (t->tt & A1_FLAG_OPTIONAL) {
2003 void **pel = (void **)el;
2004 if (*pel == NULL)
2005 break;
2006 el = *pel;
2007 } else if ((t->tt & A1_FLAG_DEFAULT) && elements > 1) {
2008 const struct asn1_template *tdefval = t - 1;
2010 /* Compare tdefval to whatever's at `el' */
2011 if (tdefval->tt & A1_DV_BOOLEAN) {
2012 const int *i = (void *)(char *)el;
2014 if ((*i && tdefval->ptr) || (!*i && !tdefval->ptr))
2015 break;
2016 } else if (tdefval->tt & A1_DV_INTEGER64) {
2017 const int64_t *i = (void *)(char *)el;
2019 if (*i == (int64_t)(intptr_t)tdefval->ptr)
2020 break;
2021 } else if (tdefval->tt & A1_DV_INTEGER32) {
2022 const int32_t *i = (void *)(char *)el;
2024 if ((int64_t)(intptr_t)tdefval->ptr <= INT_MAX &&
2025 (int64_t)(intptr_t)tdefval->ptr >= INT_MIN &&
2026 *i == (int32_t)(intptr_t)tdefval->ptr)
2027 break;
2028 } else if (tdefval->tt & A1_DV_INTEGER) {
2029 const struct heim_integer *i = (void *)(char *)el;
2031 if (der_heim_integer_cmp(i, tdefval->ptr) == 0)
2032 break;
2033 } else if (tdefval->tt & A1_DV_UTF8STRING) {
2034 const char * const *s = el;
2036 if (*s && strcmp(*s, tdefval->ptr) == 0)
2037 break;
2038 } else {
2039 abort();
2043 if ((t->tt & A1_OP_MASK) == A1_OP_TYPE) {
2044 ret += _asn1_length(t->ptr, el);
2045 } else {
2046 const struct asn1_type_func *f = t->ptr;
2047 ret += (f->length)(el);
2049 break;
2051 case A1_OP_TAG: {
2052 size_t datalen;
2053 const void *olddata = data;
2054 size_t oldtaglen = 0;
2056 data = DPO(data, t->offset);
2058 if (t->tt & A1_FLAG_OPTIONAL) {
2059 void **el = (void **)data;
2060 if (*el == NULL) {
2061 data = olddata;
2062 break;
2064 data = *el;
2065 } else if ((t->tt & A1_FLAG_DEFAULT) && elements > 1) {
2066 const struct asn1_template *tdefval = t - 1;
2067 int exclude = 0;
2069 /* Compare tdefval to whatever's at `data' */
2070 if (tdefval->tt & A1_DV_BOOLEAN) {
2071 const int *i = (void *)(char *)data;
2073 if ((*i && tdefval->ptr) || (!*i && !tdefval->ptr))
2074 exclude = 1;
2075 } else if (tdefval->tt & A1_DV_INTEGER64) {
2076 const int64_t *i = (void *)(char *)data;
2078 if (*i == (int64_t)(intptr_t)tdefval->ptr)
2079 exclude = 1;
2080 } else if (tdefval->tt & A1_DV_INTEGER32) {
2081 const int32_t *i = (void *)(char *)data;
2083 if ((int64_t)(intptr_t)tdefval->ptr <= INT_MAX &&
2084 (int64_t)(intptr_t)tdefval->ptr >= INT_MIN &&
2085 *i == (int32_t)(intptr_t)tdefval->ptr)
2086 exclude = 1;
2087 } else if (tdefval->tt & A1_DV_INTEGER) {
2088 const struct heim_integer *i = (void *)(char *)data;
2090 if (der_heim_integer_cmp(i, tdefval->ptr) == 0)
2091 exclude = 1;
2092 } else if (tdefval->tt & A1_DV_UTF8STRING) {
2093 const char * const *s = data;
2095 if (*s && strcmp(*s, tdefval->ptr) == 0)
2096 exclude = 1;
2097 } else {
2098 abort();
2100 if (exclude) {
2101 data = olddata;
2102 break;
2106 if (t->tt & A1_FLAG_IMPLICIT)
2107 oldtaglen = inner_type_taglen(t->ptr);
2109 datalen = _asn1_length(t->ptr, data);
2110 ret += datalen;
2111 ret += der_length_tag(A1_TAG_TAG(t->tt));
2112 ret += oldtaglen ? -oldtaglen : der_length_len(datalen);
2113 data = olddata;
2114 break;
2116 case A1_OP_PARSE: {
2117 unsigned int type = A1_PARSE_TYPE(t->tt);
2118 const void *el = DPOC(data, t->offset);
2120 if (type >= sizeof(asn1_template_prim)/sizeof(asn1_template_prim[0])) {
2121 ABORT_ON_ERROR();
2122 break;
2124 ret += (asn1_template_prim[type].length)(el);
2125 break;
2127 case A1_OP_SETOF:
2128 case A1_OP_SEQOF: {
2129 const struct template_of *el = DPOC(data, t->offset);
2130 size_t ellen = _asn1_sizeofType(t->ptr);
2131 const unsigned char *element = el->val;
2132 unsigned int i;
2134 for (i = 0; i < el->len; i++) {
2135 ret += _asn1_length(t->ptr, element);
2136 element += ellen;
2139 break;
2141 case A1_OP_BMEMBER: {
2142 const struct asn1_template *bmember = t->ptr;
2143 size_t size = bmember->offset;
2144 size_t belements = A1_HEADER_LEN(bmember);
2145 int rfc1510 = (bmember->tt & A1_HBF_RFC1510);
2147 if (rfc1510) {
2148 ret += 5;
2149 } else {
2151 ret += 1;
2153 bmember += belements;
2155 while (belements) {
2156 if (_asn1_bmember_isset_bit(data, bmember->offset, size)) {
2157 ret += (bmember->offset / 8) + 1;
2158 break;
2160 belements--; bmember--;
2163 break;
2165 case A1_OP_CHOICE: {
2166 const struct asn1_template *choice = t->ptr;
2167 const unsigned int *element = DPOC(data, choice->offset);
2169 if (*element > A1_HEADER_LEN(choice))
2170 break;
2172 if (*element == 0) {
2173 ret += der_length_octet_string(DPOC(data, choice->tt));
2174 } else {
2175 choice += *element;
2176 ret += _asn1_length(choice->ptr, DPOC(data, choice->offset));
2178 break;
2180 default:
2181 ABORT_ON_ERROR();
2182 break;
2184 elements--;
2185 t--;
2187 return ret;
2190 /* See commentary in _asn1_decode_open_type() */
2191 static void
2192 _asn1_free_open_type(const struct asn1_template *t, /* object set template */
2193 void *data)
2195 const struct asn1_template *tactual_type;
2196 const struct asn1_template *tos = t->ptr;
2197 unsigned int *lenp = NULL; /* Pointer to array length field */
2198 unsigned int len = 1; /* Array length */
2199 size_t i;
2200 void **dp;
2201 void **val;
2202 int *elementp = DPO(data, t->offset); /* Choice enum pointer */
2204 /* XXX We assume sizeof(enum) == sizeof(int) */
2205 if (!*elementp || *elementp >= A1_HEADER_LEN(tos) + 1)
2206 return; /* Unknown choice -> it's not decoded, nothing to free here */
2207 tactual_type = tos[3*(*elementp - 1) + 4].ptr;
2209 if (!(t->tt & A1_OS_OT_IS_ARRAY)) {
2210 dp = DPO(data, t->offset + sizeof(*elementp));
2211 while (sizeof(void *) != sizeof(*elementp) &&
2212 ((uintptr_t)dp) % sizeof(void *) != 0)
2213 dp = (void *)(((char *)dp) + sizeof(*elementp));
2214 if (*dp) {
2215 _asn1_free(tactual_type, *dp);
2216 free(*dp);
2217 *dp = NULL;
2219 return;
2222 lenp = DPO(data, t->offset + sizeof(*elementp));
2223 len = *lenp;
2224 dp = DPO(data, t->offset + sizeof(*elementp) + sizeof(*lenp));
2225 while (sizeof(void *) != sizeof(*elementp) &&
2226 ((uintptr_t)dp) % sizeof(void *) != 0)
2227 dp = (void *)(((char *)dp) + sizeof(*elementp));
2228 val = *dp;
2230 for (i = 0; i < len; i++) {
2231 if (val[i]) {
2232 _asn1_free(tactual_type, val[i]);
2233 free(val[i]);
2236 free(val);
2237 *lenp = 0;
2238 *dp = NULL;
2241 void
2242 _asn1_free(const struct asn1_template *t, void *data)
2244 size_t elements = A1_HEADER_LEN(t);
2246 if (t->tt & A1_HF_PRESERVE)
2247 der_free_octet_string(data);
2249 t++;
2251 while (elements) {
2252 switch (t->tt & A1_OP_MASK) {
2253 case A1_OP_OPENTYPE_OBJSET: {
2254 _asn1_free_open_type(t, data);
2255 break;
2257 case A1_OP_NAME: break;
2258 case A1_OP_DEFVAL: break;
2259 case A1_OP_TYPE_DECORATE:
2260 case A1_OP_TYPE:
2261 case A1_OP_TYPE_EXTERN: {
2262 void *el = DPO(data, t->offset);
2263 void **pel = (void **)el;
2265 if (t->tt & A1_FLAG_OPTIONAL) {
2266 if (*pel == NULL)
2267 break;
2268 el = *pel;
2271 if ((t->tt & A1_OP_MASK) == A1_OP_TYPE || (t->tt & A1_OP_MASK) == A1_OP_TYPE_DECORATE) {
2272 _asn1_free(t->ptr, el);
2273 } else {
2274 const struct asn1_type_func *f = t->ptr;
2275 (f->release)(el);
2277 if (t->tt & A1_FLAG_OPTIONAL) {
2278 free(el);
2279 *pel = NULL;
2282 break;
2284 case A1_OP_PARSE: {
2285 unsigned int type = A1_PARSE_TYPE(t->tt);
2286 void *el = DPO(data, t->offset);
2288 if (type >= sizeof(asn1_template_prim)/sizeof(asn1_template_prim[0])) {
2289 ABORT_ON_ERROR();
2290 break;
2292 (asn1_template_prim[type].release)(el);
2293 break;
2295 case A1_OP_TAG: {
2296 void *el = DPO(data, t->offset);
2298 if (t->tt & A1_FLAG_OPTIONAL) {
2299 void **pel = (void **)el;
2301 if (*pel == NULL)
2302 break;
2303 _asn1_free(t->ptr, *pel);
2304 free(*pel);
2305 *pel = NULL;
2306 } else {
2307 _asn1_free(t->ptr, el);
2310 break;
2312 case A1_OP_SETOF:
2313 case A1_OP_SEQOF: {
2314 struct template_of *el = DPO(data, t->offset);
2315 size_t ellen = _asn1_sizeofType(t->ptr);
2316 unsigned char *element = el->val;
2317 unsigned int i;
2319 for (i = 0; i < el->len; i++) {
2320 _asn1_free(t->ptr, element);
2321 element += ellen;
2323 free(el->val);
2324 el->val = NULL;
2325 el->len = 0;
2327 break;
2329 case A1_OP_BMEMBER:
2330 break;
2331 case A1_OP_CHOICE: {
2332 const struct asn1_template *choice = t->ptr;
2333 const unsigned int *element = DPOC(data, choice->offset);
2335 if (*element > A1_HEADER_LEN(choice))
2336 break;
2338 if (*element == 0) {
2339 der_free_octet_string(DPO(data, choice->tt));
2340 } else {
2341 choice += *element;
2342 _asn1_free(choice->ptr, DPO(data, choice->offset));
2344 break;
2346 default:
2347 ABORT_ON_ERROR();
2348 break;
2350 t++;
2351 elements--;
2355 static char *
2356 getindent(int flags, unsigned int i)
2358 char *s;
2360 if (!(flags & ASN1_PRINT_INDENT) || i == 0)
2361 return NULL;
2362 if (i > 128)
2363 i = 128;
2364 if ((s = malloc(i * 2 + 2)) == NULL)
2365 return NULL;
2366 s[0] = '\n';
2367 s[i * 2 + 1] = '\0';
2368 memset(s + 1, ' ', i * 2);
2369 return s;
2372 static struct rk_strpool *_asn1_print(const struct asn1_template *,
2373 struct rk_strpool *,
2374 int,
2375 unsigned int,
2376 const void *,
2377 const heim_octet_string *);
2379 /* See commentary in _asn1_decode_open_type() */
2380 static struct rk_strpool *
2381 _asn1_print_open_type(const struct asn1_template *t, /* object set template */
2382 struct rk_strpool *r,
2383 int flags,
2384 unsigned int indent,
2385 const void *data,
2386 const char *opentype_name)
2388 const struct asn1_template *tactual_type;
2389 const struct asn1_template *tos = t->ptr;
2390 const unsigned int *lenp = NULL; /* Pointer to array length field */
2391 unsigned int len = 1; /* Array length */
2392 size_t i;
2393 const void * const *dp;
2394 const void * const *val;
2395 const int *elementp = DPOC(data, t->offset); /* Choice enum pointer */
2396 char *indents = getindent(flags, indent);
2398 /* XXX We assume sizeof(enum) == sizeof(int) */
2399 if (!*elementp || *elementp >= A1_HEADER_LEN(tos) + 1) {
2400 r = rk_strpoolprintf(r, ",%s\"_%s_choice\":\"_ERROR_DECODING_\"",
2401 indents ? indents : "", opentype_name);
2402 free(indents);
2403 return r;
2405 tactual_type = tos[3*(*elementp - 1) + 4].ptr;
2407 r = rk_strpoolprintf(r, ",%s\"_%s_choice\":\"%s\"",
2408 indents ? indents : "", opentype_name,
2409 (const char *)tos[3*(*elementp - 1) + 2].ptr);
2410 if (!r) {
2411 free(indents);
2412 return r;
2415 if (!(t->tt & A1_OS_OT_IS_ARRAY)) {
2416 dp = DPOC(data, t->offset + sizeof(*elementp));
2417 while (sizeof(void *) != sizeof(*elementp) &&
2418 ((uintptr_t)dp) % sizeof(void *) != 0)
2419 dp = (void *)(((char *)dp) + sizeof(*elementp));
2420 if (*dp) {
2421 struct rk_strpool *r2 = NULL;
2422 char *s = NULL;
2424 r2 = _asn1_print(tactual_type, r2, flags, indent + 1, *dp, NULL);
2425 if (r2 == NULL) {
2426 r = rk_strpoolprintf(r, ",%s\"_%s\":\"_ERROR_FORMATTING_\"",
2427 indents ? indents : "", opentype_name);
2428 free(indents);
2429 return r;
2431 s = rk_strpoolcollect(r2);
2432 if (s)
2433 r = rk_strpoolprintf(r, ",%s\"_%s\":%s",
2434 indents ? indents : "", opentype_name, s);
2435 free(indents);
2436 free(s);
2438 return r;
2441 lenp = DPOC(data, t->offset + sizeof(*elementp));
2442 len = *lenp;
2443 dp = DPOC(data, t->offset + sizeof(*elementp) + sizeof(*lenp));
2444 while (sizeof(void *) != sizeof(*elementp) &&
2445 ((uintptr_t)dp) % sizeof(void *) != 0)
2446 dp = (void *)(((char *)dp) + sizeof(*elementp));
2447 val = *dp;
2449 r = rk_strpoolprintf(r, ",%s\"_%s\":[", indents ? indents : "",
2450 opentype_name);
2451 free(indents);
2452 indents = getindent(flags, indent + 1);
2453 if (indents)
2454 r = rk_strpoolprintf(r, "%s", indents ? indents : "");
2455 for (i = 0; r && i < len; i++) {
2456 struct rk_strpool *r2 = NULL;
2457 char *s = NULL;;
2459 if (val[i]) {
2460 r2 = _asn1_print(tactual_type, r2, flags, indent + 2, val[i], NULL);
2461 if (r2 == NULL) {
2462 rk_strpoolfree(r);
2463 free(indents);
2464 return NULL;
2467 if (i)
2468 r = rk_strpoolprintf(r, ",%s", indents ? indents : "");
2469 if (r)
2470 r = rk_strpoolprintf(r, "%s", (s = rk_strpoolcollect(r2)));
2471 free(s);
2473 free(indents);
2474 return rk_strpoolprintf(r, "]");
2477 static struct rk_strpool *
2478 _asn1_print(const struct asn1_template *t,
2479 struct rk_strpool *r,
2480 int flags,
2481 unsigned int indent,
2482 const void *data,
2483 const heim_octet_string *saved)
2485 const struct asn1_template *tbase = t;
2486 const struct asn1_template *tnames;
2487 size_t nelements = A1_HEADER_LEN(t);
2488 size_t elements = nelements;
2489 size_t nnames = 0;
2490 char *indents = getindent(flags, indent);
2492 for (t += nelements; t > tbase && (t->tt & A1_OP_MASK) == A1_OP_NAME; t--)
2493 nnames++;
2495 tnames = tbase + nelements - nnames + 1;
2497 if (!r)
2498 r = rk_strpoolprintf(r, "%s", "");
2500 if (nnames)
2501 r = rk_strpoolprintf(r, "%s{\"_type\":\"%s\"",
2502 indents ? indents : "",
2503 (const char *)(tnames++)->ptr);
2504 if (saved && r) {
2505 char *s = der_print_octet_string(data, 0);
2507 if (!s) {
2508 rk_strpoolfree(r);
2509 free(indents);
2510 return NULL;
2512 r = rk_strpoolprintf(r, ",%s\"_save\":\"%s\"",
2513 indents ? indents : "", s);
2514 free(s);
2516 saved = NULL;
2517 if (tbase->tt & A1_HF_PRESERVE)
2518 saved = data;
2520 t = tbase + 1;
2521 while (r && elements && (t->tt & A1_OP_MASK) != A1_OP_NAME) {
2522 switch (t->tt & A1_OP_MASK) {
2523 case A1_OP_NAME:
2524 continue;
2525 case A1_OP_DEFVAL:
2526 t++;
2527 elements--;
2528 continue;
2529 case A1_OP_OPENTYPE_OBJSET: {
2530 size_t opentype = (t->tt >> 10) & ((1<<10)-1);
2531 r = _asn1_print_open_type(t, r, flags, indent + 1, data,
2532 tbase[(nelements - nnames) + 2 + opentype].ptr);
2533 t++;
2534 elements--;
2535 continue;
2537 default: break;
2539 if (nnames)
2540 r = rk_strpoolprintf(r, ",%s\"%s\":",
2541 indents ? indents : "",
2542 (const char *)(tnames++)->ptr);
2543 switch (t->tt & A1_OP_MASK) {
2544 case A1_OP_OPENTYPE_OBJSET:
2545 break;
2546 case A1_OP_NAME: break;
2547 case A1_OP_DEFVAL: break;
2548 case A1_OP_TYPE_DECORATE: break; /* We could probably print this though */
2549 case A1_OP_TYPE:
2550 case A1_OP_TYPE_EXTERN: {
2551 const void *el = DPOC(data, t->offset);
2553 if (t->tt & A1_FLAG_OPTIONAL) {
2554 const void * const *pel = (const void *const *)el;
2555 if (*pel == NULL) {
2556 r = rk_strpoolprintf(r, "null");
2557 break;
2559 el = *pel;
2562 if ((t->tt & A1_OP_MASK) == A1_OP_TYPE) {
2563 r = _asn1_print(t->ptr, r, flags, indent + 1, el, saved);
2564 } else {
2565 const struct asn1_type_func *f = t->ptr;
2566 char *s = NULL;
2568 s = (f->print)(el, 0);
2569 if (s == NULL) {
2570 rk_strpoolfree(r);
2571 free(indents);
2572 return NULL;
2574 r = rk_strpoolprintf(r, "%s", s);
2575 free(s);
2577 break;
2579 case A1_OP_PARSE: {
2580 unsigned int type = A1_PARSE_TYPE(t->tt);
2581 const void *el = DPOC(data, t->offset);
2582 char *s = NULL;
2584 if (type >= sizeof(asn1_template_prim)/sizeof(asn1_template_prim[0])) {
2585 ABORT_ON_ERROR();
2586 break;
2589 if (type == A1T_IMEMBER && t->ptr) {
2590 /* Enumeration. Use the symbolic name of this value */
2591 const struct asn1_template *tenum = t->ptr;
2592 size_t left = 0;
2593 size_t right = A1_HEADER_LEN(tenum);
2594 size_t mid;
2595 uint32_t v = *(unsigned int *)el;
2596 int c = -1;
2598 while (left <= right) {
2599 mid = (left + right) >> 1;
2601 if ((tenum[mid].tt & A1_OP_MASK) != A1_OP_NAME)
2602 break;
2603 c = v - tenum[mid].offset;
2604 if (c < 0) {
2605 if (mid)
2606 right = mid - 1;
2607 else
2608 break;
2609 } else if (c > 0) {
2610 left = mid + 1;
2611 } else {
2612 break;
2615 if (c == 0) {
2616 r = rk_strpoolprintf(r, "\"%s\"", (const char *)tenum[mid].ptr);
2617 break;
2620 s = (asn1_template_prim[type].print)(el, flags);
2621 switch (type) {
2622 case A1T_OID:
2623 case A1T_IMEMBER:
2624 case A1T_BOOLEAN:
2625 case A1T_INTEGER:
2626 case A1T_INTEGER64:
2627 case A1T_UNSIGNED:
2628 case A1T_UNSIGNED64:
2629 if (s)
2630 r = rk_strpoolprintf(r, "%s", s);
2631 break;
2632 default: {
2633 char *s2 = NULL;
2635 if (s)
2636 (void) rk_strasvis(&s2, s, VIS_CSTYLE|VIS_TAB|VIS_NL, "\"");
2637 free(s);
2638 s = s2;
2639 if (s)
2640 r = rk_strpoolprintf(r, "\"%s\"", s);
2643 if (!s) {
2644 rk_strpoolfree(r);
2645 free(indents);
2646 return NULL;
2648 free(s);
2649 break;
2651 case A1_OP_TAG: {
2652 const void *el = DPOC(data, t->offset);
2654 if (t->tt & A1_FLAG_OPTIONAL) {
2655 const void * const *pel = (const void * const *)el;
2656 if (*pel == NULL) {
2657 r = rk_strpoolprintf(r, "null");
2658 break;
2660 el = *pel;
2663 r = _asn1_print(t->ptr, r, flags, indent + 1, el, saved);
2664 break;
2666 case A1_OP_SETOF:
2667 case A1_OP_SEQOF: {
2668 const struct template_of *el = DPOC(data, t->offset);
2669 size_t ellen = _asn1_sizeofType(t->ptr);
2670 const unsigned char *element = el->val;
2671 unsigned int i;
2673 r = rk_strpoolprintf(r, "%s[", indents ? indents : "");
2674 for (i = 0; r && i < el->len; i++) {
2675 if (i)
2676 r = rk_strpoolprintf(r, ",%s", indents ? indents : "");
2677 r = _asn1_print(t->ptr, r, flags, indent + 1, element, saved);
2678 element += ellen;
2680 if (r)
2681 r = rk_strpoolprintf(r, "]");
2682 break;
2684 case A1_OP_BMEMBER: {
2685 const struct asn1_template *bmember = t->ptr;
2686 size_t size = bmember->offset;
2687 size_t belements = A1_HEADER_LEN(bmember);
2688 int first = 1;
2690 bmember += belements;
2691 r = rk_strpoolprintf(r, "%s[", indents ? indents : "");
2692 while (r && belements) {
2693 if (r && _asn1_bmember_isset_bit(data, bmember->offset, size)) {
2694 if (!first)
2695 r = rk_strpoolprintf(r, ",");
2696 first = 0;
2697 r = rk_strpoolprintf(r, "%s\"%s\"", indents ? indents : "",
2698 (const char *)bmember->ptr);
2700 belements--; bmember--;
2702 if (r)
2703 r = rk_strpoolprintf(r, "]");
2704 break;
2706 case A1_OP_CHOICE: {
2707 const struct asn1_template *choice = t->ptr;
2708 const unsigned int *element = DPOC(data, choice->offset);
2709 unsigned int nchoices = ((uintptr_t)choice->ptr) >> 1;
2711 if (*element > A1_HEADER_LEN(choice)) {
2712 r = rk_strpoolprintf(r, "null");
2713 } else if (*element == 0) {
2714 r = rk_strpoolprintf(r, "null");
2715 } else {
2716 choice += *element;
2717 r = rk_strpoolprintf(r, "%s{\"_choice\":\"%s\",%s\"value\":",
2718 indents ? indents : "",
2719 (const char *)choice[nchoices].ptr,
2720 indents ? indents : "");
2721 if (r)
2722 r = _asn1_print(choice->ptr, r, flags, indent + 1,
2723 DPOC(data, choice->offset), NULL);
2724 if (r)
2725 r = rk_strpoolprintf(r, "}");
2727 break;
2729 default:
2730 ABORT_ON_ERROR();
2731 break;
2733 t++;
2734 elements--;
2736 free(indents);
2737 if (nnames && r)
2738 return rk_strpoolprintf(r, "}");
2739 return r;
2742 char *
2743 _asn1_print_top(const struct asn1_template *t,
2744 int flags,
2745 const void *data)
2747 struct rk_strpool *r = _asn1_print(t, NULL, flags, 0, data, NULL);
2749 if (r == NULL)
2750 return NULL;
2751 return rk_strpoolcollect(r);
2754 /* See commentary in _asn1_decode_open_type() */
2755 static int
2756 _asn1_copy_open_type(const struct asn1_template *t, /* object set template */
2757 const void *from,
2758 void *to)
2760 const struct asn1_template *tactual_type;
2761 const struct asn1_template *tos = t->ptr;
2762 size_t i;
2763 const void * const *dfromp;
2764 const void * const *valfrom;
2765 const unsigned int *lenfromp;
2766 void **dtop;
2767 void **valto;
2768 unsigned int *lentop;
2769 unsigned int len;
2770 const int *efromp = DPO(from, t->offset);
2771 int *etop = DPO(to, t->offset);
2772 int ret = 0;
2774 /* XXX We assume sizeof(enum) == sizeof(int) */
2775 if (!*efromp || *efromp >= A1_HEADER_LEN(tos) + 1) {
2776 if ((t->tt & A1_OS_OT_IS_ARRAY))
2777 memset(etop, 0, sizeof(int) + sizeof(unsigned int) + sizeof(void *));
2778 else
2779 memset(etop, 0, sizeof(int) + sizeof(void *));
2780 return 0; /* Unknown choice -> not copied */
2782 tactual_type = &tos[3*(*efromp - 1) + 4];
2784 if (!(t->tt & A1_OS_OT_IS_ARRAY)) {
2785 dfromp = DPO(from, t->offset + sizeof(*efromp));
2786 while (sizeof(void *) != sizeof(*efromp) &&
2787 ((uintptr_t)dfromp) % sizeof(void *) != 0)
2788 dfromp = (void *)(((char *)dfromp) + sizeof(*efromp));
2789 if (!*dfromp)
2790 return 0;
2792 dtop = DPO(to, t->offset + sizeof(*etop));
2793 while (sizeof(void *) != sizeof(*etop) &&
2794 ((uintptr_t)dtop) % sizeof(void *) != 0)
2795 dtop = (void *)(((char *)dtop) + sizeof(*etop));
2797 if ((*dtop = calloc(1, tactual_type->offset)) == NULL)
2798 ret = ENOMEM;
2799 if (ret == 0)
2800 ret = _asn1_copy(tactual_type->ptr, *dfromp, *dtop);
2801 if (ret == 0)
2802 *etop = *efromp;
2803 return ret;
2806 lenfromp = DPO(from, t->offset + sizeof(*efromp));
2807 dfromp = DPO(from, t->offset + sizeof(*efromp) + sizeof(*lenfromp));
2808 valfrom = *dfromp;
2809 lentop = DPO(to, t->offset + sizeof(*etop));
2810 dtop = DPO(to, t->offset + sizeof(*etop) + sizeof(*lentop));
2812 *etop = *efromp;
2814 len = *lenfromp;
2815 *lentop = 0;
2816 *dtop = NULL;
2817 if ((valto = calloc(len, sizeof(valto[0]))) == NULL)
2818 ret = ENOMEM;
2819 for (i = 0, len = *lenfromp; ret == 0 && i < len; (*lentop)++, i++) {
2820 if (valfrom[i] == NULL) {
2821 valto[i] = NULL;
2822 continue;
2824 if ((valto[i] = calloc(1, tactual_type->offset)) == NULL)
2825 ret = ENOMEM;
2826 else
2827 ret = _asn1_copy(tactual_type->ptr, valfrom[i], valto[i]);
2830 for (i = 0; ret && i < len; i++) {
2831 if (valto[i]) {
2832 _asn1_free(tactual_type->ptr, valto[i]);
2833 free(valto[i]);
2836 if (ret)
2837 free(valto);
2838 else
2839 *dtop = valto;
2840 return ret;
2844 _asn1_copy(const struct asn1_template *t, const void *from, void *to)
2846 size_t elements = A1_HEADER_LEN(t);
2847 int ret = 0;
2848 int preserve = (t->tt & A1_HF_PRESERVE);
2850 t++;
2852 if (preserve) {
2853 ret = der_copy_octet_string(from, to);
2854 if (ret)
2855 return ret;
2858 while (elements) {
2859 switch (t->tt & A1_OP_MASK) {
2860 case A1_OP_OPENTYPE_OBJSET: {
2861 _asn1_copy_open_type(t, from, to);
2862 break;
2864 case A1_OP_NAME: break;
2865 case A1_OP_DEFVAL: break;
2866 case A1_OP_TYPE_DECORATE:
2867 case A1_OP_TYPE:
2868 case A1_OP_TYPE_EXTERN: {
2869 const void *fel = DPOC(from, t->offset);
2870 void *tel = DPO(to, t->offset);
2871 void **ptel = (void **)tel;
2872 size_t size;
2874 if ((t->tt & A1_OP_MASK) == A1_OP_TYPE) {
2875 size = _asn1_sizeofType(t->ptr);
2876 } else {
2877 const struct asn1_type_func *f = t->ptr;
2878 size = f->size;
2881 if (t->tt & A1_FLAG_OPTIONAL) {
2882 void **pfel = (void **)fel;
2883 if (*pfel == NULL)
2884 break;
2885 fel = *pfel;
2887 tel = *ptel = calloc(1, size);
2888 if (tel == NULL)
2889 return ENOMEM;
2892 if ((t->tt & A1_OP_MASK) == A1_OP_TYPE ||
2893 (t->tt & A1_OP_MASK) == A1_OP_TYPE_DECORATE) {
2894 ret = _asn1_copy(t->ptr, fel, tel);
2895 } else {
2896 const struct asn1_type_func *f = t->ptr;
2897 ret = (f->copy)(fel, tel);
2900 if (ret) {
2901 if (t->tt & A1_FLAG_OPTIONAL) {
2902 free(*ptel);
2903 *ptel = NULL;
2905 return ret;
2907 break;
2909 case A1_OP_PARSE: {
2910 unsigned int type = A1_PARSE_TYPE(t->tt);
2911 const void *fel = DPOC(from, t->offset);
2912 void *tel = DPO(to, t->offset);
2914 if (type >= sizeof(asn1_template_prim)/sizeof(asn1_template_prim[0])) {
2915 ABORT_ON_ERROR();
2916 return ASN1_PARSE_ERROR;
2918 ret = (asn1_template_prim[type].copy)(fel, tel);
2919 if (ret)
2920 return ret;
2921 break;
2923 case A1_OP_TAG: {
2924 const void *oldfrom = from;
2925 void *oldto = to;
2926 void **tel = NULL;
2928 from = DPOC(from, t->offset);
2929 to = DPO(to, t->offset);
2931 if (t->tt & A1_FLAG_OPTIONAL) {
2932 void **fel = (void **)from;
2933 tel = (void **)to;
2934 if (*fel == NULL) {
2935 from = oldfrom;
2936 to = oldto;
2937 break;
2939 from = *fel;
2941 to = *tel = calloc(1, _asn1_sizeofType(t->ptr));
2942 if (to == NULL)
2943 return ENOMEM;
2946 ret = _asn1_copy(t->ptr, from, to);
2947 if (ret) {
2948 if (tel) {
2949 free(*tel);
2950 *tel = NULL;
2952 return ret;
2955 from = oldfrom;
2956 to = oldto;
2958 break;
2960 case A1_OP_SETOF:
2961 case A1_OP_SEQOF: {
2962 const struct template_of *fel = DPOC(from, t->offset);
2963 struct template_of *tel = DPO(to, t->offset);
2964 size_t ellen = _asn1_sizeofType(t->ptr);
2965 unsigned int i;
2967 tel->val = calloc(fel->len, ellen);
2968 if (tel->val == NULL)
2969 return ENOMEM;
2971 tel->len = fel->len;
2973 for (i = 0; i < fel->len; i++) {
2974 ret = _asn1_copy(t->ptr,
2975 DPOC(fel->val, (i * ellen)),
2976 DPO(tel->val, (i *ellen)));
2977 if (ret)
2978 return ret;
2980 break;
2982 case A1_OP_BMEMBER: {
2983 const struct asn1_template *bmember = t->ptr;
2984 size_t size = bmember->offset;
2985 memcpy(to, from, size);
2986 break;
2988 case A1_OP_CHOICE: {
2989 const struct asn1_template *choice = t->ptr;
2990 const unsigned int *felement = DPOC(from, choice->offset);
2991 unsigned int *telement = DPO(to, choice->offset);
2993 if (*felement > A1_HEADER_LEN(choice))
2994 return ASN1_PARSE_ERROR;
2996 *telement = *felement;
2998 if (*felement == 0) {
2999 ret = der_copy_octet_string(DPOC(from, choice->tt), DPO(to, choice->tt));
3000 } else {
3001 choice += *felement;
3002 ret = _asn1_copy(choice->ptr,
3003 DPOC(from, choice->offset),
3004 DPO(to, choice->offset));
3006 if (ret)
3007 return ret;
3008 break;
3010 default:
3011 ABORT_ON_ERROR();
3012 break;
3014 t++;
3015 elements--;
3017 return 0;
3021 _asn1_decode_top(const struct asn1_template *t, unsigned flags, const unsigned char *p, size_t len, void *data, size_t *size)
3023 int ret;
3024 memset(data, 0, t->offset);
3025 ret = _asn1_decode(t, flags, p, len, data, size);
3026 if (ret)
3027 _asn1_free_top(t, data);
3029 return ret;
3033 _asn1_copy_top(const struct asn1_template *t, const void *from, void *to)
3035 int ret;
3036 memset(to, 0, t->offset);
3037 ret = _asn1_copy(t, from, to);
3038 if (ret)
3039 _asn1_free_top(t, to);
3041 return ret;
3044 void
3045 _asn1_free_top(const struct asn1_template *t, void *data)
3047 _asn1_free(t, data);
3048 memset(data, 0, t->offset);