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