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