root/source4/heimdal/lib/asn1/gen_encode.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. encode_primitive
  2. classname
  3. valuename
  4. encode_type
  5. generate_type_encode

   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)
     /* [<][>][^][v][top][bottom][index][help] */
  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)
     /* [<][>][^][v][top][bottom][index][help] */
  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)
     /* [<][>][^][v][top][bottom][index][help] */
  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)
     /* [<][>][^][v][top][bottom][index][help] */
 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)
     /* [<][>][^][v][top][bottom][index][help] */
 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 }

/* [<][>][^][v][top][bottom][index][help] */