No empty .Rs/.Re
[netbsd-mini2440.git] / crypto / dist / heimdal / lib / asn1 / gen_decode.c
blobfd0d1a9029906cc33c8257a5189f8eaa173237ea
1 /*
2 * Copyright (c) 1997 - 2006 Kungliga Tekniska Högskolan
3 * (Royal Institute of Technology, Stockholm, Sweden).
4 * All rights reserved.
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
17 * 3. Neither the name of the Institute nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
21 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
34 #include "gen_locl.h"
35 #include "lex.h"
37 __RCSID("$Heimdal: gen_decode.c 21503 2007-07-12 11:57:19Z lha $"
38 "$NetBSD$");
40 static void
41 decode_primitive (const char *typename, const char *name, const char *forwstr)
43 #if 0
44 fprintf (codefile,
45 "e = decode_%s(p, len, %s, &l);\n"
46 "%s;\n",
47 typename,
48 name,
49 forwstr);
50 #else
51 fprintf (codefile,
52 "e = der_get_%s(p, len, %s, &l);\n"
53 "if(e) %s;\np += l; len -= l; ret += l;\n",
54 typename,
55 name,
56 forwstr);
57 #endif
60 static int
61 is_primitive_type(int type)
63 switch(type) {
64 case TInteger:
65 case TBoolean:
66 case TOctetString:
67 case TBitString:
68 case TEnumerated:
69 case TGeneralizedTime:
70 case TGeneralString:
71 case TOID:
72 case TUTCTime:
73 case TUTF8String:
74 case TPrintableString:
75 case TIA5String:
76 case TBMPString:
77 case TUniversalString:
78 case TVisibleString:
79 case TNull:
80 return 1;
81 default:
82 return 0;
86 static void
87 find_tag (const Type *t,
88 Der_class *cl, Der_type *ty, unsigned *tag)
90 switch (t->type) {
91 case TBitString:
92 *cl = ASN1_C_UNIV;
93 *ty = PRIM;
94 *tag = UT_BitString;
95 break;
96 case TBoolean:
97 *cl = ASN1_C_UNIV;
98 *ty = PRIM;
99 *tag = UT_Boolean;
100 break;
101 case TChoice:
102 errx(1, "Cannot have recursive CHOICE");
103 case TEnumerated:
104 *cl = ASN1_C_UNIV;
105 *ty = PRIM;
106 *tag = UT_Enumerated;
107 break;
108 case TGeneralString:
109 *cl = ASN1_C_UNIV;
110 *ty = PRIM;
111 *tag = UT_GeneralString;
112 break;
113 case TGeneralizedTime:
114 *cl = ASN1_C_UNIV;
115 *ty = PRIM;
116 *tag = UT_GeneralizedTime;
117 break;
118 case TIA5String:
119 *cl = ASN1_C_UNIV;
120 *ty = PRIM;
121 *tag = UT_IA5String;
122 break;
123 case TInteger:
124 *cl = ASN1_C_UNIV;
125 *ty = PRIM;
126 *tag = UT_Integer;
127 break;
128 case TNull:
129 *cl = ASN1_C_UNIV;
130 *ty = PRIM;
131 *tag = UT_Null;
132 break;
133 case TOID:
134 *cl = ASN1_C_UNIV;
135 *ty = PRIM;
136 *tag = UT_OID;
137 break;
138 case TOctetString:
139 *cl = ASN1_C_UNIV;
140 *ty = PRIM;
141 *tag = UT_OctetString;
142 break;
143 case TPrintableString:
144 *cl = ASN1_C_UNIV;
145 *ty = PRIM;
146 *tag = UT_PrintableString;
147 break;
148 case TSequence:
149 case TSequenceOf:
150 *cl = ASN1_C_UNIV;
151 *ty = CONS;
152 *tag = UT_Sequence;
153 break;
154 case TSet:
155 case TSetOf:
156 *cl = ASN1_C_UNIV;
157 *ty = CONS;
158 *tag = UT_Set;
159 break;
160 case TTag:
161 *cl = t->tag.tagclass;
162 *ty = is_primitive_type(t->subtype->type) ? PRIM : CONS;
163 *tag = t->tag.tagvalue;
164 break;
165 case TType:
166 if ((t->symbol->stype == Stype && t->symbol->type == NULL)
167 || t->symbol->stype == SUndefined) {
168 error_message("%s is imported or still undefined, "
169 " can't generate tag checking data in CHOICE "
170 "without this information",
171 t->symbol->name);
172 exit(1);
174 find_tag(t->symbol->type, cl, ty, tag);
175 return;
176 case TUTCTime:
177 *cl = ASN1_C_UNIV;
178 *ty = PRIM;
179 *tag = UT_UTCTime;
180 break;
181 case TUTF8String:
182 *cl = ASN1_C_UNIV;
183 *ty = PRIM;
184 *tag = UT_UTF8String;
185 break;
186 case TBMPString:
187 *cl = ASN1_C_UNIV;
188 *ty = PRIM;
189 *tag = UT_BMPString;
190 break;
191 case TUniversalString:
192 *cl = ASN1_C_UNIV;
193 *ty = PRIM;
194 *tag = UT_UniversalString;
195 break;
196 case TVisibleString:
197 *cl = ASN1_C_UNIV;
198 *ty = PRIM;
199 *tag = UT_VisibleString;
200 break;
201 default:
202 abort();
206 static void
207 range_check(const char *name,
208 const char *length,
209 const char *forwstr,
210 struct range *r)
212 if (r->min == r->max + 2 || r->min < r->max)
213 fprintf (codefile,
214 "if ((%s)->%s > %d) {\n"
215 "e = ASN1_MAX_CONSTRAINT; %s;\n"
216 "}\n",
217 name, length, r->max, forwstr);
218 if (r->min - 1 == r->max || r->min < r->max)
219 fprintf (codefile,
220 "if ((%s)->%s < %d) {\n"
221 "e = ASN1_MIN_CONSTRAINT; %s;\n"
222 "}\n",
223 name, length, r->min, forwstr);
224 if (r->max == r->min)
225 fprintf (codefile,
226 "if ((%s)->%s != %d) {\n"
227 "e = ASN1_EXACT_CONSTRAINT; %s;\n"
228 "}\n",
229 name, length, r->min, forwstr);
232 static int
233 decode_type (const char *name, const Type *t, int optional,
234 const char *forwstr, const char *tmpstr)
236 switch (t->type) {
237 case TType: {
238 if (optional)
239 fprintf(codefile,
240 "%s = calloc(1, sizeof(*%s));\n"
241 "if (%s == NULL) %s;\n",
242 name, name, name, forwstr);
243 fprintf (codefile,
244 "e = decode_%s(p, len, %s, &l);\n",
245 t->symbol->gen_name, name);
246 if (optional) {
247 fprintf (codefile,
248 "if(e) {\n"
249 "free(%s);\n"
250 "%s = NULL;\n"
251 "} else {\n"
252 "p += l; len -= l; ret += l;\n"
253 "}\n",
254 name, name);
255 } else {
256 fprintf (codefile,
257 "if(e) %s;\n",
258 forwstr);
259 fprintf (codefile,
260 "p += l; len -= l; ret += l;\n");
262 break;
264 case TInteger:
265 if(t->members) {
266 fprintf(codefile,
267 "{\n"
268 "int enumint;\n");
269 decode_primitive ("integer", "&enumint", forwstr);
270 fprintf(codefile,
271 "*%s = enumint;\n"
272 "}\n",
273 name);
274 } else if (t->range == NULL) {
275 decode_primitive ("heim_integer", name, forwstr);
276 } else if (t->range->min == INT_MIN && t->range->max == INT_MAX) {
277 decode_primitive ("integer", name, forwstr);
278 } else if (t->range->min == 0 && t->range->max == UINT_MAX) {
279 decode_primitive ("unsigned", name, forwstr);
280 } else if (t->range->min == 0 && t->range->max == INT_MAX) {
281 decode_primitive ("unsigned", name, forwstr);
282 } else
283 errx(1, "%s: unsupported range %d -> %d",
284 name, t->range->min, t->range->max);
285 break;
286 case TBoolean:
287 decode_primitive ("boolean", name, forwstr);
288 break;
289 case TEnumerated:
290 decode_primitive ("enumerated", name, forwstr);
291 break;
292 case TOctetString:
293 decode_primitive ("octet_string", name, forwstr);
294 if (t->range)
295 range_check(name, "length", forwstr, t->range);
296 break;
297 case TBitString: {
298 Member *m;
299 int pos = 0;
301 if (ASN1_TAILQ_EMPTY(t->members)) {
302 decode_primitive ("bit_string", name, forwstr);
303 break;
305 fprintf(codefile,
306 "if (len < 1) return ASN1_OVERRUN;\n"
307 "p++; len--; ret++;\n");
308 fprintf(codefile,
309 "do {\n"
310 "if (len < 1) break;\n");
311 ASN1_TAILQ_FOREACH(m, t->members, members) {
312 while (m->val / 8 > pos / 8) {
313 fprintf (codefile,
314 "p++; len--; ret++;\n"
315 "if (len < 1) break;\n");
316 pos += 8;
318 fprintf (codefile,
319 "(%s)->%s = (*p >> %d) & 1;\n",
320 name, m->gen_name, 7 - m->val % 8);
322 fprintf(codefile,
323 "} while(0);\n");
324 fprintf (codefile,
325 "p += len; ret += len;\n");
326 break;
328 case TSequence: {
329 Member *m;
331 if (t->members == NULL)
332 break;
334 ASN1_TAILQ_FOREACH(m, t->members, members) {
335 char *s;
337 if (m->ellipsis)
338 continue;
340 asprintf (&s, "%s(%s)->%s", m->optional ? "" : "&",
341 name, m->gen_name);
342 if (s == NULL)
343 errx(1, "malloc");
344 decode_type (s, m->type, m->optional, forwstr, m->gen_name);
345 free (s);
348 break;
350 case TSet: {
351 Member *m;
352 unsigned int memno;
354 if(t->members == NULL)
355 break;
357 fprintf(codefile, "{\n");
358 fprintf(codefile, "unsigned int members = 0;\n");
359 fprintf(codefile, "while(len > 0) {\n");
360 fprintf(codefile,
361 "Der_class class;\n"
362 "Der_type type;\n"
363 "int tag;\n"
364 "e = der_get_tag (p, len, &class, &type, &tag, NULL);\n"
365 "if(e) %s;\n", forwstr);
366 fprintf(codefile, "switch (MAKE_TAG(class, type, tag)) {\n");
367 memno = 0;
368 ASN1_TAILQ_FOREACH(m, t->members, members) {
369 char *s;
371 assert(m->type->type == TTag);
373 fprintf(codefile, "case MAKE_TAG(%s, %s, %s):\n",
374 classname(m->type->tag.tagclass),
375 is_primitive_type(m->type->subtype->type) ? "PRIM" : "CONS",
376 valuename(m->type->tag.tagclass, m->type->tag.tagvalue));
378 asprintf (&s, "%s(%s)->%s", m->optional ? "" : "&", name, m->gen_name);
379 if (s == NULL)
380 errx(1, "malloc");
381 if(m->optional)
382 fprintf(codefile,
383 "%s = calloc(1, sizeof(*%s));\n"
384 "if (%s == NULL) { e = ENOMEM; %s; }\n",
385 s, s, s, forwstr);
386 decode_type (s, m->type, 0, forwstr, m->gen_name);
387 free (s);
389 fprintf(codefile, "members |= (1 << %d);\n", memno);
390 memno++;
391 fprintf(codefile, "break;\n");
393 fprintf(codefile,
394 "default:\n"
395 "return ASN1_MISPLACED_FIELD;\n"
396 "break;\n");
397 fprintf(codefile, "}\n");
398 fprintf(codefile, "}\n");
399 memno = 0;
400 ASN1_TAILQ_FOREACH(m, t->members, members) {
401 char *s;
403 asprintf (&s, "%s->%s", name, m->gen_name);
404 if (s == NULL)
405 errx(1, "malloc");
406 fprintf(codefile, "if((members & (1 << %d)) == 0)\n", memno);
407 if(m->optional)
408 fprintf(codefile, "%s = NULL;\n", s);
409 else if(m->defval)
410 gen_assign_defval(s, m->defval);
411 else
412 fprintf(codefile, "return ASN1_MISSING_FIELD;\n");
413 free(s);
414 memno++;
416 fprintf(codefile, "}\n");
417 break;
419 case TSetOf:
420 case TSequenceOf: {
421 char *n;
422 char *sname;
424 fprintf (codefile,
425 "{\n"
426 "size_t %s_origlen = len;\n"
427 "size_t %s_oldret = ret;\n"
428 "size_t %s_olen = 0;\n"
429 "void *%s_tmp;\n"
430 "ret = 0;\n"
431 "(%s)->len = 0;\n"
432 "(%s)->val = NULL;\n",
433 tmpstr,
434 tmpstr,
435 tmpstr,
436 tmpstr,
437 name,
438 name);
440 fprintf (codefile,
441 "while(ret < %s_origlen) {\n"
442 "size_t %s_nlen = %s_olen + sizeof(*((%s)->val));\n"
443 "if (%s_olen > %s_nlen) { e = ASN1_OVERFLOW; %s; }\n"
444 "%s_olen = %s_nlen;\n"
445 "%s_tmp = realloc((%s)->val, %s_olen);\n"
446 "if (%s_tmp == NULL) { e = ENOMEM; %s; }\n"
447 "(%s)->val = %s_tmp;\n",
448 tmpstr,
449 tmpstr, tmpstr, name,
450 tmpstr, tmpstr, forwstr,
451 tmpstr, tmpstr,
452 tmpstr, name, tmpstr,
453 tmpstr, forwstr,
454 name, tmpstr);
456 asprintf (&n, "&(%s)->val[(%s)->len]", name, name);
457 if (n == NULL)
458 errx(1, "malloc");
459 asprintf (&sname, "%s_s_of", tmpstr);
460 if (sname == NULL)
461 errx(1, "malloc");
462 decode_type (n, t->subtype, 0, forwstr, sname);
463 fprintf (codefile,
464 "(%s)->len++;\n"
465 "len = %s_origlen - ret;\n"
466 "}\n"
467 "ret += %s_oldret;\n"
468 "}\n",
469 name,
470 tmpstr, tmpstr);
471 if (t->range)
472 range_check(name, "len", forwstr, t->range);
473 free (n);
474 free (sname);
475 break;
477 case TGeneralizedTime:
478 decode_primitive ("generalized_time", name, forwstr);
479 break;
480 case TGeneralString:
481 decode_primitive ("general_string", name, forwstr);
482 break;
483 case TTag:{
484 char *tname;
486 fprintf(codefile,
487 "{\n"
488 "size_t %s_datalen, %s_oldlen;\n",
489 tmpstr, tmpstr);
490 if(dce_fix)
491 fprintf(codefile,
492 "int dce_fix;\n");
493 fprintf(codefile, "e = der_match_tag_and_length(p, len, %s, %s, %s, "
494 "&%s_datalen, &l);\n",
495 classname(t->tag.tagclass),
496 is_primitive_type(t->subtype->type) ? "PRIM" : "CONS",
497 valuename(t->tag.tagclass, t->tag.tagvalue),
498 tmpstr);
499 if(optional) {
500 fprintf(codefile,
501 "if(e) {\n"
502 "%s = NULL;\n"
503 "} else {\n"
504 "%s = calloc(1, sizeof(*%s));\n"
505 "if (%s == NULL) { e = ENOMEM; %s; }\n",
506 name, name, name, name, forwstr);
507 } else {
508 fprintf(codefile, "if(e) %s;\n", forwstr);
510 fprintf (codefile,
511 "p += l; len -= l; ret += l;\n"
512 "%s_oldlen = len;\n",
513 tmpstr);
514 if(dce_fix)
515 fprintf (codefile,
516 "if((dce_fix = _heim_fix_dce(%s_datalen, &len)) < 0)\n"
517 "{ e = ASN1_BAD_FORMAT; %s; }\n",
518 tmpstr, forwstr);
519 else
520 fprintf(codefile,
521 "if (%s_datalen > len) { e = ASN1_OVERRUN; %s; }\n"
522 "len = %s_datalen;\n", tmpstr, forwstr, tmpstr);
523 asprintf (&tname, "%s_Tag", tmpstr);
524 if (tname == NULL)
525 errx(1, "malloc");
526 decode_type (name, t->subtype, 0, forwstr, tname);
527 if(dce_fix)
528 fprintf(codefile,
529 "if(dce_fix){\n"
530 "e = der_match_tag_and_length (p, len, "
531 "(Der_class)0,(Der_type)0, UT_EndOfContent, "
532 "&%s_datalen, &l);\n"
533 "if(e) %s;\np += l; len -= l; ret += l;\n"
534 "} else \n", tmpstr, forwstr);
535 fprintf(codefile,
536 "len = %s_oldlen - %s_datalen;\n",
537 tmpstr, tmpstr);
538 if(optional)
539 fprintf(codefile,
540 "}\n");
541 fprintf(codefile,
542 "}\n");
543 free(tname);
544 break;
546 case TChoice: {
547 Member *m, *have_ellipsis = NULL;
548 const char *els = "";
550 if (t->members == NULL)
551 break;
553 ASN1_TAILQ_FOREACH(m, t->members, members) {
554 const Type *tt = m->type;
555 char *s;
556 Der_class cl;
557 Der_type ty;
558 unsigned tag;
560 if (m->ellipsis) {
561 have_ellipsis = m;
562 continue;
565 find_tag(tt, &cl, &ty, &tag);
567 fprintf(codefile,
568 "%sif (der_match_tag(p, len, %s, %s, %s, NULL) == 0) {\n",
569 els,
570 classname(cl),
571 ty ? "CONS" : "PRIM",
572 valuename(cl, tag));
573 asprintf (&s, "%s(%s)->u.%s", m->optional ? "" : "&",
574 name, m->gen_name);
575 if (s == NULL)
576 errx(1, "malloc");
577 decode_type (s, m->type, m->optional, forwstr, m->gen_name);
578 fprintf(codefile,
579 "(%s)->element = %s;\n",
580 name, m->label);
581 free(s);
582 fprintf(codefile,
583 "}\n");
584 els = "else ";
586 if (have_ellipsis) {
587 fprintf(codefile,
588 "else {\n"
589 "(%s)->u.%s.data = calloc(1, len);\n"
590 "if ((%s)->u.%s.data == NULL) {\n"
591 "e = ENOMEM; %s;\n"
592 "}\n"
593 "(%s)->u.%s.length = len;\n"
594 "memcpy((%s)->u.%s.data, p, len);\n"
595 "(%s)->element = %s;\n"
596 "p += len;\n"
597 "ret += len;\n"
598 "len -= len;\n"
599 "}\n",
600 name, have_ellipsis->gen_name,
601 name, have_ellipsis->gen_name,
602 forwstr,
603 name, have_ellipsis->gen_name,
604 name, have_ellipsis->gen_name,
605 name, have_ellipsis->label);
606 } else {
607 fprintf(codefile,
608 "else {\n"
609 "e = ASN1_PARSE_ERROR;\n"
610 "%s;\n"
611 "}\n",
612 forwstr);
614 break;
616 case TUTCTime:
617 decode_primitive ("utctime", name, forwstr);
618 break;
619 case TUTF8String:
620 decode_primitive ("utf8string", name, forwstr);
621 break;
622 case TPrintableString:
623 decode_primitive ("printable_string", name, forwstr);
624 break;
625 case TIA5String:
626 decode_primitive ("ia5_string", name, forwstr);
627 break;
628 case TBMPString:
629 decode_primitive ("bmp_string", name, forwstr);
630 break;
631 case TUniversalString:
632 decode_primitive ("universal_string", name, forwstr);
633 break;
634 case TVisibleString:
635 decode_primitive ("visible_string", name, forwstr);
636 break;
637 case TNull:
638 fprintf (codefile, "/* NULL */\n");
639 break;
640 case TOID:
641 decode_primitive ("oid", name, forwstr);
642 break;
643 default :
644 abort ();
646 return 0;
649 void
650 generate_type_decode (const Symbol *s)
652 int preserve = preserve_type(s->name) ? TRUE : FALSE;
654 fprintf (headerfile,
655 "int "
656 "decode_%s(const unsigned char *, size_t, %s *, size_t *);\n",
657 s->gen_name, s->gen_name);
659 fprintf (codefile, "int\n"
660 "decode_%s(const unsigned char *p,"
661 " size_t len, %s *data, size_t *size)\n"
662 "{\n",
663 s->gen_name, s->gen_name);
665 switch (s->type->type) {
666 case TInteger:
667 case TBoolean:
668 case TOctetString:
669 case TOID:
670 case TGeneralizedTime:
671 case TGeneralString:
672 case TUTF8String:
673 case TPrintableString:
674 case TIA5String:
675 case TBMPString:
676 case TUniversalString:
677 case TVisibleString:
678 case TUTCTime:
679 case TNull:
680 case TEnumerated:
681 case TBitString:
682 case TSequence:
683 case TSequenceOf:
684 case TSet:
685 case TSetOf:
686 case TTag:
687 case TType:
688 case TChoice:
689 fprintf (codefile,
690 "size_t ret = 0;\n"
691 "size_t l;\n"
692 "int e;\n");
693 if (preserve)
694 fprintf (codefile, "const unsigned char *begin = p;\n");
696 fprintf (codefile, "\n");
697 fprintf (codefile, "memset(data, 0, sizeof(*data));\n"); /* hack to avoid `unused variable' */
699 decode_type ("data", s->type, 0, "goto fail", "Top");
700 if (preserve)
701 fprintf (codefile,
702 "data->_save.data = calloc(1, ret);\n"
703 "if (data->_save.data == NULL) { \n"
704 "e = ENOMEM; goto fail; \n"
705 "}\n"
706 "data->_save.length = ret;\n"
707 "memcpy(data->_save.data, begin, ret);\n");
708 fprintf (codefile,
709 "if(size) *size = ret;\n"
710 "return 0;\n");
711 fprintf (codefile,
712 "fail:\n"
713 "free_%s(data);\n"
714 "return e;\n",
715 s->gen_name);
716 break;
717 default:
718 abort ();
720 fprintf (codefile, "}\n\n");