2 * Copyright (C) 2006 Martin Will
3 * Copyright (C) 2000-2008 Andreas Steffen
5 * Hochschule fuer Technik Rapperswil
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>.
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
28 #include "asn1_parser.h"
31 * some common prefabricated ASN.1 constants
33 static u_char ASN1_INTEGER_0_str
[] = { 0x02, 0x00 };
34 static u_char ASN1_INTEGER_1_str
[] = { 0x02, 0x01, 0x01 };
35 static u_char ASN1_INTEGER_2_str
[] = { 0x02, 0x01, 0x02 };
37 const chunk_t ASN1_INTEGER_0
= chunk_from_buf(ASN1_INTEGER_0_str
);
38 const chunk_t ASN1_INTEGER_1
= chunk_from_buf(ASN1_INTEGER_1_str
);
39 const chunk_t ASN1_INTEGER_2
= chunk_from_buf(ASN1_INTEGER_2_str
);
44 chunk_t
asn1_algorithmIdentifier(int oid
)
46 return asn1_wrap(ASN1_SEQUENCE
, "mm",
47 asn1_build_known_oid(oid
),
48 asn1_wrap(ASN1_NULL
, ""));
54 int asn1_known_oid(chunk_t object
)
60 if (oid_names
[oid
].octet
== *object
.ptr
)
62 if (--object
.len
== 0 || oid_names
[oid
].down
== 0)
64 return oid
; /* found terminal symbol */
68 object
.ptr
++; oid
++; /* advance to next hex octet */
73 if (oid_names
[oid
].next
)
75 oid
= oid_names
[oid
].next
;
89 chunk_t
asn1_build_known_oid(int n
)
94 if (n
< 0 || n
>= OID_MAX
)
99 i
= oid_names
[n
].level
+ 1;
100 oid
= chunk_alloc(2 + i
);
101 oid
.ptr
[0] = ASN1_OID
;
106 if (oid_names
[n
].level
>= i
)
111 oid
.ptr
[--i
+ 2] = oid_names
[n
--].octet
;
121 size_t asn1_length(chunk_t
*blob
)
128 DBG2("insufficient number of octets to parse ASN.1 length");
129 return ASN1_INVALID_LENGTH
;
132 /* read length field, skip tag and length */
134 *blob
= chunk_skip(*blob
, 2);
137 { /* single length octet */
140 DBG2("length is larger than remaining blob size");
141 return ASN1_INVALID_LENGTH
;
146 /* composite length, determine number of length octets */
149 if (n
== 0 || n
> blob
->len
)
151 DBG2("number of length octets invalid");
152 return ASN1_INVALID_LENGTH
;
157 DBG2("number of length octets is larger than limit of %d octets",
159 return ASN1_INVALID_LENGTH
;
166 len
= 256*len
+ *blob
->ptr
++;
171 DBG2("length is larger than remaining blob size");
172 return ASN1_INVALID_LENGTH
;
180 int asn1_unwrap(chunk_t
*blob
, chunk_t
*inner
)
192 *blob
= chunk_skip(*blob
, 2);
194 if ((len
& 0x80) == 0)
195 { /* single length octet */
199 { /* composite length, determine number of length octets */
201 if (len
== 0 || len
> sizeof(res
.len
))
208 res
.len
= 256 * res
.len
+ blob
->ptr
[0];
209 *blob
= chunk_skip(*blob
, 1);
212 if (res
.len
> blob
->len
)
217 *blob
= chunk_skip(*blob
, res
.len
);
218 /* updating inner not before we are finished allows a caller to pass
224 #define TIME_MAX 0x7fffffff
226 static const int days
[] = { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 };
227 static const int tm_leap_1970
= 477;
230 * Converts ASN.1 UTCTIME or GENERALIZEDTIME into calender time
232 time_t asn1_to_time(const chunk_t
*utctime
, asn1_t type
)
234 int tm_year
, tm_mon
, tm_day
, tm_days
, tm_hour
, tm_min
, tm_sec
;
235 int tm_leap_4
, tm_leap_100
, tm_leap_400
, tm_leap
;
236 int tz_hour
, tz_min
, tz_offset
;
240 if ((eot
= memchr(utctime
->ptr
, 'Z', utctime
->len
)) != NULL
)
242 tz_offset
= 0; /* Zulu time with a zero time zone offset */
244 else if ((eot
= memchr(utctime
->ptr
, '+', utctime
->len
)) != NULL
)
246 if (sscanf(eot
+1, "%2d%2d", &tz_hour
, &tz_min
) != 2)
248 return 0; /* error in positive timezone offset format */
250 tz_offset
= 3600*tz_hour
+ 60*tz_min
; /* positive time zone offset */
252 else if ((eot
= memchr(utctime
->ptr
, '-', utctime
->len
)) != NULL
)
254 if (sscanf(eot
+1, "%2d%2d", &tz_hour
, &tz_min
) != 2)
256 return 0; /* error in negative timezone offset format */
258 tz_offset
= -3600*tz_hour
- 60*tz_min
; /* negative time zone offset */
262 return 0; /* error in time format */
265 /* parse ASN.1 time string */
267 const char* format
= (type
== ASN1_UTCTIME
)?
"%2d%2d%2d%2d%2d":
270 if (sscanf(utctime
->ptr
, format
, &tm_year
, &tm_mon
, &tm_day
,
271 &tm_hour
, &tm_min
) != 5)
273 return 0; /* error in [yy]yymmddhhmm time format */
277 /* is there a seconds field? */
278 if ((eot
- utctime
->ptr
) == ((type
== ASN1_UTCTIME
)?
12:14))
280 if (sscanf(eot
-2, "%2d", &tm_sec
) != 1)
282 return 0; /* error in ss seconds field format */
290 /* representation of two-digit years */
291 if (type
== ASN1_UTCTIME
)
293 tm_year
+= (tm_year
< 50) ?
2000 : 1900;
296 /* prevent large 32 bit integer overflows */
297 if (sizeof(time_t) == 4 && tm_year
> 2038)
302 /* representation of months as 0..11*/
303 if (tm_mon
< 1 || tm_mon
> 12)
305 return 0; /* error in month format */
309 /* representation of days as 0..30 */
312 /* number of leap years between last year and 1970? */
313 tm_leap_4
= (tm_year
- 1) / 4;
314 tm_leap_100
= tm_leap_4
/ 25;
315 tm_leap_400
= tm_leap_100
/ 4;
316 tm_leap
= tm_leap_4
- tm_leap_100
+ tm_leap_400
- tm_leap_1970
;
318 /* if date later then February, is the current year a leap year? */
319 if (tm_mon
> 1 && (tm_year
% 4 == 0) &&
320 (tm_year
% 100 != 0 || tm_year
% 400 == 0))
324 tm_days
= 365 * (tm_year
- 1970) + days
[tm_mon
] + tm_day
+ tm_leap
;
325 tm_secs
= 60 * (60 * (24 * tm_days
+ tm_hour
) + tm_min
) + tm_sec
- tz_offset
;
327 /* has a 32 bit overflow occurred? */
328 return (tm_secs
< 0) ? TIME_MAX
: tm_secs
;
332 * Convert a date into ASN.1 UTCTIME or GENERALIZEDTIME format
334 chunk_t
asn1_from_time(const time_t *time
, asn1_t type
)
339 chunk_t formatted_time
;
343 if (type
== ASN1_GENERALIZEDTIME
)
345 format
= "%04d%02d%02d%02d%02d%02dZ";
348 else /* ASN1_UTCTIME */
350 format
= "%02d%02d%02d%02d%02d%02dZ";
351 offset
= (t
.tm_year
< 100)?
0 : -100;
353 snprintf(buf
, BUF_LEN
, format
, t
.tm_year
+ offset
,
354 t
.tm_mon
+ 1, t
.tm_mday
, t
.tm_hour
, t
.tm_min
, t
.tm_sec
);
355 formatted_time
.ptr
= buf
;
356 formatted_time
.len
= strlen(buf
);
357 return asn1_simple_object(type
, formatted_time
);
363 void asn1_debug_simple_object(chunk_t object
, asn1_t type
, bool private)
370 oid
= asn1_known_oid(object
);
371 if (oid
!= OID_UNKNOWN
)
373 DBG2(" '%s'", oid_names
[oid
].name
);
377 case ASN1_UTF8STRING
:
379 case ASN1_PRINTABLESTRING
:
381 case ASN1_VISIBLESTRING
:
382 DBG2(" '%.*s'", (int)object
.len
, object
.ptr
);
385 case ASN1_GENERALIZEDTIME
:
387 time_t time
= asn1_to_time(&object
, type
);
389 DBG2(" '%T'", &time
, TRUE
);
406 * parse an ASN.1 simple type
408 bool asn1_parse_simple_object(chunk_t
*object
, asn1_t type
, u_int level
, const char* name
)
412 /* an ASN.1 object must possess at least a tag and length field */
415 DBG2("L%d - %s: ASN.1 object smaller than 2 octets", level
, name
);
419 if (*object
->ptr
!= type
)
421 DBG2("L%d - %s: ASN1 tag 0x%02x expected, but is 0x%02x",
422 level
, name
, type
, *object
->ptr
);
426 len
= asn1_length(object
);
428 if (len
== ASN1_INVALID_LENGTH
|| object
->len
< len
)
430 DBG2("L%d - %s: length of ASN.1 object invalid or too large",
435 DBG2("L%d - %s:", level
, name
);
436 asn1_debug_simple_object(*object
, type
, FALSE
);
441 * ASN.1 definition of an algorithmIdentifier
443 static const asn1Object_t algorithmIdentifierObjects
[] = {
444 { 0, "algorithmIdentifier", ASN1_SEQUENCE
, ASN1_NONE
}, /* 0 */
445 { 1, "algorithm", ASN1_OID
, ASN1_BODY
}, /* 1 */
446 { 1, "parameters", ASN1_EOC
, ASN1_RAW
|ASN1_OPT
}, /* 2 */
447 { 1, "end opt", ASN1_EOC
, ASN1_END
}, /* 3 */
448 { 0, "exit", ASN1_EOC
, ASN1_EXIT
}
450 #define ALGORITHM_ID_ALG 1
451 #define ALGORITHM_ID_PARAMETERS 2
456 int asn1_parse_algorithmIdentifier(chunk_t blob
, int level0
, chunk_t
*parameters
)
458 asn1_parser_t
*parser
;
461 int alg
= OID_UNKNOWN
;
463 parser
= asn1_parser_create(algorithmIdentifierObjects
, blob
);
464 parser
->set_top_level(parser
, level0
);
466 while (parser
->iterate(parser
, &objectID
, &object
))
470 case ALGORITHM_ID_ALG
:
471 alg
= asn1_known_oid(object
);
473 case ALGORITHM_ID_PARAMETERS
:
474 if (parameters
!= NULL
)
476 *parameters
= object
;
483 parser
->destroy(parser
);
488 * tests if a blob contains a valid ASN.1 set or sequence
490 bool is_asn1(chunk_t blob
)
493 u_char tag
= *blob
.ptr
;
495 if (tag
!= ASN1_SEQUENCE
&& tag
!= ASN1_SET
)
497 DBG2(" file content is not binary ASN.1");
501 len
= asn1_length(&blob
);
509 /* some websites append a surplus newline character to the blob */
510 if (len
+ 1 == blob
.len
&& *(blob
.ptr
+ len
) == '\n')
515 DBG2(" file size does not match ASN.1 coded length");
522 bool asn1_is_printablestring(chunk_t str
)
524 const char printablestring_charset
[] =
525 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789 '()+,-./:=?";
528 for (i
= 0; i
< str
.len
; i
++)
530 if (strchr(printablestring_charset
, str
.ptr
[i
]) == NULL
)
537 * codes ASN.1 lengths up to a size of 16'777'215 bytes
539 static void asn1_code_length(size_t length
, chunk_t
*code
)
543 code
->ptr
[0] = length
;
546 else if (length
< 256)
549 code
->ptr
[1] = (u_char
) length
;
552 else if (length
< 65536)
555 code
->ptr
[1] = length
>> 8;
556 code
->ptr
[2] = length
& 0x00ff;
562 code
->ptr
[1] = length
>> 16;
563 code
->ptr
[2] = (length
>> 8) & 0x00ff;
564 code
->ptr
[3] = length
& 0x0000ff;
570 * build an empty asn.1 object with tag and length fields already filled in
572 u_char
* asn1_build_object(chunk_t
*object
, asn1_t type
, size_t datalen
)
574 u_char length_buf
[4];
575 chunk_t length
= { length_buf
, 0 };
578 /* code the asn.1 length field */
579 asn1_code_length(datalen
, &length
);
581 /* allocate memory for the asn.1 TLV object */
582 object
->len
= 1 + length
.len
+ datalen
;
583 object
->ptr
= malloc(object
->len
);
585 /* set position pointer at the start of the object */
588 /* copy the asn.1 tag field and advance the pointer */
591 /* copy the asn.1 length field and advance the pointer */
592 memcpy(pos
, length
.ptr
, length
.len
);
599 * Build a simple ASN.1 object
601 chunk_t
asn1_simple_object(asn1_t tag
, chunk_t content
)
605 u_char
*pos
= asn1_build_object(&object
, tag
, content
.len
);
606 memcpy(pos
, content
.ptr
, content
.len
);
613 * Build an ASN.1 BIT_STRING object
615 chunk_t
asn1_bitstring(const char *mode
, chunk_t content
)
618 u_char
*pos
= asn1_build_object(&object
, ASN1_BIT_STRING
, 1 + content
.len
);
621 memcpy(pos
, content
.ptr
, content
.len
);
630 * Build an ASN.1 INTEGER object
632 chunk_t
asn1_integer(const char *mode
, chunk_t content
)
638 if (content
.len
== 0 || (content
.len
== 1 && *content
.ptr
== 0x00))
640 /* a zero ASN.1 integer does not have a value field */
645 /* ASN.1 integers must be positive numbers in two's complement */
646 len
= content
.len
+ ((*content
.ptr
& 0x80) ?
1 : 0);
648 pos
= asn1_build_object(&object
, ASN1_INTEGER
, len
);
649 if (len
> content
.len
)
655 memcpy(pos
, content
.ptr
, content
.len
);
665 * Build an ASN.1 object from a variable number of individual chunks.
666 * Depending on the mode, chunks either are moved ('m') or copied ('c').
668 chunk_t
asn1_wrap(asn1_t type
, const char *mode
, ...)
674 int count
= strlen(mode
);
676 /* sum up lengths of individual chunks */
677 va_start(chunks
, mode
);
679 for (i
= 0; i
< count
; i
++)
681 chunk_t ch
= va_arg(chunks
, chunk_t
);
682 construct
.len
+= ch
.len
;
686 /* allocate needed memory for construct */
687 pos
= asn1_build_object(&construct
, type
, construct
.len
);
689 /* copy or move the chunks */
690 va_start(chunks
, mode
);
691 for (i
= 0; i
< count
; i
++)
693 chunk_t ch
= va_arg(chunks
, chunk_t
);
695 memcpy(pos
, ch
.ptr
, ch
.len
);
716 * ASN.1 definition of time
718 static const asn1Object_t timeObjects
[] = {
719 { 0, "utcTime", ASN1_UTCTIME
, ASN1_OPT
|ASN1_BODY
}, /* 0 */
720 { 0, "end opt", ASN1_EOC
, ASN1_END
}, /* 1 */
721 { 0, "generalizeTime", ASN1_GENERALIZEDTIME
, ASN1_OPT
|ASN1_BODY
}, /* 2 */
722 { 0, "end opt", ASN1_EOC
, ASN1_END
}, /* 3 */
723 { 0, "exit", ASN1_EOC
, ASN1_EXIT
}
726 #define TIME_GENERALIZED 2
729 * extracts and converts a UTCTIME or GENERALIZEDTIME object
731 time_t asn1_parse_time(chunk_t blob
, int level0
)
733 asn1_parser_t
*parser
;
738 parser
= asn1_parser_create(timeObjects
, blob
);
739 parser
->set_top_level(parser
, level0
);
741 while (parser
->iterate(parser
, &objectID
, &object
))
743 if (objectID
== TIME_UTC
|| objectID
== TIME_GENERALIZED
)
745 utc_time
= asn1_to_time(&object
, (objectID
== TIME_UTC
)
746 ? ASN1_UTCTIME
: ASN1_GENERALIZEDTIME
);
749 parser
->destroy(parser
);