xref: /netbsd-src/crypto/external/bsd/heimdal/dist/lib/asn1/gen_decode.c (revision afab4e300d3a9fb07dd8c80daf53d0feb3345706)
1*afab4e30Schristos /*	$NetBSD: gen_decode.c,v 1.3 2023/06/19 21:41:42 christos Exp $	*/
2ca1c9b0cSelric 
3ca1c9b0cSelric /*
4ca1c9b0cSelric  * Copyright (c) 1997 - 2006 Kungliga Tekniska Högskolan
5ca1c9b0cSelric  * (Royal Institute of Technology, Stockholm, Sweden).
6ca1c9b0cSelric  * All rights reserved.
7ca1c9b0cSelric  *
8ca1c9b0cSelric  * Redistribution and use in source and binary forms, with or without
9ca1c9b0cSelric  * modification, are permitted provided that the following conditions
10ca1c9b0cSelric  * are met:
11ca1c9b0cSelric  *
12ca1c9b0cSelric  * 1. Redistributions of source code must retain the above copyright
13ca1c9b0cSelric  *    notice, this list of conditions and the following disclaimer.
14ca1c9b0cSelric  *
15ca1c9b0cSelric  * 2. Redistributions in binary form must reproduce the above copyright
16ca1c9b0cSelric  *    notice, this list of conditions and the following disclaimer in the
17ca1c9b0cSelric  *    documentation and/or other materials provided with the distribution.
18ca1c9b0cSelric  *
19ca1c9b0cSelric  * 3. Neither the name of the Institute nor the names of its contributors
20ca1c9b0cSelric  *    may be used to endorse or promote products derived from this software
21ca1c9b0cSelric  *    without specific prior written permission.
22ca1c9b0cSelric  *
23ca1c9b0cSelric  * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
24ca1c9b0cSelric  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25ca1c9b0cSelric  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26ca1c9b0cSelric  * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
27ca1c9b0cSelric  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28ca1c9b0cSelric  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29ca1c9b0cSelric  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30ca1c9b0cSelric  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31ca1c9b0cSelric  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32ca1c9b0cSelric  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33ca1c9b0cSelric  * SUCH DAMAGE.
34ca1c9b0cSelric  */
35ca1c9b0cSelric 
36ca1c9b0cSelric #include "gen_locl.h"
37ca1c9b0cSelric #include "lex.h"
38ca1c9b0cSelric 
39*afab4e30Schristos __RCSID("$NetBSD: gen_decode.c,v 1.3 2023/06/19 21:41:42 christos Exp $");
40ca1c9b0cSelric 
41ca1c9b0cSelric static void
decode_primitive(const char * typename,const char * name,const char * forwstr)42ca1c9b0cSelric decode_primitive (const char *typename, const char *name, const char *forwstr)
43ca1c9b0cSelric {
44ca1c9b0cSelric #if 0
45ca1c9b0cSelric     fprintf (codefile,
46ca1c9b0cSelric 	     "e = decode_%s(p, len, %s, &l);\n"
47ca1c9b0cSelric 	     "%s;\n",
48ca1c9b0cSelric 	     typename,
49ca1c9b0cSelric 	     name,
50ca1c9b0cSelric 	     forwstr);
51ca1c9b0cSelric #else
52ca1c9b0cSelric     fprintf (codefile,
53ca1c9b0cSelric 	     "e = der_get_%s(p, len, %s, &l);\n"
54ca1c9b0cSelric 	     "if(e) %s;\np += l; len -= l; ret += l;\n",
55ca1c9b0cSelric 	     typename,
56ca1c9b0cSelric 	     name,
57ca1c9b0cSelric 	     forwstr);
58ca1c9b0cSelric #endif
59ca1c9b0cSelric }
60ca1c9b0cSelric 
61ca1c9b0cSelric static void
find_tag(const Type * t,Der_class * cl,Der_type * ty,unsigned * tag)62ca1c9b0cSelric find_tag (const Type *t,
63ca1c9b0cSelric 	  Der_class *cl, Der_type *ty, unsigned *tag)
64ca1c9b0cSelric {
65ca1c9b0cSelric     switch (t->type) {
66ca1c9b0cSelric     case TBitString:
67ca1c9b0cSelric 	*cl  = ASN1_C_UNIV;
68ca1c9b0cSelric 	*ty  = PRIM;
69ca1c9b0cSelric 	*tag = UT_BitString;
70ca1c9b0cSelric 	break;
71ca1c9b0cSelric     case TBoolean:
72ca1c9b0cSelric 	*cl  = ASN1_C_UNIV;
73ca1c9b0cSelric 	*ty  = PRIM;
74ca1c9b0cSelric 	*tag = UT_Boolean;
75ca1c9b0cSelric 	break;
76ca1c9b0cSelric     case TChoice:
77ca1c9b0cSelric 	errx(1, "Cannot have recursive CHOICE");
78ca1c9b0cSelric     case TEnumerated:
79ca1c9b0cSelric 	*cl  = ASN1_C_UNIV;
80ca1c9b0cSelric 	*ty  = PRIM;
81ca1c9b0cSelric 	*tag = UT_Enumerated;
82ca1c9b0cSelric 	break;
83ca1c9b0cSelric     case TGeneralString:
84ca1c9b0cSelric 	*cl  = ASN1_C_UNIV;
85ca1c9b0cSelric 	*ty  = PRIM;
86ca1c9b0cSelric 	*tag = UT_GeneralString;
87ca1c9b0cSelric 	break;
88ca1c9b0cSelric     case TTeletexString:
89ca1c9b0cSelric 	*cl  = ASN1_C_UNIV;
90ca1c9b0cSelric 	*ty  = PRIM;
91ca1c9b0cSelric 	*tag = UT_TeletexString;
92ca1c9b0cSelric 	break;
93ca1c9b0cSelric     case TGeneralizedTime:
94ca1c9b0cSelric 	*cl  = ASN1_C_UNIV;
95ca1c9b0cSelric 	*ty  = PRIM;
96ca1c9b0cSelric 	*tag = UT_GeneralizedTime;
97ca1c9b0cSelric 	break;
98ca1c9b0cSelric     case TIA5String:
99ca1c9b0cSelric 	*cl  = ASN1_C_UNIV;
100ca1c9b0cSelric 	*ty  = PRIM;
101ca1c9b0cSelric 	*tag = UT_IA5String;
102ca1c9b0cSelric 	break;
103ca1c9b0cSelric     case TInteger:
104ca1c9b0cSelric 	*cl  = ASN1_C_UNIV;
105ca1c9b0cSelric 	*ty  = PRIM;
106ca1c9b0cSelric 	*tag = UT_Integer;
107ca1c9b0cSelric 	break;
108ca1c9b0cSelric     case TNull:
109ca1c9b0cSelric 	*cl  = ASN1_C_UNIV;
110ca1c9b0cSelric 	*ty  = PRIM;
111ca1c9b0cSelric 	*tag = UT_Null;
112ca1c9b0cSelric 	break;
113ca1c9b0cSelric     case TOID:
114ca1c9b0cSelric 	*cl  = ASN1_C_UNIV;
115ca1c9b0cSelric 	*ty  = PRIM;
116ca1c9b0cSelric 	*tag = UT_OID;
117ca1c9b0cSelric 	break;
118ca1c9b0cSelric     case TOctetString:
119ca1c9b0cSelric 	*cl  = ASN1_C_UNIV;
120ca1c9b0cSelric 	*ty  = PRIM;
121ca1c9b0cSelric 	*tag = UT_OctetString;
122ca1c9b0cSelric 	break;
123ca1c9b0cSelric     case TPrintableString:
124ca1c9b0cSelric 	*cl  = ASN1_C_UNIV;
125ca1c9b0cSelric 	*ty  = PRIM;
126ca1c9b0cSelric 	*tag = UT_PrintableString;
127ca1c9b0cSelric 	break;
128ca1c9b0cSelric     case TSequence:
129ca1c9b0cSelric     case TSequenceOf:
130ca1c9b0cSelric 	*cl  = ASN1_C_UNIV;
131ca1c9b0cSelric 	*ty  = CONS;
132ca1c9b0cSelric 	*tag = UT_Sequence;
133ca1c9b0cSelric 	break;
134ca1c9b0cSelric     case TSet:
135ca1c9b0cSelric     case TSetOf:
136ca1c9b0cSelric 	*cl  = ASN1_C_UNIV;
137ca1c9b0cSelric 	*ty  = CONS;
138ca1c9b0cSelric 	*tag = UT_Set;
139ca1c9b0cSelric 	break;
140ca1c9b0cSelric     case TTag:
141ca1c9b0cSelric 	*cl  = t->tag.tagclass;
142ca1c9b0cSelric 	*ty  = is_primitive_type(t->subtype->type) ? PRIM : CONS;
143ca1c9b0cSelric 	*tag = t->tag.tagvalue;
144ca1c9b0cSelric 	break;
145ca1c9b0cSelric     case TType:
146ca1c9b0cSelric 	if ((t->symbol->stype == Stype && t->symbol->type == NULL)
147ca1c9b0cSelric 	    || t->symbol->stype == SUndefined) {
148ca1c9b0cSelric 	    lex_error_message("%s is imported or still undefined, "
149ca1c9b0cSelric 			      " can't generate tag checking data in CHOICE "
150ca1c9b0cSelric 			      "without this information",
151ca1c9b0cSelric 			      t->symbol->name);
152ca1c9b0cSelric 	    exit(1);
153ca1c9b0cSelric 	}
154ca1c9b0cSelric 	find_tag(t->symbol->type, cl, ty, tag);
155ca1c9b0cSelric 	return;
156ca1c9b0cSelric     case TUTCTime:
157ca1c9b0cSelric 	*cl  = ASN1_C_UNIV;
158ca1c9b0cSelric 	*ty  = PRIM;
159ca1c9b0cSelric 	*tag = UT_UTCTime;
160ca1c9b0cSelric 	break;
161ca1c9b0cSelric     case TUTF8String:
162ca1c9b0cSelric 	*cl  = ASN1_C_UNIV;
163ca1c9b0cSelric 	*ty  = PRIM;
164ca1c9b0cSelric 	*tag = UT_UTF8String;
165ca1c9b0cSelric 	break;
166ca1c9b0cSelric     case TBMPString:
167ca1c9b0cSelric 	*cl  = ASN1_C_UNIV;
168ca1c9b0cSelric 	*ty  = PRIM;
169ca1c9b0cSelric 	*tag = UT_BMPString;
170ca1c9b0cSelric 	break;
171ca1c9b0cSelric     case TUniversalString:
172ca1c9b0cSelric 	*cl  = ASN1_C_UNIV;
173ca1c9b0cSelric 	*ty  = PRIM;
174ca1c9b0cSelric 	*tag = UT_UniversalString;
175ca1c9b0cSelric 	break;
176ca1c9b0cSelric     case TVisibleString:
177ca1c9b0cSelric 	*cl  = ASN1_C_UNIV;
178ca1c9b0cSelric 	*ty  = PRIM;
179ca1c9b0cSelric 	*tag = UT_VisibleString;
180ca1c9b0cSelric 	break;
181ca1c9b0cSelric     default:
182ca1c9b0cSelric 	abort();
183ca1c9b0cSelric     }
184ca1c9b0cSelric }
185ca1c9b0cSelric 
186ca1c9b0cSelric static void
range_check(const char * name,const char * length,const char * forwstr,struct range * r)187ca1c9b0cSelric range_check(const char *name,
188ca1c9b0cSelric 	    const char *length,
189ca1c9b0cSelric 	    const char *forwstr,
190ca1c9b0cSelric 	    struct range *r)
191ca1c9b0cSelric {
192ca1c9b0cSelric     if (r->min == r->max + 2 || r->min < r->max)
193ca1c9b0cSelric 	fprintf (codefile,
194b9d004c6Schristos 		 "if ((%s)->%s > %lld) {\n"
195ca1c9b0cSelric 		 "e = ASN1_MAX_CONSTRAINT; %s;\n"
196ca1c9b0cSelric 		 "}\n",
197b9d004c6Schristos 		 name, length, (long long)r->max, forwstr);
198b9d004c6Schristos     if ((r->min - 1 == r->max || r->min < r->max) && r->min > 0)
199ca1c9b0cSelric 	fprintf (codefile,
200b9d004c6Schristos 		 "if ((%s)->%s < %lld) {\n"
201ca1c9b0cSelric 		 "e = ASN1_MIN_CONSTRAINT; %s;\n"
202ca1c9b0cSelric 		 "}\n",
203b9d004c6Schristos 		 name, length, (long long)r->min, forwstr);
204ca1c9b0cSelric     if (r->max == r->min)
205ca1c9b0cSelric 	fprintf (codefile,
206b9d004c6Schristos 		 "if ((%s)->%s != %lld) {\n"
207ca1c9b0cSelric 		 "e = ASN1_EXACT_CONSTRAINT; %s;\n"
208ca1c9b0cSelric 		 "}\n",
209b9d004c6Schristos 		 name, length, (long long)r->min, forwstr);
210ca1c9b0cSelric }
211ca1c9b0cSelric 
212ca1c9b0cSelric static int
decode_type(const char * name,const Type * t,int optional,const char * forwstr,const char * tmpstr,const char * dertype,unsigned int depth)213ca1c9b0cSelric decode_type (const char *name, const Type *t, int optional,
2144f77a458Spettai 	     const char *forwstr, const char *tmpstr, const char *dertype,
2154f77a458Spettai 	     unsigned int depth)
216ca1c9b0cSelric {
217ca1c9b0cSelric     switch (t->type) {
218ca1c9b0cSelric     case TType: {
219ca1c9b0cSelric 	if (optional)
220ca1c9b0cSelric 	    fprintf(codefile,
221ca1c9b0cSelric 		    "%s = calloc(1, sizeof(*%s));\n"
222ca1c9b0cSelric 		    "if (%s == NULL) %s;\n",
223ca1c9b0cSelric 		    name, name, name, forwstr);
224ca1c9b0cSelric 	fprintf (codefile,
225ca1c9b0cSelric 		 "e = decode_%s(p, len, %s, &l);\n",
226ca1c9b0cSelric 		 t->symbol->gen_name, name);
227ca1c9b0cSelric 	if (optional) {
228ca1c9b0cSelric 	    fprintf (codefile,
229ca1c9b0cSelric 		     "if(e) {\n"
230ca1c9b0cSelric 		     "free(%s);\n"
231ca1c9b0cSelric 		     "%s = NULL;\n"
232ca1c9b0cSelric 		     "} else {\n"
233ca1c9b0cSelric 		     "p += l; len -= l; ret += l;\n"
234ca1c9b0cSelric 		     "}\n",
235ca1c9b0cSelric 		     name, name);
236ca1c9b0cSelric 	} else {
237ca1c9b0cSelric 	    fprintf (codefile,
238ca1c9b0cSelric 		     "if(e) %s;\n",
239ca1c9b0cSelric 		     forwstr);
240ca1c9b0cSelric 	    fprintf (codefile,
241ca1c9b0cSelric 		     "p += l; len -= l; ret += l;\n");
242ca1c9b0cSelric 	}
243ca1c9b0cSelric 	break;
244ca1c9b0cSelric     }
245ca1c9b0cSelric     case TInteger:
246ca1c9b0cSelric 	if(t->members) {
247b9d004c6Schristos 	    /*
248b9d004c6Schristos 	     * This will produce a worning, how its hard to fix since:
249b9d004c6Schristos 	     * if its enum to an NameType, we can add appriate
250b9d004c6Schristos 	     * type-cast. If its not though, we have to figure out if
251b9d004c6Schristos 	     * there is negative enum enum and use appropriate
252b9d004c6Schristos 	     * signness and size on the intertype we cast the result
253b9d004c6Schristos 	     * too.
254b9d004c6Schristos 	     */
255ca1c9b0cSelric 	    fprintf(codefile,
256ca1c9b0cSelric 		    "{\n"
257ca1c9b0cSelric 		    "int enumint;\n");
258ca1c9b0cSelric 	    decode_primitive ("integer", "&enumint", forwstr);
259ca1c9b0cSelric 	    fprintf(codefile,
260ca1c9b0cSelric 		    "*%s = enumint;\n"
261ca1c9b0cSelric 		    "}\n",
262ca1c9b0cSelric 		    name);
263ca1c9b0cSelric 	} else if (t->range == NULL) {
264ca1c9b0cSelric 	    decode_primitive ("heim_integer", name, forwstr);
265b9d004c6Schristos 	} else if (t->range->min < INT_MIN && t->range->max <= INT64_MAX) {
266b9d004c6Schristos 	    decode_primitive ("integer64", name, forwstr);
267b9d004c6Schristos 	} else if (t->range->min >= 0 && t->range->max > UINT_MAX) {
268b9d004c6Schristos 	    decode_primitive ("unsigned64", name, forwstr);
269b9d004c6Schristos 	} else if (t->range->min >= INT_MIN && t->range->max <= INT_MAX) {
270ca1c9b0cSelric 	    decode_primitive ("integer", name, forwstr);
271b9d004c6Schristos 	} else if (t->range->min >= 0 && t->range->max <= UINT_MAX) {
272ca1c9b0cSelric 	    decode_primitive ("unsigned", name, forwstr);
273ca1c9b0cSelric 	} else
274b9d004c6Schristos 	    errx(1, "%s: unsupported range %lld -> %lld",
275b9d004c6Schristos 		 name, (long long)t->range->min, (long long)t->range->max);
276ca1c9b0cSelric 	break;
277ca1c9b0cSelric     case TBoolean:
278ca1c9b0cSelric       decode_primitive ("boolean", name, forwstr);
279ca1c9b0cSelric       break;
280ca1c9b0cSelric     case TEnumerated:
281ca1c9b0cSelric 	decode_primitive ("enumerated", name, forwstr);
282ca1c9b0cSelric 	break;
283ca1c9b0cSelric     case TOctetString:
284ca1c9b0cSelric 	if (dertype) {
285ca1c9b0cSelric 	    fprintf(codefile,
286ca1c9b0cSelric 		    "if (%s == CONS) {\n",
287ca1c9b0cSelric 		    dertype);
288ca1c9b0cSelric 	    decode_primitive("octet_string_ber", name, forwstr);
289ca1c9b0cSelric 	    fprintf(codefile,
290ca1c9b0cSelric 		    "} else {\n");
291ca1c9b0cSelric 	}
292ca1c9b0cSelric 	decode_primitive ("octet_string", name, forwstr);
293ca1c9b0cSelric 	if (dertype)
294ca1c9b0cSelric 	    fprintf(codefile, "}\n");
295ca1c9b0cSelric 	if (t->range)
296ca1c9b0cSelric 	    range_check(name, "length", forwstr, t->range);
297ca1c9b0cSelric 	break;
298ca1c9b0cSelric     case TBitString: {
299ca1c9b0cSelric 	Member *m;
300ca1c9b0cSelric 	int pos = 0;
301ca1c9b0cSelric 
302ca1c9b0cSelric 	if (ASN1_TAILQ_EMPTY(t->members)) {
303ca1c9b0cSelric 	    decode_primitive ("bit_string", name, forwstr);
304ca1c9b0cSelric 	    break;
305ca1c9b0cSelric 	}
306ca1c9b0cSelric 	fprintf(codefile,
307ca1c9b0cSelric 		"if (len < 1) return ASN1_OVERRUN;\n"
308ca1c9b0cSelric 		"p++; len--; ret++;\n");
309ca1c9b0cSelric 	fprintf(codefile,
310ca1c9b0cSelric 		"do {\n"
311ca1c9b0cSelric 		"if (len < 1) break;\n");
312ca1c9b0cSelric 	ASN1_TAILQ_FOREACH(m, t->members, members) {
313ca1c9b0cSelric 	    while (m->val / 8 > pos / 8) {
314ca1c9b0cSelric 		fprintf (codefile,
315ca1c9b0cSelric 			 "p++; len--; ret++;\n"
316ca1c9b0cSelric 			 "if (len < 1) break;\n");
317ca1c9b0cSelric 		pos += 8;
318ca1c9b0cSelric 	    }
319ca1c9b0cSelric 	    fprintf (codefile,
320ca1c9b0cSelric 		     "(%s)->%s = (*p >> %d) & 1;\n",
321ca1c9b0cSelric 		     name, m->gen_name, 7 - m->val % 8);
322ca1c9b0cSelric 	}
323ca1c9b0cSelric 	fprintf(codefile,
324ca1c9b0cSelric 		"} while(0);\n");
325ca1c9b0cSelric 	fprintf (codefile,
326ca1c9b0cSelric 		 "p += len; ret += len;\n");
327ca1c9b0cSelric 	break;
328ca1c9b0cSelric     }
329ca1c9b0cSelric     case TSequence: {
330ca1c9b0cSelric 	Member *m;
331ca1c9b0cSelric 
332ca1c9b0cSelric 	if (t->members == NULL)
333ca1c9b0cSelric 	    break;
334ca1c9b0cSelric 
335ca1c9b0cSelric 	ASN1_TAILQ_FOREACH(m, t->members, members) {
336ca1c9b0cSelric 	    char *s = NULL;
337ca1c9b0cSelric 
338ca1c9b0cSelric 	    if (m->ellipsis)
339ca1c9b0cSelric 		continue;
340ca1c9b0cSelric 
341ca1c9b0cSelric 	    if (asprintf (&s, "%s(%s)->%s", m->optional ? "" : "&",
342ca1c9b0cSelric 			  name, m->gen_name) < 0 || s == NULL)
343ca1c9b0cSelric 		errx(1, "malloc");
3444f77a458Spettai 	    decode_type (s, m->type, m->optional, forwstr, m->gen_name, NULL,
3454f77a458Spettai 		depth + 1);
346ca1c9b0cSelric 	    free (s);
347ca1c9b0cSelric 	}
348ca1c9b0cSelric 
349ca1c9b0cSelric 	break;
350ca1c9b0cSelric     }
351ca1c9b0cSelric     case TSet: {
352ca1c9b0cSelric 	Member *m;
353ca1c9b0cSelric 	unsigned int memno;
354ca1c9b0cSelric 
355ca1c9b0cSelric 	if(t->members == NULL)
356ca1c9b0cSelric 	    break;
357ca1c9b0cSelric 
358ca1c9b0cSelric 	fprintf(codefile, "{\n");
359ca1c9b0cSelric 	fprintf(codefile, "unsigned int members = 0;\n");
360ca1c9b0cSelric 	fprintf(codefile, "while(len > 0) {\n");
361ca1c9b0cSelric 	fprintf(codefile,
362ca1c9b0cSelric 		"Der_class class;\n"
363ca1c9b0cSelric 		"Der_type type;\n"
364ca1c9b0cSelric 		"int tag;\n"
365ca1c9b0cSelric 		"e = der_get_tag (p, len, &class, &type, &tag, NULL);\n"
366ca1c9b0cSelric 		"if(e) %s;\n", forwstr);
367ca1c9b0cSelric 	fprintf(codefile, "switch (MAKE_TAG(class, type, tag)) {\n");
368ca1c9b0cSelric 	memno = 0;
369ca1c9b0cSelric 	ASN1_TAILQ_FOREACH(m, t->members, members) {
370ca1c9b0cSelric 	    char *s;
371ca1c9b0cSelric 
372ca1c9b0cSelric 	    assert(m->type->type == TTag);
373ca1c9b0cSelric 
374ca1c9b0cSelric 	    fprintf(codefile, "case MAKE_TAG(%s, %s, %s):\n",
375ca1c9b0cSelric 		    classname(m->type->tag.tagclass),
376ca1c9b0cSelric 		    is_primitive_type(m->type->subtype->type) ? "PRIM" : "CONS",
377ca1c9b0cSelric 		    valuename(m->type->tag.tagclass, m->type->tag.tagvalue));
378ca1c9b0cSelric 
379ca1c9b0cSelric 	    if (asprintf (&s, "%s(%s)->%s", m->optional ? "" : "&", name, m->gen_name) < 0 || s == NULL)
380ca1c9b0cSelric 		errx(1, "malloc");
381ca1c9b0cSelric 	    if(m->optional)
382ca1c9b0cSelric 		fprintf(codefile,
383ca1c9b0cSelric 			"%s = calloc(1, sizeof(*%s));\n"
384ca1c9b0cSelric 			"if (%s == NULL) { e = ENOMEM; %s; }\n",
385ca1c9b0cSelric 			s, s, s, forwstr);
3864f77a458Spettai 	    decode_type (s, m->type, 0, forwstr, m->gen_name, NULL, depth + 1);
387ca1c9b0cSelric 	    free (s);
388ca1c9b0cSelric 
389ca1c9b0cSelric 	    fprintf(codefile, "members |= (1 << %d);\n", memno);
390ca1c9b0cSelric 	    memno++;
391ca1c9b0cSelric 	    fprintf(codefile, "break;\n");
392ca1c9b0cSelric 	}
393ca1c9b0cSelric 	fprintf(codefile,
394ca1c9b0cSelric 		"default:\n"
395ca1c9b0cSelric 		"return ASN1_MISPLACED_FIELD;\n"
396ca1c9b0cSelric 		"break;\n");
397ca1c9b0cSelric 	fprintf(codefile, "}\n");
398ca1c9b0cSelric 	fprintf(codefile, "}\n");
399ca1c9b0cSelric 	memno = 0;
400ca1c9b0cSelric 	ASN1_TAILQ_FOREACH(m, t->members, members) {
401ca1c9b0cSelric 	    char *s;
402ca1c9b0cSelric 
403ca1c9b0cSelric 	    if (asprintf (&s, "%s->%s", name, m->gen_name) < 0 || s == NULL)
404ca1c9b0cSelric 		errx(1, "malloc");
405ca1c9b0cSelric 	    fprintf(codefile, "if((members & (1 << %d)) == 0)\n", memno);
406ca1c9b0cSelric 	    if(m->optional)
407ca1c9b0cSelric 		fprintf(codefile, "%s = NULL;\n", s);
408ca1c9b0cSelric 	    else if(m->defval)
409ca1c9b0cSelric 		gen_assign_defval(s, m->defval);
410ca1c9b0cSelric 	    else
411ca1c9b0cSelric 		fprintf(codefile, "return ASN1_MISSING_FIELD;\n");
412ca1c9b0cSelric 	    free(s);
413ca1c9b0cSelric 	    memno++;
414ca1c9b0cSelric 	}
415ca1c9b0cSelric 	fprintf(codefile, "}\n");
416ca1c9b0cSelric 	break;
417ca1c9b0cSelric     }
418ca1c9b0cSelric     case TSetOf:
419ca1c9b0cSelric     case TSequenceOf: {
420ca1c9b0cSelric 	char *n = NULL;
421ca1c9b0cSelric 	char *sname = NULL;
422ca1c9b0cSelric 
423ca1c9b0cSelric 	fprintf (codefile,
424ca1c9b0cSelric 		 "{\n"
425ca1c9b0cSelric 		 "size_t %s_origlen = len;\n"
426ca1c9b0cSelric 		 "size_t %s_oldret = ret;\n"
427ca1c9b0cSelric 		 "size_t %s_olen = 0;\n"
428ca1c9b0cSelric 		 "void *%s_tmp;\n"
429ca1c9b0cSelric 		 "ret = 0;\n"
430ca1c9b0cSelric 		 "(%s)->len = 0;\n"
431ca1c9b0cSelric 		 "(%s)->val = NULL;\n",
432ca1c9b0cSelric 		 tmpstr,
433ca1c9b0cSelric 		 tmpstr,
434ca1c9b0cSelric 		 tmpstr,
435ca1c9b0cSelric 		 tmpstr,
436ca1c9b0cSelric 		 name,
437ca1c9b0cSelric 		 name);
438ca1c9b0cSelric 
439ca1c9b0cSelric 	fprintf (codefile,
440ca1c9b0cSelric 		 "while(ret < %s_origlen) {\n"
441ca1c9b0cSelric 		 "size_t %s_nlen = %s_olen + sizeof(*((%s)->val));\n"
442ca1c9b0cSelric 		 "if (%s_olen > %s_nlen) { e = ASN1_OVERFLOW; %s; }\n"
443ca1c9b0cSelric 		 "%s_olen = %s_nlen;\n"
444ca1c9b0cSelric 		 "%s_tmp = realloc((%s)->val, %s_olen);\n"
445ca1c9b0cSelric 		 "if (%s_tmp == NULL) { e = ENOMEM; %s; }\n"
446ca1c9b0cSelric 		 "(%s)->val = %s_tmp;\n",
447ca1c9b0cSelric 		 tmpstr,
448ca1c9b0cSelric 		 tmpstr, tmpstr, name,
449ca1c9b0cSelric 		 tmpstr, tmpstr, forwstr,
450ca1c9b0cSelric 		 tmpstr, tmpstr,
451ca1c9b0cSelric 		 tmpstr, name, tmpstr,
452ca1c9b0cSelric 		 tmpstr, forwstr,
453ca1c9b0cSelric 		 name, tmpstr);
454ca1c9b0cSelric 
455ca1c9b0cSelric 	if (asprintf (&n, "&(%s)->val[(%s)->len]", name, name) < 0 || n == NULL)
456ca1c9b0cSelric 	    errx(1, "malloc");
457ca1c9b0cSelric 	if (asprintf (&sname, "%s_s_of", tmpstr) < 0 || sname == NULL)
458ca1c9b0cSelric 	    errx(1, "malloc");
4594f77a458Spettai 	decode_type (n, t->subtype, 0, forwstr, sname, NULL, depth + 1);
460ca1c9b0cSelric 	fprintf (codefile,
461ca1c9b0cSelric 		 "(%s)->len++;\n"
462ca1c9b0cSelric 		 "len = %s_origlen - ret;\n"
463ca1c9b0cSelric 		 "}\n"
464ca1c9b0cSelric 		 "ret += %s_oldret;\n"
465ca1c9b0cSelric 		 "}\n",
466ca1c9b0cSelric 		 name,
467ca1c9b0cSelric 		 tmpstr, tmpstr);
468ca1c9b0cSelric 	if (t->range)
469ca1c9b0cSelric 	    range_check(name, "len", forwstr, t->range);
470ca1c9b0cSelric 	free (n);
471ca1c9b0cSelric 	free (sname);
472ca1c9b0cSelric 	break;
473ca1c9b0cSelric     }
474ca1c9b0cSelric     case TGeneralizedTime:
475ca1c9b0cSelric 	decode_primitive ("generalized_time", name, forwstr);
476ca1c9b0cSelric 	break;
477ca1c9b0cSelric     case TGeneralString:
478ca1c9b0cSelric 	decode_primitive ("general_string", name, forwstr);
479ca1c9b0cSelric 	break;
480ca1c9b0cSelric     case TTeletexString:
481ca1c9b0cSelric 	decode_primitive ("general_string", name, forwstr);
482ca1c9b0cSelric 	break;
483ca1c9b0cSelric     case TTag:{
484ca1c9b0cSelric     	char *tname = NULL, *typestring = NULL;
485ca1c9b0cSelric 	char *ide = NULL;
486ca1c9b0cSelric 
487ca1c9b0cSelric 	if (asprintf(&typestring, "%s_type", tmpstr) < 0 || typestring == NULL)
488ca1c9b0cSelric 	    errx(1, "malloc");
489ca1c9b0cSelric 
490ca1c9b0cSelric 	fprintf(codefile,
491ca1c9b0cSelric 		"{\n"
492ca1c9b0cSelric 		"size_t %s_datalen, %s_oldlen;\n"
493ca1c9b0cSelric 		"Der_type %s;\n",
494ca1c9b0cSelric 		tmpstr, tmpstr, typestring);
495ca1c9b0cSelric 	if(support_ber)
496ca1c9b0cSelric 	    fprintf(codefile,
4974f77a458Spettai 		    "int is_indefinite%u;\n", depth);
498ca1c9b0cSelric 
499ca1c9b0cSelric 	fprintf(codefile, "e = der_match_tag_and_length(p, len, %s, &%s, %s, "
500ca1c9b0cSelric 		"&%s_datalen, &l);\n",
501ca1c9b0cSelric 		classname(t->tag.tagclass),
502ca1c9b0cSelric 		typestring,
503ca1c9b0cSelric 		valuename(t->tag.tagclass, t->tag.tagvalue),
504ca1c9b0cSelric 		tmpstr);
505ca1c9b0cSelric 
506ca1c9b0cSelric 	/* XXX hardcode for now */
507ca1c9b0cSelric 	if (support_ber && t->subtype->type == TOctetString) {
508ca1c9b0cSelric 	    ide = typestring;
509ca1c9b0cSelric 	} else {
510ca1c9b0cSelric 	    fprintf(codefile,
511ca1c9b0cSelric 		    "if (e == 0 && %s != %s) { e = ASN1_BAD_ID; }\n",
512ca1c9b0cSelric 		    typestring,
513ca1c9b0cSelric 		    is_primitive_type(t->subtype->type) ? "PRIM" : "CONS");
514ca1c9b0cSelric 	}
515ca1c9b0cSelric 
516ca1c9b0cSelric 	if(optional) {
517ca1c9b0cSelric 	    fprintf(codefile,
518ca1c9b0cSelric 		    "if(e) {\n"
519ca1c9b0cSelric 		    "%s = NULL;\n"
520ca1c9b0cSelric 		    "} else {\n"
521ca1c9b0cSelric 		     "%s = calloc(1, sizeof(*%s));\n"
522ca1c9b0cSelric 		     "if (%s == NULL) { e = ENOMEM; %s; }\n",
523ca1c9b0cSelric 		     name, name, name, name, forwstr);
524ca1c9b0cSelric 	} else {
525ca1c9b0cSelric 	    fprintf(codefile, "if(e) %s;\n", forwstr);
526ca1c9b0cSelric 	}
527ca1c9b0cSelric 	fprintf (codefile,
528ca1c9b0cSelric 		 "p += l; len -= l; ret += l;\n"
529ca1c9b0cSelric 		 "%s_oldlen = len;\n",
530ca1c9b0cSelric 		 tmpstr);
531ca1c9b0cSelric 	if(support_ber)
532ca1c9b0cSelric 	    fprintf (codefile,
5334f77a458Spettai 		     "if((is_indefinite%u = _heim_fix_dce(%s_datalen, &len)) < 0)\n"
534ca1c9b0cSelric 		     "{ e = ASN1_BAD_FORMAT; %s; }\n"
5354f77a458Spettai 		     "if (is_indefinite%u) { if (len < 2) { e = ASN1_OVERRUN; %s; } len -= 2; }",
5364f77a458Spettai 		     depth, tmpstr, forwstr, depth, forwstr);
537ca1c9b0cSelric 	else
538ca1c9b0cSelric 	    fprintf(codefile,
539ca1c9b0cSelric 		    "if (%s_datalen > len) { e = ASN1_OVERRUN; %s; }\n"
540ca1c9b0cSelric 		    "len = %s_datalen;\n", tmpstr, forwstr, tmpstr);
541ca1c9b0cSelric 	if (asprintf (&tname, "%s_Tag", tmpstr) < 0 || tname == NULL)
542ca1c9b0cSelric 	    errx(1, "malloc");
5434f77a458Spettai 	decode_type (name, t->subtype, 0, forwstr, tname, ide, depth + 1);
544ca1c9b0cSelric 	if(support_ber)
545ca1c9b0cSelric 	    fprintf(codefile,
5464f77a458Spettai 		    "if(is_indefinite%u){\n"
547ca1c9b0cSelric 		    "len += 2;\n"
548ca1c9b0cSelric 		    "e = der_match_tag_and_length(p, len, "
549ca1c9b0cSelric 		    "(Der_class)0, &%s, UT_EndOfContent, "
550ca1c9b0cSelric 		    "&%s_datalen, &l);\n"
551ca1c9b0cSelric 		    "if(e) %s;\n"
552ca1c9b0cSelric 		    "p += l; len -= l; ret += l;\n"
553ca1c9b0cSelric 		    "if (%s != (Der_type)0) { e = ASN1_BAD_ID; %s; }\n"
554ca1c9b0cSelric 		    "} else \n",
5554f77a458Spettai 		    depth,
556ca1c9b0cSelric 		    typestring,
557ca1c9b0cSelric 		    tmpstr,
558ca1c9b0cSelric 		    forwstr,
559ca1c9b0cSelric 		    typestring, forwstr);
560ca1c9b0cSelric 	fprintf(codefile,
561ca1c9b0cSelric 		"len = %s_oldlen - %s_datalen;\n",
562ca1c9b0cSelric 		tmpstr, tmpstr);
563ca1c9b0cSelric 	if(optional)
564ca1c9b0cSelric 	    fprintf(codefile,
565ca1c9b0cSelric 		    "}\n");
566ca1c9b0cSelric 	fprintf(codefile,
567ca1c9b0cSelric 		"}\n");
568ca1c9b0cSelric 	free(tname);
569ca1c9b0cSelric 	free(typestring);
570ca1c9b0cSelric 	break;
571ca1c9b0cSelric     }
572ca1c9b0cSelric     case TChoice: {
573ca1c9b0cSelric 	Member *m, *have_ellipsis = NULL;
574ca1c9b0cSelric 	const char *els = "";
575ca1c9b0cSelric 
576ca1c9b0cSelric 	if (t->members == NULL)
577ca1c9b0cSelric 	    break;
578ca1c9b0cSelric 
579ca1c9b0cSelric 	ASN1_TAILQ_FOREACH(m, t->members, members) {
580ca1c9b0cSelric 	    const Type *tt = m->type;
581ca1c9b0cSelric 	    char *s = NULL;
582ca1c9b0cSelric 	    Der_class cl;
583ca1c9b0cSelric 	    Der_type  ty;
584ca1c9b0cSelric 	    unsigned  tag;
585ca1c9b0cSelric 
586ca1c9b0cSelric 	    if (m->ellipsis) {
587ca1c9b0cSelric 		have_ellipsis = m;
588ca1c9b0cSelric 		continue;
589ca1c9b0cSelric 	    }
590ca1c9b0cSelric 
591ca1c9b0cSelric 	    find_tag(tt, &cl, &ty, &tag);
592ca1c9b0cSelric 
593ca1c9b0cSelric 	    fprintf(codefile,
594ca1c9b0cSelric 		    "%sif (der_match_tag(p, len, %s, %s, %s, NULL) == 0) {\n",
595ca1c9b0cSelric 		    els,
596ca1c9b0cSelric 		    classname(cl),
597ca1c9b0cSelric 		    ty ? "CONS" : "PRIM",
598ca1c9b0cSelric 		    valuename(cl, tag));
599*afab4e30Schristos 	    fprintf(codefile,
600*afab4e30Schristos 		    "(%s)->element = %s;\n",
601*afab4e30Schristos 		    name, m->label);
602ca1c9b0cSelric 	    if (asprintf (&s, "%s(%s)->u.%s", m->optional ? "" : "&",
603ca1c9b0cSelric 			  name, m->gen_name) < 0 || s == NULL)
604ca1c9b0cSelric 		errx(1, "malloc");
6054f77a458Spettai 	    decode_type (s, m->type, m->optional, forwstr, m->gen_name, NULL,
6064f77a458Spettai 		depth + 1);
607ca1c9b0cSelric 	    free(s);
608ca1c9b0cSelric 	    fprintf(codefile,
609ca1c9b0cSelric 		    "}\n");
610ca1c9b0cSelric 	    els = "else ";
611ca1c9b0cSelric 	}
612ca1c9b0cSelric 	if (have_ellipsis) {
613ca1c9b0cSelric 	    fprintf(codefile,
614ca1c9b0cSelric 		    "else {\n"
615*afab4e30Schristos 		    "(%s)->element = %s;\n"
616ca1c9b0cSelric 		    "(%s)->u.%s.data = calloc(1, len);\n"
617ca1c9b0cSelric 		    "if ((%s)->u.%s.data == NULL) {\n"
618ca1c9b0cSelric 		    "e = ENOMEM; %s;\n"
619ca1c9b0cSelric 		    "}\n"
620ca1c9b0cSelric 		    "(%s)->u.%s.length = len;\n"
621ca1c9b0cSelric 		    "memcpy((%s)->u.%s.data, p, len);\n"
622ca1c9b0cSelric 		    "p += len;\n"
623ca1c9b0cSelric 		    "ret += len;\n"
6244f77a458Spettai 		    "len = 0;\n"
625ca1c9b0cSelric 		    "}\n",
626*afab4e30Schristos 		    name, have_ellipsis->label,
627ca1c9b0cSelric 		    name, have_ellipsis->gen_name,
628ca1c9b0cSelric 		    name, have_ellipsis->gen_name,
629ca1c9b0cSelric 		    forwstr,
630ca1c9b0cSelric 		    name, have_ellipsis->gen_name,
631*afab4e30Schristos 		    name, have_ellipsis->gen_name);
632ca1c9b0cSelric 	} else {
633ca1c9b0cSelric 	    fprintf(codefile,
634ca1c9b0cSelric 		    "else {\n"
635ca1c9b0cSelric 		    "e = ASN1_PARSE_ERROR;\n"
636ca1c9b0cSelric 		    "%s;\n"
637ca1c9b0cSelric 		    "}\n",
638ca1c9b0cSelric 		    forwstr);
639ca1c9b0cSelric 	}
640ca1c9b0cSelric 	break;
641ca1c9b0cSelric     }
642ca1c9b0cSelric     case TUTCTime:
643ca1c9b0cSelric 	decode_primitive ("utctime", name, forwstr);
644ca1c9b0cSelric 	break;
645ca1c9b0cSelric     case TUTF8String:
646ca1c9b0cSelric 	decode_primitive ("utf8string", name, forwstr);
647ca1c9b0cSelric 	break;
648ca1c9b0cSelric     case TPrintableString:
649ca1c9b0cSelric 	decode_primitive ("printable_string", name, forwstr);
650ca1c9b0cSelric 	break;
651ca1c9b0cSelric     case TIA5String:
652ca1c9b0cSelric 	decode_primitive ("ia5_string", name, forwstr);
653ca1c9b0cSelric 	break;
654ca1c9b0cSelric     case TBMPString:
655ca1c9b0cSelric 	decode_primitive ("bmp_string", name, forwstr);
656ca1c9b0cSelric 	break;
657ca1c9b0cSelric     case TUniversalString:
658ca1c9b0cSelric 	decode_primitive ("universal_string", name, forwstr);
659ca1c9b0cSelric 	break;
660ca1c9b0cSelric     case TVisibleString:
661ca1c9b0cSelric 	decode_primitive ("visible_string", name, forwstr);
662ca1c9b0cSelric 	break;
663ca1c9b0cSelric     case TNull:
664ca1c9b0cSelric 	fprintf (codefile, "/* NULL */\n");
665ca1c9b0cSelric 	break;
666ca1c9b0cSelric     case TOID:
667ca1c9b0cSelric 	decode_primitive ("oid", name, forwstr);
668ca1c9b0cSelric 	break;
669ca1c9b0cSelric     default :
670ca1c9b0cSelric 	abort ();
671ca1c9b0cSelric     }
672ca1c9b0cSelric     return 0;
673ca1c9b0cSelric }
674ca1c9b0cSelric 
675ca1c9b0cSelric void
generate_type_decode(const Symbol * s)676ca1c9b0cSelric generate_type_decode (const Symbol *s)
677ca1c9b0cSelric {
678ca1c9b0cSelric     int preserve = preserve_type(s->name) ? TRUE : FALSE;
679ca1c9b0cSelric 
680ca1c9b0cSelric     fprintf (codefile, "int ASN1CALL\n"
6814f77a458Spettai 	     "decode_%s(const unsigned char *p HEIMDAL_UNUSED_ATTRIBUTE,"
6824f77a458Spettai 	     " size_t len HEIMDAL_UNUSED_ATTRIBUTE, %s *data, size_t *size)\n"
683ca1c9b0cSelric 	     "{\n",
684ca1c9b0cSelric 	     s->gen_name, s->gen_name);
685ca1c9b0cSelric 
686ca1c9b0cSelric     switch (s->type->type) {
687ca1c9b0cSelric     case TInteger:
688ca1c9b0cSelric     case TBoolean:
689ca1c9b0cSelric     case TOctetString:
690ca1c9b0cSelric     case TOID:
691ca1c9b0cSelric     case TGeneralizedTime:
692ca1c9b0cSelric     case TGeneralString:
693ca1c9b0cSelric     case TTeletexString:
694ca1c9b0cSelric     case TUTF8String:
695ca1c9b0cSelric     case TPrintableString:
696ca1c9b0cSelric     case TIA5String:
697ca1c9b0cSelric     case TBMPString:
698ca1c9b0cSelric     case TUniversalString:
699ca1c9b0cSelric     case TVisibleString:
700ca1c9b0cSelric     case TUTCTime:
701ca1c9b0cSelric     case TNull:
702ca1c9b0cSelric     case TEnumerated:
703ca1c9b0cSelric     case TBitString:
704ca1c9b0cSelric     case TSequence:
705ca1c9b0cSelric     case TSequenceOf:
706ca1c9b0cSelric     case TSet:
707ca1c9b0cSelric     case TSetOf:
708ca1c9b0cSelric     case TTag:
709ca1c9b0cSelric     case TType:
710ca1c9b0cSelric     case TChoice:
711ca1c9b0cSelric 	fprintf (codefile,
712ca1c9b0cSelric 		 "size_t ret = 0;\n"
7134f77a458Spettai 		 "size_t l HEIMDAL_UNUSED_ATTRIBUTE;\n"
7144f77a458Spettai 		 "int e HEIMDAL_UNUSED_ATTRIBUTE;\n");
715ca1c9b0cSelric 	if (preserve)
716ca1c9b0cSelric 	    fprintf (codefile, "const unsigned char *begin = p;\n");
717ca1c9b0cSelric 
718ca1c9b0cSelric 	fprintf (codefile, "\n");
719ca1c9b0cSelric 	fprintf (codefile, "memset(data, 0, sizeof(*data));\n"); /* hack to avoid `unused variable' */
720ca1c9b0cSelric 
7214f77a458Spettai 	decode_type ("data", s->type, 0, "goto fail", "Top", NULL, 1);
722ca1c9b0cSelric 	if (preserve)
723ca1c9b0cSelric 	    fprintf (codefile,
724ca1c9b0cSelric 		     "data->_save.data = calloc(1, ret);\n"
725ca1c9b0cSelric 		     "if (data->_save.data == NULL) { \n"
726ca1c9b0cSelric 		     "e = ENOMEM; goto fail; \n"
727ca1c9b0cSelric 		     "}\n"
728ca1c9b0cSelric 		     "data->_save.length = ret;\n"
729ca1c9b0cSelric 		     "memcpy(data->_save.data, begin, ret);\n");
730ca1c9b0cSelric 	fprintf (codefile,
731ca1c9b0cSelric 		 "if(size) *size = ret;\n"
732ca1c9b0cSelric 		 "return 0;\n");
733ca1c9b0cSelric 	fprintf (codefile,
734ca1c9b0cSelric 		 "fail:\n"
735ca1c9b0cSelric 		 "free_%s(data);\n"
736ca1c9b0cSelric 		 "return e;\n",
737ca1c9b0cSelric 		 s->gen_name);
738ca1c9b0cSelric 	break;
739ca1c9b0cSelric     default:
740ca1c9b0cSelric 	abort ();
741ca1c9b0cSelric     }
742ca1c9b0cSelric     fprintf (codefile, "}\n\n");
743ca1c9b0cSelric }
744