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 36 RCSID("$Id$"); 37 38 static void 39 encode_primitive (const char *typename, const char *name) 40 { 41 fprintf (codefile, 42 "e = der_put_%s(p, len, %s, &l);\n" 43 "if (e) return e;\np -= l; len -= l; ret += l;\n\n", 44 typename, 45 name); 46 } 47 48 const char * 49 classname(Der_class class) 50 { 51 const char *cn[] = { "ASN1_C_UNIV", "ASN1_C_APPL", 52 "ASN1_C_CONTEXT", "ASN1_C_PRIV" }; 53 if(class < ASN1_C_UNIV || class > ASN1_C_PRIVATE) 54 return "???"; 55 return cn[class]; 56 } 57 58 59 const char * 60 valuename(Der_class class, int value) 61 { 62 static char s[32]; 63 struct { 64 int value; 65 const char *s; 66 } *p, values[] = { 67 #define X(Y) { Y, #Y } 68 X(UT_BMPString), 69 X(UT_BitString), 70 X(UT_Boolean), 71 X(UT_EmbeddedPDV), 72 X(UT_Enumerated), 73 X(UT_External), 74 X(UT_GeneralString), 75 X(UT_GeneralizedTime), 76 X(UT_GraphicString), 77 X(UT_IA5String), 78 X(UT_Integer), 79 X(UT_Null), 80 X(UT_NumericString), 81 X(UT_OID), 82 X(UT_ObjectDescriptor), 83 X(UT_OctetString), 84 X(UT_PrintableString), 85 X(UT_Real), 86 X(UT_RelativeOID), 87 X(UT_Sequence), 88 X(UT_Set), 89 X(UT_TeletexString), 90 X(UT_UTCTime), 91 X(UT_UTF8String), 92 X(UT_UniversalString), 93 X(UT_VideotexString), 94 X(UT_VisibleString), 95 #undef X 96 { -1, NULL } 97 }; 98 if(class == ASN1_C_UNIV) { 99 for(p = values; p->value != -1; p++) 100 if(p->value == value) 101 return p->s; 102 } 103 snprintf(s, sizeof(s), "%d", value); 104 return s; 105 } 106 107 static int 108 encode_type (const char *name, const Type *t, const char *tmpstr) 109 { 110 int constructed = 1; 111 112 switch (t->type) { 113 case TType: 114 #if 0 115 encode_type (name, t->symbol->type); 116 #endif 117 fprintf (codefile, 118 "e = encode_%s(p, len, %s, &l);\n" 119 "if (e) return e;\np -= l; len -= l; ret += l;\n\n", 120 t->symbol->gen_name, name); 121 break; 122 case TInteger: 123 if(t->members) { 124 fprintf(codefile, 125 "{\n" 126 "int enumint = (int)*%s;\n", 127 name); 128 encode_primitive ("integer", "&enumint"); 129 fprintf(codefile, "}\n;"); 130 } else if (t->range == NULL) { 131 encode_primitive ("heim_integer", name); 132 } else if (t->range->min < INT_MIN && t->range->max <= INT64_MAX) { 133 encode_primitive ("integer64", name); 134 } else if (t->range->min >= 0 && t->range->max > UINT_MAX) { 135 encode_primitive ("unsigned64", name); 136 } else if (t->range->min >= INT_MIN && t->range->max <= INT_MAX) { 137 encode_primitive ("integer", name); 138 } else if (t->range->min >= 0 && t->range->max <= UINT_MAX) { 139 encode_primitive ("unsigned", name); 140 } else 141 errx(1, "%s: unsupported range %" PRId64 " -> %" PRId64, 142 name, t->range->min, t->range->max); 143 constructed = 0; 144 break; 145 case TBoolean: 146 encode_primitive ("boolean", name); 147 constructed = 0; 148 break; 149 case TOctetString: 150 encode_primitive ("octet_string", name); 151 constructed = 0; 152 break; 153 case TBitString: { 154 Member *m; 155 int pos; 156 157 if (ASN1_TAILQ_EMPTY(t->members)) { 158 encode_primitive("bit_string", name); 159 constructed = 0; 160 break; 161 } 162 163 fprintf (codefile, "{\n" 164 "unsigned char c = 0;\n"); 165 if (!rfc1510_bitstring) 166 fprintf (codefile, 167 "int rest = 0;\n" 168 "int bit_set = 0;\n"); 169 #if 0 170 pos = t->members->prev->val; 171 /* fix for buggy MIT (and OSF?) code */ 172 if (pos > 31) 173 abort (); 174 #endif 175 /* 176 * It seems that if we do not always set pos to 31 here, the MIT 177 * code will do the wrong thing. 178 * 179 * I hate ASN.1 (and DER), but I hate it even more when everybody 180 * has to screw it up differently. 181 */ 182 pos = ASN1_TAILQ_LAST(t->members, memhead)->val; 183 if (rfc1510_bitstring) { 184 if (pos < 31) 185 pos = 31; 186 } 187 188 ASN1_TAILQ_FOREACH_REVERSE(m, t->members, memhead, members) { 189 while (m->val / 8 < pos / 8) { 190 if (!rfc1510_bitstring) 191 fprintf (codefile, 192 "if (c != 0 || bit_set) {\n"); 193 fprintf (codefile, 194 "if (len < 1) return ASN1_OVERFLOW;\n" 195 "*p-- = c; len--; ret++;\n"); 196 if (!rfc1510_bitstring) 197 fprintf (codefile, 198 "if (!bit_set) {\n" 199 "rest = 0;\n" 200 "while(c) { \n" 201 "if (c & 1) break;\n" 202 "c = c >> 1;\n" 203 "rest++;\n" 204 "}\n" 205 "bit_set = 1;\n" 206 "}\n" 207 "}\n"); 208 fprintf (codefile, 209 "c = 0;\n"); 210 pos -= 8; 211 } 212 fprintf (codefile, 213 "if((%s)->%s) {\n" 214 "c |= 1<<%d;\n", 215 name, m->gen_name, 7 - m->val % 8); 216 fprintf (codefile, 217 "}\n"); 218 } 219 220 if (!rfc1510_bitstring) 221 fprintf (codefile, 222 "if (c != 0 || bit_set) {\n"); 223 fprintf (codefile, 224 "if (len < 1) return ASN1_OVERFLOW;\n" 225 "*p-- = c; len--; ret++;\n"); 226 if (!rfc1510_bitstring) 227 fprintf (codefile, 228 "if (!bit_set) {\n" 229 "rest = 0;\n" 230 "if(c) { \n" 231 "while(c) { \n" 232 "if (c & 1) break;\n" 233 "c = c >> 1;\n" 234 "rest++;\n" 235 "}\n" 236 "}\n" 237 "}\n" 238 "}\n"); 239 240 fprintf (codefile, 241 "if (len < 1) return ASN1_OVERFLOW;\n" 242 "*p-- = %s;\n" 243 "len -= 1;\n" 244 "ret += 1;\n" 245 "}\n\n", 246 rfc1510_bitstring ? "0" : "rest"); 247 constructed = 0; 248 break; 249 } 250 case TEnumerated : { 251 encode_primitive ("enumerated", name); 252 constructed = 0; 253 break; 254 } 255 256 case TSet: 257 case TSequence: { 258 Member *m; 259 260 if (t->members == NULL) 261 break; 262 263 ASN1_TAILQ_FOREACH_REVERSE(m, t->members, memhead, members) { 264 char *s = NULL; 265 266 if (m->ellipsis) 267 continue; 268 269 if (asprintf (&s, "%s(%s)->%s", m->optional ? "" : "&", name, m->gen_name) < 0 || s == NULL) 270 errx(1, "malloc"); 271 fprintf(codefile, "/* %s */\n", m->name); 272 if (m->optional) 273 fprintf (codefile, 274 "if(%s) ", 275 s); 276 else if(m->defval) 277 gen_compare_defval(s + 1, m->defval); 278 fprintf (codefile, "{\n"); 279 fprintf (codefile, "size_t %s_oldret HEIMDAL_UNUSED_ATTRIBUTE = ret;\n", tmpstr); 280 fprintf (codefile, "ret = 0;\n"); 281 encode_type (s, m->type, m->gen_name); 282 fprintf (codefile, "ret += %s_oldret;\n", tmpstr); 283 fprintf (codefile, "}\n"); 284 free (s); 285 } 286 break; 287 } 288 case TSetOf: { 289 290 fprintf(codefile, 291 "{\n" 292 "struct heim_octet_string *val;\n" 293 "size_t elen = 0, totallen = 0;\n" 294 "int eret = 0;\n"); 295 296 fprintf(codefile, 297 "if ((%s)->len > UINT_MAX/sizeof(val[0]))\n" 298 "return ERANGE;\n", 299 name); 300 301 fprintf(codefile, 302 "val = malloc(sizeof(val[0]) * (%s)->len);\n" 303 "if (val == NULL && (%s)->len != 0) return ENOMEM;\n", 304 name, name); 305 306 fprintf(codefile, 307 "for(i = 0; i < (int)(%s)->len; i++) {\n", 308 name); 309 310 fprintf(codefile, 311 "ASN1_MALLOC_ENCODE(%s, val[i].data, " 312 "val[i].length, &(%s)->val[i], &elen, eret);\n", 313 t->subtype->symbol->gen_name, 314 name); 315 316 fprintf(codefile, 317 "if(eret) {\n" 318 "i--;\n" 319 "while (i >= 0) {\n" 320 "free(val[i].data);\n" 321 "i--;\n" 322 "}\n" 323 "free(val);\n" 324 "return eret;\n" 325 "}\n" 326 "totallen += elen;\n" 327 "}\n"); 328 329 fprintf(codefile, 330 "if (totallen > len) {\n" 331 "for (i = 0; i < (int)(%s)->len; i++) {\n" 332 "free(val[i].data);\n" 333 "}\n" 334 "free(val);\n" 335 "return ASN1_OVERFLOW;\n" 336 "}\n", 337 name); 338 339 fprintf(codefile, 340 "qsort(val, (%s)->len, sizeof(val[0]), _heim_der_set_sort);\n", 341 name); 342 343 fprintf (codefile, 344 "for(i = (int)(%s)->len - 1; i >= 0; --i) {\n" 345 "p -= val[i].length;\n" 346 "ret += val[i].length;\n" 347 "memcpy(p + 1, val[i].data, val[i].length);\n" 348 "free(val[i].data);\n" 349 "}\n" 350 "free(val);\n" 351 "}\n", 352 name); 353 break; 354 } 355 case TSequenceOf: { 356 char *sname = NULL; 357 char *n = NULL; 358 359 fprintf (codefile, 360 "for(i = (int)(%s)->len - 1; i >= 0; --i) {\n" 361 "size_t %s_for_oldret = ret;\n" 362 "ret = 0;\n", 363 name, tmpstr); 364 if (asprintf (&n, "&(%s)->val[i]", name) < 0 || n == NULL) 365 errx(1, "malloc"); 366 if (asprintf (&sname, "%s_S_Of", tmpstr) < 0 || sname == NULL) 367 errx(1, "malloc"); 368 encode_type (n, t->subtype, sname); 369 fprintf (codefile, 370 "ret += %s_for_oldret;\n" 371 "}\n", 372 tmpstr); 373 free (n); 374 free (sname); 375 break; 376 } 377 case TGeneralizedTime: 378 encode_primitive ("generalized_time", name); 379 constructed = 0; 380 break; 381 case TGeneralString: 382 encode_primitive ("general_string", name); 383 constructed = 0; 384 break; 385 case TTeletexString: 386 encode_primitive ("general_string", name); 387 constructed = 0; 388 break; 389 case TTag: { 390 char *tname = NULL; 391 int c; 392 if (asprintf (&tname, "%s_tag", tmpstr) < 0 || tname == NULL) 393 errx(1, "malloc"); 394 c = encode_type (name, t->subtype, tname); 395 fprintf (codefile, 396 "e = der_put_length_and_tag (p, len, ret, %s, %s, %s, &l);\n" 397 "if (e) return e;\np -= l; len -= l; ret += l;\n\n", 398 classname(t->tag.tagclass), 399 c ? "CONS" : "PRIM", 400 valuename(t->tag.tagclass, t->tag.tagvalue)); 401 free (tname); 402 break; 403 } 404 case TChoice:{ 405 Member *m, *have_ellipsis = NULL; 406 char *s = NULL; 407 408 if (t->members == NULL) 409 break; 410 411 fprintf(codefile, "\n"); 412 413 if (asprintf (&s, "(%s)", name) < 0 || s == NULL) 414 errx(1, "malloc"); 415 fprintf(codefile, "switch(%s->element) {\n", s); 416 417 ASN1_TAILQ_FOREACH_REVERSE(m, t->members, memhead, members) { 418 char *s2 = NULL; 419 420 if (m->ellipsis) { 421 have_ellipsis = m; 422 continue; 423 } 424 425 fprintf (codefile, "case %s: {", m->label); 426 if (asprintf(&s2, "%s(%s)->u.%s", m->optional ? "" : "&", 427 s, m->gen_name) < 0 || s2 == NULL) 428 errx(1, "malloc"); 429 if (m->optional) 430 fprintf (codefile, "if(%s) {\n", s2); 431 fprintf (codefile, "size_t %s_oldret = ret;\n", tmpstr); 432 fprintf (codefile, "ret = 0;\n"); 433 constructed = encode_type (s2, m->type, m->gen_name); 434 fprintf (codefile, "ret += %s_oldret;\n", tmpstr); 435 if(m->optional) 436 fprintf (codefile, "}\n"); 437 fprintf(codefile, "break;\n"); 438 fprintf(codefile, "}\n"); 439 free (s2); 440 } 441 free (s); 442 if (have_ellipsis) { 443 fprintf(codefile, 444 "case %s: {\n" 445 "if (len < (%s)->u.%s.length)\n" 446 "return ASN1_OVERFLOW;\n" 447 "p -= (%s)->u.%s.length;\n" 448 "ret += (%s)->u.%s.length;\n" 449 "memcpy(p + 1, (%s)->u.%s.data, (%s)->u.%s.length);\n" 450 "break;\n" 451 "}\n", 452 have_ellipsis->label, 453 name, have_ellipsis->gen_name, 454 name, have_ellipsis->gen_name, 455 name, have_ellipsis->gen_name, 456 name, have_ellipsis->gen_name, 457 name, have_ellipsis->gen_name); 458 } 459 fprintf(codefile, "};\n"); 460 break; 461 } 462 case TOID: 463 encode_primitive ("oid", name); 464 constructed = 0; 465 break; 466 case TUTCTime: 467 encode_primitive ("utctime", name); 468 constructed = 0; 469 break; 470 case TUTF8String: 471 encode_primitive ("utf8string", name); 472 constructed = 0; 473 break; 474 case TPrintableString: 475 encode_primitive ("printable_string", name); 476 constructed = 0; 477 break; 478 case TIA5String: 479 encode_primitive ("ia5_string", name); 480 constructed = 0; 481 break; 482 case TBMPString: 483 encode_primitive ("bmp_string", name); 484 constructed = 0; 485 break; 486 case TUniversalString: 487 encode_primitive ("universal_string", name); 488 constructed = 0; 489 break; 490 case TVisibleString: 491 encode_primitive ("visible_string", name); 492 constructed = 0; 493 break; 494 case TNull: 495 fprintf (codefile, "/* NULL */\n"); 496 constructed = 0; 497 break; 498 default: 499 abort (); 500 } 501 return constructed; 502 } 503 504 void 505 generate_type_encode (const Symbol *s) 506 { 507 fprintf (codefile, "int ASN1CALL\n" 508 "encode_%s(unsigned char *p HEIMDAL_UNUSED_ATTRIBUTE, size_t len HEIMDAL_UNUSED_ATTRIBUTE," 509 " const %s *data, size_t *size)\n" 510 "{\n", 511 s->gen_name, s->gen_name); 512 513 switch (s->type->type) { 514 case TInteger: 515 case TBoolean: 516 case TOctetString: 517 case TGeneralizedTime: 518 case TGeneralString: 519 case TTeletexString: 520 case TUTCTime: 521 case TUTF8String: 522 case TPrintableString: 523 case TIA5String: 524 case TBMPString: 525 case TUniversalString: 526 case TVisibleString: 527 case TNull: 528 case TBitString: 529 case TEnumerated: 530 case TOID: 531 case TSequence: 532 case TSequenceOf: 533 case TSet: 534 case TSetOf: 535 case TTag: 536 case TType: 537 case TChoice: 538 fprintf (codefile, 539 "size_t ret HEIMDAL_UNUSED_ATTRIBUTE = 0;\n" 540 "size_t l HEIMDAL_UNUSED_ATTRIBUTE;\n" 541 "int i HEIMDAL_UNUSED_ATTRIBUTE, e HEIMDAL_UNUSED_ATTRIBUTE;\n\n"); 542 543 encode_type("data", s->type, "Top"); 544 545 fprintf (codefile, "*size = ret;\n" 546 "return 0;\n"); 547 break; 548 default: 549 abort (); 550 } 551 fprintf (codefile, "}\n\n"); 552 } 553