xref: /freebsd/crypto/heimdal/lib/asn1/gen_encode.c (revision 1b6c76a2fe091c74f08427e6c870851025a9cf67)
1 /*
2  * Copyright (c) 1997 - 2000 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.11 2000/06/19 15:19:08 joda 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 TBitString: {
80 	Member *m;
81 	int pos;
82 	int rest;
83 	int tag = -1;
84 
85 	if (t->members == NULL)
86 	    break;
87 
88 	fprintf (codefile, "{\n"
89 		 "unsigned char c = 0;\n");
90 	pos = t->members->prev->val;
91 	/* fix for buggy MIT (and OSF?) code */
92 	if (pos > 31)
93 	    abort ();
94 	/*
95 	 * It seems that if we do not always set pos to 31 here, the MIT
96 	 * code will do the wrong thing.
97 	 *
98 	 * I hate ASN.1 (and DER), but I hate it even more when everybody
99 	 * has to screw it up differently.
100 	 */
101 	pos = 31;
102 	rest = 7 - (pos % 8);
103 
104 	for (m = t->members->prev; m && tag != m->val; m = m->prev) {
105 	    while (m->val / 8 < pos / 8) {
106 		fprintf (codefile,
107 			 "*p-- = c; len--; ret++;\n"
108 			 "c = 0;\n");
109 		pos -= 8;
110 	    }
111 	    fprintf (codefile,
112 		     "if(%s->%s) c |= 1<<%d;\n", name, m->gen_name,
113 		     7 - m->val % 8);
114 
115 	    if (tag == -1)
116 		tag = m->val;
117 	}
118 
119 	fprintf (codefile,
120 		 "*p-- = c;\n"
121 		 "*p-- = %d;\n"
122 		 "len -= 2;\n"
123 		 "ret += 2;\n"
124 		 "}\n\n"
125 		 "e = der_put_length_and_tag (p, len, ret, UNIV, PRIM,"
126 		 "UT_BitString, &l);\n"
127 		 "BACK;\n",
128 		 rest);
129 	break;
130     }
131     case TSequence: {
132 	Member *m;
133 	int tag = -1;
134 
135 	if (t->members == NULL)
136 	    break;
137 
138 	for (m = t->members->prev; m && tag != m->val; m = m->prev) {
139 	    char *s;
140 
141 	    asprintf (&s, "%s(%s)->%s", m->optional ? "" : "&", name, m->gen_name);
142 	    if (m->optional)
143 		fprintf (codefile,
144 			 "if(%s)\n",
145 			 s);
146 #if 1
147 	    fprintf (codefile, "{\n"
148 		     "int oldret = ret;\n"
149 		     "ret = 0;\n");
150 #endif
151 	    encode_type (s, m->type);
152 	    fprintf (codefile,
153 		     "e = der_put_length_and_tag (p, len, ret, CONTEXT, CONS, "
154 		     "%d, &l);\n"
155 		     "BACK;\n",
156 		     m->val);
157 #if 1
158 	    fprintf (codefile,
159 		     "ret += oldret;\n"
160 		     "}\n");
161 #endif
162 	    if (tag == -1)
163 		tag = m->val;
164 	    free (s);
165 	}
166 	fprintf (codefile,
167 		 "e = der_put_length_and_tag (p, len, ret, UNIV, CONS, UT_Sequence, &l);\n"
168 		 "BACK;\n");
169 	break;
170     }
171     case TSequenceOf: {
172 	char *n;
173 
174 	fprintf (codefile,
175 		 "for(i = (%s)->len - 1; i >= 0; --i) {\n"
176 #if 1
177 		 "int oldret = ret;\n"
178 		 "ret = 0;\n",
179 #else
180 		 ,
181 #endif
182 		 name);
183 	asprintf (&n, "&(%s)->val[i]", name);
184 	encode_type (n, t->subtype);
185 	fprintf (codefile,
186 #if 1
187 		 "ret += oldret;\n"
188 #endif
189 		 "}\n"
190 		 "e = der_put_length_and_tag (p, len, ret, UNIV, CONS, UT_Sequence, &l);\n"
191 		 "BACK;\n");
192 	free (n);
193 	break;
194     }
195     case TGeneralizedTime:
196 	encode_primitive ("generalized_time", name);
197 	break;
198     case TGeneralString:
199 	encode_primitive ("general_string", name);
200 	break;
201     case TApplication:
202 	encode_type (name, t->subtype);
203 	fprintf (codefile,
204 		 "e = der_put_length_and_tag (p, len, ret, APPL, CONS, %d, &l);\n"
205 		 "BACK;\n",
206 		 t->application);
207 	break;
208     default:
209 	abort ();
210     }
211 }
212 
213 void
214 generate_type_encode (const Symbol *s)
215 {
216   fprintf (headerfile,
217 	   "int    "
218 	   "encode_%s(unsigned char *, size_t, const %s *, size_t *);\n",
219 	   s->gen_name, s->gen_name);
220 
221   fprintf (codefile, "#define BACK if (e) return e; p -= l; len -= l; ret += l\n\n");
222 
223 
224   fprintf (codefile, "int\n"
225 	   "encode_%s(unsigned char *p, size_t len,"
226 	   " const %s *data, size_t *size)\n"
227 	   "{\n",
228 	   s->gen_name, s->gen_name);
229 
230   switch (s->type->type) {
231   case TInteger:
232   case TUInteger:
233   case TOctetString:
234   case TGeneralizedTime:
235   case TGeneralString:
236   case TBitString:
237   case TSequence:
238   case TSequenceOf:
239   case TApplication:
240   case TType:
241     fprintf (codefile,
242 	     "size_t ret = 0;\n"
243 	     "size_t l;\n"
244 	     "int i, e;\n\n");
245     fprintf(codefile, "i = 0;\n"); /* hack to avoid `unused variable' */
246 
247       encode_type("data", s->type);
248 
249     fprintf (codefile, "*size = ret;\n"
250 	     "return 0;\n");
251     break;
252   default:
253     abort ();
254   }
255   fprintf (codefile, "}\n\n");
256 }
257