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: gen_encode.c 22429 2008-01-13 10:25:50Z lha $"); 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; 263 264 if (m->ellipsis) 265 continue; 266 267 asprintf (&s, "%s(%s)->%s", m->optional ? "" : "&", name, m->gen_name); 268 if (s == NULL) 269 errx(1, "malloc"); 270 fprintf(codefile, "/* %s */\n", m->name); 271 if (m->optional) 272 fprintf (codefile, 273 "if(%s) ", 274 s); 275 else if(m->defval) 276 gen_compare_defval(s + 1, m->defval); 277 fprintf (codefile, "{\n"); 278 fprintf (codefile, "size_t %s_oldret = ret;\n", tmpstr); 279 fprintf (codefile, "ret = 0;\n"); 280 encode_type (s, m->type, m->gen_name); 281 fprintf (codefile, "ret += %s_oldret;\n", tmpstr); 282 fprintf (codefile, "}\n"); 283 free (s); 284 } 285 break; 286 } 287 case TSetOf: { 288 289 fprintf(codefile, 290 "{\n" 291 "struct heim_octet_string *val;\n" 292 "size_t elen, totallen = 0;\n" 293 "int eret;\n"); 294 295 fprintf(codefile, 296 "if ((%s)->len > UINT_MAX/sizeof(val[0]))\n" 297 "return ERANGE;\n", 298 name); 299 300 fprintf(codefile, 301 "val = malloc(sizeof(val[0]) * (%s)->len);\n" 302 "if (val == NULL && (%s)->len != 0) return ENOMEM;\n", 303 name, name); 304 305 fprintf(codefile, 306 "for(i = 0; i < (%s)->len; i++) {\n", 307 name); 308 309 fprintf(codefile, 310 "ASN1_MALLOC_ENCODE(%s, val[i].data, " 311 "val[i].length, &(%s)->val[i], &elen, eret);\n", 312 t->subtype->symbol->gen_name, 313 name); 314 315 fprintf(codefile, 316 "if(eret) {\n" 317 "i--;\n" 318 "while (i >= 0) {\n" 319 "free(val[i].data);\n" 320 "i--;\n" 321 "}\n" 322 "free(val);\n" 323 "return eret;\n" 324 "}\n" 325 "totallen += elen;\n" 326 "}\n"); 327 328 fprintf(codefile, 329 "if (totallen > len) {\n" 330 "for (i = 0; i < (%s)->len; i++) {\n" 331 "free(val[i].data);\n" 332 "}\n" 333 "free(val);\n" 334 "return ASN1_OVERFLOW;\n" 335 "}\n", 336 name); 337 338 fprintf(codefile, 339 "qsort(val, (%s)->len, sizeof(val[0]), _heim_der_set_sort);\n", 340 name); 341 342 fprintf (codefile, 343 "for(i = (%s)->len - 1; i >= 0; --i) {\n" 344 "p -= val[i].length;\n" 345 "ret += val[i].length;\n" 346 "memcpy(p + 1, val[i].data, val[i].length);\n" 347 "free(val[i].data);\n" 348 "}\n" 349 "free(val);\n" 350 "}\n", 351 name); 352 break; 353 } 354 case TSequenceOf: { 355 char *n; 356 char *sname; 357 358 fprintf (codefile, 359 "for(i = (%s)->len - 1; i >= 0; --i) {\n" 360 "size_t %s_for_oldret = ret;\n" 361 "ret = 0;\n", 362 name, tmpstr); 363 asprintf (&n, "&(%s)->val[i]", name); 364 if (n == NULL) 365 errx(1, "malloc"); 366 asprintf (&sname, "%s_S_Of", tmpstr); 367 if (sname == NULL) 368 errx(1, "malloc"); 369 encode_type (n, t->subtype, sname); 370 fprintf (codefile, 371 "ret += %s_for_oldret;\n" 372 "}\n", 373 tmpstr); 374 free (n); 375 free (sname); 376 break; 377 } 378 case TGeneralizedTime: 379 encode_primitive ("generalized_time", name); 380 constructed = 0; 381 break; 382 case TGeneralString: 383 encode_primitive ("general_string", name); 384 constructed = 0; 385 break; 386 case TTag: { 387 char *tname; 388 int c; 389 asprintf (&tname, "%s_tag", tmpstr); 390 if (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; 405 406 if (t->members == NULL) 407 break; 408 409 fprintf(codefile, "\n"); 410 411 asprintf (&s, "(%s)", name); 412 if (s == NULL) 413 errx(1, "malloc"); 414 fprintf(codefile, "switch(%s->element) {\n", s); 415 416 ASN1_TAILQ_FOREACH_REVERSE(m, t->members, memhead, members) { 417 char *s2; 418 419 if (m->ellipsis) { 420 have_ellipsis = m; 421 continue; 422 } 423 424 fprintf (codefile, "case %s: {", m->label); 425 asprintf(&s2, "%s(%s)->u.%s", m->optional ? "" : "&", 426 s, m->gen_name); 427 if (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 (headerfile, 508 "int " 509 "encode_%s(unsigned char *, size_t, const %s *, size_t *);\n", 510 s->gen_name, s->gen_name); 511 512 fprintf (codefile, "int\n" 513 "encode_%s(unsigned char *p, size_t len," 514 " const %s *data, size_t *size)\n" 515 "{\n", 516 s->gen_name, s->gen_name); 517 518 switch (s->type->type) { 519 case TInteger: 520 case TBoolean: 521 case TOctetString: 522 case TGeneralizedTime: 523 case TGeneralString: 524 case TUTCTime: 525 case TUTF8String: 526 case TPrintableString: 527 case TIA5String: 528 case TBMPString: 529 case TUniversalString: 530 case TVisibleString: 531 case TNull: 532 case TBitString: 533 case TEnumerated: 534 case TOID: 535 case TSequence: 536 case TSequenceOf: 537 case TSet: 538 case TSetOf: 539 case TTag: 540 case TType: 541 case TChoice: 542 fprintf (codefile, 543 "size_t ret = 0;\n" 544 "size_t l;\n" 545 "int i, e;\n\n"); 546 fprintf(codefile, "i = 0;\n"); /* hack to avoid `unused variable' */ 547 548 encode_type("data", s->type, "Top"); 549 550 fprintf (codefile, "*size = ret;\n" 551 "return 0;\n"); 552 break; 553 default: 554 abort (); 555 } 556 fprintf (codefile, "}\n\n"); 557 } 558