5a32d6e64f7e32cc73dbe0f7393924d3c7a449d5
[strongswan.git] / src / libstrongswan / asn1 / asn1_parser.c
1 /*
2 * Copyright (C) 2006 Martin Will
3 * Copyright (C) 2000-2008 Andreas Steffen
4 *
5 * Hochschule fuer Technik Rapperswil
6 *
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License as published by the
9 * Free Software Foundation; either version 2 of the License, or (at your
10 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
11 *
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
14 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
15 * for more details.
16 *
17 * $Id: asn1.c 3589 2008-03-13 14:14:44Z martin $
18 */
19
20 #include <stdio.h>
21 #include <string.h>
22 #include <time.h>
23
24 #include <library.h>
25 #include <debug.h>
26
27 #include "asn1.h"
28 #include "asn1_parser.h"
29
30 #define ASN1_MAX_LEVEL 10
31
32 typedef struct private_asn1_parser_t private_asn1_parser_t;
33
34 /**
35 * Private data of an asn1_cxt_t object.
36 */
37 struct private_asn1_parser_t {
38 /**
39 * Public interface.
40 */
41 asn1_parser_t public;
42
43 /**
44 * Syntax definition of ASN.1 object
45 */
46 asn1Object_t const *objects;
47
48 /**
49 * Total number of syntax definition lines
50 */
51 int roof;
52
53 /**
54 * Current syntax definition line
55 */
56 int line;
57
58 /**
59 * Current stat of the parsing operation
60 */
61 bool success;
62
63 /**
64 * Declare object data as private - use debug level 4 to log it
65 */
66 bool private;
67
68 /**
69 * Top-most type is implicit - ignore it
70 */
71 bool implicit;
72
73 /**
74 * Top-most parsing level - defaults to 0
75 */
76 u_int level0;
77
78 /**
79 * Jump back address for loops for each level
80 */
81 int loopAddr[ASN1_MAX_LEVEL + 1];
82
83 /**
84 * Current parsing pointer for each level
85 */
86 chunk_t blobs[ASN1_MAX_LEVEL + 2];
87 };
88
89 /**
90 * Implementation of asn1_parser_t.iterate
91 */
92 static bool iterate(private_asn1_parser_t *this, int *objectID, chunk_t *object)
93 {
94 chunk_t *blob, *blob1;
95 u_char *start_ptr;
96 u_int level;
97 asn1Object_t obj;
98
99 *object = chunk_empty;
100
101 /* Terminate if the end of the object syntax definition has been reached */
102 if (++(this->line) >= this->roof)
103 {
104 return FALSE;
105 }
106 obj = this->objects[this->line];
107
108 if (obj.flags & ASN1_END) /* end of loop or option found */
109 {
110 if (this->loopAddr[obj.level] && this->blobs[obj.level+1].len > 0)
111 {
112 this->line = this->loopAddr[obj.level]; /* another iteration */
113 obj = this->objects[this->line];
114 }
115 else
116 {
117 this->loopAddr[obj.level] = 0; /* exit loop or option*/
118 goto end;
119 }
120 }
121
122 level = this->level0 + obj.level;
123 blob = this->blobs + obj.level;
124 blob1 = blob + 1;
125 start_ptr = blob->ptr;
126
127 /* handle ASN.1 defaults values */
128 if ((obj.flags & ASN1_DEF) && (blob->len == 0 || *start_ptr != obj.type) )
129 {
130 /* field is missing */
131 DBG2("L%d - %s:", level, obj.name);
132 if (obj.type & ASN1_CONSTRUCTED)
133 {
134 this->line++ ; /* skip context-specific tag */
135 }
136 goto end;
137 }
138
139 /* handle ASN.1 options */
140
141 if ((obj.flags & ASN1_OPT)
142 && (blob->len == 0 || *start_ptr != obj.type))
143 {
144 /* advance to end of missing option field */
145 do
146 {
147 this->line++;
148 }
149 while (!((this->objects[this->line].flags & ASN1_END) &&
150 (this->objects[this->line].level == obj.level)));
151 goto end;
152 }
153
154 /* an ASN.1 object must possess at least a tag and length field */
155
156 if (blob->len < 2)
157 {
158 DBG1("L%d - %s: ASN.1 object smaller than 2 octets",
159 level, obj.name);
160 this->success = FALSE;
161 goto end;
162 }
163
164 blob1->len = asn1_length(blob);
165
166 if (blob1->len == ASN1_INVALID_LENGTH || blob->len < blob1->len)
167 {
168 DBG1("L%d - %s: length of ASN.1 object invalid or too large",
169 level, obj.name);
170 this->success = FALSE;
171 }
172
173 blob1->ptr = blob->ptr;
174 blob->ptr += blob1->len;
175 blob->len -= blob1->len;
176
177 /* return raw ASN.1 object without prior type checking */
178
179 if (obj.flags & ASN1_RAW)
180 {
181 DBG2("L%d - %s:", level, obj.name);
182 object->ptr = start_ptr;
183 object->len = (size_t)(blob->ptr - start_ptr);
184 goto end;
185 }
186
187 if (*start_ptr != obj.type && !(this->implicit && this->line == 0))
188 {
189 DBG1("L%d - %s: ASN1 tag 0x%02x expected, but is 0x%02x",
190 level, obj.name, obj.type, *start_ptr);
191 DBG3("%b", start_ptr, (u_int)(blob->ptr - start_ptr));
192 this->success = FALSE;
193 goto end;
194 }
195
196 DBG2("L%d - %s:", level, obj.name);
197
198 /* In case of "SEQUENCE OF" or "SET OF" start a loop */
199 if (obj.flags & ASN1_LOOP)
200 {
201 if (blob1->len > 0)
202 {
203 /* at least one item, start the loop */
204 this->loopAddr[obj.level] = this->line + 1;
205 }
206 else
207 {
208 /* no items, advance directly to end of loop */
209 do
210 {
211 this->line++;
212 }
213 while (!((this->objects[this->line].flags & ASN1_END) &&
214 (this->objects[this->line].level == obj.level)));
215 goto end;
216 }
217 }
218
219 if (obj.flags & ASN1_OBJ)
220 {
221 object->ptr = start_ptr;
222 object->len = (size_t)(blob->ptr - start_ptr);
223 if (this->private)
224 {
225 DBG4("%B", object);
226 }
227 else
228 {
229 DBG3("%B", object);
230 }
231 }
232 else if (obj.flags & ASN1_BODY)
233 {
234 *object = *blob1;
235 asn1_debug_simple_object(*object, obj.type, this->private);
236 }
237
238 end:
239 *objectID = this->line;
240 return this->success;
241 }
242
243 /**
244 * Implementation of asn1_parser_t.get_level
245 */
246 static u_int get_level(private_asn1_parser_t *this)
247 {
248 return this->level0 + this->objects[this->line].level;
249 }
250
251 /**
252 * Implementation of asn1_parser_t.set_top_level
253 */
254 static void set_top_level(private_asn1_parser_t *this, u_int level0)
255 {
256 this->level0 = level0;
257 }
258
259 /**
260 * Implementation of asn1_parser_t.set_flags
261 */
262 static void set_flags(private_asn1_parser_t *this, bool implicit, bool private)
263 {
264 this->implicit = implicit;
265 this->private = private;
266 }
267
268 /**
269 * Implementation of asn1_parser_t.success
270 */
271 static bool success(private_asn1_parser_t *this)
272 {
273 return this->success;
274 }
275
276 /**
277 * Implementation of asn1_parser_t.destroy
278 */
279 static void destroy(private_asn1_parser_t *this)
280 {
281 free(this);
282 }
283
284 /**
285 * Defined in header.
286 */
287 asn1_parser_t* asn1_parser_create(asn1Object_t const *objects, int roof, chunk_t blob)
288 {
289 private_asn1_parser_t *this = malloc_thing(private_asn1_parser_t);
290
291 memset(this, '\0', sizeof(private_asn1_parser_t));
292 this->objects = objects;
293 this->blobs[0] = blob;
294 this->line = -1;
295 this->roof = roof;
296 this->success = TRUE;
297
298 this->public.iterate = (bool (*)(asn1_parser_t*, int*, chunk_t*))iterate;
299 this->public.get_level = (u_int (*)(asn1_parser_t*))get_level;
300 this->public.set_top_level = (void (*)(asn1_parser_t*, u_int))set_top_level;
301 this->public.set_flags = (void (*)(asn1_parser_t*, bool, bool))set_flags;
302 this->public.success = (bool (*)(asn1_parser_t*))success;
303 this->public.destroy = (void (*)(asn1_parser_t*))destroy;
304
305 return &this->public;
306 }