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
encode_primitive(const char * typename,const char * name)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 *
classname(Der_class class)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 *
valuename(Der_class class,int value)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
encode_type(const char * name,const Type * t,const char * tmpstr)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
generate_type_encode(const Symbol * s)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