xref: /freebsd/crypto/heimdal/lib/asn1/gen.c (revision 1e413cf93298b5b97441a21d9a50fdcd0ee9945e)
1 /*
2  * Copyright (c) 1997 - 2002 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: gen.c,v 1.50 2003/04/17 07:09:18 lha Exp $");
37 
38 FILE *headerfile, *codefile, *logfile;
39 
40 #define STEM "asn1"
41 
42 static const char *orig_filename;
43 static char *header;
44 static char *headerbase = STEM;
45 
46 /*
47  * list of all IMPORTs
48  */
49 
50 struct import {
51     const char *module;
52     struct import *next;
53 };
54 
55 static struct import *imports = NULL;
56 
57 void
58 add_import (const char *module)
59 {
60     struct import *tmp = emalloc (sizeof(*tmp));
61 
62     tmp->module = module;
63     tmp->next   = imports;
64     imports     = tmp;
65 }
66 
67 const char *
68 filename (void)
69 {
70     return orig_filename;
71 }
72 
73 void
74 init_generate (const char *filename, const char *base)
75 {
76     orig_filename = filename;
77     if(base)
78 	asprintf(&headerbase, "%s", base);
79     asprintf(&header, "%s.h", headerbase);
80     headerfile = fopen (header, "w");
81     if (headerfile == NULL)
82 	err (1, "open %s", header);
83     fprintf (headerfile,
84 	     "/* Generated from %s */\n"
85 	     "/* Do not edit */\n\n",
86 	     filename);
87     fprintf (headerfile,
88 	     "#ifndef __%s_h__\n"
89 	     "#define __%s_h__\n\n", headerbase, headerbase);
90     fprintf (headerfile,
91 	     "#include <stddef.h>\n"
92 	     "#include <time.h>\n\n");
93 #ifndef HAVE_TIMEGM
94     fprintf (headerfile, "time_t timegm (struct tm*);\n\n");
95 #endif
96     fprintf (headerfile,
97 	     "#ifndef __asn1_common_definitions__\n"
98 	     "#define __asn1_common_definitions__\n\n");
99     fprintf (headerfile,
100 	     "typedef struct octet_string {\n"
101 	     "  size_t length;\n"
102 	     "  void *data;\n"
103 	     "} octet_string;\n\n");
104     fprintf (headerfile,
105 	     "typedef char *general_string;\n\n"
106 	     );
107     fprintf (headerfile,
108 	     "typedef struct oid {\n"
109 	     "  size_t length;\n"
110 	     "  unsigned *components;\n"
111 	     "} oid;\n\n");
112     fputs("#define ASN1_MALLOC_ENCODE(T, B, BL, S, L, R)                  \\\n"
113 	  "  do {                                                         \\\n"
114 	  "    (BL) = length_##T((S));                                    \\\n"
115 	  "    (B) = malloc((BL));                                        \\\n"
116 	  "    if((B) == NULL) {                                          \\\n"
117 	  "      (R) = ENOMEM;                                            \\\n"
118 	  "    } else {                                                   \\\n"
119 	  "      (R) = encode_##T(((unsigned char*)(B)) + (BL) - 1, (BL), \\\n"
120 	  "                       (S), (L));                              \\\n"
121 	  "      if((R) != 0) {                                           \\\n"
122 	  "        free((B));                                             \\\n"
123 	  "        (B) = NULL;                                            \\\n"
124 	  "      }                                                        \\\n"
125 	  "    }                                                          \\\n"
126 	  "  } while (0)\n\n",
127 	  headerfile);
128     fprintf (headerfile, "#endif\n\n");
129     logfile = fopen(STEM "_files", "w");
130     if (logfile == NULL)
131 	err (1, "open " STEM "_files");
132 }
133 
134 void
135 close_generate (void)
136 {
137     fprintf (headerfile, "#endif /* __%s_h__ */\n", headerbase);
138 
139     fclose (headerfile);
140     fprintf (logfile, "\n");
141     fclose (logfile);
142 }
143 
144 void
145 generate_constant (const Symbol *s)
146 {
147   fprintf (headerfile, "enum { %s = %d };\n\n",
148 	   s->gen_name, s->constant);
149 }
150 
151 static void
152 space(int level)
153 {
154     while(level-- > 0)
155 	fprintf(headerfile, "  ");
156 }
157 
158 static void
159 define_asn1 (int level, Type *t)
160 {
161     switch (t->type) {
162     case TType:
163 	space(level);
164 	fprintf (headerfile, "%s", t->symbol->name);
165 	break;
166     case TInteger:
167 	space(level);
168 	fprintf (headerfile, "INTEGER");
169 	break;
170     case TUInteger:
171 	space(level);
172 	fprintf (headerfile, "UNSIGNED INTEGER");
173 	break;
174     case TOctetString:
175 	space(level);
176 	fprintf (headerfile, "OCTET STRING");
177 	break;
178     case TOID :
179 	space(level);
180 	fprintf(headerfile, "OBJECT IDENTIFIER");
181 	break;
182     case TBitString: {
183 	Member *m;
184 	int tag = -1;
185 
186 	space(level);
187 	fprintf (headerfile, "BIT STRING {\n");
188 	for (m = t->members; m && m->val != tag; m = m->next) {
189 	    if (tag == -1)
190 		tag = m->val;
191 	    space(level + 1);
192 	    fprintf (headerfile, "%s(%d)%s\n", m->name, m->val,
193 		     m->next->val == tag?"":",");
194 
195 	}
196 	space(level);
197 	fprintf (headerfile, "}");
198 	break;
199     }
200     case TEnumerated : {
201 	Member *m;
202 	int tag = -1;
203 
204 	space(level);
205 	fprintf (headerfile, "ENUMERATED {\n");
206 	for (m = t->members; m && m->val != tag; m = m->next) {
207 	    if (tag == -1)
208 		tag = m->val;
209 	    space(level + 1);
210 	    fprintf (headerfile, "%s(%d)%s\n", m->name, m->val,
211 		     m->next->val == tag?"":",");
212 
213 	}
214 	space(level);
215 	fprintf (headerfile, "}");
216 	break;
217     }
218     case TSequence: {
219 	Member *m;
220 	int tag;
221 	int max_width = 0;
222 
223 	space(level);
224 	fprintf (headerfile, "SEQUENCE {\n");
225 	for (m = t->members, tag = -1; m && m->val != tag; m = m->next) {
226 	    if (tag == -1)
227 		tag = m->val;
228 	    if(strlen(m->name) + (m->val > 9) > max_width)
229 		max_width = strlen(m->name) + (m->val > 9);
230 	}
231 	max_width += 3 + 2;
232 	if(max_width < 16) max_width = 16;
233 	for (m = t->members, tag = -1 ; m && m->val != tag; m = m->next) {
234 	    int width;
235 	    if (tag == -1)
236 		tag = m->val;
237 	    space(level + 1);
238 	    fprintf(headerfile, "%s[%d]", m->name, m->val);
239 	    width = max_width - strlen(m->name) - 3 - (m->val > 9) - 2;
240 	    fprintf(headerfile, "%*s", width, "");
241 	    define_asn1(level + 1, m->type);
242 	    if(m->optional)
243 		fprintf(headerfile, " OPTIONAL");
244 	    if(m->next->val != tag)
245 		fprintf (headerfile, ",");
246 	    fprintf (headerfile, "\n");
247 	}
248 	space(level);
249 	fprintf (headerfile, "}");
250 	break;
251     }
252     case TSequenceOf: {
253 	space(level);
254 	fprintf (headerfile, "SEQUENCE OF ");
255 	define_asn1 (0, t->subtype);
256 	break;
257     }
258     case TGeneralizedTime:
259 	space(level);
260 	fprintf (headerfile, "GeneralizedTime");
261 	break;
262     case TGeneralString:
263 	space(level);
264 	fprintf (headerfile, "GeneralString");
265 	break;
266     case TApplication:
267 	fprintf (headerfile, "[APPLICATION %d] ", t->application);
268 	define_asn1 (level, t->subtype);
269 	break;
270     default:
271 	abort ();
272     }
273 }
274 
275 static void
276 define_type (int level, char *name, Type *t, int typedefp)
277 {
278     switch (t->type) {
279     case TType:
280 	space(level);
281 	fprintf (headerfile, "%s %s;\n", t->symbol->gen_name, name);
282 	break;
283     case TInteger:
284 	space(level);
285         if(t->members == NULL) {
286             fprintf (headerfile, "int %s;\n", name);
287         } else {
288             Member *m;
289             int tag = -1;
290             fprintf (headerfile, "enum %s {\n", typedefp ? name : "");
291 	    for (m = t->members; m && m->val != tag; m = m->next) {
292                 if(tag == -1)
293                     tag = m->val;
294                 space (level + 1);
295                 fprintf(headerfile, "%s = %d%s\n", m->gen_name, m->val,
296                         m->next->val == tag ? "" : ",");
297             }
298             fprintf (headerfile, "} %s;\n", name);
299         }
300 	break;
301     case TUInteger:
302 	space(level);
303 	fprintf (headerfile, "unsigned int %s;\n", name);
304 	break;
305     case TOctetString:
306 	space(level);
307 	fprintf (headerfile, "octet_string %s;\n", name);
308 	break;
309     case TOID :
310 	space(level);
311 	fprintf (headerfile, "oid %s;\n", name);
312 	break;
313     case TBitString: {
314 	Member *m;
315 	Type i;
316 	int tag = -1;
317 
318 	i.type = TUInteger;
319 	space(level);
320 	fprintf (headerfile, "struct %s {\n", typedefp ? name : "");
321 	for (m = t->members; m && m->val != tag; m = m->next) {
322 	    char *n;
323 
324 	    asprintf (&n, "%s:1", m->gen_name);
325 	    define_type (level + 1, n, &i, FALSE);
326 	    free (n);
327 	    if (tag == -1)
328 		tag = m->val;
329 	}
330 	space(level);
331 	fprintf (headerfile, "} %s;\n\n", name);
332 	break;
333     }
334     case TEnumerated: {
335 	Member *m;
336 	int tag = -1;
337 
338 	space(level);
339 	fprintf (headerfile, "enum %s {\n", typedefp ? name : "");
340 	for (m = t->members; m && m->val != tag; m = m->next) {
341 	    if (tag == -1)
342 		tag = m->val;
343 	    space(level + 1);
344 	    fprintf (headerfile, "%s = %d%s\n", m->gen_name, m->val,
345                         m->next->val == tag ? "" : ",");
346 	}
347 	space(level);
348 	fprintf (headerfile, "} %s;\n\n", name);
349 	break;
350     }
351     case TSequence: {
352 	Member *m;
353 	int tag = -1;
354 
355 	space(level);
356 	fprintf (headerfile, "struct %s {\n", typedefp ? name : "");
357 	for (m = t->members; m && m->val != tag; m = m->next) {
358 	    if (m->optional) {
359 		char *n;
360 
361 		asprintf (&n, "*%s", m->gen_name);
362 		define_type (level + 1, n, m->type, FALSE);
363 		free (n);
364 	    } else
365 		define_type (level + 1, m->gen_name, m->type, FALSE);
366 	    if (tag == -1)
367 		tag = m->val;
368 	}
369 	space(level);
370 	fprintf (headerfile, "} %s;\n", name);
371 	break;
372     }
373     case TSequenceOf: {
374 	Type i;
375 
376 	i.type = TUInteger;
377 	i.application = 0;
378 
379 	space(level);
380 	fprintf (headerfile, "struct %s {\n", typedefp ? name : "");
381 	define_type (level + 1, "len", &i, FALSE);
382 	define_type (level + 1, "*val", t->subtype, FALSE);
383 	space(level);
384 	fprintf (headerfile, "} %s;\n", name);
385 	break;
386     }
387     case TGeneralizedTime:
388 	space(level);
389 	fprintf (headerfile, "time_t %s;\n", name);
390 	break;
391     case TGeneralString:
392 	space(level);
393 	fprintf (headerfile, "general_string %s;\n", name);
394 	break;
395     case TApplication:
396 	define_type (level, name, t->subtype, FALSE);
397 	break;
398     default:
399 	abort ();
400     }
401 }
402 
403 static void
404 generate_type_header (const Symbol *s)
405 {
406     fprintf (headerfile, "/*\n");
407     fprintf (headerfile, "%s ::= ", s->name);
408     define_asn1 (0, s->type);
409     fprintf (headerfile, "\n*/\n\n");
410 
411     fprintf (headerfile, "typedef ");
412     define_type (0, s->gen_name, s->type, TRUE);
413 
414     fprintf (headerfile, "\n");
415 }
416 
417 
418 void
419 generate_type (const Symbol *s)
420 {
421     struct import *i;
422     char *filename;
423 
424     asprintf (&filename, "%s_%s.x", STEM, s->gen_name);
425     codefile = fopen (filename, "w");
426     if (codefile == NULL)
427 	err (1, "fopen %s", filename);
428     fprintf(logfile, "%s ", filename);
429     free(filename);
430     fprintf (codefile,
431 	     "/* Generated from %s */\n"
432 	     "/* Do not edit */\n\n"
433 	     "#include <stdio.h>\n"
434 	     "#include <stdlib.h>\n"
435 	     "#include <time.h>\n"
436 	     "#include <string.h>\n"
437 	     "#include <errno.h>\n",
438 	     orig_filename);
439 
440     for (i = imports; i != NULL; i = i->next)
441 	fprintf (codefile,
442 		 "#include <%s_asn1.h>\n",
443 		 i->module);
444     fprintf (codefile,
445 	     "#include <%s.h>\n",
446 	     headerbase);
447     fprintf (codefile,
448 	     "#include <asn1_err.h>\n"
449 	     "#include <der.h>\n"
450 	     "#include <parse_units.h>\n\n");
451     generate_type_header (s);
452     generate_type_encode (s);
453     generate_type_decode (s);
454     generate_type_free (s);
455     generate_type_length (s);
456     generate_type_copy (s);
457     generate_glue (s);
458     fprintf(headerfile, "\n\n");
459     fclose(codefile);
460 }
461