/src/strongswan/src/libstrongswan/asn1/asn1_parser.c
Line | Count | Source |
1 | | /* |
2 | | * Copyright (C) 2006 Martin Will |
3 | | * Copyright (C) 2000-2017 Andreas Steffen |
4 | | * |
5 | | * Copyright (C) secunet Security Networks AG |
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 | | |
18 | | #include <stdio.h> |
19 | | #include <string.h> |
20 | | #include <time.h> |
21 | | |
22 | | #include <utils/debug.h> |
23 | | |
24 | | #include "asn1.h" |
25 | | #include "asn1_parser.h" |
26 | | |
27 | | #define ASN1_MAX_LEVEL 10 |
28 | | |
29 | | typedef struct private_asn1_parser_t private_asn1_parser_t; |
30 | | |
31 | | /** |
32 | | * Private data of an asn1_cxt_t object. |
33 | | */ |
34 | | struct private_asn1_parser_t { |
35 | | /** |
36 | | * Public interface. |
37 | | */ |
38 | | asn1_parser_t public; |
39 | | |
40 | | /** |
41 | | * Syntax definition of ASN.1 object |
42 | | */ |
43 | | asn1Object_t const *objects; |
44 | | |
45 | | /** |
46 | | * Current syntax definition line |
47 | | */ |
48 | | int line; |
49 | | |
50 | | /** |
51 | | * Current stat of the parsing operation |
52 | | */ |
53 | | bool success; |
54 | | |
55 | | /** |
56 | | * Declare object data as private - use debug level 4 to log it |
57 | | */ |
58 | | bool private; |
59 | | |
60 | | /** |
61 | | * Top-most type is implicit - ignore it |
62 | | */ |
63 | | bool implicit; |
64 | | |
65 | | /** |
66 | | * Top-most parsing level - defaults to 0 |
67 | | */ |
68 | | u_int level0; |
69 | | |
70 | | /** |
71 | | * Jump back address for loops for each level |
72 | | */ |
73 | | int loopAddr[ASN1_MAX_LEVEL + 1]; |
74 | | |
75 | | /** |
76 | | * Current parsing pointer for each level |
77 | | */ |
78 | | chunk_t blobs[ASN1_MAX_LEVEL + 2]; |
79 | | |
80 | | /** |
81 | | * Parsing a CHOICE on the current level ? |
82 | | */ |
83 | | bool choice[ASN1_MAX_LEVEL + 2]; |
84 | | |
85 | | }; |
86 | | |
87 | | METHOD(asn1_parser_t, iterate, bool, |
88 | | private_asn1_parser_t *this, int *objectID, chunk_t *object) |
89 | 1.09M | { |
90 | 1.09M | chunk_t *blob, *blob1, blob_ori; |
91 | 1.09M | u_char *start_ptr; |
92 | 1.09M | u_int level DBG_UNUSED; |
93 | 1.09M | asn1Object_t obj; |
94 | | |
95 | 1.09M | *object = chunk_empty; |
96 | | |
97 | | /* Advance to the next object syntax definition line */ |
98 | 1.09M | obj = this->objects[++(this->line)]; |
99 | | |
100 | | /* Terminate if the end of the object syntax definition has been reached */ |
101 | 1.09M | if (obj.flags & ASN1_EXIT) |
102 | 92.7k | { |
103 | 92.7k | return FALSE; |
104 | 92.7k | } |
105 | | |
106 | 1.00M | if (obj.flags & ASN1_END) /* end of loop or choice or option found */ |
107 | 203k | { |
108 | 203k | if (this->loopAddr[obj.level] && this->blobs[obj.level+1].len > 0) |
109 | 106k | { |
110 | 106k | this->line = this->loopAddr[obj.level]; /* another iteration */ |
111 | 106k | obj = this->objects[this->line]; |
112 | 106k | } |
113 | 97.1k | else |
114 | 97.1k | { |
115 | 97.1k | this->loopAddr[obj.level] = 0; /* exit loop */ |
116 | | |
117 | 97.1k | if (obj.flags & ASN1_CHOICE) /* end of choices */ |
118 | 5.24k | { |
119 | 5.24k | if (this->choice[obj.level+1]) |
120 | 119 | { |
121 | 119 | DBG1(DBG_ASN, "L%d - %s: incorrect choice encoding", |
122 | 119 | this->level0 + obj.level, obj.name); |
123 | 119 | this->success = FALSE; |
124 | 119 | goto end; |
125 | 119 | } |
126 | 5.24k | } |
127 | | |
128 | 96.9k | if (obj.flags & ASN1_CH) /* end of choice */ |
129 | 5.12k | { |
130 | | /* parsed a valid choice */ |
131 | 5.12k | this->choice[obj.level] = FALSE; |
132 | | |
133 | | /* advance to end of choices */ |
134 | 5.12k | do |
135 | 11.9k | { |
136 | 11.9k | this->line++; |
137 | 11.9k | } |
138 | 11.9k | while (!((this->objects[this->line].flags & ASN1_END) && |
139 | 7.79k | (this->objects[this->line].flags & ASN1_CHOICE) && |
140 | 5.18k | (this->objects[this->line].level == obj.level-1))); |
141 | 5.12k | this->line--; |
142 | 5.12k | } |
143 | | |
144 | 96.9k | goto end; |
145 | 97.1k | } |
146 | 203k | } |
147 | | |
148 | 905k | level = this->level0 + obj.level; |
149 | 905k | blob = this->blobs + obj.level; |
150 | 905k | blob_ori = *blob; |
151 | 905k | blob1 = blob + 1; |
152 | 905k | start_ptr = blob->ptr; |
153 | | |
154 | | /* handle ASN.1 defaults values */ |
155 | 905k | if ((obj.flags & ASN1_DEF) && (blob->len == 0 || *start_ptr != obj.type) ) |
156 | 38.1k | { |
157 | | /* field is missing */ |
158 | 38.1k | DBG2(DBG_ASN, "L%d - %s:", level, obj.name); |
159 | 38.1k | if (obj.type & ASN1_CONSTRUCTED) |
160 | 9.36k | { |
161 | 9.36k | this->line++ ; /* skip context-specific tag */ |
162 | 9.36k | } |
163 | 38.1k | goto end; |
164 | 38.1k | } |
165 | | |
166 | | /* handle ASN.1 options */ |
167 | 866k | if ((obj.flags & ASN1_OPT) |
168 | 280k | && (blob->len == 0 || *start_ptr != obj.type)) |
169 | 178k | { |
170 | | /* advance to end of missing option field */ |
171 | 178k | do |
172 | 352k | { |
173 | 352k | this->line++; |
174 | 352k | } |
175 | 352k | while (!((this->objects[this->line].flags & ASN1_END) && |
176 | 186k | (this->objects[this->line].level == obj.level))); |
177 | 178k | goto end; |
178 | 178k | } |
179 | | |
180 | | /* an ASN.1 object must possess at least a tag and length field */ |
181 | 688k | if (blob->len < 2) |
182 | 17.9k | { |
183 | 17.9k | DBG1(DBG_ASN, "L%d - %s: ASN.1 object smaller than 2 octets", |
184 | 17.9k | level, obj.name); |
185 | 17.9k | this->success = FALSE; |
186 | 17.9k | goto end; |
187 | 17.9k | } |
188 | | |
189 | 670k | blob1->len = asn1_length(blob); |
190 | | |
191 | 670k | if (blob1->len == ASN1_INVALID_LENGTH) |
192 | 6.56k | { |
193 | 6.56k | DBG1(DBG_ASN, "L%d - %s: length of ASN.1 object invalid or too large", |
194 | 6.56k | level, obj.name); |
195 | 6.56k | this->success = FALSE; |
196 | 6.56k | goto end; |
197 | 6.56k | } |
198 | | |
199 | 663k | blob1->ptr = blob->ptr; |
200 | 663k | blob->ptr += blob1->len; |
201 | 663k | blob->len -= blob1->len; |
202 | | |
203 | | /* handle ASN.1 choice without explicit context encoding */ |
204 | 663k | if ((obj.flags & ASN1_CHOICE) && obj.type == ASN1_EOC) |
205 | 4.14k | { |
206 | 4.14k | DBG2(DBG_ASN, "L%d - %s:", level, obj.name); |
207 | 4.14k | this->choice[obj.level+1] = TRUE; |
208 | 4.14k | *blob1 = blob_ori; |
209 | 4.14k | goto end; |
210 | 4.14k | } |
211 | | |
212 | | /* return raw ASN.1 object without prior type checking */ |
213 | 659k | if (obj.flags & ASN1_RAW) |
214 | 139k | { |
215 | 139k | DBG2(DBG_ASN, "L%d - %s:", level, obj.name); |
216 | 139k | object->ptr = start_ptr; |
217 | 139k | object->len = (size_t)(blob->ptr - start_ptr); |
218 | 139k | goto end; |
219 | 139k | } |
220 | | |
221 | 520k | if (*start_ptr != obj.type && !(this->implicit && this->line == 0)) |
222 | 31.3k | { |
223 | 31.3k | DBG2(DBG_ASN, "L%d - %s: ASN1 tag 0x%02x expected, but is 0x%02x", |
224 | 31.3k | level, obj.name, obj.type, *start_ptr); |
225 | 31.3k | DBG3(DBG_ASN, "%b", start_ptr, (u_int)(blob->ptr - start_ptr)); |
226 | 31.3k | this->success = FALSE; |
227 | 31.3k | goto end; |
228 | 31.3k | } |
229 | | |
230 | 489k | DBG2(DBG_ASN, "L%d - %s:", level, obj.name); |
231 | | |
232 | | /* In case of "SEQUENCE OF" or "SET OF" start a loop */ |
233 | 489k | if (obj.flags & ASN1_LOOP) |
234 | 29.4k | { |
235 | 29.4k | if (blob1->len > 0) |
236 | 28.2k | { |
237 | | /* at least one item, start the loop */ |
238 | 28.2k | this->loopAddr[obj.level] = this->line + 1; |
239 | 28.2k | } |
240 | 1.14k | else |
241 | 1.14k | { |
242 | | /* no items, advance directly to end of loop */ |
243 | 1.14k | do |
244 | 7.92k | { |
245 | 7.92k | this->line++; |
246 | 7.92k | } |
247 | 7.92k | while (!((this->objects[this->line].flags & ASN1_END) && |
248 | 2.50k | (this->objects[this->line].level == obj.level))); |
249 | 1.14k | goto end; |
250 | 1.14k | } |
251 | 29.4k | } |
252 | | |
253 | | /* In case of a "CHOICE" start to scan for exactly one valid choice */ |
254 | 488k | if (obj.flags & ASN1_CHOICE) |
255 | 1.54k | { |
256 | 1.54k | if (blob1->len == 0) |
257 | 9 | { |
258 | 9 | DBG1(DBG_ASN, "L%d - %s: contains no choice", level, obj.name); |
259 | 9 | this->success = FALSE; |
260 | 9 | goto end; |
261 | 9 | } |
262 | 1.53k | this->choice[obj.level+1] = TRUE; |
263 | 1.53k | } |
264 | | |
265 | 488k | if (obj.flags & ASN1_OBJ) |
266 | 57.5k | { |
267 | 57.5k | object->ptr = start_ptr; |
268 | 57.5k | object->len = (size_t)(blob->ptr - start_ptr); |
269 | 57.5k | if (this->private) |
270 | 0 | { |
271 | 0 | DBG4(DBG_ASN, "%B", object); |
272 | 0 | } |
273 | 57.5k | else |
274 | 57.5k | { |
275 | 57.5k | DBG3(DBG_ASN, "%B", object); |
276 | 57.5k | } |
277 | 57.5k | } |
278 | 430k | else if (obj.flags & ASN1_BODY) |
279 | 261k | { |
280 | 261k | *object = *blob1; |
281 | 261k | asn1_debug_simple_object(*object, obj.type, this->private); |
282 | 261k | } |
283 | | |
284 | 1.00M | end: |
285 | 1.00M | *objectID = this->line; |
286 | 1.00M | return this->success; |
287 | 488k | } |
288 | | |
289 | | METHOD(asn1_parser_t, get_level, u_int, |
290 | | private_asn1_parser_t *this) |
291 | 500k | { |
292 | 500k | return this->level0 + this->objects[this->line].level; |
293 | 500k | } |
294 | | |
295 | | METHOD(asn1_parser_t, set_top_level, void, |
296 | | private_asn1_parser_t *this, u_int level0) |
297 | 94.9k | { |
298 | 94.9k | this->level0 = level0; |
299 | 94.9k | } |
300 | | |
301 | | METHOD(asn1_parser_t, set_flags, void, |
302 | | private_asn1_parser_t *this, bool implicit, bool private) |
303 | 3.69k | { |
304 | 3.69k | this->implicit = implicit; |
305 | 3.69k | this->private = private; |
306 | 3.69k | } |
307 | | |
308 | | METHOD(asn1_parser_t, success, bool, |
309 | | private_asn1_parser_t *this) |
310 | 83.5k | { |
311 | 83.5k | return this->success; |
312 | 83.5k | } |
313 | | |
314 | | METHOD(asn1_parser_t, destroy, void, |
315 | | private_asn1_parser_t *this) |
316 | 175k | { |
317 | 175k | free(this); |
318 | 175k | } |
319 | | |
320 | | /** |
321 | | * Defined in header. |
322 | | */ |
323 | | asn1_parser_t* asn1_parser_create(asn1Object_t const *objects, chunk_t blob) |
324 | 175k | { |
325 | 175k | private_asn1_parser_t *this; |
326 | | |
327 | 175k | INIT(this, |
328 | 175k | .public = { |
329 | 175k | .iterate = _iterate, |
330 | 175k | .get_level = _get_level, |
331 | 175k | .set_top_level = _set_top_level, |
332 | 175k | .set_flags = _set_flags, |
333 | 175k | .success = _success, |
334 | 175k | .destroy = _destroy, |
335 | 175k | }, |
336 | 175k | .objects = objects, |
337 | 175k | .blobs[0] = blob, |
338 | 175k | .line = -1, |
339 | 175k | .success = TRUE, |
340 | 175k | ); |
341 | | |
342 | 175k | return &this->public; |
343 | 175k | } |