Branch data Line data Source code
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 : 294 : encode_primitive (const char *typename, const char *name)
40 : : {
41 : 294 : 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 : 294 : }
47 : :
48 : : const char *
49 : 2089 : classname(Der_class class)
50 : : {
51 : : const char *cn[] = { "ASN1_C_UNIV", "ASN1_C_APPL",
52 : 2089 : "ASN1_C_CONTEXT", "ASN1_C_PRIV" };
53 [ - + ]: 2089 : if(class < ASN1_C_UNIV || class > ASN1_C_PRIVATE)
54 : 0 : return "???";
55 : 2089 : return cn[class];
56 : : }
57 : :
58 : :
59 : : const char *
60 : 2089 : 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 : 2089 : };
98 [ + + ]: 2089 : if(class == ASN1_C_UNIV) {
99 [ + - ]: 16814 : for(p = values; p->value != -1; p++)
100 [ + + ]: 16814 : if(p->value == value)
101 : 1028 : return p->s;
102 : : }
103 : 1061 : snprintf(s, sizeof(s), "%d", value);
104 : 2089 : return s;
105 : : }
106 : :
107 : : static int
108 : 2030 : encode_type (const char *name, const Type *t, const char *tmpstr)
109 : : {
110 : 2030 : int constructed = 1;
111 : :
112 [ + + + + : 2030 : switch (t->type) {
+ - + + +
+ + + + +
+ + + + +
+ + + +
- ]
113 : : case TType:
114 : : #if 0
115 : : encode_type (name, t->symbol->type);
116 : : #endif
117 : 448 : 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 : 448 : t->symbol->gen_name, name);
121 : 448 : break;
122 : : case TInteger:
123 [ + + ]: 88 : if(t->members) {
124 : 16 : fprintf(codefile,
125 : : "{\n"
126 : : "int enumint = (int)*%s;\n",
127 : : name);
128 : 16 : encode_primitive ("integer", "&enumint");
129 : 16 : fprintf(codefile, "}\n;");
130 [ + + ]: 72 : } else if (t->range == NULL) {
131 : 38 : encode_primitive ("heim_integer", name);
132 [ + + ][ + - ]: 41 : } else if (t->range->min == INT_MIN && t->range->max == INT_MAX) {
133 : 7 : encode_primitive ("integer", name);
134 [ + - ][ + - ]: 54 : } else if (t->range->min == 0 && t->range->max == UINT_MAX) {
135 : 27 : encode_primitive ("unsigned", name);
136 [ # # ][ # # ]: 0 : } else if (t->range->min == 0 && t->range->max == INT_MAX) {
137 : 0 : encode_primitive ("unsigned", name);
138 : : } else
139 : 0 : errx(1, "%s: unsupported range %d -> %d",
140 : 0 : name, t->range->min, t->range->max);
141 : 88 : constructed = 0;
142 : 88 : break;
143 : : case TBoolean:
144 : 8 : encode_primitive ("boolean", name);
145 : 8 : constructed = 0;
146 : 8 : break;
147 : : case TOctetString:
148 : 96 : encode_primitive ("octet_string", name);
149 : 96 : constructed = 0;
150 : 96 : break;
151 : : case TBitString: {
152 : : Member *m;
153 : : int pos;
154 : :
155 [ + + ]: 22 : if (ASN1_TAILQ_EMPTY(t->members)) {
156 : 12 : encode_primitive("bit_string", name);
157 : 12 : constructed = 0;
158 : 12 : break;
159 : : }
160 : :
161 : 10 : fprintf (codefile, "{\n"
162 : : "unsigned char c = 0;\n");
163 [ + + ]: 10 : if (!rfc1510_bitstring)
164 : 5 : 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 : 10 : pos = ASN1_TAILQ_LAST(t->members, memhead)->val;
181 [ + + ]: 10 : if (rfc1510_bitstring) {
182 [ + + ]: 5 : if (pos < 31)
183 : 4 : pos = 31;
184 : : }
185 : :
186 [ + + ]: 101 : ASN1_TAILQ_FOREACH_REVERSE(m, t->members, memhead, members) {
187 [ + + ]: 111 : while (m->val / 8 < pos / 8) {
188 [ + + ]: 20 : if (!rfc1510_bitstring)
189 : 5 : fprintf (codefile,
190 : : "if (c != 0 || bit_set) {\n");
191 : 20 : fprintf (codefile,
192 : : "if (len < 1) return ASN1_OVERFLOW;\n"
193 : : "*p-- = c; len--; ret++;\n");
194 [ + + ]: 20 : if (!rfc1510_bitstring)
195 : 5 : 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 : 20 : fprintf (codefile,
207 : : "c = 0;\n");
208 : 20 : pos -= 8;
209 : : }
210 : 91 : fprintf (codefile,
211 : : "if((%s)->%s) {\n"
212 : : "c |= 1<<%d;\n",
213 : 91 : name, m->gen_name, 7 - m->val % 8);
214 : 91 : fprintf (codefile,
215 : : "}\n");
216 : : }
217 : :
218 [ + + ]: 10 : if (!rfc1510_bitstring)
219 : 5 : fprintf (codefile,
220 : : "if (c != 0 || bit_set) {\n");
221 : 10 : fprintf (codefile,
222 : : "if (len < 1) return ASN1_OVERFLOW;\n"
223 : : "*p-- = c; len--; ret++;\n");
224 [ + + ]: 10 : if (!rfc1510_bitstring)
225 : 5 : 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 [ + + ]: 10 : 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 : 10 : rfc1510_bitstring ? "0" : "rest");
245 : 10 : constructed = 0;
246 : 10 : break;
247 : : }
248 : : case TEnumerated : {
249 : 0 : encode_primitive ("enumerated", name);
250 : 0 : constructed = 0;
251 : 0 : break;
252 : : }
253 : :
254 : : case TSet:
255 : : case TSequence: {
256 : : Member *m;
257 : :
258 [ - + ]: 169 : if (t->members == NULL)
259 : 0 : break;
260 : :
261 [ + + ]: 801 : ASN1_TAILQ_FOREACH_REVERSE(m, t->members, memhead, members) {
262 : 632 : char *s = NULL;
263 : :
264 [ + + ]: 632 : if (m->ellipsis)
265 : 27 : continue;
266 : :
267 [ + + ][ + - ]: 605 : if (asprintf (&s, "%s(%s)->%s", m->optional ? "" : "&", name, m->gen_name) < 0 || s == NULL)
[ - + ]
268 : 0 : errx(1, "malloc");
269 : 605 : fprintf(codefile, "/* %s */\n", m->name);
270 [ + + ]: 605 : if (m->optional)
271 : 230 : fprintf (codefile,
272 : : "if(%s) ",
273 : : s);
274 [ - + ]: 375 : else if(m->defval)
275 : 0 : gen_compare_defval(s + 1, m->defval);
276 : 605 : fprintf (codefile, "{\n");
277 : 605 : fprintf (codefile, "size_t %s_oldret HEIMDAL_UNUSED_ATTRIBUTE = ret;\n", tmpstr);
278 : 605 : fprintf (codefile, "ret = 0;\n");
279 : 605 : encode_type (s, m->type, m->gen_name);
280 : 605 : fprintf (codefile, "ret += %s_oldret;\n", tmpstr);
281 : 605 : fprintf (codefile, "}\n");
282 : 605 : free (s);
283 : : }
284 : 169 : break;
285 : : }
286 : : case TSetOf: {
287 : :
288 : 18 : fprintf(codefile,
289 : : "{\n"
290 : : "struct heim_octet_string *val;\n"
291 : : "size_t elen = 0, totallen = 0;\n"
292 : : "int eret = 0;\n");
293 : :
294 : 18 : fprintf(codefile,
295 : : "if ((%s)->len > UINT_MAX/sizeof(val[0]))\n"
296 : : "return ERANGE;\n",
297 : : name);
298 : :
299 : 18 : fprintf(codefile,
300 : : "val = malloc(sizeof(val[0]) * (%s)->len);\n"
301 : : "if (val == NULL && (%s)->len != 0) return ENOMEM;\n",
302 : : name, name);
303 : :
304 : 18 : fprintf(codefile,
305 : : "for(i = 0; i < (int)(%s)->len; i++) {\n",
306 : : name);
307 : :
308 : 18 : fprintf(codefile,
309 : : "ASN1_MALLOC_ENCODE(%s, val[i].data, "
310 : : "val[i].length, &(%s)->val[i], &elen, eret);\n",
311 : 18 : t->subtype->symbol->gen_name,
312 : : name);
313 : :
314 : 18 : fprintf(codefile,
315 : : "if(eret) {\n"
316 : : "i--;\n"
317 : : "while (i >= 0) {\n"
318 : : "free(val[i].data);\n"
319 : : "i--;\n"
320 : : "}\n"
321 : : "free(val);\n"
322 : : "return eret;\n"
323 : : "}\n"
324 : : "totallen += elen;\n"
325 : : "}\n");
326 : :
327 : 18 : fprintf(codefile,
328 : : "if (totallen > len) {\n"
329 : : "for (i = 0; i < (int)(%s)->len; i++) {\n"
330 : : "free(val[i].data);\n"
331 : : "}\n"
332 : : "free(val);\n"
333 : : "return ASN1_OVERFLOW;\n"
334 : : "}\n",
335 : : name);
336 : :
337 : 18 : fprintf(codefile,
338 : : "qsort(val, (%s)->len, sizeof(val[0]), _heim_der_set_sort);\n",
339 : : name);
340 : :
341 : 18 : fprintf (codefile,
342 : : "for(i = (int)(%s)->len - 1; i >= 0; --i) {\n"
343 : : "p -= val[i].length;\n"
344 : : "ret += val[i].length;\n"
345 : : "memcpy(p + 1, val[i].data, val[i].length);\n"
346 : : "free(val[i].data);\n"
347 : : "}\n"
348 : : "free(val);\n"
349 : : "}\n",
350 : : name);
351 : 18 : break;
352 : : }
353 : : case TSequenceOf: {
354 : 54 : char *sname = NULL;
355 : 54 : char *n = NULL;
356 : :
357 : 54 : fprintf (codefile,
358 : : "for(i = (int)(%s)->len - 1; i >= 0; --i) {\n"
359 : : "size_t %s_for_oldret = ret;\n"
360 : : "ret = 0;\n",
361 : : name, tmpstr);
362 [ + - ][ - + ]: 54 : if (asprintf (&n, "&(%s)->val[i]", name) < 0 || n == NULL)
363 : 0 : errx(1, "malloc");
364 [ + - ][ - + ]: 54 : if (asprintf (&sname, "%s_S_Of", tmpstr) < 0 || sname == NULL)
365 : 0 : errx(1, "malloc");
366 : 54 : encode_type (n, t->subtype, sname);
367 : 54 : fprintf (codefile,
368 : : "ret += %s_for_oldret;\n"
369 : : "}\n",
370 : : tmpstr);
371 : 54 : free (n);
372 : 54 : free (sname);
373 : 54 : break;
374 : : }
375 : : case TGeneralizedTime:
376 : 6 : encode_primitive ("generalized_time", name);
377 : 6 : constructed = 0;
378 : 6 : break;
379 : : case TGeneralString:
380 : 14 : encode_primitive ("general_string", name);
381 : 14 : constructed = 0;
382 : 14 : break;
383 : : case TTeletexString:
384 : 1 : encode_primitive ("general_string", name);
385 : 1 : constructed = 0;
386 : 1 : break;
387 : : case TTag: {
388 : 1014 : char *tname = NULL;
389 : : int c;
390 [ + - ][ - + ]: 1014 : if (asprintf (&tname, "%s_tag", tmpstr) < 0 || tname == NULL)
391 : 0 : errx(1, "malloc");
392 : 1014 : c = encode_type (name, t->subtype, tname);
393 [ + + ]: 1014 : 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 : 1014 : classname(t->tag.tagclass),
397 : : c ? "CONS" : "PRIM",
398 : 1014 : valuename(t->tag.tagclass, t->tag.tagvalue));
399 : 1014 : free (tname);
400 : 1014 : break;
401 : : }
402 : : case TChoice:{
403 : 20 : Member *m, *have_ellipsis = NULL;
404 : 20 : char *s = NULL;
405 : :
406 [ - + ]: 20 : if (t->members == NULL)
407 : 0 : break;
408 : :
409 : 20 : fprintf(codefile, "\n");
410 : :
411 [ + - ][ - + ]: 20 : if (asprintf (&s, "(%s)", name) < 0 || s == NULL)
412 : 0 : errx(1, "malloc");
413 : 20 : fprintf(codefile, "switch(%s->element) {\n", s);
414 : :
415 [ + + ]: 86 : ASN1_TAILQ_FOREACH_REVERSE(m, t->members, memhead, members) {
416 : 66 : char *s2 = NULL;
417 : :
418 [ + + ]: 66 : if (m->ellipsis) {
419 : 5 : have_ellipsis = m;
420 : 5 : continue;
421 : : }
422 : :
423 : 61 : fprintf (codefile, "case %s: {", m->label);
424 [ + - ][ - + ]: 61 : if (asprintf(&s2, "%s(%s)->u.%s", m->optional ? "" : "&",
425 [ - + ]: 61 : s, m->gen_name) < 0 || s2 == NULL)
426 : 0 : errx(1, "malloc");
427 [ - + ]: 61 : if (m->optional)
428 : 0 : fprintf (codefile, "if(%s) {\n", s2);
429 : 61 : fprintf (codefile, "size_t %s_oldret = ret;\n", tmpstr);
430 : 61 : fprintf (codefile, "ret = 0;\n");
431 : 61 : constructed = encode_type (s2, m->type, m->gen_name);
432 : 61 : fprintf (codefile, "ret += %s_oldret;\n", tmpstr);
433 [ - + ]: 61 : if(m->optional)
434 : 0 : fprintf (codefile, "}\n");
435 : 61 : fprintf(codefile, "break;\n");
436 : 61 : fprintf(codefile, "}\n");
437 : 61 : free (s2);
438 : : }
439 : 20 : free (s);
440 [ + + ]: 20 : if (have_ellipsis) {
441 : 5 : fprintf(codefile,
442 : : "case %s: {\n"
443 : : "if (len < (%s)->u.%s.length)\n"
444 : : "return ASN1_OVERFLOW;\n"
445 : : "p -= (%s)->u.%s.length;\n"
446 : : "ret += (%s)->u.%s.length;\n"
447 : : "memcpy(p + 1, (%s)->u.%s.data, (%s)->u.%s.length);\n"
448 : : "break;\n"
449 : : "}\n",
450 : : have_ellipsis->label,
451 : : name, have_ellipsis->gen_name,
452 : : name, have_ellipsis->gen_name,
453 : : name, have_ellipsis->gen_name,
454 : : name, have_ellipsis->gen_name,
455 : : name, have_ellipsis->gen_name);
456 : : }
457 : 20 : fprintf(codefile, "};\n");
458 : 20 : break;
459 : : }
460 : : case TOID:
461 : 19 : encode_primitive ("oid", name);
462 : 19 : constructed = 0;
463 : 19 : break;
464 : : case TUTCTime:
465 : 1 : encode_primitive ("utctime", name);
466 : 1 : constructed = 0;
467 : 1 : break;
468 : : case TUTF8String:
469 : 40 : encode_primitive ("utf8string", name);
470 : 40 : constructed = 0;
471 : 40 : break;
472 : : case TPrintableString:
473 : 1 : encode_primitive ("printable_string", name);
474 : 1 : constructed = 0;
475 : 1 : break;
476 : : case TIA5String:
477 : 4 : encode_primitive ("ia5_string", name);
478 : 4 : constructed = 0;
479 : 4 : break;
480 : : case TBMPString:
481 : 2 : encode_primitive ("bmp_string", name);
482 : 2 : constructed = 0;
483 : 2 : break;
484 : : case TUniversalString:
485 : 1 : encode_primitive ("universal_string", name);
486 : 1 : constructed = 0;
487 : 1 : break;
488 : : case TVisibleString:
489 : 1 : encode_primitive ("visible_string", name);
490 : 1 : constructed = 0;
491 : 1 : break;
492 : : case TNull:
493 : 3 : fprintf (codefile, "/* NULL */\n");
494 : 3 : constructed = 0;
495 : 3 : break;
496 : : default:
497 : 0 : abort ();
498 : : }
499 : 2030 : return constructed;
500 : : }
501 : :
502 : : void
503 : 296 : generate_type_encode (const Symbol *s)
504 : : {
505 : 296 : fprintf (codefile, "int ASN1CALL\n"
506 : : "encode_%s(unsigned char *p HEIMDAL_UNUSED_ATTRIBUTE, size_t len HEIMDAL_UNUSED_ATTRIBUTE,"
507 : : " const %s *data, size_t *size)\n"
508 : : "{\n",
509 : : s->gen_name, s->gen_name);
510 : :
511 [ + - ]: 296 : switch (s->type->type) {
512 : : case TInteger:
513 : : case TBoolean:
514 : : case TOctetString:
515 : : case TGeneralizedTime:
516 : : case TGeneralString:
517 : : case TTeletexString:
518 : : case TUTCTime:
519 : : case TUTF8String:
520 : : case TPrintableString:
521 : : case TIA5String:
522 : : case TBMPString:
523 : : case TUniversalString:
524 : : case TVisibleString:
525 : : case TNull:
526 : : case TBitString:
527 : : case TEnumerated:
528 : : case TOID:
529 : : case TSequence:
530 : : case TSequenceOf:
531 : : case TSet:
532 : : case TSetOf:
533 : : case TTag:
534 : : case TType:
535 : : case TChoice:
536 : 296 : fprintf (codefile,
537 : : "size_t ret HEIMDAL_UNUSED_ATTRIBUTE = 0;\n"
538 : : "size_t l HEIMDAL_UNUSED_ATTRIBUTE;\n"
539 : : "int i HEIMDAL_UNUSED_ATTRIBUTE, e HEIMDAL_UNUSED_ATTRIBUTE;\n\n");
540 : :
541 : 296 : encode_type("data", s->type, "Top");
542 : :
543 : 296 : fprintf (codefile, "*size = ret;\n"
544 : : "return 0;\n");
545 : : break;
546 : : default:
547 : 0 : abort ();
548 : : }
549 : 296 : fprintf (codefile, "}\n\n");
550 : 296 : }
|