No empty .Rs/.Re
[netbsd-mini2440.git] / crypto / dist / heimdal / lib / asn1 / gen_encode.c
blobb93f90562552320fb2b697f74117029ae2607367
1 /*
2 * Copyright (c) 1997 - 2006 Kungliga Tekniska Högskolan
3 * (Royal Institute of Technology, Stockholm, Sweden).
4 * All rights reserved.
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
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.
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.
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.
34 #include "gen_locl.h"
36 __RCSID("$Heimdal: gen_encode.c 22429 2008-01-13 10:25:50Z lha $"
37 "$NetBSD$");
39 static void
40 encode_primitive (const char *typename, const char *name)
42 fprintf (codefile,
43 "e = der_put_%s(p, len, %s, &l);\n"
44 "if (e) return e;\np -= l; len -= l; ret += l;\n\n",
45 typename,
46 name);
49 const char *
50 classname(Der_class class)
52 const char *cn[] = { "ASN1_C_UNIV", "ASN1_C_APPL",
53 "ASN1_C_CONTEXT", "ASN1_C_PRIV" };
54 if(class < ASN1_C_UNIV || class > ASN1_C_PRIVATE)
55 return "???";
56 return cn[class];
60 const char *
61 valuename(Der_class class, int value)
63 static char s[32];
64 struct {
65 int value;
66 const char *s;
67 } *p, values[] = {
68 #define X(Y) { Y, #Y }
69 X(UT_BMPString),
70 X(UT_BitString),
71 X(UT_Boolean),
72 X(UT_EmbeddedPDV),
73 X(UT_Enumerated),
74 X(UT_External),
75 X(UT_GeneralString),
76 X(UT_GeneralizedTime),
77 X(UT_GraphicString),
78 X(UT_IA5String),
79 X(UT_Integer),
80 X(UT_Null),
81 X(UT_NumericString),
82 X(UT_OID),
83 X(UT_ObjectDescriptor),
84 X(UT_OctetString),
85 X(UT_PrintableString),
86 X(UT_Real),
87 X(UT_RelativeOID),
88 X(UT_Sequence),
89 X(UT_Set),
90 X(UT_TeletexString),
91 X(UT_UTCTime),
92 X(UT_UTF8String),
93 X(UT_UniversalString),
94 X(UT_VideotexString),
95 X(UT_VisibleString),
96 #undef X
97 { -1, NULL }
99 if(class == ASN1_C_UNIV) {
100 for(p = values; p->value != -1; p++)
101 if(p->value == value)
102 return p->s;
104 snprintf(s, sizeof(s), "%d", value);
105 return s;
108 static int
109 encode_type (const char *name, const Type *t, const char *tmpstr)
111 int constructed = 1;
113 switch (t->type) {
114 case TType:
115 #if 0
116 encode_type (name, t->symbol->type);
117 #endif
118 fprintf (codefile,
119 "e = encode_%s(p, len, %s, &l);\n"
120 "if (e) return e;\np -= l; len -= l; ret += l;\n\n",
121 t->symbol->gen_name, name);
122 break;
123 case TInteger:
124 if(t->members) {
125 fprintf(codefile,
126 "{\n"
127 "int enumint = (int)*%s;\n",
128 name);
129 encode_primitive ("integer", "&enumint");
130 fprintf(codefile, "}\n;");
131 } else if (t->range == NULL) {
132 encode_primitive ("heim_integer", name);
133 } else if (t->range->min == INT_MIN && t->range->max == INT_MAX) {
134 encode_primitive ("integer", name);
135 } else if (t->range->min == 0 && t->range->max == UINT_MAX) {
136 encode_primitive ("unsigned", name);
137 } else if (t->range->min == 0 && t->range->max == INT_MAX) {
138 encode_primitive ("unsigned", name);
139 } else
140 errx(1, "%s: unsupported range %d -> %d",
141 name, t->range->min, t->range->max);
142 constructed = 0;
143 break;
144 case TBoolean:
145 encode_primitive ("boolean", name);
146 constructed = 0;
147 break;
148 case TOctetString:
149 encode_primitive ("octet_string", name);
150 constructed = 0;
151 break;
152 case TBitString: {
153 Member *m;
154 int pos;
156 if (ASN1_TAILQ_EMPTY(t->members)) {
157 encode_primitive("bit_string", name);
158 constructed = 0;
159 break;
162 fprintf (codefile, "{\n"
163 "unsigned char c = 0;\n");
164 if (!rfc1510_bitstring)
165 fprintf (codefile,
166 "int rest = 0;\n"
167 "int bit_set = 0;\n");
168 #if 0
169 pos = t->members->prev->val;
170 /* fix for buggy MIT (and OSF?) code */
171 if (pos > 31)
172 abort ();
173 #endif
175 * It seems that if we do not always set pos to 31 here, the MIT
176 * code will do the wrong thing.
178 * I hate ASN.1 (and DER), but I hate it even more when everybody
179 * has to screw it up differently.
181 pos = ASN1_TAILQ_LAST(t->members, memhead)->val;
182 if (rfc1510_bitstring) {
183 if (pos < 31)
184 pos = 31;
187 ASN1_TAILQ_FOREACH_REVERSE(m, t->members, memhead, members) {
188 while (m->val / 8 < pos / 8) {
189 if (!rfc1510_bitstring)
190 fprintf (codefile,
191 "if (c != 0 || bit_set) {\n");
192 fprintf (codefile,
193 "if (len < 1) return ASN1_OVERFLOW;\n"
194 "*p-- = c; len--; ret++;\n");
195 if (!rfc1510_bitstring)
196 fprintf (codefile,
197 "if (!bit_set) {\n"
198 "rest = 0;\n"
199 "while(c) { \n"
200 "if (c & 1) break;\n"
201 "c = c >> 1;\n"
202 "rest++;\n"
203 "}\n"
204 "bit_set = 1;\n"
205 "}\n"
206 "}\n");
207 fprintf (codefile,
208 "c = 0;\n");
209 pos -= 8;
211 fprintf (codefile,
212 "if((%s)->%s) {\n"
213 "c |= 1<<%d;\n",
214 name, m->gen_name, 7 - m->val % 8);
215 fprintf (codefile,
216 "}\n");
219 if (!rfc1510_bitstring)
220 fprintf (codefile,
221 "if (c != 0 || bit_set) {\n");
222 fprintf (codefile,
223 "if (len < 1) return ASN1_OVERFLOW;\n"
224 "*p-- = c; len--; ret++;\n");
225 if (!rfc1510_bitstring)
226 fprintf (codefile,
227 "if (!bit_set) {\n"
228 "rest = 0;\n"
229 "if(c) { \n"
230 "while(c) { \n"
231 "if (c & 1) break;\n"
232 "c = c >> 1;\n"
233 "rest++;\n"
234 "}\n"
235 "}\n"
236 "}\n"
237 "}\n");
239 fprintf (codefile,
240 "if (len < 1) return ASN1_OVERFLOW;\n"
241 "*p-- = %s;\n"
242 "len -= 1;\n"
243 "ret += 1;\n"
244 "}\n\n",
245 rfc1510_bitstring ? "0" : "rest");
246 constructed = 0;
247 break;
249 case TEnumerated : {
250 encode_primitive ("enumerated", name);
251 constructed = 0;
252 break;
255 case TSet:
256 case TSequence: {
257 Member *m;
259 if (t->members == NULL)
260 break;
262 ASN1_TAILQ_FOREACH_REVERSE(m, t->members, memhead, members) {
263 char *s;
265 if (m->ellipsis)
266 continue;
268 asprintf (&s, "%s(%s)->%s", m->optional ? "" : "&", name, m->gen_name);
269 if (s == NULL)
270 errx(1, "malloc");
271 fprintf(codefile, "/* %s */\n", m->name);
272 if (m->optional)
273 fprintf (codefile,
274 "if(%s) ",
276 else if(m->defval)
277 gen_compare_defval(s + 1, m->defval);
278 fprintf (codefile, "{\n");
279 fprintf (codefile, "size_t %s_oldret = ret;\n", tmpstr);
280 fprintf (codefile, "ret = 0;\n");
281 encode_type (s, m->type, m->gen_name);
282 fprintf (codefile, "ret += %s_oldret;\n", tmpstr);
283 fprintf (codefile, "}\n");
284 free (s);
286 break;
288 case TSetOf: {
290 fprintf(codefile,
291 "{\n"
292 "struct heim_octet_string *val;\n"
293 "size_t elen, totallen = 0;\n"
294 "int eret;\n");
296 fprintf(codefile,
297 "if ((%s)->len > UINT_MAX/sizeof(val[0]))\n"
298 "return ERANGE;\n",
299 name);
301 fprintf(codefile,
302 "val = malloc(sizeof(val[0]) * (%s)->len);\n"
303 "if (val == NULL && (%s)->len != 0) return ENOMEM;\n",
304 name, name);
306 fprintf(codefile,
307 "for(i = 0; i < (%s)->len; i++) {\n",
308 name);
310 fprintf(codefile,
311 "ASN1_MALLOC_ENCODE(%s, val[i].data, "
312 "val[i].length, &(%s)->val[i], &elen, eret);\n",
313 t->subtype->symbol->gen_name,
314 name);
316 fprintf(codefile,
317 "if(eret) {\n"
318 "i--;\n"
319 "while (i >= 0) {\n"
320 "free(val[i].data);\n"
321 "i--;\n"
322 "}\n"
323 "free(val);\n"
324 "return eret;\n"
325 "}\n"
326 "totallen += elen;\n"
327 "}\n");
329 fprintf(codefile,
330 "if (totallen > len) {\n"
331 "for (i = 0; i < (%s)->len; i++) {\n"
332 "free(val[i].data);\n"
333 "}\n"
334 "free(val);\n"
335 "return ASN1_OVERFLOW;\n"
336 "}\n",
337 name);
339 fprintf(codefile,
340 "qsort(val, (%s)->len, sizeof(val[0]), _heim_der_set_sort);\n",
341 name);
343 fprintf (codefile,
344 "for(i = (%s)->len - 1; i >= 0; --i) {\n"
345 "p -= val[i].length;\n"
346 "ret += val[i].length;\n"
347 "memcpy(p + 1, val[i].data, val[i].length);\n"
348 "free(val[i].data);\n"
349 "}\n"
350 "free(val);\n"
351 "}\n",
352 name);
353 break;
355 case TSequenceOf: {
356 char *n;
357 char *sname;
359 fprintf (codefile,
360 "for(i = (%s)->len - 1; i >= 0; --i) {\n"
361 "size_t %s_for_oldret = ret;\n"
362 "ret = 0;\n",
363 name, tmpstr);
364 asprintf (&n, "&(%s)->val[i]", name);
365 if (n == NULL)
366 errx(1, "malloc");
367 asprintf (&sname, "%s_S_Of", tmpstr);
368 if (sname == NULL)
369 errx(1, "malloc");
370 encode_type (n, t->subtype, sname);
371 fprintf (codefile,
372 "ret += %s_for_oldret;\n"
373 "}\n",
374 tmpstr);
375 free (n);
376 free (sname);
377 break;
379 case TGeneralizedTime:
380 encode_primitive ("generalized_time", name);
381 constructed = 0;
382 break;
383 case TGeneralString:
384 encode_primitive ("general_string", name);
385 constructed = 0;
386 break;
387 case TTag: {
388 char *tname;
389 int c;
390 asprintf (&tname, "%s_tag", tmpstr);
391 if (tname == NULL)
392 errx(1, "malloc");
393 c = encode_type (name, t->subtype, tname);
394 fprintf (codefile,
395 "e = der_put_length_and_tag (p, len, ret, %s, %s, %s, &l);\n"
396 "if (e) return e;\np -= l; len -= l; ret += l;\n\n",
397 classname(t->tag.tagclass),
398 c ? "CONS" : "PRIM",
399 valuename(t->tag.tagclass, t->tag.tagvalue));
400 free (tname);
401 break;
403 case TChoice:{
404 Member *m, *have_ellipsis = NULL;
405 char *s;
407 if (t->members == NULL)
408 break;
410 fprintf(codefile, "\n");
412 asprintf (&s, "(%s)", name);
413 if (s == NULL)
414 errx(1, "malloc");
415 fprintf(codefile, "switch(%s->element) {\n", s);
417 ASN1_TAILQ_FOREACH_REVERSE(m, t->members, memhead, members) {
418 char *s2;
420 if (m->ellipsis) {
421 have_ellipsis = m;
422 continue;
425 fprintf (codefile, "case %s: {", m->label);
426 asprintf(&s2, "%s(%s)->u.%s", m->optional ? "" : "&",
427 s, m->gen_name);
428 if (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);
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);
460 fprintf(codefile, "};\n");
461 break;
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 ();
502 return constructed;
505 void
506 generate_type_encode (const Symbol *s)
508 fprintf (headerfile,
509 "int "
510 "encode_%s(unsigned char *, size_t, const %s *, size_t *);\n",
511 s->gen_name, s->gen_name);
513 fprintf (codefile, "int\n"
514 "encode_%s(unsigned char *p, size_t len,"
515 " const %s *data, size_t *size)\n"
516 "{\n",
517 s->gen_name, s->gen_name);
519 switch (s->type->type) {
520 case TInteger:
521 case TBoolean:
522 case TOctetString:
523 case TGeneralizedTime:
524 case TGeneralString:
525 case TUTCTime:
526 case TUTF8String:
527 case TPrintableString:
528 case TIA5String:
529 case TBMPString:
530 case TUniversalString:
531 case TVisibleString:
532 case TNull:
533 case TBitString:
534 case TEnumerated:
535 case TOID:
536 case TSequence:
537 case TSequenceOf:
538 case TSet:
539 case TSetOf:
540 case TTag:
541 case TType:
542 case TChoice:
543 fprintf (codefile,
544 "size_t ret = 0;\n"
545 "size_t l;\n"
546 "int i, e;\n\n");
547 fprintf(codefile, "i = 0;\n"); /* hack to avoid `unused variable' */
549 encode_type("data", s->type, "Top");
551 fprintf (codefile, "*size = ret;\n"
552 "return 0;\n");
553 break;
554 default:
555 abort ();
557 fprintf (codefile, "}\n\n");