1 /* $NetBSD: gen_encode.c,v 1.2 2017/01/28 21:31:45 christos Exp $ */ 2 3 /* 4 * Copyright (c) 1997 - 2006 Kungliga Tekniska Högskolan 5 * (Royal Institute of Technology, Stockholm, Sweden). 6 * All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * 3. Neither the name of the Institute nor the names of its contributors 20 * may be used to endorse or promote products derived from this software 21 * without specific prior written permission. 22 * 23 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND 24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 26 * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE 27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 33 * SUCH DAMAGE. 34 */ 35 36 #include "gen_locl.h" 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 ((int)class >= sizeof(cn) / sizeof(cn[0])) 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 %lld -> %lld", 142 name, (long long)t->range->min, (long long)t->range->max); 143 144 constructed = 0; 145 break; 146 case TBoolean: 147 encode_primitive ("boolean", name); 148 constructed = 0; 149 break; 150 case TOctetString: 151 encode_primitive ("octet_string", name); 152 constructed = 0; 153 break; 154 case TBitString: { 155 Member *m; 156 int pos; 157 158 if (ASN1_TAILQ_EMPTY(t->members)) { 159 encode_primitive("bit_string", name); 160 constructed = 0; 161 break; 162 } 163 164 fprintf (codefile, "{\n" 165 "unsigned char c = 0;\n"); 166 if (!rfc1510_bitstring) 167 fprintf (codefile, 168 "int rest = 0;\n" 169 "int bit_set = 0;\n"); 170 #if 0 171 pos = t->members->prev->val; 172 /* fix for buggy MIT (and OSF?) code */ 173 if (pos > 31) 174 abort (); 175 #endif 176 /* 177 * It seems that if we do not always set pos to 31 here, the MIT 178 * code will do the wrong thing. 179 * 180 * I hate ASN.1 (and DER), but I hate it even more when everybody 181 * has to screw it up differently. 182 */ 183 pos = ASN1_TAILQ_LAST(t->members, memhead)->val; 184 if (rfc1510_bitstring) { 185 if (pos < 31) 186 pos = 31; 187 } 188 189 ASN1_TAILQ_FOREACH_REVERSE(m, t->members, memhead, members) { 190 while (m->val / 8 < pos / 8) { 191 if (!rfc1510_bitstring) 192 fprintf (codefile, 193 "if (c != 0 || bit_set) {\n"); 194 fprintf (codefile, 195 "if (len < 1) return ASN1_OVERFLOW;\n" 196 "*p-- = c; len--; ret++;\n"); 197 if (!rfc1510_bitstring) 198 fprintf (codefile, 199 "if (!bit_set) {\n" 200 "rest = 0;\n" 201 "while(c) { \n" 202 "if (c & 1) break;\n" 203 "c = c >> 1;\n" 204 "rest++;\n" 205 "}\n" 206 "bit_set = 1;\n" 207 "}\n" 208 "}\n"); 209 fprintf (codefile, 210 "c = 0;\n"); 211 pos -= 8; 212 } 213 fprintf (codefile, 214 "if((%s)->%s) {\n" 215 "c |= 1<<%d;\n", 216 name, m->gen_name, 7 - m->val % 8); 217 fprintf (codefile, 218 "}\n"); 219 } 220 221 if (!rfc1510_bitstring) 222 fprintf (codefile, 223 "if (c != 0 || bit_set) {\n"); 224 fprintf (codefile, 225 "if (len < 1) return ASN1_OVERFLOW;\n" 226 "*p-- = c; len--; ret++;\n"); 227 if (!rfc1510_bitstring) 228 fprintf (codefile, 229 "if (!bit_set) {\n" 230 "rest = 0;\n" 231 "if(c) { \n" 232 "while(c) { \n" 233 "if (c & 1) break;\n" 234 "c = c >> 1;\n" 235 "rest++;\n" 236 "}\n" 237 "}\n" 238 "}\n" 239 "}\n"); 240 241 fprintf (codefile, 242 "if (len < 1) return ASN1_OVERFLOW;\n" 243 "*p-- = %s;\n" 244 "len -= 1;\n" 245 "ret += 1;\n" 246 "}\n\n", 247 rfc1510_bitstring ? "0" : "rest"); 248 constructed = 0; 249 break; 250 } 251 case TEnumerated : { 252 encode_primitive ("enumerated", name); 253 constructed = 0; 254 break; 255 } 256 257 case TSet: 258 case TSequence: { 259 Member *m; 260 261 if (t->members == NULL) 262 break; 263 264 ASN1_TAILQ_FOREACH_REVERSE(m, t->members, memhead, members) { 265 char *s = NULL; 266 267 if (m->ellipsis) 268 continue; 269 270 if (asprintf (&s, "%s(%s)->%s", m->optional ? "" : "&", name, m->gen_name) < 0 || s == NULL) 271 errx(1, "malloc"); 272 fprintf(codefile, "/* %s */\n", m->name); 273 if (m->optional) 274 fprintf (codefile, 275 "if(%s) ", 276 s); 277 else if(m->defval) 278 gen_compare_defval(s + 1, m->defval); 279 fprintf (codefile, "{\n"); 280 fprintf (codefile, "size_t %s_oldret HEIMDAL_UNUSED_ATTRIBUTE = ret;\n", tmpstr); 281 fprintf (codefile, "ret = 0;\n"); 282 encode_type (s, m->type, m->gen_name); 283 fprintf (codefile, "ret += %s_oldret;\n", tmpstr); 284 fprintf (codefile, "}\n"); 285 free (s); 286 } 287 break; 288 } 289 case TSetOf: { 290 291 fprintf(codefile, 292 "{\n" 293 "heim_octet_string *val;\n" 294 "size_t elen = 0, totallen = 0;\n" 295 "int eret = 0;\n"); 296 297 fprintf(codefile, 298 "if ((%s)->len > UINT_MAX/sizeof(val[0]))\n" 299 "return ERANGE;\n", 300 name); 301 302 fprintf(codefile, 303 "val = malloc(sizeof(val[0]) * (%s)->len);\n" 304 "if (val == NULL && (%s)->len != 0) return ENOMEM;\n", 305 name, name); 306 307 fprintf(codefile, 308 "for(i = 0; i < (int)(%s)->len; i++) {\n", 309 name); 310 311 fprintf(codefile, 312 "ASN1_MALLOC_ENCODE(%s, val[i].data, " 313 "val[i].length, &(%s)->val[i], &elen, eret);\n", 314 t->subtype->symbol->gen_name, 315 name); 316 317 fprintf(codefile, 318 "if(eret) {\n" 319 "i--;\n" 320 "while (i >= 0) {\n" 321 "free(val[i].data);\n" 322 "i--;\n" 323 "}\n" 324 "free(val);\n" 325 "return eret;\n" 326 "}\n" 327 "totallen += elen;\n" 328 "}\n"); 329 330 fprintf(codefile, 331 "if (totallen > len) {\n" 332 "for (i = 0; i < (int)(%s)->len; i++) {\n" 333 "free(val[i].data);\n" 334 "}\n" 335 "free(val);\n" 336 "return ASN1_OVERFLOW;\n" 337 "}\n", 338 name); 339 340 fprintf(codefile, 341 "qsort(val, (%s)->len, sizeof(val[0]), _heim_der_set_sort);\n", 342 name); 343 344 fprintf (codefile, 345 "for(i = (int)(%s)->len - 1; i >= 0; --i) {\n" 346 "p -= val[i].length;\n" 347 "ret += val[i].length;\n" 348 "memcpy(p + 1, val[i].data, val[i].length);\n" 349 "free(val[i].data);\n" 350 "}\n" 351 "free(val);\n" 352 "}\n", 353 name); 354 break; 355 } 356 case TSequenceOf: { 357 char *sname = NULL; 358 char *n = NULL; 359 360 fprintf (codefile, 361 "for(i = (int)(%s)->len - 1; i >= 0; --i) {\n" 362 "size_t %s_for_oldret = ret;\n" 363 "ret = 0;\n", 364 name, tmpstr); 365 if (asprintf (&n, "&(%s)->val[i]", name) < 0 || n == NULL) 366 errx(1, "malloc"); 367 if (asprintf (&sname, "%s_S_Of", tmpstr) < 0 || 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 TTeletexString: 387 encode_primitive ("general_string", name); 388 constructed = 0; 389 break; 390 case TTag: { 391 char *tname = NULL; 392 int c; 393 if (asprintf (&tname, "%s_tag", tmpstr) < 0 || tname == NULL) 394 errx(1, "malloc"); 395 c = encode_type (name, t->subtype, tname); 396 fprintf (codefile, 397 "e = der_put_length_and_tag (p, len, ret, %s, %s, %s, &l);\n" 398 "if (e) return e;\np -= l; len -= l; ret += l;\n\n", 399 classname(t->tag.tagclass), 400 c ? "CONS" : "PRIM", 401 valuename(t->tag.tagclass, t->tag.tagvalue)); 402 free (tname); 403 break; 404 } 405 case TChoice:{ 406 Member *m, *have_ellipsis = NULL; 407 char *s = NULL; 408 409 if (t->members == NULL) 410 break; 411 412 fprintf(codefile, "\n"); 413 414 if (asprintf (&s, "(%s)", name) < 0 || s == NULL) 415 errx(1, "malloc"); 416 fprintf(codefile, "switch(%s->element) {\n", s); 417 418 ASN1_TAILQ_FOREACH_REVERSE(m, t->members, memhead, members) { 419 char *s2 = NULL; 420 421 if (m->ellipsis) { 422 have_ellipsis = m; 423 continue; 424 } 425 426 fprintf (codefile, "case %s: {", m->label); 427 if (asprintf(&s2, "%s(%s)->u.%s", m->optional ? "" : "&", 428 s, m->gen_name) < 0 || s2 == NULL) 429 errx(1, "malloc"); 430 if (m->optional) 431 fprintf (codefile, "if(%s) {\n", s2); 432 fprintf (codefile, "size_t %s_oldret = ret;\n", tmpstr); 433 fprintf (codefile, "ret = 0;\n"); 434 constructed = encode_type (s2, m->type, m->gen_name); 435 fprintf (codefile, "ret += %s_oldret;\n", tmpstr); 436 if(m->optional) 437 fprintf (codefile, "}\n"); 438 fprintf(codefile, "break;\n"); 439 fprintf(codefile, "}\n"); 440 free (s2); 441 } 442 free (s); 443 if (have_ellipsis) { 444 fprintf(codefile, 445 "case %s: {\n" 446 "if (len < (%s)->u.%s.length)\n" 447 "return ASN1_OVERFLOW;\n" 448 "p -= (%s)->u.%s.length;\n" 449 "ret += (%s)->u.%s.length;\n" 450 "memcpy(p + 1, (%s)->u.%s.data, (%s)->u.%s.length);\n" 451 "break;\n" 452 "}\n", 453 have_ellipsis->label, 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 name, have_ellipsis->gen_name); 459 } 460 fprintf(codefile, "};\n"); 461 break; 462 } 463 case TOID: 464 encode_primitive ("oid", name); 465 constructed = 0; 466 break; 467 case TUTCTime: 468 encode_primitive ("utctime", name); 469 constructed = 0; 470 break; 471 case TUTF8String: 472 encode_primitive ("utf8string", name); 473 constructed = 0; 474 break; 475 case TPrintableString: 476 encode_primitive ("printable_string", name); 477 constructed = 0; 478 break; 479 case TIA5String: 480 encode_primitive ("ia5_string", name); 481 constructed = 0; 482 break; 483 case TBMPString: 484 encode_primitive ("bmp_string", name); 485 constructed = 0; 486 break; 487 case TUniversalString: 488 encode_primitive ("universal_string", name); 489 constructed = 0; 490 break; 491 case TVisibleString: 492 encode_primitive ("visible_string", name); 493 constructed = 0; 494 break; 495 case TNull: 496 fprintf (codefile, "/* NULL */\n"); 497 constructed = 0; 498 break; 499 default: 500 abort (); 501 } 502 return constructed; 503 } 504 505 void 506 generate_type_encode (const Symbol *s) 507 { 508 fprintf (codefile, "int ASN1CALL\n" 509 "encode_%s(unsigned char *p HEIMDAL_UNUSED_ATTRIBUTE, size_t len HEIMDAL_UNUSED_ATTRIBUTE," 510 " const %s *data, size_t *size)\n" 511 "{\n", 512 s->gen_name, s->gen_name); 513 514 switch (s->type->type) { 515 case TInteger: 516 case TBoolean: 517 case TOctetString: 518 case TGeneralizedTime: 519 case TGeneralString: 520 case TTeletexString: 521 case TUTCTime: 522 case TUTF8String: 523 case TPrintableString: 524 case TIA5String: 525 case TBMPString: 526 case TUniversalString: 527 case TVisibleString: 528 case TNull: 529 case TBitString: 530 case TEnumerated: 531 case TOID: 532 case TSequence: 533 case TSequenceOf: 534 case TSet: 535 case TSetOf: 536 case TTag: 537 case TType: 538 case TChoice: 539 fprintf (codefile, 540 "size_t ret HEIMDAL_UNUSED_ATTRIBUTE = 0;\n" 541 "size_t l HEIMDAL_UNUSED_ATTRIBUTE;\n" 542 "int i HEIMDAL_UNUSED_ATTRIBUTE, e HEIMDAL_UNUSED_ATTRIBUTE;\n\n"); 543 544 encode_type("data", s->type, "Top"); 545 546 fprintf (codefile, "*size = ret;\n" 547 "return 0;\n"); 548 break; 549 default: 550 abort (); 551 } 552 fprintf (codefile, "}\n\n"); 553 } 554