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
36RCSID("$Id: gen_encode.c 22429 2008-01-13 10:25:50Z lha $");
37
38static void
39encode_primitive (const char *typename, const char *name)
40{
41    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}
47
48const char *
49classname(Der_class class)
50{
51    const char *cn[] = { "ASN1_C_UNIV", "ASN1_C_APPL",
52			 "ASN1_C_CONTEXT", "ASN1_C_PRIV" };
53    if(class < ASN1_C_UNIV || class > ASN1_C_PRIVATE)
54	return "???";
55    return cn[class];
56}
57
58
59const char *
60valuename(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    };
98    if(class == ASN1_C_UNIV) {
99	for(p = values; p->value != -1; p++)
100	    if(p->value == value)
101		return p->s;
102    }
103    snprintf(s, sizeof(s), "%d", value);
104    return s;
105}
106
107static int
108encode_type (const char *name, const Type *t, const char *tmpstr)
109{
110    int constructed = 1;
111
112    switch (t->type) {
113    case TType:
114#if 0
115	encode_type (name, t->symbol->type);
116#endif
117	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	break;
122    case TInteger:
123	if(t->members) {
124	    fprintf(codefile,
125		    "{\n"
126		    "int enumint = (int)*%s;\n",
127		    name);
128	    encode_primitive ("integer", "&enumint");
129	    fprintf(codefile, "}\n;");
130	} else if (t->range == NULL) {
131	    encode_primitive ("heim_integer", name);
132	} else if (t->range->min == INT_MIN && t->range->max == INT_MAX) {
133	    encode_primitive ("integer", name);
134	} else if (t->range->min == 0 && t->range->max == UINT_MAX) {
135	    encode_primitive ("unsigned", name);
136	} else if (t->range->min == 0 && t->range->max == INT_MAX) {
137	    encode_primitive ("unsigned", name);
138	} else
139	    errx(1, "%s: unsupported range %d -> %d",
140		 name, t->range->min, t->range->max);
141	constructed = 0;
142	break;
143    case TBoolean:
144	encode_primitive ("boolean", name);
145	constructed = 0;
146	break;
147    case TOctetString:
148	encode_primitive ("octet_string", name);
149	constructed = 0;
150	break;
151    case TBitString: {
152	Member *m;
153	int pos;
154
155	if (ASN1_TAILQ_EMPTY(t->members)) {
156	    encode_primitive("bit_string", name);
157	    constructed = 0;
158	    break;
159	}
160
161	fprintf (codefile, "{\n"
162		 "unsigned char c = 0;\n");
163	if (!rfc1510_bitstring)
164	    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	pos = ASN1_TAILQ_LAST(t->members, memhead)->val;
181	if (rfc1510_bitstring) {
182	    if (pos < 31)
183		pos = 31;
184	}
185
186	ASN1_TAILQ_FOREACH_REVERSE(m, t->members, memhead, members) {
187	    while (m->val / 8 < pos / 8) {
188		if (!rfc1510_bitstring)
189		    fprintf (codefile,
190			     "if (c != 0 || bit_set) {\n");
191		fprintf (codefile,
192			 "if (len < 1) return ASN1_OVERFLOW;\n"
193			 "*p-- = c; len--; ret++;\n");
194		if (!rfc1510_bitstring)
195		    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		fprintf (codefile,
207			 "c = 0;\n");
208		pos -= 8;
209	    }
210	    fprintf (codefile,
211		     "if((%s)->%s) {\n"
212		     "c |= 1<<%d;\n",
213		     name, m->gen_name, 7 - m->val % 8);
214	    fprintf (codefile,
215		     "}\n");
216	}
217
218	if (!rfc1510_bitstring)
219	    fprintf (codefile,
220		     "if (c != 0 || bit_set) {\n");
221	fprintf (codefile,
222		 "if (len < 1) return ASN1_OVERFLOW;\n"
223		 "*p-- = c; len--; ret++;\n");
224	if (!rfc1510_bitstring)
225	    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	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	constructed = 0;
246	break;
247    }
248    case TEnumerated : {
249	encode_primitive ("enumerated", name);
250	constructed = 0;
251	break;
252    }
253
254    case TSet:
255    case TSequence: {
256	Member *m;
257
258	if (t->members == NULL)
259	    break;
260
261	ASN1_TAILQ_FOREACH_REVERSE(m, t->members, memhead, members) {
262	    char *s;
263
264	    if (m->ellipsis)
265		continue;
266
267	    asprintf (&s, "%s(%s)->%s", m->optional ? "" : "&", name, m->gen_name);
268	    if (s == NULL)
269		errx(1, "malloc");
270	    fprintf(codefile, "/* %s */\n", m->name);
271	    if (m->optional)
272		fprintf (codefile,
273			 "if(%s) ",
274			 s);
275	    else if(m->defval)
276		gen_compare_defval(s + 1, m->defval);
277	    fprintf (codefile, "{\n");
278	    fprintf (codefile, "size_t %s_oldret = ret;\n", tmpstr);
279	    fprintf (codefile, "ret = 0;\n");
280	    encode_type (s, m->type, m->gen_name);
281	    fprintf (codefile, "ret += %s_oldret;\n", tmpstr);
282	    fprintf (codefile, "}\n");
283	    free (s);
284	}
285	break;
286    }
287    case TSetOf: {
288
289	fprintf(codefile,
290		"{\n"
291		"struct heim_octet_string *val;\n"
292		"size_t elen, totallen = 0;\n"
293		"int eret;\n");
294
295	fprintf(codefile,
296		"if ((%s)->len > UINT_MAX/sizeof(val[0]))\n"
297		"return ERANGE;\n",
298		name);
299
300	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	fprintf(codefile,
306		"for(i = 0; i < (%s)->len; i++) {\n",
307		name);
308
309	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	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	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	fprintf(codefile,
339		"qsort(val, (%s)->len, sizeof(val[0]), _heim_der_set_sort);\n",
340		name);
341
342	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	break;
353    }
354    case TSequenceOf: {
355	char *n;
356	char *sname;
357
358	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	asprintf (&n, "&(%s)->val[i]", name);
364	if (n == NULL)
365	    errx(1, "malloc");
366	asprintf (&sname, "%s_S_Of", tmpstr);
367	if (sname == NULL)
368	    errx(1, "malloc");
369	encode_type (n, t->subtype, sname);
370	fprintf (codefile,
371		 "ret += %s_for_oldret;\n"
372		 "}\n",
373		 tmpstr);
374	free (n);
375	free (sname);
376	break;
377    }
378    case TGeneralizedTime:
379	encode_primitive ("generalized_time", name);
380	constructed = 0;
381	break;
382    case TGeneralString:
383	encode_primitive ("general_string", name);
384	constructed = 0;
385	break;
386    case TTag: {
387    	char *tname;
388	int c;
389	asprintf (&tname, "%s_tag", tmpstr);
390	if (tname == NULL)
391	    errx(1, "malloc");
392	c = encode_type (name, t->subtype, tname);
393	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		 classname(t->tag.tagclass),
397		 c ? "CONS" : "PRIM",
398		 valuename(t->tag.tagclass, t->tag.tagvalue));
399	free (tname);
400	break;
401    }
402    case TChoice:{
403	Member *m, *have_ellipsis = NULL;
404	char *s;
405
406	if (t->members == NULL)
407	    break;
408
409	fprintf(codefile, "\n");
410
411	asprintf (&s, "(%s)", name);
412	if (s == NULL)
413	    errx(1, "malloc");
414	fprintf(codefile, "switch(%s->element) {\n", s);
415
416	ASN1_TAILQ_FOREACH_REVERSE(m, t->members, memhead, members) {
417	    char *s2;
418
419	    if (m->ellipsis) {
420		have_ellipsis = m;
421		continue;
422	    }
423
424	    fprintf (codefile, "case %s: {", m->label);
425	    asprintf(&s2, "%s(%s)->u.%s", m->optional ? "" : "&",
426		     s, m->gen_name);
427	    if (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);
440	}
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);
458	}
459	fprintf(codefile, "};\n");
460	break;
461    }
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 ();
500    }
501    return constructed;
502}
503
504void
505generate_type_encode (const Symbol *s)
506{
507    fprintf (headerfile,
508	     "int    "
509	     "encode_%s(unsigned char *, size_t, const %s *, size_t *);\n",
510	     s->gen_name, s->gen_name);
511
512    fprintf (codefile, "int\n"
513	     "encode_%s(unsigned char *p, size_t len,"
514	     " const %s *data, size_t *size)\n"
515	     "{\n",
516	     s->gen_name, s->gen_name);
517
518    switch (s->type->type) {
519    case TInteger:
520    case TBoolean:
521    case TOctetString:
522    case TGeneralizedTime:
523    case TGeneralString:
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	fprintf (codefile,
543		 "size_t ret = 0;\n"
544		 "size_t l;\n"
545		 "int i, e;\n\n");
546	fprintf(codefile, "i = 0;\n"); /* hack to avoid `unused variable' */
547
548	encode_type("data", s->type, "Top");
549
550	fprintf (codefile, "*size = ret;\n"
551		 "return 0;\n");
552	break;
553    default:
554	abort ();
555    }
556    fprintf (codefile, "}\n\n");
557}
558