]> git.ipfire.org Git - people/ms/strongswan.git/blame - Source/charon/asn1/der_decoder.c
- rewrote a lot of RSA stuff
[people/ms/strongswan.git] / Source / charon / asn1 / der_decoder.c
CommitLineData
9c781c15
MW
1/**
2 * @file der_decoder.c
3 *
4 * @brief Implementation of der_decoder_t.
5 */
6
7/*
efadbf79
MW
8 * Copyright (C) 2000-2004 Andreas Steffen
9 * Copyright (C) 2006 Martin Willi
9c781c15
MW
10 * Hochschule fuer Technik Rapperswil
11 *
efadbf79
MW
12 * Some parts taken over from pluto/asn1.c
13 *
9c781c15
MW
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
27#include "der_decoder.h"
28
29#include <utils/allocator.h>
30#include <daemon.h>
31
32
33
34typedef struct private_der_decoder_t private_der_decoder_t;
35
36/**
37 * Private data of a der_decoder_t object.
38 */
39struct private_der_decoder_t {
40 /**
41 * Public interface for this signer.
42 */
43 der_decoder_t public;
44
efadbf79
MW
45 /**
46 * Rule which was just processed
47 */
9c781c15
MW
48 asn1_rule_t *rule;
49
efadbf79
MW
50 /**
51 * First rule of the hole ruleset
52 */
9c781c15
MW
53 asn1_rule_t *first_rule;
54
efadbf79
MW
55 /**
56 * Output data struct
57 */
9c781c15
MW
58 void *output;
59
efadbf79
MW
60 /**
61 * Complex things like this need a logger ;-)
62 */
9c781c15
MW
63 logger_t *logger;
64};
65
66status_t read_hdr(private_der_decoder_t *this, chunk_t *data);
67
efadbf79
MW
68/**
69 * Read a sequence from data, parse its contents recursivly
70 */
9c781c15
MW
71status_t read_sequence(private_der_decoder_t *this, chunk_t data)
72{
efadbf79
MW
73 status_t status;
74 asn1_rule_t *next_rule;
75
76 while(TRUE)
9c781c15 77 {
efadbf79
MW
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 }
9c781c15 89 }
efadbf79
MW
90
91 this->logger->log(this->logger, CONTROL|LEVEL2, "Sequence end");
9c781c15
MW
92 return SUCCESS;
93}
94
efadbf79
MW
95/**
96 * Read choice of data, parse if one of the choosable types arise
97 */
98status_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}
9c781c15 127
efadbf79
MW
128/**
129 * Read a utc or generalized time
130 */
131status_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 */
9c781c15
MW
219status_t read_int(private_der_decoder_t *this, chunk_t data)
220{
221 this->logger->log_chunk(this->logger, CONTROL|LEVEL2, "ASN1_INTEGER", data);
9c781c15 222
efadbf79 223 if (this->rule->flags & ASN1_MPZ)
9c781c15 224 {
efadbf79
MW
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 }
9c781c15
MW
237 }
238 return SUCCESS;
239}
240
efadbf79
MW
241/**
242 * Read boolean value
243 */
244status_t read_bool(private_der_decoder_t *this, chunk_t data)
9c781c15 245{
efadbf79
MW
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);
9c781c15 249
efadbf79
MW
250 *boolean = *data.ptr;
251
252 return SUCCESS;
253}
254
255/**
256 * Read an OID
257 */
258status_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 */
9c781c15
MW
262 return SUCCESS;
263}
264
efadbf79
MW
265/**
266 * Read a bitstring
267 */
268status_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 chunk_t *chunk = (chunk_t*)((u_int8_t*)this->output + this->rule->data_offset);
277
278 *chunk = allocator_clone_chunk(data);
279
280 this->logger->log_chunk(this->logger, CONTROL|LEVEL2, "ASN1_BITSTRING", data);
281 return SUCCESS;
282}
283
284/**
285 * Read any type which appears in a chunk
286 */
287status_t read_any(private_der_decoder_t *this, chunk_t data)
288{
289 chunk_t *chunk = (chunk_t*)((u_int8_t*)this->output + this->rule->data_offset);
290
291 *chunk = allocator_clone_chunk(data);
292
293 this->logger->log_chunk(this->logger, CONTROL|LEVEL2, "ASN1_ANY", data);
294 return SUCCESS;
295}
296
297/**
298 * Read the length field of a type
299 */
9c781c15
MW
300u_int32_t read_length(chunk_t *data)
301{
302 u_int8_t n;
303 size_t len;
304
305 /* read first octet of length field */
efadbf79
MW
306 n = *data->ptr;
307 data->ptr++; data->len--;
9c781c15
MW
308
309 if ((n & 0x80) == 0)
310 {
311 /* single length octet */
312 return n;
313 }
314
315 /* composite length, determine number of length octets */
316 n &= 0x7f;
317
318 if (n > data->len)
319 {
320 /* length longer than available bytes */
321 return -1;
322 }
323
324 if (n > sizeof(len))
325 {
326 /* larger than size_t can hold */
327 return -1;
328 }
329
330 len = 0;
331 while (n-- > 0)
332 {
efadbf79
MW
333 len = 256 * len + *data->ptr;
334 data->ptr++; data->len--;
9c781c15
MW
335 }
336 return len;
337}
338
efadbf79
MW
339/**
340 * Read the next field
341 */
9c781c15
MW
342status_t read_hdr(private_der_decoder_t *this, chunk_t *data)
343{
344 chunk_t inner;
efadbf79 345 /* TODO: Redo this that an average mid-european can understand it */
9c781c15 346
efadbf79 347beginning:
9c781c15
MW
348 /* advance to the next rule */
349 this->rule++;
350
efadbf79
MW
351 this->logger->log(this->logger, CONTROL|LEVEL2, "reading rule %d %s",
352 this->rule - this->first_rule,
353 mapping_find(asn1_type_m, this->rule->type));
9c781c15 354
9c781c15
MW
355 switch (this->rule->type)
356 {
efadbf79
MW
357 case ASN1_END:
358 /* ignore, handled outside */
359 return SUCCESS;
360 case ASN1_CHOICE:
361 /* CHOICE has no type/length */
362 break;
363 default:
364 /* anything else has type/length */
365 if (data->len == 0)
9c781c15 366 {
efadbf79 367 goto beginning;
9c781c15 368 }
efadbf79
MW
369 this->logger->log_chunk(this->logger, CONTROL|LEVEL3, "reading from:", *data);
370
371 /* read type, advance in data */
372 if (this->rule->type != ASN1_ANY && *(data->ptr) != this->rule->type)
9c781c15 373 {
efadbf79
MW
374 if (this->rule->flags & ASN1_OPTIONAL)
375 {
376 goto beginning;
377 }
378 if (this->rule->flags & ASN1_DEFAULT)
379 {
380 goto beginning;
381 }
382 this->logger->log(this->logger, CONTROL|LEVEL2, "Bad byte found: %x, %x expected",
383 *data->ptr, this->rule->type);
384 return PARSE_ERROR;
9c781c15 385 }
efadbf79
MW
386 data->ptr++;
387 data->len--;
388
389 /* read length, advance in data */
390 inner.len = read_length(data);
391 if (inner.len == -1)
392 {
393 this->logger->log(this->logger, CONTROL|LEVEL2, "Error reading length");
394 return PARSE_ERROR;
395 }
396 this->logger->log(this->logger, CONTROL|LEVEL2, "Length is %d", inner.len);
397 inner.ptr = data->ptr;
398
399 /* advance in data, at the size of the inner */
400 data->ptr += inner.len;
401 data->len -= inner.len;
9c781c15
MW
402 }
403
efadbf79
MW
404 /* process inner */
405 while (TRUE)
406 {
407 switch (this->rule->type)
408 {
409 case ASN1_INTEGER:
410 return read_int(this, inner);
411 case ASN1_BOOLEAN:
412 return read_bool(this, inner);
413 case ASN1_SEQUENCE:
414 case ASN1_SET:
415 return read_sequence(this, inner);
416 case ASN1_TAG_E_0:
417 case ASN1_TAG_E_1:
418 case ASN1_TAG_E_2:
419 case ASN1_TAG_E_3:
420 case ASN1_TAG_E_4:
421 case ASN1_TAG_E_5:
422 case ASN1_TAG_E_6:
423 case ASN1_TAG_E_7:
424 return read_hdr(this, &inner);
425 case ASN1_TAG_I_0:
426 case ASN1_TAG_I_1:
427 case ASN1_TAG_I_2:
428 case ASN1_TAG_I_3:
429 case ASN1_TAG_I_4:
430 case ASN1_TAG_I_5:
431 case ASN1_TAG_I_6:
432 case ASN1_TAG_I_7:
433 this->rule++;
434 continue;
435 case ASN1_OID:
436 return read_oid(this, inner);
437 case ASN1_CHOICE:
438 return read_choice(this, data);
439 case ASN1_NULL:
440 return SUCCESS;
441 case ASN1_ANY:
442 return read_any(this, inner);
443 case ASN1_UTCTIME:
444 return read_time(this, inner);
445 case ASN1_GENERALIZEDTIME:
446 return read_time(this, inner);
447 case ASN1_BITSTRING:
448 return read_bitstring(this, inner);
449 case ASN1_OCTETSTRING:
450 return read_any(this, inner);
451 default:
452 return NOT_SUPPORTED;
453 }
454 }
9c781c15
MW
455}
456
efadbf79
MW
457/**
458 * Implements der_decoder_t.decode
459 */
9c781c15
MW
460status_t decode(private_der_decoder_t *this, chunk_t input, void *output)
461{
462 this->rule = this->first_rule - 1;
463 this->output = output;
efadbf79 464 /* start parsing recursivly */
9c781c15
MW
465 return read_hdr(this, &input);
466}
467
468/**
469 * Implementation of der_decoder.destroy.
470 */
471static void destroy(private_der_decoder_t *this)
472{
473 allocator_free(this);
474}
475
476/*
477 * Described in header.
478 */
479der_decoder_t *der_decoder_create(asn1_rule_t *rules)
480{
481 private_der_decoder_t *this = allocator_alloc_thing(private_der_decoder_t);
482
483 /* public functions */
484 this->public.decode = (status_t (*) (der_decoder_t*,chunk_t,void*))decode;
485 this->public.destroy = (void (*) (der_decoder_t*))destroy;
486
487 this->first_rule = rules;
488 this->logger = charon->logger_manager->get_logger(charon->logger_manager, DER_DECODER);
489
490 return &(this->public);
491}