4 * @brief Implementation of der_decoder_t.
8 * Copyright (C) 2000-2004 Andreas Steffen
9 * Copyright (C) 2006 Martin Willi
10 * Hochschule fuer Technik Rapperswil
12 * Some parts taken over from pluto/asn1.c
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>.
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
28 #include "der_decoder.h"
34 typedef struct private_der_decoder_t private_der_decoder_t
;
37 * Private data of a der_decoder_t object.
39 struct private_der_decoder_t
{
41 * Public interface for this signer.
46 * Rule which was just processed
51 * First rule of the whole ruleset
53 asn1_rule_t
*first_rule
;
61 * Complex things like this need a logger ;-)
66 status_t
read_hdr(private_der_decoder_t
*this, chunk_t
*data
);
69 * Read a sequence from data, parse its contents recursivly
71 status_t
read_sequence(private_der_decoder_t
*this, chunk_t data
)
74 asn1_rule_t
*next_rule
;
78 next_rule
= this->rule
+ 1;
79 if (next_rule
->type
== ASN1_END
)
84 status
= read_hdr(this, &data
);
85 if (status
!= SUCCESS
)
91 this->logger
->log(this->logger
, CONTROL
|LEVEL2
, "Sequence end");
96 * Read choice of data, parse if one of the choosable types arise
98 status_t
read_choice(private_der_decoder_t
*this, chunk_t
*data
)
100 status_t status
= PARSE_ERROR
;
101 asn1_rule_t
*next_rule
;
104 this->logger
->log_chunk(this->logger
, CONTROL
|LEVEL2
, "Choice data", *data
);
108 next_rule
= this->rule
+ 1;
109 if (next_rule
->type
== ASN1_END
)
114 if (!found
&& *(data
->ptr
) == next_rule
->type
)
117 status
= read_hdr(this, data
);
124 this->logger
->log(this->logger
, CONTROL
|LEVEL2
, "Choice end");
129 * Read a utc or generalized time
131 status_t
read_time(private_der_decoder_t
*this, chunk_t data
)
137 time_t *result
= (time_t*)((u_int8_t
*)this->output
+ this->rule
->data_offset
);
140 this->logger
->log_chunk(this->logger
, CONTROL
|LEVEL2
, "TIME", data
);
142 if ((eot
= memchr(data
.ptr
, 'Z', data
.len
)) != NULL
)
144 /* Zulu time with a zero time zone offset */
147 else if ((eot
= memchr(data
.ptr
, '+', data
.len
)) != NULL
)
151 sscanf(eot
+1, "%2d%2d", &tz_hour
, &tz_min
);
152 /* positive time zone offset */
153 tz_offset
= 3600*tz_hour
+ 60*tz_min
;
155 else if ((eot
= memchr(data
.ptr
, '-', data
.len
)) != NULL
)
159 sscanf(eot
+1, "%2d%2d", &tz_hour
, &tz_min
);
160 /* negative time zone offset */
161 tz_offset
= -3600*tz_hour
- 60*tz_min
;
165 /* error in time format */
169 if (this->rule
->type
== ASN1_UTCTIME
)
171 format
= "%2d%2d%2d%2d%2d";
175 format
= "%4d%2d%2d%2d%2d";
178 sscanf(data
.ptr
, format
, &t
.tm_year
, &t
.tm_mon
, &t
.tm_mday
, &t
.tm_hour
, &t
.tm_min
);
180 /* is there a seconds field? */
181 if ((eot
- data
.ptr
) == ((this->rule
->type
== ASN1_UTCTIME
)?
12:14))
183 sscanf(eot
-2, "%2d", &t
.tm_sec
);
190 /* representation of year */
191 if (t
.tm_year
>= 1900)
195 else if (t
.tm_year
>= 100)
199 else if (t
.tm_year
< 50)
204 /* representation of month 0..11*/
207 /* set daylight saving time to off */
210 /* compensate timezone */
212 *result
= mktime(&t
) - timezone
- tz_offset
;
217 * Read an integer as u_int or as mpz_t
219 status_t
read_int(private_der_decoder_t
*this, chunk_t data
)
221 this->logger
->log_chunk(this->logger
, CONTROL
|LEVEL2
, "ASN1_INTEGER", data
);
223 if (this->rule
->flags
& ASN1_MPZ
)
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
);
230 u_int
*integ
= (u_int
*)((u_int8_t
*)this->output
+ this->rule
->data_offset
);
233 while (data
.len
-- > 0)
235 *integ
= 256 * (*integ
) + *data
.ptr
++;
244 status_t
read_bool(private_der_decoder_t
*this, chunk_t data
)
246 this->logger
->log_chunk(this->logger
, CONTROL
|LEVEL2
, "ASN1_BOOLEAN", data
);
248 bool *boolean
= (u_int
*)((u_int8_t
*)this->output
+ this->rule
->data_offset
);
250 *boolean
= *data
.ptr
;
258 status_t
read_oid(private_der_decoder_t
*this, chunk_t data
)
260 this->logger
->log_chunk(this->logger
, CONTROL
|LEVEL2
, "ASN1_OID", data
);
261 /* TODO: OID parsing stuff */
268 status_t
read_bitstring(private_der_decoder_t
*this, chunk_t data
)
270 /* TODO: cleanly determine amount of unused bits */
272 /* skip "unused-bits-in-following-byte"-byte */
281 chunk_t
*chunk
= (chunk_t
*)((u_int8_t
*)this->output
+ this->rule
->data_offset
);
283 *chunk
= chunk_clone(data
);
285 this->logger
->log_chunk(this->logger
, CONTROL
|LEVEL2
, "ASN1_BITSTRING", data
);
290 * Read any type which appears in a chunk
292 status_t
read_any(private_der_decoder_t
*this, chunk_t data
)
294 chunk_t
*chunk
= (chunk_t
*)((u_int8_t
*)this->output
+ this->rule
->data_offset
);
296 *chunk
= chunk_clone(data
);
298 this->logger
->log_chunk(this->logger
, CONTROL
|LEVEL2
, "ASN1_ANY", data
);
303 * Read the length field of a type
305 u_int32_t
read_length(chunk_t
*data
)
315 /* read first octet of length field */
317 data
->ptr
++; data
->len
--;
321 /* single length octet */
325 /* composite length, determine number of length octets */
330 /* length longer than available bytes */
336 /* larger than size_t can hold */
343 len
= 256 * len
+ *data
->ptr
;
344 data
->ptr
++; data
->len
--;
350 * Read the next field
352 status_t
read_hdr(private_der_decoder_t
*this, chunk_t
*data
)
355 /* TODO: Redo this that an average mid-european can understand it */
358 /* advance to the next rule */
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
));
365 switch (this->rule
->type
)
368 /* ignore, handled outside */
371 /* CHOICE has no type/length */
374 /* anything else has type/length */
379 this->logger
->log_chunk(this->logger
, CONTROL
|LEVEL3
, "reading from:", *data
);
381 /* read type, advance in data */
382 if (this->rule
->type
!= ASN1_ANY
&& *(data
->ptr
) != this->rule
->type
)
384 if (this->rule
->flags
& ASN1_OPTIONAL
)
388 if (this->rule
->flags
& ASN1_DEFAULT
)
392 this->logger
->log(this->logger
, CONTROL
|LEVEL2
, "Bad byte found: %x, %x expected",
393 *data
->ptr
, this->rule
->type
);
399 /* read length, advance in data */
400 inner
.len
= read_length(data
);
403 this->logger
->log(this->logger
, CONTROL
|LEVEL2
, "Error reading length");
406 this->logger
->log(this->logger
, CONTROL
|LEVEL2
, "Length is %d", inner
.len
);
407 inner
.ptr
= data
->ptr
;
409 /* advance in data, at the size of the inner */
410 data
->ptr
+= inner
.len
;
411 data
->len
-= inner
.len
;
417 switch (this->rule
->type
)
420 return read_int(this, inner
);
422 return read_bool(this, inner
);
425 return read_sequence(this, inner
);
434 return read_hdr(this, &inner
);
446 return read_oid(this, inner
);
448 return read_choice(this, data
);
452 return read_any(this, inner
);
454 return read_time(this, inner
);
455 case ASN1_GENERALIZEDTIME
:
456 return read_time(this, inner
);
458 return read_bitstring(this, inner
);
459 case ASN1_OCTETSTRING
:
460 return read_any(this, inner
);
462 return NOT_SUPPORTED
;
468 * Implements der_decoder_t.decode
470 status_t
decode(private_der_decoder_t
*this, chunk_t input
, void *output
)
472 this->rule
= this->first_rule
- 1;
473 this->output
= output
;
474 /* start parsing recursivly */
475 return read_hdr(this, &input
);
479 * Implementation of der_decoder.destroy.
481 static void destroy(private_der_decoder_t
*this)
483 this->logger
->destroy(this->logger
);
488 * Described in header.
490 der_decoder_t
*der_decoder_create(asn1_rule_t
*rules
)
492 private_der_decoder_t
*this = malloc_thing(private_der_decoder_t
);
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
;
498 this->first_rule
= rules
;
499 this->logger
= logger_create("[DERDC]", CONTROL
, FALSE
, NULL
);
501 return &(this->public);