xref: /freebsd/crypto/heimdal/lib/asn1/gen_encode.c (revision c98323078dede7579020518ec84cdcb478e5c142)
1 /*
2  * Copyright (c) 1997 - 2001 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_encode.c,v 1.12 2001/09/25 13:39:26 assar Exp $");
37 
38 static void
39 encode_primitive (const char *typename, const char *name)
40 {
41     fprintf (codefile,
42 	     "e = encode_%s(p, len, %s, &l);\n"
43 	     "BACK;\n",
44 	     typename,
45 	     name);
46 }
47 
48 static void
49 encode_type (const char *name, const Type *t)
50 {
51     switch (t->type) {
52     case TType:
53 #if 0
54 	encode_type (name, t->symbol->type);
55 #endif
56 	fprintf (codefile,
57 		 "e = encode_%s(p, len, %s, &l);\n"
58 		 "BACK;\n",
59 		 t->symbol->gen_name, name);
60 	break;
61     case TInteger:
62 	if(t->members == NULL)
63 	    encode_primitive ("integer", name);
64 	else {
65 	    char *s;
66 	    asprintf(&s, "(const int*)%s", name);
67 	    if(s == NULL)
68 		errx(1, "out of memory");
69 	    encode_primitive ("integer", s);
70 	    free(s);
71 	}
72 	break;
73     case TUInteger:
74 	encode_primitive ("unsigned", name);
75 	break;
76     case TOctetString:
77 	encode_primitive ("octet_string", name);
78 	break;
79     case TOID :
80 	encode_primitive ("oid", name);
81 	break;
82     case TBitString: {
83 	Member *m;
84 	int pos;
85 	int rest;
86 	int tag = -1;
87 
88 	if (t->members == NULL)
89 	    break;
90 
91 	fprintf (codefile, "{\n"
92 		 "unsigned char c = 0;\n");
93 	pos = t->members->prev->val;
94 	/* fix for buggy MIT (and OSF?) code */
95 	if (pos > 31)
96 	    abort ();
97 	/*
98 	 * It seems that if we do not always set pos to 31 here, the MIT
99 	 * code will do the wrong thing.
100 	 *
101 	 * I hate ASN.1 (and DER), but I hate it even more when everybody
102 	 * has to screw it up differently.
103 	 */
104 	pos = 31;
105 	rest = 7 - (pos % 8);
106 
107 	for (m = t->members->prev; m && tag != m->val; m = m->prev) {
108 	    while (m->val / 8 < pos / 8) {
109 		fprintf (codefile,
110 			 "*p-- = c; len--; ret++;\n"
111 			 "c = 0;\n");
112 		pos -= 8;
113 	    }
114 	    fprintf (codefile,
115 		     "if(%s->%s) c |= 1<<%d;\n", name, m->gen_name,
116 		     7 - m->val % 8);
117 
118 	    if (tag == -1)
119 		tag = m->val;
120 	}
121 
122 	fprintf (codefile,
123 		 "*p-- = c;\n"
124 		 "*p-- = %d;\n"
125 		 "len -= 2;\n"
126 		 "ret += 2;\n"
127 		 "}\n\n"
128 		 "e = der_put_length_and_tag (p, len, ret, UNIV, PRIM,"
129 		 "UT_BitString, &l);\n"
130 		 "BACK;\n",
131 		 rest);
132 	break;
133     }
134     case TEnumerated : {
135 	encode_primitive ("enumerated", name);
136 	break;
137     }
138     case TSequence: {
139 	Member *m;
140 	int tag = -1;
141 
142 	if (t->members == NULL)
143 	    break;
144 
145 	for (m = t->members->prev; m && tag != m->val; m = m->prev) {
146 	    char *s;
147 
148 	    asprintf (&s, "%s(%s)->%s", m->optional ? "" : "&", name, m->gen_name);
149 	    if (m->optional)
150 		fprintf (codefile,
151 			 "if(%s)\n",
152 			 s);
153 #if 1
154 	    fprintf (codefile, "{\n"
155 		     "int oldret = ret;\n"
156 		     "ret = 0;\n");
157 #endif
158 	    encode_type (s, m->type);
159 	    fprintf (codefile,
160 		     "e = der_put_length_and_tag (p, len, ret, CONTEXT, CONS, "
161 		     "%d, &l);\n"
162 		     "BACK;\n",
163 		     m->val);
164 #if 1
165 	    fprintf (codefile,
166 		     "ret += oldret;\n"
167 		     "}\n");
168 #endif
169 	    if (tag == -1)
170 		tag = m->val;
171 	    free (s);
172 	}
173 	fprintf (codefile,
174 		 "e = der_put_length_and_tag (p, len, ret, UNIV, CONS, UT_Sequence, &l);\n"
175 		 "BACK;\n");
176 	break;
177     }
178     case TSequenceOf: {
179 	char *n;
180 
181 	fprintf (codefile,
182 		 "for(i = (%s)->len - 1; i >= 0; --i) {\n"
183 #if 1
184 		 "int oldret = ret;\n"
185 		 "ret = 0;\n",
186 #else
187 		 ,
188 #endif
189 		 name);
190 	asprintf (&n, "&(%s)->val[i]", name);
191 	encode_type (n, t->subtype);
192 	fprintf (codefile,
193 #if 1
194 		 "ret += oldret;\n"
195 #endif
196 		 "}\n"
197 		 "e = der_put_length_and_tag (p, len, ret, UNIV, CONS, UT_Sequence, &l);\n"
198 		 "BACK;\n");
199 	free (n);
200 	break;
201     }
202     case TGeneralizedTime:
203 	encode_primitive ("generalized_time", name);
204 	break;
205     case TGeneralString:
206 	encode_primitive ("general_string", name);
207 	break;
208     case TApplication:
209 	encode_type (name, t->subtype);
210 	fprintf (codefile,
211 		 "e = der_put_length_and_tag (p, len, ret, APPL, CONS, %d, &l);\n"
212 		 "BACK;\n",
213 		 t->application);
214 	break;
215     default:
216 	abort ();
217     }
218 }
219 
220 void
221 generate_type_encode (const Symbol *s)
222 {
223   fprintf (headerfile,
224 	   "int    "
225 	   "encode_%s(unsigned char *, size_t, const %s *, size_t *);\n",
226 	   s->gen_name, s->gen_name);
227 
228   fprintf (codefile, "#define BACK if (e) return e; p -= l; len -= l; ret += l\n\n");
229 
230 
231   fprintf (codefile, "int\n"
232 	   "encode_%s(unsigned char *p, size_t len,"
233 	   " const %s *data, size_t *size)\n"
234 	   "{\n",
235 	   s->gen_name, s->gen_name);
236 
237   switch (s->type->type) {
238   case TInteger:
239   case TUInteger:
240   case TOctetString:
241   case TGeneralizedTime:
242   case TGeneralString:
243   case TBitString:
244   case TEnumerated:
245   case TOID:
246   case TSequence:
247   case TSequenceOf:
248   case TApplication:
249   case TType:
250     fprintf (codefile,
251 	     "size_t ret = 0;\n"
252 	     "size_t l;\n"
253 	     "int i, e;\n\n");
254     fprintf(codefile, "i = 0;\n"); /* hack to avoid `unused variable' */
255 
256       encode_type("data", s->type);
257 
258     fprintf (codefile, "*size = ret;\n"
259 	     "return 0;\n");
260     break;
261   default:
262     abort ();
263   }
264   fprintf (codefile, "}\n\n");
265 }
266