etc/services - sync with NetBSD-8
[minix.git] / crypto / external / bsd / heimdal / dist / lib / asn1 / gen_encode.c
blob6b0d5a081b31722631cde767efbd8d5e4ae2cc0f
1 /* $NetBSD: gen_encode.c,v 1.1.1.2 2014/04/24 12:45:28 pettai Exp $ */
3 /*
4 * Copyright (c) 1997 - 2006 Kungliga Tekniska Högskolan
5 * (Royal Institute of Technology, Stockholm, Sweden).
6 * All rights reserved.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
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.
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.
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.
36 #include "gen_locl.h"
38 __RCSID("NetBSD");
40 static void
41 encode_primitive (const char *typename, const char *name)
43 fprintf (codefile,
44 "e = der_put_%s(p, len, %s, &l);\n"
45 "if (e) return e;\np -= l; len -= l; ret += l;\n\n",
46 typename,
47 name);
50 const char *
51 classname(Der_class class)
53 const char *cn[] = { "ASN1_C_UNIV", "ASN1_C_APPL",
54 "ASN1_C_CONTEXT", "ASN1_C_PRIV" };
55 if(class < ASN1_C_UNIV || class > ASN1_C_PRIVATE)
56 return "???";
57 return cn[class];
61 const char *
62 valuename(Der_class class, int value)
64 static char s[32];
65 struct {
66 int value;
67 const char *s;
68 } *p, values[] = {
69 #define X(Y) { Y, #Y }
70 X(UT_BMPString),
71 X(UT_BitString),
72 X(UT_Boolean),
73 X(UT_EmbeddedPDV),
74 X(UT_Enumerated),
75 X(UT_External),
76 X(UT_GeneralString),
77 X(UT_GeneralizedTime),
78 X(UT_GraphicString),
79 X(UT_IA5String),
80 X(UT_Integer),
81 X(UT_Null),
82 X(UT_NumericString),
83 X(UT_OID),
84 X(UT_ObjectDescriptor),
85 X(UT_OctetString),
86 X(UT_PrintableString),
87 X(UT_Real),
88 X(UT_RelativeOID),
89 X(UT_Sequence),
90 X(UT_Set),
91 X(UT_TeletexString),
92 X(UT_UTCTime),
93 X(UT_UTF8String),
94 X(UT_UniversalString),
95 X(UT_VideotexString),
96 X(UT_VisibleString),
97 #undef X
98 { -1, NULL }
100 if(class == ASN1_C_UNIV) {
101 for(p = values; p->value != -1; p++)
102 if(p->value == value)
103 return p->s;
105 snprintf(s, sizeof(s), "%d", value);
106 return s;
109 static int
110 encode_type (const char *name, const Type *t, const char *tmpstr)
112 int constructed = 1;
114 switch (t->type) {
115 case TType:
116 #if 0
117 encode_type (name, t->symbol->type);
118 #endif
119 fprintf (codefile,
120 "e = encode_%s(p, len, %s, &l);\n"
121 "if (e) return e;\np -= l; len -= l; ret += l;\n\n",
122 t->symbol->gen_name, name);
123 break;
124 case TInteger:
125 if(t->members) {
126 fprintf(codefile,
127 "{\n"
128 "int enumint = (int)*%s;\n",
129 name);
130 encode_primitive ("integer", "&enumint");
131 fprintf(codefile, "}\n;");
132 } else if (t->range == NULL) {
133 encode_primitive ("heim_integer", name);
134 } else if (t->range->min == INT_MIN && t->range->max == INT_MAX) {
135 encode_primitive ("integer", name);
136 } else if (t->range->min == 0 && t->range->max == UINT_MAX) {
137 encode_primitive ("unsigned", name);
138 } else if (t->range->min == 0 && t->range->max == INT_MAX) {
139 encode_primitive ("unsigned", name);
140 } else
141 errx(1, "%s: unsupported range %d -> %d",
142 name, t->range->min, t->range->max);
143 constructed = 0;
144 break;
145 case TBoolean:
146 encode_primitive ("boolean", name);
147 constructed = 0;
148 break;
149 case TOctetString:
150 encode_primitive ("octet_string", name);
151 constructed = 0;
152 break;
153 case TBitString: {
154 Member *m;
155 int pos;
157 if (ASN1_TAILQ_EMPTY(t->members)) {
158 encode_primitive("bit_string", name);
159 constructed = 0;
160 break;
163 fprintf (codefile, "{\n"
164 "unsigned char c = 0;\n");
165 if (!rfc1510_bitstring)
166 fprintf (codefile,
167 "int rest = 0;\n"
168 "int bit_set = 0;\n");
169 #if 0
170 pos = t->members->prev->val;
171 /* fix for buggy MIT (and OSF?) code */
172 if (pos > 31)
173 abort ();
174 #endif
176 * It seems that if we do not always set pos to 31 here, the MIT
177 * code will do the wrong thing.
179 * I hate ASN.1 (and DER), but I hate it even more when everybody
180 * has to screw it up differently.
182 pos = ASN1_TAILQ_LAST(t->members, memhead)->val;
183 if (rfc1510_bitstring) {
184 if (pos < 31)
185 pos = 31;
188 ASN1_TAILQ_FOREACH_REVERSE(m, t->members, memhead, members) {
189 while (m->val / 8 < pos / 8) {
190 if (!rfc1510_bitstring)
191 fprintf (codefile,
192 "if (c != 0 || bit_set) {\n");
193 fprintf (codefile,
194 "if (len < 1) return ASN1_OVERFLOW;\n"
195 "*p-- = c; len--; ret++;\n");
196 if (!rfc1510_bitstring)
197 fprintf (codefile,
198 "if (!bit_set) {\n"
199 "rest = 0;\n"
200 "while(c) { \n"
201 "if (c & 1) break;\n"
202 "c = c >> 1;\n"
203 "rest++;\n"
204 "}\n"
205 "bit_set = 1;\n"
206 "}\n"
207 "}\n");
208 fprintf (codefile,
209 "c = 0;\n");
210 pos -= 8;
212 fprintf (codefile,
213 "if((%s)->%s) {\n"
214 "c |= 1<<%d;\n",
215 name, m->gen_name, 7 - m->val % 8);
216 fprintf (codefile,
217 "}\n");
220 if (!rfc1510_bitstring)
221 fprintf (codefile,
222 "if (c != 0 || bit_set) {\n");
223 fprintf (codefile,
224 "if (len < 1) return ASN1_OVERFLOW;\n"
225 "*p-- = c; len--; ret++;\n");
226 if (!rfc1510_bitstring)
227 fprintf (codefile,
228 "if (!bit_set) {\n"
229 "rest = 0;\n"
230 "if(c) { \n"
231 "while(c) { \n"
232 "if (c & 1) break;\n"
233 "c = c >> 1;\n"
234 "rest++;\n"
235 "}\n"
236 "}\n"
237 "}\n"
238 "}\n");
240 fprintf (codefile,
241 "if (len < 1) return ASN1_OVERFLOW;\n"
242 "*p-- = %s;\n"
243 "len -= 1;\n"
244 "ret += 1;\n"
245 "}\n\n",
246 rfc1510_bitstring ? "0" : "rest");
247 constructed = 0;
248 break;
250 case TEnumerated : {
251 encode_primitive ("enumerated", name);
252 constructed = 0;
253 break;
256 case TSet:
257 case TSequence: {
258 Member *m;
260 if (t->members == NULL)
261 break;
263 ASN1_TAILQ_FOREACH_REVERSE(m, t->members, memhead, members) {
264 char *s = NULL;
266 if (m->ellipsis)
267 continue;
269 if (asprintf (&s, "%s(%s)->%s", m->optional ? "" : "&", name, m->gen_name) < 0 || 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 HEIMDAL_UNUSED_ATTRIBUTE = 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 = 0, totallen = 0;\n"
294 "int eret = 0;\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 < (int)(%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 < (int)(%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 = (int)(%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 *sname = NULL;
357 char *n = NULL;
359 fprintf (codefile,
360 "for(i = (int)(%s)->len - 1; i >= 0; --i) {\n"
361 "size_t %s_for_oldret = ret;\n"
362 "ret = 0;\n",
363 name, tmpstr);
364 if (asprintf (&n, "&(%s)->val[i]", name) < 0 || n == NULL)
365 errx(1, "malloc");
366 if (asprintf (&sname, "%s_S_Of", tmpstr) < 0 || sname == NULL)
367 errx(1, "malloc");
368 encode_type (n, t->subtype, sname);
369 fprintf (codefile,
370 "ret += %s_for_oldret;\n"
371 "}\n",
372 tmpstr);
373 free (n);
374 free (sname);
375 break;
377 case TGeneralizedTime:
378 encode_primitive ("generalized_time", name);
379 constructed = 0;
380 break;
381 case TGeneralString:
382 encode_primitive ("general_string", name);
383 constructed = 0;
384 break;
385 case TTeletexString:
386 encode_primitive ("general_string", name);
387 constructed = 0;
388 break;
389 case TTag: {
390 char *tname = NULL;
391 int c;
392 if (asprintf (&tname, "%s_tag", tmpstr) < 0 || tname == NULL)
393 errx(1, "malloc");
394 c = encode_type (name, t->subtype, tname);
395 fprintf (codefile,
396 "e = der_put_length_and_tag (p, len, ret, %s, %s, %s, &l);\n"
397 "if (e) return e;\np -= l; len -= l; ret += l;\n\n",
398 classname(t->tag.tagclass),
399 c ? "CONS" : "PRIM",
400 valuename(t->tag.tagclass, t->tag.tagvalue));
401 free (tname);
402 break;
404 case TChoice:{
405 Member *m, *have_ellipsis = NULL;
406 char *s = NULL;
408 if (t->members == NULL)
409 break;
411 fprintf(codefile, "\n");
413 if (asprintf (&s, "(%s)", name) < 0 || 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 = NULL;
420 if (m->ellipsis) {
421 have_ellipsis = m;
422 continue;
425 fprintf (codefile, "case %s: {", m->label);
426 if (asprintf(&s2, "%s(%s)->u.%s", m->optional ? "" : "&",
427 s, m->gen_name) < 0 || s2 == NULL)
428 errx(1, "malloc");
429 if (m->optional)
430 fprintf (codefile, "if(%s) {\n", s2);
431 fprintf (codefile, "size_t %s_oldret = ret;\n", tmpstr);
432 fprintf (codefile, "ret = 0;\n");
433 constructed = encode_type (s2, m->type, m->gen_name);
434 fprintf (codefile, "ret += %s_oldret;\n", tmpstr);
435 if(m->optional)
436 fprintf (codefile, "}\n");
437 fprintf(codefile, "break;\n");
438 fprintf(codefile, "}\n");
439 free (s2);
441 free (s);
442 if (have_ellipsis) {
443 fprintf(codefile,
444 "case %s: {\n"
445 "if (len < (%s)->u.%s.length)\n"
446 "return ASN1_OVERFLOW;\n"
447 "p -= (%s)->u.%s.length;\n"
448 "ret += (%s)->u.%s.length;\n"
449 "memcpy(p + 1, (%s)->u.%s.data, (%s)->u.%s.length);\n"
450 "break;\n"
451 "}\n",
452 have_ellipsis->label,
453 name, have_ellipsis->gen_name,
454 name, have_ellipsis->gen_name,
455 name, have_ellipsis->gen_name,
456 name, have_ellipsis->gen_name,
457 name, have_ellipsis->gen_name);
459 fprintf(codefile, "};\n");
460 break;
462 case TOID:
463 encode_primitive ("oid", name);
464 constructed = 0;
465 break;
466 case TUTCTime:
467 encode_primitive ("utctime", name);
468 constructed = 0;
469 break;
470 case TUTF8String:
471 encode_primitive ("utf8string", name);
472 constructed = 0;
473 break;
474 case TPrintableString:
475 encode_primitive ("printable_string", name);
476 constructed = 0;
477 break;
478 case TIA5String:
479 encode_primitive ("ia5_string", name);
480 constructed = 0;
481 break;
482 case TBMPString:
483 encode_primitive ("bmp_string", name);
484 constructed = 0;
485 break;
486 case TUniversalString:
487 encode_primitive ("universal_string", name);
488 constructed = 0;
489 break;
490 case TVisibleString:
491 encode_primitive ("visible_string", name);
492 constructed = 0;
493 break;
494 case TNull:
495 fprintf (codefile, "/* NULL */\n");
496 constructed = 0;
497 break;
498 default:
499 abort ();
501 return constructed;
504 void
505 generate_type_encode (const Symbol *s)
507 fprintf (codefile, "int ASN1CALL\n"
508 "encode_%s(unsigned char *p HEIMDAL_UNUSED_ATTRIBUTE, size_t len HEIMDAL_UNUSED_ATTRIBUTE,"
509 " const %s *data, size_t *size)\n"
510 "{\n",
511 s->gen_name, s->gen_name);
513 switch (s->type->type) {
514 case TInteger:
515 case TBoolean:
516 case TOctetString:
517 case TGeneralizedTime:
518 case TGeneralString:
519 case TTeletexString:
520 case TUTCTime:
521 case TUTF8String:
522 case TPrintableString:
523 case TIA5String:
524 case TBMPString:
525 case TUniversalString:
526 case TVisibleString:
527 case TNull:
528 case TBitString:
529 case TEnumerated:
530 case TOID:
531 case TSequence:
532 case TSequenceOf:
533 case TSet:
534 case TSetOf:
535 case TTag:
536 case TType:
537 case TChoice:
538 fprintf (codefile,
539 "size_t ret HEIMDAL_UNUSED_ATTRIBUTE = 0;\n"
540 "size_t l HEIMDAL_UNUSED_ATTRIBUTE;\n"
541 "int i HEIMDAL_UNUSED_ATTRIBUTE, e HEIMDAL_UNUSED_ATTRIBUTE;\n\n");
543 encode_type("data", s->type, "Top");
545 fprintf (codefile, "*size = ret;\n"
546 "return 0;\n");
547 break;
548 default:
549 abort ();
551 fprintf (codefile, "}\n\n");