- leak detective is usable, but does not show static function names
[strongswan.git] / Source / lib / asn1 / der_decoder.c
1 /**
2 * @file der_decoder.c
3 *
4 * @brief Implementation of der_decoder_t.
5 */
6
7 /*
8 * Copyright (C) 2000-2004 Andreas Steffen
9 * Copyright (C) 2006 Martin Willi
10 * Hochschule fuer Technik Rapperswil
11 *
12 * Some parts taken over from pluto/asn1.c
13 *
14 * This program is free software; you can redistribute it and/or modify it
15 * under the terms of the GNU General Public License as published by the
16 * Free Software Foundation; either version 2 of the License, or (at your
17 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
18 *
19 * This program is distributed in the hope that it will be useful, but
20 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
21 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
22 * for more details.
23 */
24
25 #include <gmp.h>
26 #include <string.h>
27
28 #include "der_decoder.h"
29
30 #include <daemon.h>
31
32
33
34 typedef struct private_der_decoder_t private_der_decoder_t;
35
36 /**
37 * Private data of a der_decoder_t object.
38 */
39 struct private_der_decoder_t {
40 /**
41 * Public interface for this signer.
42 */
43 der_decoder_t public;
44
45 /**
46 * Rule which was just processed
47 */
48 asn1_rule_t *rule;
49
50 /**
51 * First rule of the whole ruleset
52 */
53 asn1_rule_t *first_rule;
54
55 /**
56 * Output data struct
57 */
58 void *output;
59
60 /**
61 * Complex things like this need a logger ;-)
62 */
63 logger_t *logger;
64 };
65
66 status_t read_hdr(private_der_decoder_t *this, chunk_t *data);
67
68 /**
69 * Read a sequence from data, parse its contents recursivly
70 */
71 status_t read_sequence(private_der_decoder_t *this, chunk_t data)
72 {
73 status_t status;
74 asn1_rule_t *next_rule;
75
76 while(TRUE)
77 {
78 next_rule = this->rule + 1;
79 if (next_rule->type == ASN1_END)
80 {
81 this->rule++;
82 break;
83 }
84 status = read_hdr(this, &data);
85 if (status != SUCCESS)
86 {
87 return status;
88 }
89 }
90
91 this->logger->log(this->logger, CONTROL|LEVEL2, "Sequence end");
92 return SUCCESS;
93 }
94
95 /**
96 * Read choice of data, parse if one of the choosable types arise
97 */
98 status_t read_choice(private_der_decoder_t *this, chunk_t *data)
99 {
100 status_t status = PARSE_ERROR;
101 asn1_rule_t *next_rule;
102 bool found = FALSE;
103
104 this->logger->log_chunk(this->logger, CONTROL|LEVEL2, "Choice data", *data);
105
106 while(TRUE)
107 {
108 next_rule = this->rule + 1;
109 if (next_rule->type == ASN1_END)
110 {
111 this->rule++;
112 return status;
113 }
114 if (!found && *(data->ptr) == next_rule->type)
115 {
116 found = TRUE;
117 status = read_hdr(this, data);
118 }
119 else
120 {
121 this->rule++;
122 }
123 }
124 this->logger->log(this->logger, CONTROL|LEVEL2, "Choice end");
125 return status;
126 }
127
128 /**
129 * Read a utc or generalized time
130 */
131 status_t read_time(private_der_decoder_t *this, chunk_t data)
132 {
133 struct tm t;
134 time_t tz_offset;
135 u_char *eot = NULL;
136 const char* format;
137 time_t *result = (time_t*)((u_int8_t*)this->output + this->rule->data_offset);
138
139 /* TODO: Test it */
140 this->logger->log_chunk(this->logger, CONTROL|LEVEL2, "TIME", data);
141
142 if ((eot = memchr(data.ptr, 'Z', data.len)) != NULL)
143 {
144 /* Zulu time with a zero time zone offset */
145 tz_offset = 0;
146 }
147 else if ((eot = memchr(data.ptr, '+', data.len)) != NULL)
148 {
149 int tz_hour, tz_min;
150
151 sscanf(eot+1, "%2d%2d", &tz_hour, &tz_min);
152 /* positive time zone offset */
153 tz_offset = 3600*tz_hour + 60*tz_min;
154 }
155 else if ((eot = memchr(data.ptr, '-', data.len)) != NULL)
156 {
157 int tz_hour, tz_min;
158
159 sscanf(eot+1, "%2d%2d", &tz_hour, &tz_min);
160 /* negative time zone offset */
161 tz_offset = -3600*tz_hour - 60*tz_min;
162 }
163 else
164 {
165 /* error in time format */
166 return PARSE_ERROR;
167 }
168
169 if (this->rule->type == ASN1_UTCTIME)
170 {
171 format = "%2d%2d%2d%2d%2d";
172 }
173 else
174 {
175 format = "%4d%2d%2d%2d%2d";
176 }
177
178 sscanf(data.ptr, format, &t.tm_year, &t.tm_mon, &t.tm_mday, &t.tm_hour, &t.tm_min);
179
180 /* is there a seconds field? */
181 if ((eot - data.ptr) == ((this->rule->type == ASN1_UTCTIME)?12:14))
182 {
183 sscanf(eot-2, "%2d", &t.tm_sec);
184 }
185 else
186 {
187 t.tm_sec = 0;
188 }
189
190 /* representation of year */
191 if (t.tm_year >= 1900)
192 {
193 t.tm_year -= 1900;
194 }
195 else if (t.tm_year >= 100)
196 {
197 return PARSE_ERROR;
198 }
199 else if (t.tm_year < 50)
200 {
201 t.tm_year += 100;
202 }
203
204 /* representation of month 0..11*/
205 t.tm_mon--;
206
207 /* set daylight saving time to off */
208 t.tm_isdst = 0;
209
210 /* compensate timezone */
211
212 *result = mktime(&t) - timezone - tz_offset;
213 return SUCCESS;
214 }
215
216 /**
217 * Read an integer as u_int or as mpz_t
218 */
219 status_t read_int(private_der_decoder_t *this, chunk_t data)
220 {
221 this->logger->log_chunk(this->logger, CONTROL|LEVEL2, "ASN1_INTEGER", data);
222
223 if (this->rule->flags & ASN1_MPZ)
224 {
225 mpz_t *mpz = (mpz_t*)((u_int8_t*)this->output + this->rule->data_offset);
226 mpz_import(*mpz, data.len, 1, 1, 1, 0, data.ptr);
227 }
228 else
229 {
230 u_int *integ = (u_int*)((u_int8_t*)this->output + this->rule->data_offset);
231
232 *integ = 0;
233 while (data.len-- > 0)
234 {
235 *integ = 256 * (*integ) + *data.ptr++;
236 }
237 }
238 return SUCCESS;
239 }
240
241 /**
242 * Read boolean value
243 */
244 status_t read_bool(private_der_decoder_t *this, chunk_t data)
245 {
246 this->logger->log_chunk(this->logger, CONTROL|LEVEL2, "ASN1_BOOLEAN", data);
247
248 bool *boolean = (u_int*)((u_int8_t*)this->output + this->rule->data_offset);
249
250 *boolean = *data.ptr;
251
252 return SUCCESS;
253 }
254
255 /**
256 * Read an OID
257 */
258 status_t read_oid(private_der_decoder_t *this, chunk_t data)
259 {
260 this->logger->log_chunk(this->logger, CONTROL|LEVEL2, "ASN1_OID", data);
261 /* TODO: OID parsing stuff */
262 return SUCCESS;
263 }
264
265 /**
266 * Read a bitstring
267 */
268 status_t read_bitstring(private_der_decoder_t *this, chunk_t data)
269 {
270 /* TODO: cleanly determine amount of unused bits */
271
272 /* skip "unused-bits-in-following-byte"-byte */
273 data.ptr += 1;
274 data.len -= 1;
275
276 if (data.len < 1)
277 {
278 return FAILED;
279 }
280
281 chunk_t *chunk = (chunk_t*)((u_int8_t*)this->output + this->rule->data_offset);
282
283 *chunk = chunk_clone(data);
284
285 this->logger->log_chunk(this->logger, CONTROL|LEVEL2, "ASN1_BITSTRING", data);
286 return SUCCESS;
287 }
288
289 /**
290 * Read any type which appears in a chunk
291 */
292 status_t read_any(private_der_decoder_t *this, chunk_t data)
293 {
294 chunk_t *chunk = (chunk_t*)((u_int8_t*)this->output + this->rule->data_offset);
295
296 *chunk = chunk_clone(data);
297
298 this->logger->log_chunk(this->logger, CONTROL|LEVEL2, "ASN1_ANY", data);
299 return SUCCESS;
300 }
301
302 /**
303 * Read the length field of a type
304 */
305 u_int32_t read_length(chunk_t *data)
306 {
307 u_int8_t n;
308 size_t len;
309
310 if (data->len < 1)
311 {
312 return -1;
313 }
314
315 /* read first octet of length field */
316 n = *data->ptr;
317 data->ptr++; data->len--;
318
319 if ((n & 0x80) == 0)
320 {
321 /* single length octet */
322 return n;
323 }
324
325 /* composite length, determine number of length octets */
326 n &= 0x7f;
327
328 if (n > data->len)
329 {
330 /* length longer than available bytes */
331 return -1;
332 }
333
334 if (n > sizeof(len))
335 {
336 /* larger than size_t can hold */
337 return -1;
338 }
339
340 len = 0;
341 while (n-- > 0)
342 {
343 len = 256 * len + *data->ptr;
344 data->ptr++; data->len--;
345 }
346 return len;
347 }
348
349 /**
350 * Read the next field
351 */
352 status_t read_hdr(private_der_decoder_t *this, chunk_t *data)
353 {
354 chunk_t inner;
355 /* TODO: Redo this that an average mid-european can understand it */
356
357 beginning:
358 /* advance to the next rule */
359 this->rule++;
360
361 this->logger->log(this->logger, CONTROL|LEVEL2, "reading rule %d %s",
362 this->rule - this->first_rule,
363 mapping_find(asn1_type_m, this->rule->type));
364
365 switch (this->rule->type)
366 {
367 case ASN1_END:
368 /* ignore, handled outside */
369 return SUCCESS;
370 case ASN1_CHOICE:
371 /* CHOICE has no type/length */
372 break;
373 default:
374 /* anything else has type/length */
375 if (data->len == 0)
376 {
377 goto beginning;
378 }
379 this->logger->log_chunk(this->logger, CONTROL|LEVEL3, "reading from:", *data);
380
381 /* read type, advance in data */
382 if (this->rule->type != ASN1_ANY && *(data->ptr) != this->rule->type)
383 {
384 if (this->rule->flags & ASN1_OPTIONAL)
385 {
386 goto beginning;
387 }
388 if (this->rule->flags & ASN1_DEFAULT)
389 {
390 goto beginning;
391 }
392 this->logger->log(this->logger, CONTROL|LEVEL2, "Bad byte found: %x, %x expected",
393 *data->ptr, this->rule->type);
394 return PARSE_ERROR;
395 }
396 data->ptr++;
397 data->len--;
398
399 /* read length, advance in data */
400 inner.len = read_length(data);
401 if (inner.len == -1)
402 {
403 this->logger->log(this->logger, CONTROL|LEVEL2, "Error reading length");
404 return PARSE_ERROR;
405 }
406 this->logger->log(this->logger, CONTROL|LEVEL2, "Length is %d", inner.len);
407 inner.ptr = data->ptr;
408
409 /* advance in data, at the size of the inner */
410 data->ptr += inner.len;
411 data->len -= inner.len;
412 }
413
414 /* process inner */
415 while (TRUE)
416 {
417 switch (this->rule->type)
418 {
419 case ASN1_INTEGER:
420 return read_int(this, inner);
421 case ASN1_BOOLEAN:
422 return read_bool(this, inner);
423 case ASN1_SEQUENCE:
424 case ASN1_SET:
425 return read_sequence(this, inner);
426 case ASN1_TAG_E_0:
427 case ASN1_TAG_E_1:
428 case ASN1_TAG_E_2:
429 case ASN1_TAG_E_3:
430 case ASN1_TAG_E_4:
431 case ASN1_TAG_E_5:
432 case ASN1_TAG_E_6:
433 case ASN1_TAG_E_7:
434 return read_hdr(this, &inner);
435 case ASN1_TAG_I_0:
436 case ASN1_TAG_I_1:
437 case ASN1_TAG_I_2:
438 case ASN1_TAG_I_3:
439 case ASN1_TAG_I_4:
440 case ASN1_TAG_I_5:
441 case ASN1_TAG_I_6:
442 case ASN1_TAG_I_7:
443 this->rule++;
444 continue;
445 case ASN1_OID:
446 return read_oid(this, inner);
447 case ASN1_CHOICE:
448 return read_choice(this, data);
449 case ASN1_NULL:
450 return SUCCESS;
451 case ASN1_ANY:
452 return read_any(this, inner);
453 case ASN1_UTCTIME:
454 return read_time(this, inner);
455 case ASN1_GENERALIZEDTIME:
456 return read_time(this, inner);
457 case ASN1_BITSTRING:
458 return read_bitstring(this, inner);
459 case ASN1_OCTETSTRING:
460 return read_any(this, inner);
461 default:
462 return NOT_SUPPORTED;
463 }
464 }
465 }
466
467 /**
468 * Implements der_decoder_t.decode
469 */
470 status_t decode(private_der_decoder_t *this, chunk_t input, void *output)
471 {
472 this->rule = this->first_rule - 1;
473 this->output = output;
474 /* start parsing recursivly */
475 return read_hdr(this, &input);
476 }
477
478 /**
479 * Implementation of der_decoder.destroy.
480 */
481 static void destroy(private_der_decoder_t *this)
482 {
483 this->logger->destroy(this->logger);
484 free(this);
485 }
486
487 /*
488 * Described in header.
489 */
490 der_decoder_t *der_decoder_create(asn1_rule_t *rules)
491 {
492 private_der_decoder_t *this = malloc_thing(private_der_decoder_t);
493
494 /* public functions */
495 this->public.decode = (status_t (*) (der_decoder_t*,chunk_t,void*))decode;
496 this->public.destroy = (void (*) (der_decoder_t*))destroy;
497
498 this->first_rule = rules;
499 this->logger = logger_create("[DERDC]", CONTROL, FALSE, NULL);
500
501 return &(this->public);
502 }