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
36static void
37encode_primitive (const char *typename, const char *name)
38{
39    fprintf (codefile,
40	     "e = der_put_%s(p, len, %s, &l);\n"
41	     "if (e) return e;\np -= l; len -= l; ret += l;\n\n",
42	     typename,
43	     name);
44}
45
46const char *
47classname(Der_class class)
48{
49    const char *cn[] = { "ASN1_C_UNIV", "ASN1_C_APPL",
50			 "ASN1_C_CONTEXT", "ASN1_C_PRIV" };
51    if ((size_t)class >= sizeof(cn) / sizeof(cn[0]))
52	return "???";
53    return cn[class];
54}
55
56
57const char *
58valuename(Der_class class, int value)
59{
60    static char s[32];
61    struct {
62	int value;
63	const char *s;
64    } *p, values[] = {
65#define X(Y) { Y, #Y }
66	X(UT_BMPString),
67	X(UT_BitString),
68	X(UT_Boolean),
69	X(UT_EmbeddedPDV),
70	X(UT_Enumerated),
71	X(UT_External),
72	X(UT_GeneralString),
73	X(UT_GeneralizedTime),
74	X(UT_GraphicString),
75	X(UT_IA5String),
76	X(UT_Integer),
77	X(UT_Null),
78	X(UT_NumericString),
79	X(UT_OID),
80	X(UT_ObjectDescriptor),
81	X(UT_OctetString),
82	X(UT_PrintableString),
83	X(UT_Real),
84	X(UT_RelativeOID),
85	X(UT_Sequence),
86	X(UT_Set),
87	X(UT_TeletexString),
88	X(UT_UTCTime),
89	X(UT_UTF8String),
90	X(UT_UniversalString),
91	X(UT_VideotexString),
92	X(UT_VisibleString),
93#undef X
94	{ -1, NULL }
95    };
96    if(class == ASN1_C_UNIV) {
97	for(p = values; p->value != -1; p++)
98	    if(p->value == value)
99		return p->s;
100    }
101    snprintf(s, sizeof(s), "%d", value);
102    return s;
103}
104
105static int
106encode_type (const char *name, const Type *t, const char *tmpstr)
107{
108    int constructed = 1;
109
110    switch (t->type) {
111    case TType:
112#if 0
113	encode_type (name, t->symbol->type);
114#endif
115	fprintf (codefile,
116		 "e = encode_%s(p, len, %s, &l);\n"
117		 "if (e) return e;\np -= l; len -= l; ret += l;\n\n",
118		 t->symbol->gen_name, name);
119	break;
120    case TInteger:
121	if(t->members) {
122	    fprintf(codefile,
123		    "{\n"
124		    "int enumint = (int)*%s;\n",
125		    name);
126	    encode_primitive ("integer", "&enumint");
127	    fprintf(codefile, "}\n;");
128	} else if (t->range == NULL) {
129	    encode_primitive ("heim_integer", name);
130	} else if (t->range->min == INT_MIN && t->range->max == INT_MAX) {
131	    encode_primitive ("integer", name);
132	} else if (t->range->min == 0 && (unsigned int)t->range->max == UINT_MAX) {
133	    encode_primitive ("unsigned", name);
134	} else if (t->range->min == 0 && t->range->max == INT_MAX) {
135	    encode_primitive ("unsigned", name);
136	} else
137	    errx(1, "%s: unsupported range %d -> %d",
138		 name, t->range->min, t->range->max);
139	constructed = 0;
140	break;
141    case TBoolean:
142	encode_primitive ("boolean", name);
143	constructed = 0;
144	break;
145    case TOctetString:
146	encode_primitive ("octet_string", name);
147	constructed = 0;
148	break;
149    case TBitString: {
150	Member *m;
151	int pos;
152
153	if (ASN1_TAILQ_EMPTY(t->members)) {
154	    encode_primitive("bit_string", name);
155	    constructed = 0;
156	    break;
157	}
158
159	fprintf (codefile, "{\n"
160		 "unsigned char c = 0;\n");
161	if (!rfc1510_bitstring)
162	    fprintf (codefile,
163		     "int rest = 0;\n"
164		     "int bit_set = 0;\n");
165#if 0
166	pos = t->members->prev->val;
167	/* fix for buggy MIT (and OSF?) code */
168	if (pos > 31)
169	    abort ();
170#endif
171	/*
172	 * It seems that if we do not always set pos to 31 here, the MIT
173	 * code will do the wrong thing.
174	 *
175	 * I hate ASN.1 (and DER), but I hate it even more when everybody
176	 * has to screw it up differently.
177	 */
178	pos = ASN1_TAILQ_LAST(t->members, memhead)->val;
179	if (rfc1510_bitstring) {
180	    if (pos < 31)
181		pos = 31;
182	}
183
184	ASN1_TAILQ_FOREACH_REVERSE(m, t->members, memhead, members) {
185	    while (m->val / 8 < pos / 8) {
186		if (!rfc1510_bitstring)
187		    fprintf (codefile,
188			     "if (c != 0 || bit_set) {\n");
189		fprintf (codefile,
190			 "if (len < 1) return ASN1_OVERFLOW;\n"
191			 "*p-- = c; len--; ret++;\n");
192		if (!rfc1510_bitstring)
193		    fprintf (codefile,
194			     "if (!bit_set) {\n"
195			     "rest = 0;\n"
196			     "while(c) { \n"
197			     "if (c & 1) break;\n"
198			     "c = c >> 1;\n"
199			     "rest++;\n"
200			     "}\n"
201			     "bit_set = 1;\n"
202			     "}\n"
203			     "}\n");
204		fprintf (codefile,
205			 "c = 0;\n");
206		pos -= 8;
207	    }
208	    fprintf (codefile,
209		     "if((%s)->%s) {\n"
210		     "c |= 1<<%d;\n",
211		     name, m->gen_name, 7 - m->val % 8);
212	    fprintf (codefile,
213		     "}\n");
214	}
215
216	if (!rfc1510_bitstring)
217	    fprintf (codefile,
218		     "if (c != 0 || bit_set) {\n");
219	fprintf (codefile,
220		 "if (len < 1) return ASN1_OVERFLOW;\n"
221		 "*p-- = c; len--; ret++;\n");
222	if (!rfc1510_bitstring)
223	    fprintf (codefile,
224		     "if (!bit_set) {\n"
225		     "rest = 0;\n"
226		     "if(c) { \n"
227		     "while(c) { \n"
228		     "if (c & 1) break;\n"
229		     "c = c >> 1;\n"
230		     "rest++;\n"
231		     "}\n"
232		     "}\n"
233		     "}\n"
234		     "}\n");
235
236	fprintf (codefile,
237		 "if (len < 1) return ASN1_OVERFLOW;\n"
238		 "*p-- = %s;\n"
239		 "len -= 1;\n"
240		 "ret += 1;\n"
241		 "}\n\n",
242		 rfc1510_bitstring ? "0" : "rest");
243	constructed = 0;
244	break;
245    }
246    case TEnumerated : {
247	encode_primitive ("enumerated", name);
248	constructed = 0;
249	break;
250    }
251
252    case TSet:
253    case TSequence: {
254	Member *m;
255
256	if (t->members == NULL)
257	    break;
258
259	ASN1_TAILQ_FOREACH_REVERSE(m, t->members, memhead, members) {
260	    char *s = NULL;
261
262	    if (m->ellipsis)
263		continue;
264
265	    if (asprintf (&s, "%s(%s)->%s", m->optional ? "" : "&", name, m->gen_name) < 0 || s == NULL)
266		errx(1, "malloc");
267	    fprintf(codefile, "/* %s */\n", m->name);
268	    if (m->optional)
269		fprintf (codefile,
270			 "if(%s) ",
271			 s);
272	    else if(m->defval)
273		gen_compare_defval(s + 1, m->defval);
274	    fprintf (codefile, "{\n");
275	    fprintf (codefile, "size_t %s_oldret HEIMDAL_UNUSED_ATTRIBUTE = ret;\n", tmpstr);
276	    fprintf (codefile, "ret = 0;\n");
277	    encode_type (s, m->type, m->gen_name);
278	    fprintf (codefile, "ret += %s_oldret;\n", tmpstr);
279	    fprintf (codefile, "}\n");
280	    free (s);
281	}
282	break;
283    }
284    case TSetOf: {
285
286	fprintf(codefile,
287		"{\n"
288		"heim_octet_string *val;\n"
289		"size_t elen = 0, totallen = 0;\n"
290		"int eret = 0;\n");
291
292	fprintf(codefile,
293		"if ((%s)->len > UINT_MAX/sizeof(val[0]))\n"
294		"return ERANGE;\n",
295		name);
296
297	fprintf(codefile,
298		"val = malloc(sizeof(val[0]) * (%s)->len);\n"
299		"if (val == NULL && (%s)->len != 0) return ENOMEM;\n",
300		name, name);
301
302	fprintf(codefile,
303		"for(i = 0; i < (int)(%s)->len; i++) {\n",
304		name);
305
306	fprintf(codefile,
307		"ASN1_MALLOC_ENCODE(%s, val[i].data, "
308		"val[i].length, &(%s)->val[i], &elen, eret);\n",
309		t->subtype->symbol->gen_name,
310		name);
311
312	fprintf(codefile,
313		"if(eret) {\n"
314		"i--;\n"
315		"while (i >= 0) {\n"
316		"free(val[i].data);\n"
317		"i--;\n"
318		"}\n"
319		"free(val);\n"
320		"return eret;\n"
321		"}\n"
322		"totallen += elen;\n"
323		"}\n");
324
325	fprintf(codefile,
326		"if (totallen > len) {\n"
327		"for (i = 0; i < (int)(%s)->len; i++) {\n"
328		"free(val[i].data);\n"
329		"}\n"
330		"free(val);\n"
331		"return ASN1_OVERFLOW;\n"
332		"}\n",
333		name);
334
335	fprintf(codefile,
336		"qsort(val, (%s)->len, sizeof(val[0]), _heim_der_set_sort);\n",
337		name);
338
339	fprintf (codefile,
340		 "for(i = (int)(%s)->len - 1; i >= 0; --i) {\n"
341		 "p -= val[i].length;\n"
342		 "ret += val[i].length;\n"
343		 "memcpy(p + 1, val[i].data, val[i].length);\n"
344		 "free(val[i].data);\n"
345		 "}\n"
346		 "free(val);\n"
347		 "}\n",
348		 name);
349	break;
350    }
351    case TSequenceOf: {
352	char *sname = NULL;
353	char *n = NULL;
354
355	fprintf (codefile,
356		 "for(i = (int)(%s)->len - 1; i >= 0; --i) {\n"
357		 "size_t %s_for_oldret = ret;\n"
358		 "ret = 0;\n",
359		 name, tmpstr);
360	if (asprintf (&n, "&(%s)->val[i]", name) < 0 || n == NULL)
361	    errx(1, "malloc");
362	if (asprintf (&sname, "%s_S_Of", tmpstr) < 0 || sname == NULL)
363	    errx(1, "malloc");
364	encode_type (n, t->subtype, sname);
365	fprintf (codefile,
366		 "ret += %s_for_oldret;\n"
367		 "}\n",
368		 tmpstr);
369	free (n);
370	free (sname);
371	break;
372    }
373    case TGeneralizedTime:
374	encode_primitive ("generalized_time", name);
375	constructed = 0;
376	break;
377    case TGeneralString:
378	encode_primitive ("general_string", name);
379	constructed = 0;
380	break;
381    case TTeletexString:
382	encode_primitive ("general_string", name);
383	constructed = 0;
384	break;
385    case TTag: {
386    	char *tname = NULL;
387	int c;
388	if (asprintf (&tname, "%s_tag", tmpstr) < 0 || tname == NULL)
389	    errx(1, "malloc");
390	c = encode_type (name, t->subtype, tname);
391	fprintf (codefile,
392		 "e = der_put_length_and_tag (p, len, ret, %s, %s, %s, &l);\n"
393		 "if (e) return e;\np -= l; len -= l; ret += l;\n\n",
394		 classname(t->tag.tagclass),
395		 c ? "CONS" : "PRIM",
396		 valuename(t->tag.tagclass, t->tag.tagvalue));
397	free (tname);
398	break;
399    }
400    case TChoice:{
401	Member *m, *have_ellipsis = NULL;
402	char *s = NULL;
403
404	if (t->members == NULL)
405	    break;
406
407	fprintf(codefile, "\n");
408
409	if (asprintf (&s, "(%s)", name) < 0 || s == NULL)
410	    errx(1, "malloc");
411	fprintf(codefile, "switch(%s->element) {\n", s);
412
413	fprintf(codefile,
414		"case ASN1_CHOICE_INVALID: ret = ASN1_INVALID_CHOICE;\nbreak;\n");
415
416	ASN1_TAILQ_FOREACH_REVERSE(m, t->members, memhead, members) {
417	    char *s2 = NULL;
418
419	    if (m->ellipsis) {
420		have_ellipsis = m;
421		continue;
422	    }
423
424	    fprintf (codefile, "case %s: {", m->label);
425	    if (asprintf(&s2, "%s(%s)->u.%s", m->optional ? "" : "&",
426			 s, m->gen_name) < 0 || s2 == NULL)
427		errx(1, "malloc");
428	    if (m->optional)
429		fprintf (codefile, "if(%s) {\n", s2);
430	    fprintf (codefile, "size_t %s_oldret = ret;\n", tmpstr);
431	    fprintf (codefile, "ret = 0;\n");
432	    constructed = encode_type (s2, m->type, m->gen_name);
433	    fprintf (codefile, "ret += %s_oldret;\n", tmpstr);
434	    if(m->optional)
435		fprintf (codefile, "}\n");
436	    fprintf(codefile, "break;\n");
437	    fprintf(codefile, "}\n");
438	    free (s2);
439	}
440	free (s);
441	if (have_ellipsis) {
442	    fprintf(codefile,
443		    "case %s: {\n"
444		    "if (len < (%s)->u.%s.length)\n"
445		    "return ASN1_OVERFLOW;\n"
446		    "p -= (%s)->u.%s.length;\n"
447		    "ret += (%s)->u.%s.length;\n"
448		    "memcpy(p + 1, (%s)->u.%s.data, (%s)->u.%s.length);\n"
449		    "break;\n"
450		    "}\n",
451		    have_ellipsis->label,
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		    name, have_ellipsis->gen_name);
457	}
458	fprintf(codefile, "};\n");
459	break;
460    }
461    case TOID:
462	encode_primitive ("oid", name);
463	constructed = 0;
464	break;
465    case TUTCTime:
466	encode_primitive ("utctime", name);
467	constructed = 0;
468	break;
469    case TUTF8String:
470	encode_primitive ("utf8string", name);
471	constructed = 0;
472	break;
473    case TPrintableString:
474	encode_primitive ("printable_string", name);
475	constructed = 0;
476	break;
477    case TIA5String:
478	encode_primitive ("ia5_string", name);
479	constructed = 0;
480	break;
481    case TBMPString:
482	encode_primitive ("bmp_string", name);
483	constructed = 0;
484	break;
485    case TUniversalString:
486	encode_primitive ("universal_string", name);
487	constructed = 0;
488	break;
489    case TVisibleString:
490	encode_primitive ("visible_string", name);
491	constructed = 0;
492	break;
493    case TNull:
494	fprintf (codefile, "/* NULL */\n");
495	constructed = 0;
496	break;
497    }
498    return constructed;
499}
500
501void
502generate_type_encode (const Symbol *s)
503{
504    fprintf (codefile, "int ASN1CALL\n"
505	     "encode_%s(unsigned char *p HEIMDAL_UNUSED_ATTRIBUTE, size_t len HEIMDAL_UNUSED_ATTRIBUTE,"
506	     " const %s *data, size_t *size)\n"
507	     "{\n",
508	     s->gen_name, s->gen_name);
509
510    switch (s->type->type) {
511    case TInteger:
512    case TBoolean:
513    case TOctetString:
514    case TGeneralizedTime:
515    case TGeneralString:
516    case TTeletexString:
517    case TUTCTime:
518    case TUTF8String:
519    case TPrintableString:
520    case TIA5String:
521    case TBMPString:
522    case TUniversalString:
523    case TVisibleString:
524    case TNull:
525    case TBitString:
526    case TEnumerated:
527    case TOID:
528    case TSequence:
529    case TSequenceOf:
530    case TSet:
531    case TSetOf:
532    case TTag:
533    case TType:
534    case TChoice:
535	fprintf (codefile,
536		 "size_t ret HEIMDAL_UNUSED_ATTRIBUTE = 0;\n"
537		 "size_t l HEIMDAL_UNUSED_ATTRIBUTE;\n"
538		 "int i HEIMDAL_UNUSED_ATTRIBUTE, e HEIMDAL_UNUSED_ATTRIBUTE;\n\n");
539
540	encode_type("data", s->type, "Top");
541
542	fprintf (codefile, "*size = ret;\n"
543		 "return 0;\n");
544	break;
545    }
546    fprintf (codefile, "}\n\n");
547}
548