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
29 #include "asn1_parser.h"
32 * some common prefabricated ASN.1 constants
34 static u_char ASN1_INTEGER_0_str
[] = { 0x02, 0x00 };
35 static u_char ASN1_INTEGER_1_str
[] = { 0x02, 0x01, 0x01 };
36 static u_char ASN1_INTEGER_2_str
[] = { 0x02, 0x01, 0x02 };
38 const chunk_t ASN1_INTEGER_0
= chunk_from_buf(ASN1_INTEGER_0_str
);
39 const chunk_t ASN1_INTEGER_1
= chunk_from_buf(ASN1_INTEGER_1_str
);
40 const chunk_t ASN1_INTEGER_2
= chunk_from_buf(ASN1_INTEGER_2_str
);
43 * some popular algorithmIdentifiers
46 static u_char ASN1_md2_id_str
[] = {
49 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x02, 0x02,
53 static u_char ASN1_md5_id_str
[] = {
56 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x02, 0x05,
60 static u_char ASN1_sha1_id_str
[] = {
63 0x2B, 0x0E,0x03, 0x02, 0x1A,
67 static u_char ASN1_sha256_id_str
[] = {
70 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01,
74 static u_char ASN1_sha384_id_str
[] = {
77 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x02,
81 static u_char ASN1_sha512_id_str
[] = {
84 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03,
88 static u_char ASN1_md2WithRSA_id_str
[] = {
91 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x02,
95 static u_char ASN1_md5WithRSA_id_str
[] = {
98 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x04,
102 static u_char ASN1_sha1WithRSA_id_str
[] = {
105 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x05,
109 static u_char ASN1_sha256WithRSA_id_str
[] = {
112 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x0B,
116 static u_char ASN1_sha384WithRSA_id_str
[] = {
119 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x0C,
123 static u_char ASN1_sha512WithRSA_id_str
[] = {
126 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x0D,
130 static u_char ASN1_rsaEncryption_id_str
[] = {
133 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x01,
137 static const chunk_t ASN1_md2_id
= chunk_from_buf(ASN1_md2_id_str
);
138 static const chunk_t ASN1_md5_id
= chunk_from_buf(ASN1_md5_id_str
);
139 static const chunk_t ASN1_sha1_id
= chunk_from_buf(ASN1_sha1_id_str
);
140 static const chunk_t ASN1_sha256_id
= chunk_from_buf(ASN1_sha256_id_str
);
141 static const chunk_t ASN1_sha384_id
= chunk_from_buf(ASN1_sha384_id_str
);
142 static const chunk_t ASN1_sha512_id
= chunk_from_buf(ASN1_sha512_id_str
);
143 static const chunk_t ASN1_rsaEncryption_id
= chunk_from_buf(ASN1_rsaEncryption_id_str
);
144 static const chunk_t ASN1_md2WithRSA_id
= chunk_from_buf(ASN1_md2WithRSA_id_str
);
145 static const chunk_t ASN1_md5WithRSA_id
= chunk_from_buf(ASN1_md5WithRSA_id_str
);
146 static const chunk_t ASN1_sha1WithRSA_id
= chunk_from_buf(ASN1_sha1WithRSA_id_str
);
147 static const chunk_t ASN1_sha256WithRSA_id
= chunk_from_buf(ASN1_sha256WithRSA_id_str
);
148 static const chunk_t ASN1_sha384WithRSA_id
= chunk_from_buf(ASN1_sha384WithRSA_id_str
);
149 static const chunk_t ASN1_sha512WithRSA_id
= chunk_from_buf(ASN1_sha512WithRSA_id_str
);
154 chunk_t
asn1_algorithmIdentifier(int oid
)
158 case OID_RSA_ENCRYPTION
:
159 return ASN1_rsaEncryption_id
;
160 case OID_MD2_WITH_RSA
:
161 return ASN1_md2WithRSA_id
;
162 case OID_MD5_WITH_RSA
:
163 return ASN1_md5WithRSA_id
;
164 case OID_SHA1_WITH_RSA
:
165 return ASN1_sha1WithRSA_id
;
166 case OID_SHA256_WITH_RSA
:
167 return ASN1_sha256WithRSA_id
;
168 case OID_SHA384_WITH_RSA
:
169 return ASN1_sha384WithRSA_id
;
170 case OID_SHA512_WITH_RSA
:
171 return ASN1_sha512WithRSA_id
;
179 return ASN1_sha256_id
;
181 return ASN1_sha384_id
;
183 return ASN1_sha512_id
;
192 int asn1_known_oid(chunk_t object
)
198 if (oid_names
[oid
].octet
== *object
.ptr
)
200 if (--object
.len
== 0 || oid_names
[oid
].down
== 0)
202 return oid
; /* found terminal symbol */
206 object
.ptr
++; oid
++; /* advance to next hex octet */
211 if (oid_names
[oid
].next
)
212 oid
= oid_names
[oid
].next
;
223 u_int
asn1_length(chunk_t
*blob
)
228 /* advance from tag field on to length field */
232 /* read first octet of length field */
237 {/* single length octet */
241 /* composite length, determine number of length octets */
246 DBG2("number of length octets is larger than ASN.1 object");
247 return ASN1_INVALID_LENGTH
;
252 DBG2("number of length octets is larger than limit of %d octets",
254 return ASN1_INVALID_LENGTH
;
261 len
= 256*len
+ *blob
->ptr
++;
267 #define TIME_MAX 0x7fffffff
270 * Converts ASN.1 UTCTIME or GENERALIZEDTIME into calender time
272 time_t asn1_to_time(const chunk_t
*utctime
, asn1_t type
)
275 time_t tc
, tz_offset
;
278 if ((eot
= memchr(utctime
->ptr
, 'Z', utctime
->len
)) != NULL
)
280 tz_offset
= 0; /* Zulu time with a zero time zone offset */
282 else if ((eot
= memchr(utctime
->ptr
, '+', utctime
->len
)) != NULL
)
286 sscanf(eot
+1, "%2d%2d", &tz_hour
, &tz_min
);
287 tz_offset
= 3600*tz_hour
+ 60*tz_min
; /* positive time zone offset */
289 else if ((eot
= memchr(utctime
->ptr
, '-', utctime
->len
)) != NULL
)
293 sscanf(eot
+1, "%2d%2d", &tz_hour
, &tz_min
);
294 tz_offset
= -3600*tz_hour
- 60*tz_min
; /* negative time zone offset */
298 return 0; /* error in time format */
301 /* parse ASN.1 time string */
303 const char* format
= (type
== ASN1_UTCTIME
)?
"%2d%2d%2d%2d%2d":
306 sscanf(utctime
->ptr
, format
, &t
.tm_year
, &t
.tm_mon
, &t
.tm_mday
,
307 &t
.tm_hour
, &t
.tm_min
);
310 /* is there a seconds field? */
311 if ((eot
- utctime
->ptr
) == ((type
== ASN1_UTCTIME
)?
12:14))
313 sscanf(eot
-2, "%2d", &t
.tm_sec
);
320 /* representation of year */
321 if (t
.tm_year
>= 1900)
325 else if (t
.tm_year
>= 100)
329 else if (t
.tm_year
< 50)
334 /* representation of month 0..11*/
337 /* set daylight saving time to off */
340 /* convert to time_t */
343 /* if no conversion overflow occurred, compensate timezone */
344 return (tc
== -1) ? TIME_MAX
: (tc
- timezone
- tz_offset
);
348 * Convert a date into ASN.1 UTCTIME or GENERALIZEDTIME format
350 chunk_t
asn1_from_time(const time_t *time
, asn1_t type
)
355 chunk_t formatted_time
;
359 if (type
== ASN1_GENERALIZEDTIME
)
361 format
= "%04d%02d%02d%02d%02d%02dZ";
364 else /* ASN1_UTCTIME */
366 format
= "%02d%02d%02d%02d%02d%02dZ";
367 offset
= (t
.tm_year
< 100)?
0 : -100;
369 snprintf(buf
, BUF_LEN
, format
, t
.tm_year
+ offset
,
370 t
.tm_mon
+ 1, t
.tm_mday
, t
.tm_hour
, t
.tm_min
, t
.tm_sec
);
371 formatted_time
.ptr
= buf
;
372 formatted_time
.len
= strlen(buf
);
373 return asn1_simple_object(type
, formatted_time
);
379 void asn1_debug_simple_object(chunk_t object
, asn1_t type
, bool private)
386 oid
= asn1_known_oid(object
);
387 if (oid
!= OID_UNKNOWN
)
389 DBG2(" '%s'", oid_names
[oid
].name
);
393 case ASN1_UTF8STRING
:
395 case ASN1_PRINTABLESTRING
:
397 case ASN1_VISIBLESTRING
:
398 DBG2(" '%.*s'", (int)object
.len
, object
.ptr
);
401 case ASN1_GENERALIZEDTIME
:
403 time_t time
= asn1_to_time(&object
, type
);
405 DBG2(" '%T'", &time
, TRUE
);
422 * parse an ASN.1 simple type
424 bool asn1_parse_simple_object(chunk_t
*object
, asn1_t type
, u_int level
, const char* name
)
428 /* an ASN.1 object must possess at least a tag and length field */
431 DBG2("L%d - %s: ASN.1 object smaller than 2 octets", level
, name
);
435 if (*object
->ptr
!= type
)
437 DBG2("L%d - %s: ASN1 tag 0x%02x expected, but is 0x%02x",
438 level
, name
, type
, *object
->ptr
);
442 len
= asn1_length(object
);
444 if (len
== ASN1_INVALID_LENGTH
|| object
->len
< len
)
446 DBG2("L%d - %s: length of ASN.1 object invalid or too large",
451 DBG2("L%d - %s:", level
, name
);
452 asn1_debug_simple_object(*object
, type
, FALSE
);
457 * ASN.1 definition of an algorithmIdentifier
459 static const asn1Object_t algorithmIdentifierObjects
[] = {
460 { 0, "algorithmIdentifier", ASN1_SEQUENCE
, ASN1_NONE
}, /* 0 */
461 { 1, "algorithm", ASN1_OID
, ASN1_BODY
}, /* 1 */
462 { 1, "parameters", ASN1_EOC
, ASN1_RAW
|ASN1_OPT
}, /* 2 */
463 { 1, "end opt", ASN1_EOC
, ASN1_END
}, /* 3 */
464 { 0, "exit", ASN1_EOC
, ASN1_EXIT
}
466 #define ALGORITHM_ID_ALG 1
467 #define ALGORITHM_ID_PARAMETERS 2
472 int asn1_parse_algorithmIdentifier(chunk_t blob
, int level0
, chunk_t
*parameters
)
474 asn1_parser_t
*parser
;
477 int alg
= OID_UNKNOWN
;
479 parser
= asn1_parser_create(algorithmIdentifierObjects
, blob
);
480 parser
->set_top_level(parser
, level0
);
482 while (parser
->iterate(parser
, &objectID
, &object
))
486 case ALGORITHM_ID_ALG
:
487 alg
= asn1_known_oid(object
);
489 case ALGORITHM_ID_PARAMETERS
:
490 if (parameters
!= NULL
)
492 *parameters
= object
;
499 parser
->destroy(parser
);
504 * tests if a blob contains a valid ASN.1 set or sequence
506 bool is_asn1(chunk_t blob
)
509 u_char tag
= *blob
.ptr
;
511 if (tag
!= ASN1_SEQUENCE
&& tag
!= ASN1_SET
)
513 DBG2(" file content is not binary ASN.1");
517 len
= asn1_length(&blob
);
525 /* some websites append a surplus newline character to the blob */
526 if (len
+ 1 == blob
.len
&& *(blob
.ptr
+ len
) == '\n')
531 DBG2(" file size does not match ASN.1 coded length");
538 bool asn1_is_printablestring(chunk_t str
)
540 const char printablestring_charset
[] =
541 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789 '()+,-./:=?";
544 for (i
= 0; i
< str
.len
; i
++)
546 if (strchr(printablestring_charset
, str
.ptr
[i
]) == NULL
)
553 * codes ASN.1 lengths up to a size of 16'777'215 bytes
555 static void asn1_code_length(size_t length
, chunk_t
*code
)
559 code
->ptr
[0] = length
;
562 else if (length
< 256)
565 code
->ptr
[1] = (u_char
) length
;
568 else if (length
< 65536)
571 code
->ptr
[1] = length
>> 8;
572 code
->ptr
[2] = length
& 0x00ff;
578 code
->ptr
[1] = length
>> 16;
579 code
->ptr
[2] = (length
>> 8) & 0x00ff;
580 code
->ptr
[3] = length
& 0x0000ff;
586 * build an empty asn.1 object with tag and length fields already filled in
588 u_char
* asn1_build_object(chunk_t
*object
, asn1_t type
, size_t datalen
)
590 u_char length_buf
[4];
591 chunk_t length
= { length_buf
, 0 };
594 /* code the asn.1 length field */
595 asn1_code_length(datalen
, &length
);
597 /* allocate memory for the asn.1 TLV object */
598 object
->len
= 1 + length
.len
+ datalen
;
599 object
->ptr
= malloc(object
->len
);
601 /* set position pointer at the start of the object */
604 /* copy the asn.1 tag field and advance the pointer */
607 /* copy the asn.1 length field and advance the pointer */
608 memcpy(pos
, length
.ptr
, length
.len
);
615 * Build a simple ASN.1 object
617 chunk_t
asn1_simple_object(asn1_t tag
, chunk_t content
)
621 u_char
*pos
= asn1_build_object(&object
, tag
, content
.len
);
622 memcpy(pos
, content
.ptr
, content
.len
);
629 * Build an ASN.1 BITSTRING object
631 chunk_t
asn1_bitstring(const char *mode
, chunk_t content
)
634 u_char
*pos
= asn1_build_object(&object
, ASN1_BIT_STRING
, 1 + content
.len
);
637 memcpy(pos
, content
.ptr
, content
.len
);
646 * Build an ASN.1 object from a variable number of individual chunks.
647 * Depending on the mode, chunks either are moved ('m') or copied ('c').
649 chunk_t
asn1_wrap(asn1_t type
, const char *mode
, ...)
655 int count
= strlen(mode
);
657 /* sum up lengths of individual chunks */
658 va_start(chunks
, mode
);
660 for (i
= 0; i
< count
; i
++)
662 chunk_t ch
= va_arg(chunks
, chunk_t
);
663 construct
.len
+= ch
.len
;
667 /* allocate needed memory for construct */
668 pos
= asn1_build_object(&construct
, type
, construct
.len
);
670 /* copy or move the chunks */
671 va_start(chunks
, mode
);
672 for (i
= 0; i
< count
; i
++)
674 chunk_t ch
= va_arg(chunks
, chunk_t
);
676 memcpy(pos
, ch
.ptr
, ch
.len
);
690 * ASN.1 definition of time
692 static const asn1Object_t timeObjects
[] = {
693 { 0, "utcTime", ASN1_UTCTIME
, ASN1_OPT
|ASN1_BODY
}, /* 0 */
694 { 0, "end opt", ASN1_EOC
, ASN1_END
}, /* 1 */
695 { 0, "generalizeTime", ASN1_GENERALIZEDTIME
, ASN1_OPT
|ASN1_BODY
}, /* 2 */
696 { 0, "end opt", ASN1_EOC
, ASN1_END
}, /* 3 */
697 { 0, "exit", ASN1_EOC
, ASN1_EXIT
}
700 #define TIME_GENERALIZED 2
703 * extracts and converts a UTCTIME or GENERALIZEDTIME object
705 time_t asn1_parse_time(chunk_t blob
, int level0
)
707 asn1_parser_t
*parser
;
712 parser
= asn1_parser_create(timeObjects
, blob
);
713 parser
->set_top_level(parser
, level0
);
715 while (parser
->iterate(parser
, &objectID
, &object
))
717 if (objectID
== TIME_UTC
|| objectID
== TIME_GENERALIZED
)
719 utc_time
= asn1_to_time(&object
, (objectID
== TIME_UTC
)
720 ? ASN1_UTCTIME
: ASN1_GENERALIZEDTIME
);
723 parser
->destroy(parser
);