]> git.ipfire.org Git - thirdparty/strongswan.git/blame - src/libstrongswan/asn1/asn1_parser.c
Update copyright headers after acquisition by secunet
[thirdparty/strongswan.git] / src / libstrongswan / asn1 / asn1_parser.c
CommitLineData
d3d7e46b
AS
1/*
2 * Copyright (C) 2006 Martin Will
407fcca2 3 * Copyright (C) 2000-2017 Andreas Steffen
19ef2aec
TB
4 *
5 * Copyright (C) secunet Security Networks AG
d3d7e46b
AS
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.
d3d7e46b
AS
16 */
17
18#include <stdio.h>
19#include <string.h>
20#include <time.h>
21
f05b4272 22#include <utils/debug.h>
d3d7e46b
AS
23
24#include "asn1.h"
25#include "asn1_parser.h"
26
27#define ASN1_MAX_LEVEL 10
28
29typedef struct private_asn1_parser_t private_asn1_parser_t;
30
31/**
32 * Private data of an asn1_cxt_t object.
33 */
34struct 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
d3d7e46b
AS
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 /**
7daf5226 56 * Declare object data as private - use debug level 4 to log it
d3d7e46b
AS
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];
407fcca2
AS
79
80 /**
81 * Parsing a CHOICE on the current level ?
82 */
83 bool choice[ASN1_MAX_LEVEL + 2];
84
d3d7e46b
AS
85};
86
3cd69cfa
AS
87METHOD(asn1_parser_t, iterate, bool,
88 private_asn1_parser_t *this, int *objectID, chunk_t *object)
d3d7e46b 89{
407fcca2 90 chunk_t *blob, *blob1, blob_ori;
d3d7e46b
AS
91 u_char *start_ptr;
92 u_int level;
93 asn1Object_t obj;
7daf5226 94
d3d7e46b
AS
95 *object = chunk_empty;
96
460025e2
AS
97 /* Advance to the next object syntax definition line */
98 obj = this->objects[++(this->line)];
99
d3d7e46b 100 /* Terminate if the end of the object syntax definition has been reached */
460025e2 101 if (obj.flags & ASN1_EXIT)
d3d7e46b
AS
102 {
103 return FALSE;
104 }
7daf5226 105
407fcca2 106 if (obj.flags & ASN1_END) /* end of loop or choice or option found */
d3d7e46b
AS
107 {
108 if (this->loopAddr[obj.level] && this->blobs[obj.level+1].len > 0)
109 {
110 this->line = this->loopAddr[obj.level]; /* another iteration */
111 obj = this->objects[this->line];
112 }
113 else
114 {
407fcca2
AS
115 this->loopAddr[obj.level] = 0; /* exit loop */
116
117 if (obj.flags & ASN1_CHOICE) /* end of choices */
118 {
119 if (this->choice[obj.level+1])
120 {
121 DBG1(DBG_ASN, "L%d - %s: incorrect choice encoding",
122 this->level0 + obj.level, obj.name);
123 this->success = FALSE;
124 goto end;
125 }
126 }
127
128 if (obj.flags & ASN1_CH) /* end of choice */
129 {
130 /* parsed a valid choice */
131 this->choice[obj.level] = FALSE;
132
133 /* advance to end of choices */
134 do
135 {
136 this->line++;
137 }
138 while (!((this->objects[this->line].flags & ASN1_END) &&
139 (this->objects[this->line].flags & ASN1_CHOICE) &&
140 (this->objects[this->line].level == obj.level-1)));
141 this->line--;
142 }
143
d3d7e46b
AS
144 goto end;
145 }
146 }
7daf5226 147
d3d7e46b
AS
148 level = this->level0 + obj.level;
149 blob = this->blobs + obj.level;
407fcca2 150 blob_ori = *blob;
d3d7e46b
AS
151 blob1 = blob + 1;
152 start_ptr = blob->ptr;
7daf5226 153
d3d7e46b
AS
154 /* handle ASN.1 defaults values */
155 if ((obj.flags & ASN1_DEF) && (blob->len == 0 || *start_ptr != obj.type) )
156 {
157 /* field is missing */
c7f3a056 158 DBG2(DBG_ASN, "L%d - %s:", level, obj.name);
d3d7e46b
AS
159 if (obj.type & ASN1_CONSTRUCTED)
160 {
161 this->line++ ; /* skip context-specific tag */
162 }
163 goto end;
164 }
7daf5226 165
d3d7e46b 166 /* handle ASN.1 options */
d3d7e46b
AS
167 if ((obj.flags & ASN1_OPT)
168 && (blob->len == 0 || *start_ptr != obj.type))
169 {
170 /* advance to end of missing option field */
171 do
172 {
173 this->line++;
174 }
175 while (!((this->objects[this->line].flags & ASN1_END) &&
176 (this->objects[this->line].level == obj.level)));
177 goto end;
178 }
7daf5226 179
d3d7e46b 180 /* an ASN.1 object must possess at least a tag and length field */
d3d7e46b
AS
181 if (blob->len < 2)
182 {
c7f3a056 183 DBG1(DBG_ASN, "L%d - %s: ASN.1 object smaller than 2 octets",
d3d7e46b
AS
184 level, obj.name);
185 this->success = FALSE;
186 goto end;
187 }
7daf5226 188
d3d7e46b 189 blob1->len = asn1_length(blob);
7daf5226 190
b29832c7 191 if (blob1->len == ASN1_INVALID_LENGTH)
d3d7e46b 192 {
c7f3a056 193 DBG1(DBG_ASN, "L%d - %s: length of ASN.1 object invalid or too large",
d3d7e46b
AS
194 level, obj.name);
195 this->success = FALSE;
1f9e4d02 196 goto end;
d3d7e46b 197 }
7daf5226 198
d3d7e46b
AS
199 blob1->ptr = blob->ptr;
200 blob->ptr += blob1->len;
201 blob->len -= blob1->len;
7daf5226 202
407fcca2
AS
203 /* handle ASN.1 choice without explicit context encoding */
204 if ((obj.flags & ASN1_CHOICE) && obj.type == ASN1_EOC)
205 {
206 DBG2(DBG_ASN, "L%d - %s:", level, obj.name);
207 this->choice[obj.level+1] = TRUE;
208 *blob1 = blob_ori;
209 goto end;
210 }
7daf5226 211
407fcca2 212 /* return raw ASN.1 object without prior type checking */
d3d7e46b
AS
213 if (obj.flags & ASN1_RAW)
214 {
c7f3a056 215 DBG2(DBG_ASN, "L%d - %s:", level, obj.name);
d3d7e46b
AS
216 object->ptr = start_ptr;
217 object->len = (size_t)(blob->ptr - start_ptr);
218 goto end;
219 }
220
221 if (*start_ptr != obj.type && !(this->implicit && this->line == 0))
222 {
e81260d4 223 DBG2(DBG_ASN, "L%d - %s: ASN1 tag 0x%02x expected, but is 0x%02x",
d3d7e46b 224 level, obj.name, obj.type, *start_ptr);
c7f3a056 225 DBG3(DBG_ASN, "%b", start_ptr, (u_int)(blob->ptr - start_ptr));
d3d7e46b
AS
226 this->success = FALSE;
227 goto end;
228 }
7daf5226 229
c7f3a056 230 DBG2(DBG_ASN, "L%d - %s:", level, obj.name);
7daf5226
MW
231
232 /* In case of "SEQUENCE OF" or "SET OF" start a loop */
d3d7e46b
AS
233 if (obj.flags & ASN1_LOOP)
234 {
235 if (blob1->len > 0)
236 {
237 /* at least one item, start the loop */
238 this->loopAddr[obj.level] = this->line + 1;
239 }
240 else
241 {
242 /* no items, advance directly to end of loop */
243 do
244 {
245 this->line++;
246 }
247 while (!((this->objects[this->line].flags & ASN1_END) &&
248 (this->objects[this->line].level == obj.level)));
249 goto end;
250 }
251 }
252
407fcca2
AS
253 /* In case of a "CHOICE" start to scan for exactly one valid choice */
254 if (obj.flags & ASN1_CHOICE)
255 {
256 if (blob1->len == 0)
257 {
258 DBG1(DBG_ASN, "L%d - %s: contains no choice", level, obj.name);
259 this->success = FALSE;
260 goto end;
261 }
262 this->choice[obj.level+1] = TRUE;
263 }
264
d3d7e46b
AS
265 if (obj.flags & ASN1_OBJ)
266 {
267 object->ptr = start_ptr;
268 object->len = (size_t)(blob->ptr - start_ptr);
269 if (this->private)
270 {
c7f3a056 271 DBG4(DBG_ASN, "%B", object);
d3d7e46b
AS
272 }
273 else
274 {
c7f3a056 275 DBG3(DBG_ASN, "%B", object);
d3d7e46b
AS
276 }
277 }
278 else if (obj.flags & ASN1_BODY)
279 {
280 *object = *blob1;
281 asn1_debug_simple_object(*object, obj.type, this->private);
282 }
283
284end:
285 *objectID = this->line;
286 return this->success;
287}
288
3cd69cfa
AS
289METHOD(asn1_parser_t, get_level, u_int,
290private_asn1_parser_t *this)
d3d7e46b
AS
291{
292 return this->level0 + this->objects[this->line].level;
293}
294
3cd69cfa
AS
295METHOD(asn1_parser_t, set_top_level, void,
296 private_asn1_parser_t *this, u_int level0)
d3d7e46b
AS
297{
298 this->level0 = level0;
299}
300
3cd69cfa
AS
301METHOD(asn1_parser_t, set_flags, void,
302 private_asn1_parser_t *this, bool implicit, bool private)
d3d7e46b
AS
303{
304 this->implicit = implicit;
305 this->private = private;
306}
307
3cd69cfa
AS
308METHOD(asn1_parser_t, success, bool,
309 private_asn1_parser_t *this)
d3d7e46b
AS
310{
311 return this->success;
312}
313
3cd69cfa
AS
314METHOD(asn1_parser_t, destroy, void,
315 private_asn1_parser_t *this)
d3d7e46b
AS
316{
317 free(this);
318}
319
320/**
321 * Defined in header.
322 */
460025e2 323asn1_parser_t* asn1_parser_create(asn1Object_t const *objects, chunk_t blob)
d3d7e46b 324{
3cd69cfa
AS
325 private_asn1_parser_t *this;
326
327 INIT(this,
328 .public = {
329 .iterate = _iterate,
330 .get_level = _get_level,
331 .set_top_level = _set_top_level,
332 .set_flags = _set_flags,
333 .success = _success,
334 .destroy = _destroy,
375dacca 335 },
3cd69cfa
AS
336 .objects = objects,
337 .blobs[0] = blob,
338 .line = -1,
339 .success = TRUE,
340 );
d3d7e46b
AS
341
342 return &this->public;
343}