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)
40 288 : {
41 288 : 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 288 : }
47 :
48 : const char *
49 : classname(Der_class class)
50 2061 : {
51 : const char *cn[] = { "ASN1_C_UNIV", "ASN1_C_APPL",
52 2061 : "ASN1_C_CONTEXT", "ASN1_C_PRIV" };
53 2061 : if(class < ASN1_C_UNIV || class > ASN1_C_PRIVATE)
54 0 : return "???";
55 2061 : return cn[class];
56 : }
57 :
58 :
59 : const char *
60 : valuename(Der_class class, int value)
61 2061 : {
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 2061 : };
98 2061 : if(class == ASN1_C_UNIV) {
99 16616 : for(p = values; p->value != -1; p++)
100 16616 : if(p->value == value)
101 1014 : return p->s;
102 : }
103 1047 : snprintf(s, sizeof(s), "%d", value);
104 1047 : return s;
105 : }
106 :
107 : static int
108 : encode_type (const char *name, const Type *t, const char *tmpstr)
109 2007 : {
110 2007 : int constructed = 1;
111 :
112 2007 : switch (t->type) {
113 : case TType:
114 : #if 0
115 : encode_type (name, t->symbol->type);
116 : #endif
117 444 : 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 444 : break;
122 : case TInteger:
123 83 : 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 67 : } else if (t->range == NULL) {
131 35 : encode_primitive ("heim_integer", name);
132 39 : } else if (t->range->min == INT_MIN && t->range->max == INT_MAX) {
133 7 : encode_primitive ("integer", name);
134 50 : } else if (t->range->min == 0 && t->range->max == UINT_MAX) {
135 25 : 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 : name, t->range->min, t->range->max);
141 83 : constructed = 0;
142 83 : 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 99 : ASN1_TAILQ_FOREACH_REVERSE(m, t->members, memhead, members) {
187 197 : while (m->val / 8 < pos / 8) {
188 19 : if (!rfc1510_bitstring)
189 4 : fprintf (codefile,
190 : "if (c != 0 || bit_set) {\n");
191 19 : fprintf (codefile,
192 : "if (len < 1) return ASN1_OVERFLOW;\n"
193 : "*p-- = c; len--; ret++;\n");
194 19 : if (!rfc1510_bitstring)
195 4 : 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 19 : fprintf (codefile,
207 : "c = 0;\n");
208 19 : pos -= 8;
209 : }
210 89 : fprintf (codefile,
211 : "if((%s)->%s) {\n"
212 : "c |= 1<<%d;\n",
213 : name, m->gen_name, 7 - m->val % 8);
214 89 : 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 : 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 168 : if (t->members == NULL)
259 0 : break;
260 :
261 795 : ASN1_TAILQ_FOREACH_REVERSE(m, t->members, memhead, members) {
262 : char *s;
263 :
264 627 : if (m->ellipsis)
265 26 : continue;
266 :
267 601 : asprintf (&s, "%s(%s)->%s", m->optional ? "" : "&", name, m->gen_name);
268 601 : if (s == NULL)
269 0 : errx(1, "malloc");
270 601 : fprintf(codefile, "/* %s */\n", m->name);
271 601 : if (m->optional)
272 228 : fprintf (codefile,
273 : "if(%s) ",
274 : s);
275 373 : else if(m->defval)
276 0 : gen_compare_defval(s + 1, m->defval);
277 601 : fprintf (codefile, "{\n");
278 601 : fprintf (codefile, "size_t %s_oldret = ret;\n", tmpstr);
279 601 : fprintf (codefile, "ret = 0;\n");
280 601 : encode_type (s, m->type, m->gen_name);
281 601 : fprintf (codefile, "ret += %s_oldret;\n", tmpstr);
282 601 : fprintf (codefile, "}\n");
283 601 : free (s);
284 : }
285 168 : break;
286 : }
287 : case TSetOf: {
288 :
289 18 : fprintf(codefile,
290 : "{\n"
291 : "struct heim_octet_string *val;\n"
292 : "size_t elen, totallen = 0;\n"
293 : "int eret;\n");
294 :
295 18 : fprintf(codefile,
296 : "if ((%s)->len > UINT_MAX/sizeof(val[0]))\n"
297 : "return ERANGE;\n",
298 : name);
299 :
300 18 : 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 18 : fprintf(codefile,
306 : "for(i = 0; i < (%s)->len; i++) {\n",
307 : name);
308 :
309 18 : 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 18 : 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 18 : 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 18 : fprintf(codefile,
339 : "qsort(val, (%s)->len, sizeof(val[0]), _heim_der_set_sort);\n",
340 : name);
341 :
342 18 : 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 18 : break;
353 : }
354 : case TSequenceOf: {
355 : char *n;
356 : char *sname;
357 :
358 54 : 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 54 : asprintf (&n, "&(%s)->val[i]", name);
364 54 : if (n == NULL)
365 0 : errx(1, "malloc");
366 54 : asprintf (&sname, "%s_S_Of", tmpstr);
367 54 : if (sname == NULL)
368 0 : errx(1, "malloc");
369 54 : encode_type (n, t->subtype, sname);
370 54 : fprintf (codefile,
371 : "ret += %s_for_oldret;\n"
372 : "}\n",
373 : tmpstr);
374 54 : free (n);
375 54 : free (sname);
376 54 : break;
377 : }
378 : case TGeneralizedTime:
379 6 : encode_primitive ("generalized_time", name);
380 6 : constructed = 0;
381 6 : break;
382 : case TGeneralString:
383 14 : encode_primitive ("general_string", name);
384 14 : constructed = 0;
385 14 : break;
386 : case TTeletexString:
387 1 : encode_primitive ("general_string", name);
388 1 : constructed = 0;
389 1 : break;
390 : case TTag: {
391 : char *tname;
392 : int c;
393 1002 : asprintf (&tname, "%s_tag", tmpstr);
394 1002 : if (tname == NULL)
395 0 : errx(1, "malloc");
396 1002 : c = encode_type (name, t->subtype, tname);
397 1002 : fprintf (codefile,
398 : "e = der_put_length_and_tag (p, len, ret, %s, %s, %s, &l);\n"
399 : "if (e) return e;\np -= l; len -= l; ret += l;\n\n",
400 : classname(t->tag.tagclass),
401 : c ? "CONS" : "PRIM",
402 : valuename(t->tag.tagclass, t->tag.tagvalue));
403 1002 : free (tname);
404 1002 : break;
405 : }
406 : case TChoice:{
407 20 : Member *m, *have_ellipsis = NULL;
408 : char *s;
409 :
410 20 : if (t->members == NULL)
411 0 : break;
412 :
413 20 : fprintf(codefile, "\n");
414 :
415 20 : asprintf (&s, "(%s)", name);
416 20 : if (s == NULL)
417 0 : errx(1, "malloc");
418 20 : fprintf(codefile, "switch(%s->element) {\n", s);
419 :
420 82 : ASN1_TAILQ_FOREACH_REVERSE(m, t->members, memhead, members) {
421 : char *s2;
422 :
423 62 : if (m->ellipsis) {
424 5 : have_ellipsis = m;
425 5 : continue;
426 : }
427 :
428 57 : fprintf (codefile, "case %s: {", m->label);
429 57 : asprintf(&s2, "%s(%s)->u.%s", m->optional ? "" : "&",
430 : s, m->gen_name);
431 57 : if (s2 == NULL)
432 0 : errx(1, "malloc");
433 57 : if (m->optional)
434 0 : fprintf (codefile, "if(%s) {\n", s2);
435 57 : fprintf (codefile, "size_t %s_oldret = ret;\n", tmpstr);
436 57 : fprintf (codefile, "ret = 0;\n");
437 57 : constructed = encode_type (s2, m->type, m->gen_name);
438 57 : fprintf (codefile, "ret += %s_oldret;\n", tmpstr);
439 57 : if(m->optional)
440 0 : fprintf (codefile, "}\n");
441 57 : fprintf(codefile, "break;\n");
442 57 : fprintf(codefile, "}\n");
443 57 : free (s2);
444 : }
445 20 : free (s);
446 20 : if (have_ellipsis) {
447 5 : fprintf(codefile,
448 : "case %s: {\n"
449 : "if (len < (%s)->u.%s.length)\n"
450 : "return ASN1_OVERFLOW;\n"
451 : "p -= (%s)->u.%s.length;\n"
452 : "ret += (%s)->u.%s.length;\n"
453 : "memcpy(p + 1, (%s)->u.%s.data, (%s)->u.%s.length);\n"
454 : "break;\n"
455 : "}\n",
456 : have_ellipsis->label,
457 : name, have_ellipsis->gen_name,
458 : name, have_ellipsis->gen_name,
459 : name, have_ellipsis->gen_name,
460 : name, have_ellipsis->gen_name,
461 : name, have_ellipsis->gen_name);
462 : }
463 20 : fprintf(codefile, "};\n");
464 20 : break;
465 : }
466 : case TOID:
467 19 : encode_primitive ("oid", name);
468 19 : constructed = 0;
469 19 : break;
470 : case TUTCTime:
471 1 : encode_primitive ("utctime", name);
472 1 : constructed = 0;
473 1 : break;
474 : case TUTF8String:
475 39 : encode_primitive ("utf8string", name);
476 39 : constructed = 0;
477 39 : break;
478 : case TPrintableString:
479 1 : encode_primitive ("printable_string", name);
480 1 : constructed = 0;
481 1 : break;
482 : case TIA5String:
483 4 : encode_primitive ("ia5_string", name);
484 4 : constructed = 0;
485 4 : break;
486 : case TBMPString:
487 2 : encode_primitive ("bmp_string", name);
488 2 : constructed = 0;
489 2 : break;
490 : case TUniversalString:
491 1 : encode_primitive ("universal_string", name);
492 1 : constructed = 0;
493 1 : break;
494 : case TVisibleString:
495 1 : encode_primitive ("visible_string", name);
496 1 : constructed = 0;
497 1 : break;
498 : case TNull:
499 3 : fprintf (codefile, "/* NULL */\n");
500 3 : constructed = 0;
501 3 : break;
502 : default:
503 0 : abort ();
504 : }
505 2007 : return constructed;
506 : }
507 :
508 : void
509 : generate_type_encode (const Symbol *s)
510 293 : {
511 293 : fprintf (codefile, "int\n"
512 : "encode_%s(unsigned char *p, size_t len,"
513 : " const %s *data, size_t *size)\n"
514 : "{\n",
515 : s->gen_name, s->gen_name);
516 :
517 293 : switch (s->type->type) {
518 : case TInteger:
519 : case TBoolean:
520 : case TOctetString:
521 : case TGeneralizedTime:
522 : case TGeneralString:
523 : case TTeletexString:
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 293 : fprintf (codefile,
543 : "size_t ret = 0;\n"
544 : "size_t l;\n"
545 : "int i, e;\n\n");
546 293 : fprintf(codefile, "i = 0;\n"); /* hack to avoid `unused variable' */
547 :
548 293 : encode_type("data", s->type, "Top");
549 :
550 293 : fprintf (codefile, "*size = ret;\n"
551 : "return 0;\n");
552 : break;
553 : default:
554 0 : abort ();
555 : }
556 293 : fprintf (codefile, "}\n\n");
557 293 : }
|