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