source: heimdal/trunk/lib/asn1/template.c@ 8

Last change on this file since 8 was 1, checked in by Paul Smedley, 10 years ago

Initial commit of Heimdal 1.5.3

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