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
22 #include <utils/debug.h>
26 #include "asn1_parser.h"
29 * Commonly used ASN1 values.
31 const chunk_t ASN1_INTEGER_0
= chunk_from_chars(0x02, 0x01, 0x00);
32 const chunk_t ASN1_INTEGER_1
= chunk_from_chars(0x02, 0x01, 0x01);
33 const chunk_t ASN1_INTEGER_2
= chunk_from_chars(0x02, 0x01, 0x02);
38 chunk_t
asn1_algorithmIdentifier(int oid
)
42 /* some algorithmIdentifiers have a NULL parameters field and some do not */
45 case OID_ECDSA_WITH_SHA1
:
46 case OID_ECDSA_WITH_SHA224
:
47 case OID_ECDSA_WITH_SHA256
:
48 case OID_ECDSA_WITH_SHA384
:
49 case OID_ECDSA_WITH_SHA512
:
50 parameters
= chunk_empty
;
53 parameters
= asn1_simple_object(ASN1_NULL
, chunk_empty
);
56 return asn1_wrap(ASN1_SEQUENCE
, "mm", asn1_build_known_oid(oid
), parameters
);
62 int asn1_known_oid(chunk_t object
)
68 if (oid_names
[oid
].octet
== *object
.ptr
)
70 if (--object
.len
== 0 || oid_names
[oid
].down
== 0)
72 return oid
; /* found terminal symbol */
76 object
.ptr
++; oid
++; /* advance to next hex octet */
81 if (oid_names
[oid
].next
)
83 oid
= oid_names
[oid
].next
;
97 chunk_t
asn1_build_known_oid(int n
)
102 if (n
< 0 || n
>= OID_MAX
)
107 i
= oid_names
[n
].level
+ 1;
108 oid
= chunk_alloc(2 + i
);
109 oid
.ptr
[0] = ASN1_OID
;
114 if (oid_names
[n
].level
>= i
)
119 oid
.ptr
[--i
+ 2] = oid_names
[n
--].octet
;
129 chunk_t
asn1_oid_from_string(char *str
)
131 enumerator_t
*enumerator
;
134 int i
= 0, pos
= 0, shift
;
135 u_int val
, shifted_val
, first
= 0;
137 enumerator
= enumerator_create_token(str
, ".", "");
138 while (enumerator
->enumerate(enumerator
, &str
))
140 val
= strtoul(str
, &end
, 10);
141 if (end
== str
|| pos
> countof(buf
))
152 buf
[pos
++] = first
* 40 + val
;
155 shift
= 28; /* sufficient to handle 32 bit node numbers */
158 shifted_val
= val
>> shift
;
160 if (shifted_val
) /* do not encode leading zeroes */
162 buf
[pos
++] = 0x80 | (shifted_val
& 0x7F);
165 buf
[pos
++] = val
& 0x7F;
168 enumerator
->destroy(enumerator
);
170 return chunk_clone(chunk_create(buf
, pos
));
176 char *asn1_oid_to_string(chunk_t oid
)
178 char buf
[64], *pos
= buf
;
186 val
= oid
.ptr
[0] / 40;
187 len
= snprintf(buf
, sizeof(buf
), "%u.%u", val
, oid
.ptr
[0] - val
* 40);
188 oid
= chunk_skip(oid
, 1);
189 if (len
< 0 || len
>= sizeof(buf
))
198 val
= (val
<< 7) + (u_int
)(oid
.ptr
[0] & 0x7f);
200 if (oid
.ptr
[0] < 128)
202 len
= snprintf(pos
, sizeof(buf
) + buf
- pos
, ".%u", val
);
203 if (len
< 0 || len
>= sizeof(buf
) + buf
- pos
)
210 oid
= chunk_skip(oid
, 1);
212 return (val
== 0) ?
strdup(buf
) : NULL
;
218 size_t asn1_length(chunk_t
*blob
)
225 DBG2(DBG_ASN
, "insufficient number of octets to parse ASN.1 length");
226 return ASN1_INVALID_LENGTH
;
229 /* read length field, skip tag and length */
235 { /* single length octet */
238 DBG2(DBG_ASN
, "length is larger than remaining blob size");
239 return ASN1_INVALID_LENGTH
;
244 /* composite length, determine number of length octets */
247 if (n
== 0 || n
> blob
->len
)
249 DBG2(DBG_ASN
, "number of length octets invalid");
250 return ASN1_INVALID_LENGTH
;
255 DBG2(DBG_ASN
, "number of length octets is larger than limit of"
256 " %d octets", (int)sizeof(len
));
257 return ASN1_INVALID_LENGTH
;
264 len
= 256*len
+ *blob
->ptr
++;
269 DBG2(DBG_ASN
, "length is larger than remaining blob size");
270 return ASN1_INVALID_LENGTH
;
278 int asn1_unwrap(chunk_t
*blob
, chunk_t
*inner
)
290 *blob
= chunk_skip(*blob
, 2);
292 if ((len
& 0x80) == 0)
293 { /* single length octet */
297 { /* composite length, determine number of length octets */
299 if (len
== 0 || len
> sizeof(res
.len
))
306 res
.len
= 256 * res
.len
+ blob
->ptr
[0];
307 *blob
= chunk_skip(*blob
, 1);
310 if (res
.len
> blob
->len
)
315 *blob
= chunk_skip(*blob
, res
.len
);
316 /* updating inner not before we are finished allows a caller to pass
322 static const int days
[] = { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 };
323 static const int tm_leap_1970
= 477;
326 * Converts ASN.1 UTCTIME or GENERALIZEDTIME into calender time
328 time_t asn1_to_time(const chunk_t
*utctime
, asn1_t type
)
330 int tm_year
, tm_mon
, tm_day
, tm_hour
, tm_min
, tm_sec
;
331 int tm_leap_4
, tm_leap_100
, tm_leap_400
, tm_leap
;
332 int tz_hour
, tz_min
, tz_offset
;
333 time_t tm_days
, tm_secs
;
336 if ((eot
= memchr(utctime
->ptr
, 'Z', utctime
->len
)) != NULL
)
338 tz_offset
= 0; /* Zulu time with a zero time zone offset */
340 else if ((eot
= memchr(utctime
->ptr
, '+', utctime
->len
)) != NULL
)
342 if (sscanf(eot
+1, "%2d%2d", &tz_hour
, &tz_min
) != 2)
344 return 0; /* error in positive timezone offset format */
346 tz_offset
= 3600*tz_hour
+ 60*tz_min
; /* positive time zone offset */
348 else if ((eot
= memchr(utctime
->ptr
, '-', utctime
->len
)) != NULL
)
350 if (sscanf(eot
+1, "%2d%2d", &tz_hour
, &tz_min
) != 2)
352 return 0; /* error in negative timezone offset format */
354 tz_offset
= -3600*tz_hour
- 60*tz_min
; /* negative time zone offset */
358 return 0; /* error in time format */
361 /* parse ASN.1 time string */
363 const char* format
= (type
== ASN1_UTCTIME
)?
"%2d%2d%2d%2d%2d":
366 if (sscanf(utctime
->ptr
, format
, &tm_year
, &tm_mon
, &tm_day
,
367 &tm_hour
, &tm_min
) != 5)
369 return 0; /* error in [yy]yymmddhhmm time format */
373 /* is there a seconds field? */
374 if ((eot
- utctime
->ptr
) == ((type
== ASN1_UTCTIME
)?
12:14))
376 if (sscanf(eot
-2, "%2d", &tm_sec
) != 1)
378 return 0; /* error in ss seconds field format */
386 /* representation of two-digit years */
387 if (type
== ASN1_UTCTIME
)
389 tm_year
+= (tm_year
< 50) ?
2000 : 1900;
392 /* prevent large 32 bit integer overflows */
393 if (sizeof(time_t) == 4 && tm_year
> 2038)
395 return TIME_32_BIT_SIGNED_MAX
;
398 /* representation of months as 0..11*/
399 if (tm_mon
< 1 || tm_mon
> 12)
401 return 0; /* error in month format */
405 /* representation of days as 0..30 */
408 /* number of leap years between last year and 1970? */
409 tm_leap_4
= (tm_year
- 1) / 4;
410 tm_leap_100
= tm_leap_4
/ 25;
411 tm_leap_400
= tm_leap_100
/ 4;
412 tm_leap
= tm_leap_4
- tm_leap_100
+ tm_leap_400
- tm_leap_1970
;
414 /* if date later then February, is the current year a leap year? */
415 if (tm_mon
> 1 && (tm_year
% 4 == 0) &&
416 (tm_year
% 100 != 0 || tm_year
% 400 == 0))
420 tm_days
= 365 * (tm_year
- 1970) + days
[tm_mon
] + tm_day
+ tm_leap
;
421 tm_secs
= 60 * (60 * (24 * tm_days
+ tm_hour
) + tm_min
) + tm_sec
- tz_offset
;
423 /* has a 32 bit signed integer overflow occurred? */
424 return (tm_secs
< 0) ? TIME_32_BIT_SIGNED_MAX
: tm_secs
;
428 * Convert a date into ASN.1 UTCTIME or GENERALIZEDTIME format
430 chunk_t
asn1_from_time(const time_t *time
, asn1_t type
)
435 chunk_t formatted_time
;
439 /* RFC 5280 says that dates through the year 2049 MUST be encoded as UTCTIME
440 * and dates in 2050 or later MUST be encoded as GENERALIZEDTIME. We only
441 * enforce the latter to avoid overflows but allow callers to force the
442 * encoding to GENERALIZEDTIME */
443 type
= (t
.tm_year
>= 150) ? ASN1_GENERALIZEDTIME
: type
;
444 if (type
== ASN1_GENERALIZEDTIME
)
446 format
= "%04d%02d%02d%02d%02d%02dZ";
449 else /* ASN1_UTCTIME */
451 format
= "%02d%02d%02d%02d%02d%02dZ";
452 offset
= (t
.tm_year
< 100) ?
0 : -100;
454 snprintf(buf
, BUF_LEN
, format
, t
.tm_year
+ offset
,
455 t
.tm_mon
+ 1, t
.tm_mday
, t
.tm_hour
, t
.tm_min
, t
.tm_sec
);
456 formatted_time
.ptr
= buf
;
457 formatted_time
.len
= strlen(buf
);
458 return asn1_simple_object(type
, formatted_time
);
464 void asn1_debug_simple_object(chunk_t object
, asn1_t type
, bool private)
471 oid
= asn1_known_oid(object
);
472 if (oid
== OID_UNKNOWN
)
474 char *oid_str
= asn1_oid_to_string(object
);
480 DBG2(DBG_ASN
, " %s", oid_str
);
485 DBG2(DBG_ASN
, " '%s'", oid_names
[oid
].name
);
488 case ASN1_UTF8STRING
:
490 case ASN1_PRINTABLESTRING
:
492 case ASN1_VISIBLESTRING
:
493 DBG2(DBG_ASN
, " '%.*s'", (int)object
.len
, object
.ptr
);
496 case ASN1_GENERALIZEDTIME
:
498 time_t time
= asn1_to_time(&object
, type
);
500 DBG2(DBG_ASN
, " '%T'", &time
, TRUE
);
508 DBG4(DBG_ASN
, "%B", &object
);
512 DBG3(DBG_ASN
, "%B", &object
);
517 * parse an ASN.1 simple type
519 bool asn1_parse_simple_object(chunk_t
*object
, asn1_t type
, u_int level
, const char* name
)
523 /* an ASN.1 object must possess at least a tag and length field */
526 DBG2(DBG_ASN
, "L%d - %s: ASN.1 object smaller than 2 octets", level
,
531 if (*object
->ptr
!= type
)
533 DBG2(DBG_ASN
, "L%d - %s: ASN1 tag 0x%02x expected, but is 0x%02x",
534 level
, name
, type
, *object
->ptr
);
538 len
= asn1_length(object
);
540 if (len
== ASN1_INVALID_LENGTH
|| object
->len
< len
)
542 DBG2(DBG_ASN
, "L%d - %s: length of ASN.1 object invalid or too large",
547 DBG2(DBG_ASN
, "L%d - %s:", level
, name
);
548 asn1_debug_simple_object(*object
, type
, FALSE
);
553 * Described in header
555 u_int64_t
asn1_parse_integer_uint64(chunk_t blob
)
560 for (i
= 0; i
< blob
.len
; i
++)
561 { /* if it is longer than 8 bytes, we just use the 8 LSBs */
563 val
|= (u_int64_t
)blob
.ptr
[i
];
569 * ASN.1 definition of an algorithmIdentifier
571 static const asn1Object_t algorithmIdentifierObjects
[] = {
572 { 0, "algorithmIdentifier", ASN1_SEQUENCE
, ASN1_NONE
}, /* 0 */
573 { 1, "algorithm", ASN1_OID
, ASN1_BODY
}, /* 1 */
574 { 1, "parameters", ASN1_OID
, ASN1_RAW
|ASN1_OPT
}, /* 2 */
575 { 1, "end opt", ASN1_EOC
, ASN1_END
}, /* 3 */
576 { 1, "parameters", ASN1_SEQUENCE
, ASN1_RAW
|ASN1_OPT
}, /* 4 */
577 { 1, "end opt", ASN1_EOC
, ASN1_END
}, /* 5 */
578 { 1, "parameters", ASN1_OCTET_STRING
, ASN1_RAW
|ASN1_OPT
}, /* 6 */
579 { 1, "end opt", ASN1_EOC
, ASN1_END
}, /* 7 */
580 { 0, "exit", ASN1_EOC
, ASN1_EXIT
}
582 #define ALGORITHM_ID_ALG 1
583 #define ALGORITHM_ID_PARAMETERS_OID 2
584 #define ALGORITHM_ID_PARAMETERS_SEQ 4
585 #define ALGORITHM_ID_PARAMETERS_OCT 6
590 int asn1_parse_algorithmIdentifier(chunk_t blob
, int level0
, chunk_t
*parameters
)
592 asn1_parser_t
*parser
;
595 int alg
= OID_UNKNOWN
;
597 parser
= asn1_parser_create(algorithmIdentifierObjects
, blob
);
598 parser
->set_top_level(parser
, level0
);
600 while (parser
->iterate(parser
, &objectID
, &object
))
604 case ALGORITHM_ID_ALG
:
605 alg
= asn1_known_oid(object
);
607 case ALGORITHM_ID_PARAMETERS_OID
:
608 case ALGORITHM_ID_PARAMETERS_SEQ
:
609 case ALGORITHM_ID_PARAMETERS_OCT
:
610 if (parameters
!= NULL
)
612 *parameters
= object
;
619 parser
->destroy(parser
);
624 * tests if a blob contains a valid ASN.1 set or sequence
626 bool is_asn1(chunk_t blob
)
631 if (!blob
.len
|| !blob
.ptr
)
637 if (tag
!= ASN1_SEQUENCE
&& tag
!= ASN1_SET
&& tag
!= ASN1_OCTET_STRING
)
639 DBG2(DBG_ASN
, " file content is not binary ASN.1");
643 len
= asn1_length(&blob
);
651 /* some websites append a surplus newline character to the blob */
652 if (len
+ 1 == blob
.len
&& *(blob
.ptr
+ len
) == '\n')
657 DBG2(DBG_ASN
, " file size does not match ASN.1 coded length");
664 bool asn1_is_printablestring(chunk_t str
)
666 const char printablestring_charset
[] =
667 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789 '()+,-./:=?";
670 for (i
= 0; i
< str
.len
; i
++)
672 if (strchr(printablestring_charset
, str
.ptr
[i
]) == NULL
)
679 * codes ASN.1 lengths up to a size of 16'777'215 bytes
681 static void asn1_code_length(size_t length
, chunk_t
*code
)
685 code
->ptr
[0] = length
;
688 else if (length
< 256)
691 code
->ptr
[1] = (u_char
) length
;
694 else if (length
< 65536)
697 code
->ptr
[1] = length
>> 8;
698 code
->ptr
[2] = length
& 0x00ff;
704 code
->ptr
[1] = length
>> 16;
705 code
->ptr
[2] = (length
>> 8) & 0x00ff;
706 code
->ptr
[3] = length
& 0x0000ff;
712 * build an empty asn.1 object with tag and length fields already filled in
714 u_char
* asn1_build_object(chunk_t
*object
, asn1_t type
, size_t datalen
)
716 u_char length_buf
[4];
717 chunk_t length
= { length_buf
, 0 };
720 /* code the asn.1 length field */
721 asn1_code_length(datalen
, &length
);
723 /* allocate memory for the asn.1 TLV object */
724 object
->len
= 1 + length
.len
+ datalen
;
725 object
->ptr
= malloc(object
->len
);
727 /* set position pointer at the start of the object */
730 /* copy the asn.1 tag field and advance the pointer */
733 /* copy the asn.1 length field and advance the pointer */
734 memcpy(pos
, length
.ptr
, length
.len
);
741 * Build a simple ASN.1 object
743 chunk_t
asn1_simple_object(asn1_t tag
, chunk_t content
)
747 u_char
*pos
= asn1_build_object(&object
, tag
, content
.len
);
748 memcpy(pos
, content
.ptr
, content
.len
);
755 * Build an ASN.1 BIT_STRING object
757 chunk_t
asn1_bitstring(const char *mode
, chunk_t content
)
760 u_char
*pos
= asn1_build_object(&object
, ASN1_BIT_STRING
, 1 + content
.len
);
763 memcpy(pos
, content
.ptr
, content
.len
);
772 * Build an ASN.1 INTEGER object
774 chunk_t
asn1_integer(const char *mode
, chunk_t content
)
780 if (content
.len
== 0)
781 { /* make sure 0 is encoded properly */
782 content
= chunk_from_chars(0x00);
785 /* ASN.1 integers must be positive numbers in two's complement */
786 len
= content
.len
+ ((*content
.ptr
& 0x80) ?
1 : 0);
787 pos
= asn1_build_object(&object
, ASN1_INTEGER
, len
);
788 if (len
> content
.len
)
794 memcpy(pos
, content
.ptr
, content
.len
);
804 * Build an ASN.1 object from a variable number of individual chunks.
805 * Depending on the mode, chunks either are moved ('m') or copied ('c').
807 chunk_t
asn1_wrap(asn1_t type
, const char *mode
, ...)
813 int count
= strlen(mode
);
815 /* sum up lengths of individual chunks */
816 va_start(chunks
, mode
);
818 for (i
= 0; i
< count
; i
++)
820 chunk_t ch
= va_arg(chunks
, chunk_t
);
821 construct
.len
+= ch
.len
;
825 /* allocate needed memory for construct */
826 pos
= asn1_build_object(&construct
, type
, construct
.len
);
828 /* copy or move the chunks */
829 va_start(chunks
, mode
);
830 for (i
= 0; i
< count
; i
++)
832 chunk_t ch
= va_arg(chunks
, chunk_t
);
834 memcpy(pos
, ch
.ptr
, ch
.len
);
855 * ASN.1 definition of time
857 static const asn1Object_t timeObjects
[] = {
858 { 0, "utcTime", ASN1_UTCTIME
, ASN1_OPT
|ASN1_BODY
}, /* 0 */
859 { 0, "end opt", ASN1_EOC
, ASN1_END
}, /* 1 */
860 { 0, "generalizeTime", ASN1_GENERALIZEDTIME
, ASN1_OPT
|ASN1_BODY
}, /* 2 */
861 { 0, "end opt", ASN1_EOC
, ASN1_END
}, /* 3 */
862 { 0, "exit", ASN1_EOC
, ASN1_EXIT
}
865 #define TIME_GENERALIZED 2
868 * extracts and converts a UTCTIME or GENERALIZEDTIME object
870 time_t asn1_parse_time(chunk_t blob
, int level0
)
872 asn1_parser_t
*parser
;
877 parser
= asn1_parser_create(timeObjects
, blob
);
878 parser
->set_top_level(parser
, level0
);
880 while (parser
->iterate(parser
, &objectID
, &object
))
882 if (objectID
== TIME_UTC
|| objectID
== TIME_GENERALIZED
)
884 utc_time
= asn1_to_time(&object
, (objectID
== TIME_UTC
)
885 ? ASN1_UTCTIME
: ASN1_GENERALIZEDTIME
);
888 parser
->destroy(parser
);