more intuitive leap year check
[strongswan.git] / src / libstrongswan / asn1 / asn1.c
1 /*
2 * Copyright (C) 2006 Martin Will
3 * Copyright (C) 2000-2008 Andreas Steffen
4 *
5 * Hochschule fuer Technik Rapperswil
6 *
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>.
11 *
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
15 * for more details.
16 */
17
18 #include <stdio.h>
19 #include <string.h>
20 #include <time.h>
21 #include <pthread.h>
22
23 #include <utils.h>
24 #include <debug.h>
25
26 #include "oid.h"
27 #include "asn1.h"
28 #include "asn1_parser.h"
29
30 /**
31 * some common prefabricated ASN.1 constants
32 */
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 };
36
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);
40
41 /**
42 * some popular algorithmIdentifiers
43 */
44
45 static u_char ASN1_md2_id_str[] = {
46 0x30, 0x0c,
47 0x06, 0x08,
48 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x02, 0x02,
49 0x05,0x00,
50 };
51
52 static u_char ASN1_md5_id_str[] = {
53 0x30, 0x0C,
54 0x06, 0x08,
55 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x02, 0x05,
56 0x05, 0x00
57 };
58
59 static u_char ASN1_sha1_id_str[] = {
60 0x30, 0x09,
61 0x06, 0x05,
62 0x2B, 0x0E,0x03, 0x02, 0x1A,
63 0x05, 0x00
64 };
65
66 static u_char ASN1_sha256_id_str[] = {
67 0x30, 0x0d,
68 0x06, 0x09,
69 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01,
70 0x05, 0x00
71 };
72
73 static u_char ASN1_sha384_id_str[] = {
74 0x30, 0x0d,
75 0x06, 0x09,
76 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x02,
77 0x05, 0x00
78 };
79
80 static u_char ASN1_sha512_id_str[] = {
81 0x30, 0x0d,
82 0x06, 0x09,
83 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03,
84 0x05,0x00
85 };
86
87 static u_char ASN1_md2WithRSA_id_str[] = {
88 0x30, 0x0D,
89 0x06, 0x09,
90 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x02,
91 0x05, 0x00
92 };
93
94 static u_char ASN1_md5WithRSA_id_str[] = {
95 0x30, 0x0D,
96 0x06, 0x09,
97 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x04,
98 0x05, 0x00
99 };
100
101 static u_char ASN1_sha1WithRSA_id_str[] = {
102 0x30, 0x0D,
103 0x06, 0x09,
104 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x05,
105 0x05, 0x00
106 };
107
108 static u_char ASN1_sha256WithRSA_id_str[] = {
109 0x30, 0x0D,
110 0x06, 0x09,
111 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x0B,
112 0x05, 0x00
113 };
114
115 static u_char ASN1_sha384WithRSA_id_str[] = {
116 0x30, 0x0D,
117 0x06, 0x09,
118 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x0C,
119 0x05, 0x00
120 };
121
122 static u_char ASN1_sha512WithRSA_id_str[] = {
123 0x30, 0x0D,
124 0x06, 0x09,
125 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x0D,
126 0x05, 0x00
127 };
128
129 static u_char ASN1_rsaEncryption_id_str[] = {
130 0x30, 0x0D,
131 0x06, 0x09,
132 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x01,
133 0x05, 0x00
134 };
135
136 static const chunk_t ASN1_md2_id = chunk_from_buf(ASN1_md2_id_str);
137 static const chunk_t ASN1_md5_id = chunk_from_buf(ASN1_md5_id_str);
138 static const chunk_t ASN1_sha1_id = chunk_from_buf(ASN1_sha1_id_str);
139 static const chunk_t ASN1_sha256_id = chunk_from_buf(ASN1_sha256_id_str);
140 static const chunk_t ASN1_sha384_id = chunk_from_buf(ASN1_sha384_id_str);
141 static const chunk_t ASN1_sha512_id = chunk_from_buf(ASN1_sha512_id_str);
142 static const chunk_t ASN1_rsaEncryption_id = chunk_from_buf(ASN1_rsaEncryption_id_str);
143 static const chunk_t ASN1_md2WithRSA_id = chunk_from_buf(ASN1_md2WithRSA_id_str);
144 static const chunk_t ASN1_md5WithRSA_id = chunk_from_buf(ASN1_md5WithRSA_id_str);
145 static const chunk_t ASN1_sha1WithRSA_id = chunk_from_buf(ASN1_sha1WithRSA_id_str);
146 static const chunk_t ASN1_sha256WithRSA_id = chunk_from_buf(ASN1_sha256WithRSA_id_str);
147 static const chunk_t ASN1_sha384WithRSA_id = chunk_from_buf(ASN1_sha384WithRSA_id_str);
148 static const chunk_t ASN1_sha512WithRSA_id = chunk_from_buf(ASN1_sha512WithRSA_id_str);
149
150 /*
151 * Defined in header.
152 */
153 chunk_t asn1_algorithmIdentifier(int oid)
154 {
155 switch (oid)
156 {
157 case OID_RSA_ENCRYPTION:
158 return ASN1_rsaEncryption_id;
159 case OID_MD2_WITH_RSA:
160 return ASN1_md2WithRSA_id;
161 case OID_MD5_WITH_RSA:
162 return ASN1_md5WithRSA_id;
163 case OID_SHA1_WITH_RSA:
164 return ASN1_sha1WithRSA_id;
165 case OID_SHA256_WITH_RSA:
166 return ASN1_sha256WithRSA_id;
167 case OID_SHA384_WITH_RSA:
168 return ASN1_sha384WithRSA_id;
169 case OID_SHA512_WITH_RSA:
170 return ASN1_sha512WithRSA_id;
171 case OID_MD2:
172 return ASN1_md2_id;
173 case OID_MD5:
174 return ASN1_md5_id;
175 case OID_SHA1:
176 return ASN1_sha1_id;
177 case OID_SHA256:
178 return ASN1_sha256_id;
179 case OID_SHA384:
180 return ASN1_sha384_id;
181 case OID_SHA512:
182 return ASN1_sha512_id;
183 default:
184 return chunk_empty;
185 }
186 }
187
188 /*
189 * Defined in header.
190 */
191 int asn1_known_oid(chunk_t object)
192 {
193 int oid = 0;
194
195 while (object.len)
196 {
197 if (oid_names[oid].octet == *object.ptr)
198 {
199 if (--object.len == 0 || oid_names[oid].down == 0)
200 {
201 return oid; /* found terminal symbol */
202 }
203 else
204 {
205 object.ptr++; oid++; /* advance to next hex octet */
206 }
207 }
208 else
209 {
210 if (oid_names[oid].next)
211 {
212 oid = oid_names[oid].next;
213 }
214 else
215 {
216 return OID_UNKNOWN;
217 }
218 }
219 }
220 return -1;
221 }
222
223 /*
224 * Defined in header.
225 */
226 chunk_t asn1_build_known_oid(int n)
227 {
228 chunk_t oid;
229 int i;
230
231 if (n < 0 || n >= OID_MAX)
232 {
233 return chunk_empty;
234 }
235
236 i = oid_names[n].level + 1;
237 oid = chunk_alloc(2 + i);
238 oid.ptr[0] = ASN1_OID;
239 oid.ptr[1] = i;
240
241 do
242 {
243 if (oid_names[n].level >= i)
244 {
245 n--;
246 continue;
247 }
248 oid.ptr[--i + 2] = oid_names[n--].octet;
249 }
250 while (i > 0);
251
252 return oid;
253 }
254
255 /*
256 * Defined in header.
257 */
258 u_int asn1_length(chunk_t *blob)
259 {
260 u_char n;
261 size_t len;
262
263 /* advance from tag field on to length field */
264 blob->ptr++;
265 blob->len--;
266
267 /* read first octet of length field */
268 n = *blob->ptr++;
269 blob->len--;
270
271 if ((n & 0x80) == 0)
272 {/* single length octet */
273 return n;
274 }
275
276 /* composite length, determine number of length octets */
277 n &= 0x7f;
278
279 if (n > blob->len)
280 {
281 DBG2("number of length octets is larger than ASN.1 object");
282 return ASN1_INVALID_LENGTH;
283 }
284
285 if (n > sizeof(len))
286 {
287 DBG2("number of length octets is larger than limit of %d octets",
288 (int)sizeof(len));
289 return ASN1_INVALID_LENGTH;
290 }
291
292 len = 0;
293
294 while (n-- > 0)
295 {
296 len = 256*len + *blob->ptr++;
297 blob->len--;
298 }
299 return len;
300 }
301
302 #define TIME_MAX 0x7fffffff
303
304 static const int days[] = { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 };
305 static const int tm_leap_1970 = 477;
306
307 /**
308 * Converts ASN.1 UTCTIME or GENERALIZEDTIME into calender time
309 */
310 time_t asn1_to_time(const chunk_t *utctime, asn1_t type)
311 {
312 int tm_year, tm_mon, tm_day, tm_days, tm_hour, tm_min, tm_sec;
313 int tm_leap_4, tm_leap_100, tm_leap_400, tm_leap;
314 int tz_hour, tz_min, tz_offset;
315 time_t tm_secs;
316 u_char *eot = NULL;
317
318 if ((eot = memchr(utctime->ptr, 'Z', utctime->len)) != NULL)
319 {
320 tz_offset = 0; /* Zulu time with a zero time zone offset */
321 }
322 else if ((eot = memchr(utctime->ptr, '+', utctime->len)) != NULL)
323 {
324 sscanf(eot+1, "%2d%2d", &tz_hour, &tz_min);
325 tz_offset = 3600*tz_hour + 60*tz_min; /* positive time zone offset */
326 }
327 else if ((eot = memchr(utctime->ptr, '-', utctime->len)) != NULL)
328 {
329 sscanf(eot+1, "%2d%2d", &tz_hour, &tz_min);
330 tz_offset = -3600*tz_hour - 60*tz_min; /* negative time zone offset */
331 }
332 else
333 {
334 return 0; /* error in time format */
335 }
336
337 /* parse ASN.1 time string */
338 {
339 const char* format = (type == ASN1_UTCTIME)? "%2d%2d%2d%2d%2d":
340 "%4d%2d%2d%2d%2d";
341
342 sscanf(utctime->ptr, format, &tm_year, &tm_mon, &tm_day, &tm_hour, &tm_min);
343 }
344
345 /* is there a seconds field? */
346 if ((eot - utctime->ptr) == ((type == ASN1_UTCTIME)?12:14))
347 {
348 sscanf(eot-2, "%2d", &tm_sec);
349 }
350 else
351 {
352 tm_sec = 0;
353 }
354
355 /* representation of two-digit years */
356 if (type == ASN1_UTCTIME)
357 {
358 tm_year += (tm_year < 50) ? 2000 : 1900;
359 }
360
361 /* prevent large 32 bit integer overflows */
362 if (sizeof(time_t) == 4 && tm_year > 2038)
363 {
364 return TIME_MAX;
365 }
366
367 /* representation of months as 0..11*/
368 if (tm_mon > 12)
369 {
370 return 0; /* error in time format */
371 }
372 tm_mon--;
373
374 /* representation of days as 0..30 */
375 tm_day--;
376
377 /* number of leap years between last year and 1970? */
378 tm_leap_4 = (tm_year - 1) / 4;
379 tm_leap_100 = tm_leap_4 / 25;
380 tm_leap_400 = tm_leap_100 / 4;
381 tm_leap = tm_leap_4 - tm_leap_100 + tm_leap_400 - tm_leap_1970;
382
383 /* if date later then February, is the current year a leap year? */
384 if (tm_mon > 1 && (tm_year % 4 == 0) &&
385 (tm_year % 100 != 0 || tm_year % 400 == 0))
386 {
387 tm_leap++;
388 }
389 tm_days = 365 * (tm_year - 1970) + days[tm_mon] + tm_day + tm_leap;
390 tm_secs = 60 * (60 * (24 * tm_days + tm_hour) + tm_min) + tm_sec - tz_offset;
391
392 /* has a 32 bit overflow occurred? */
393 return (tm_secs < 0) ? TIME_MAX : tm_secs;
394 }
395
396 /**
397 * Convert a date into ASN.1 UTCTIME or GENERALIZEDTIME format
398 */
399 chunk_t asn1_from_time(const time_t *time, asn1_t type)
400 {
401 int offset;
402 const char *format;
403 char buf[BUF_LEN];
404 chunk_t formatted_time;
405 struct tm t;
406
407 gmtime_r(time, &t);
408 if (type == ASN1_GENERALIZEDTIME)
409 {
410 format = "%04d%02d%02d%02d%02d%02dZ";
411 offset = 1900;
412 }
413 else /* ASN1_UTCTIME */
414 {
415 format = "%02d%02d%02d%02d%02d%02dZ";
416 offset = (t.tm_year < 100)? 0 : -100;
417 }
418 snprintf(buf, BUF_LEN, format, t.tm_year + offset,
419 t.tm_mon + 1, t.tm_mday, t.tm_hour, t.tm_min, t.tm_sec);
420 formatted_time.ptr = buf;
421 formatted_time.len = strlen(buf);
422 return asn1_simple_object(type, formatted_time);
423 }
424
425 /*
426 * Defined in header.
427 */
428 void asn1_debug_simple_object(chunk_t object, asn1_t type, bool private)
429 {
430 int oid;
431
432 switch (type)
433 {
434 case ASN1_OID:
435 oid = asn1_known_oid(object);
436 if (oid != OID_UNKNOWN)
437 {
438 DBG2(" '%s'", oid_names[oid].name);
439 return;
440 }
441 break;
442 case ASN1_UTF8STRING:
443 case ASN1_IA5STRING:
444 case ASN1_PRINTABLESTRING:
445 case ASN1_T61STRING:
446 case ASN1_VISIBLESTRING:
447 DBG2(" '%.*s'", (int)object.len, object.ptr);
448 return;
449 case ASN1_UTCTIME:
450 case ASN1_GENERALIZEDTIME:
451 {
452 time_t time = asn1_to_time(&object, type);
453
454 DBG2(" '%T'", &time, TRUE);
455 }
456 return;
457 default:
458 break;
459 }
460 if (private)
461 {
462 DBG4("%B", &object);
463 }
464 else
465 {
466 DBG3("%B", &object);
467 }
468 }
469
470 /**
471 * parse an ASN.1 simple type
472 */
473 bool asn1_parse_simple_object(chunk_t *object, asn1_t type, u_int level, const char* name)
474 {
475 size_t len;
476
477 /* an ASN.1 object must possess at least a tag and length field */
478 if (object->len < 2)
479 {
480 DBG2("L%d - %s: ASN.1 object smaller than 2 octets", level, name);
481 return FALSE;
482 }
483
484 if (*object->ptr != type)
485 {
486 DBG2("L%d - %s: ASN1 tag 0x%02x expected, but is 0x%02x",
487 level, name, type, *object->ptr);
488 return FALSE;
489 }
490
491 len = asn1_length(object);
492
493 if (len == ASN1_INVALID_LENGTH || object->len < len)
494 {
495 DBG2("L%d - %s: length of ASN.1 object invalid or too large",
496 level, name);
497 return FALSE;
498 }
499
500 DBG2("L%d - %s:", level, name);
501 asn1_debug_simple_object(*object, type, FALSE);
502 return TRUE;
503 }
504
505 /**
506 * ASN.1 definition of an algorithmIdentifier
507 */
508 static const asn1Object_t algorithmIdentifierObjects[] = {
509 { 0, "algorithmIdentifier", ASN1_SEQUENCE, ASN1_NONE }, /* 0 */
510 { 1, "algorithm", ASN1_OID, ASN1_BODY }, /* 1 */
511 { 1, "parameters", ASN1_EOC, ASN1_RAW|ASN1_OPT }, /* 2 */
512 { 1, "end opt", ASN1_EOC, ASN1_END }, /* 3 */
513 { 0, "exit", ASN1_EOC, ASN1_EXIT }
514 };
515 #define ALGORITHM_ID_ALG 1
516 #define ALGORITHM_ID_PARAMETERS 2
517
518 /*
519 * Defined in header
520 */
521 int asn1_parse_algorithmIdentifier(chunk_t blob, int level0, chunk_t *parameters)
522 {
523 asn1_parser_t *parser;
524 chunk_t object;
525 int objectID;
526 int alg = OID_UNKNOWN;
527
528 parser = asn1_parser_create(algorithmIdentifierObjects, blob);
529 parser->set_top_level(parser, level0);
530
531 while (parser->iterate(parser, &objectID, &object))
532 {
533 switch (objectID)
534 {
535 case ALGORITHM_ID_ALG:
536 alg = asn1_known_oid(object);
537 break;
538 case ALGORITHM_ID_PARAMETERS:
539 if (parameters != NULL)
540 {
541 *parameters = object;
542 }
543 break;
544 default:
545 break;
546 }
547 }
548 parser->destroy(parser);
549 return alg;
550 }
551
552 /*
553 * tests if a blob contains a valid ASN.1 set or sequence
554 */
555 bool is_asn1(chunk_t blob)
556 {
557 u_int len;
558 u_char tag = *blob.ptr;
559
560 if (tag != ASN1_SEQUENCE && tag != ASN1_SET)
561 {
562 DBG2(" file content is not binary ASN.1");
563 return FALSE;
564 }
565
566 len = asn1_length(&blob);
567
568 /* exact match */
569 if (len == blob.len)
570 {
571 return TRUE;
572 }
573
574 /* some websites append a surplus newline character to the blob */
575 if (len + 1 == blob.len && *(blob.ptr + len) == '\n')
576 {
577 return TRUE;
578 }
579
580 DBG2(" file size does not match ASN.1 coded length");
581 return FALSE;
582 }
583
584 /*
585 * Defined in header.
586 */
587 bool asn1_is_printablestring(chunk_t str)
588 {
589 const char printablestring_charset[] =
590 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789 '()+,-./:=?";
591 u_int i;
592
593 for (i = 0; i < str.len; i++)
594 {
595 if (strchr(printablestring_charset, str.ptr[i]) == NULL)
596 return FALSE;
597 }
598 return TRUE;
599 }
600
601 /**
602 * codes ASN.1 lengths up to a size of 16'777'215 bytes
603 */
604 static void asn1_code_length(size_t length, chunk_t *code)
605 {
606 if (length < 128)
607 {
608 code->ptr[0] = length;
609 code->len = 1;
610 }
611 else if (length < 256)
612 {
613 code->ptr[0] = 0x81;
614 code->ptr[1] = (u_char) length;
615 code->len = 2;
616 }
617 else if (length < 65536)
618 {
619 code->ptr[0] = 0x82;
620 code->ptr[1] = length >> 8;
621 code->ptr[2] = length & 0x00ff;
622 code->len = 3;
623 }
624 else
625 {
626 code->ptr[0] = 0x83;
627 code->ptr[1] = length >> 16;
628 code->ptr[2] = (length >> 8) & 0x00ff;
629 code->ptr[3] = length & 0x0000ff;
630 code->len = 4;
631 }
632 }
633
634 /**
635 * build an empty asn.1 object with tag and length fields already filled in
636 */
637 u_char* asn1_build_object(chunk_t *object, asn1_t type, size_t datalen)
638 {
639 u_char length_buf[4];
640 chunk_t length = { length_buf, 0 };
641 u_char *pos;
642
643 /* code the asn.1 length field */
644 asn1_code_length(datalen, &length);
645
646 /* allocate memory for the asn.1 TLV object */
647 object->len = 1 + length.len + datalen;
648 object->ptr = malloc(object->len);
649
650 /* set position pointer at the start of the object */
651 pos = object->ptr;
652
653 /* copy the asn.1 tag field and advance the pointer */
654 *pos++ = type;
655
656 /* copy the asn.1 length field and advance the pointer */
657 memcpy(pos, length.ptr, length.len);
658 pos += length.len;
659
660 return pos;
661 }
662
663 /**
664 * Build a simple ASN.1 object
665 */
666 chunk_t asn1_simple_object(asn1_t tag, chunk_t content)
667 {
668 chunk_t object;
669
670 u_char *pos = asn1_build_object(&object, tag, content.len);
671 memcpy(pos, content.ptr, content.len);
672 pos += content.len;
673
674 return object;
675 }
676
677 /**
678 * Build an ASN.1 BITSTRING object
679 */
680 chunk_t asn1_bitstring(const char *mode, chunk_t content)
681 {
682 chunk_t object;
683 u_char *pos = asn1_build_object(&object, ASN1_BIT_STRING, 1 + content.len);
684
685 *pos++ = 0x00;
686 memcpy(pos, content.ptr, content.len);
687 if (*mode == 'm')
688 {
689 free(content.ptr);
690 }
691 return object;
692 }
693
694 /**
695 * Build an ASN.1 object from a variable number of individual chunks.
696 * Depending on the mode, chunks either are moved ('m') or copied ('c').
697 */
698 chunk_t asn1_wrap(asn1_t type, const char *mode, ...)
699 {
700 chunk_t construct;
701 va_list chunks;
702 u_char *pos;
703 int i;
704 int count = strlen(mode);
705
706 /* sum up lengths of individual chunks */
707 va_start(chunks, mode);
708 construct.len = 0;
709 for (i = 0; i < count; i++)
710 {
711 chunk_t ch = va_arg(chunks, chunk_t);
712 construct.len += ch.len;
713 }
714 va_end(chunks);
715
716 /* allocate needed memory for construct */
717 pos = asn1_build_object(&construct, type, construct.len);
718
719 /* copy or move the chunks */
720 va_start(chunks, mode);
721 for (i = 0; i < count; i++)
722 {
723 chunk_t ch = va_arg(chunks, chunk_t);
724
725 memcpy(pos, ch.ptr, ch.len);
726 pos += ch.len;
727
728 if (*mode++ == 'm')
729 {
730 free(ch.ptr);
731 }
732 }
733 va_end(chunks);
734
735 return construct;
736 }
737
738 /**
739 * ASN.1 definition of time
740 */
741 static const asn1Object_t timeObjects[] = {
742 { 0, "utcTime", ASN1_UTCTIME, ASN1_OPT|ASN1_BODY }, /* 0 */
743 { 0, "end opt", ASN1_EOC, ASN1_END }, /* 1 */
744 { 0, "generalizeTime", ASN1_GENERALIZEDTIME, ASN1_OPT|ASN1_BODY }, /* 2 */
745 { 0, "end opt", ASN1_EOC, ASN1_END }, /* 3 */
746 { 0, "exit", ASN1_EOC, ASN1_EXIT }
747 };
748 #define TIME_UTC 0
749 #define TIME_GENERALIZED 2
750
751 /**
752 * extracts and converts a UTCTIME or GENERALIZEDTIME object
753 */
754 time_t asn1_parse_time(chunk_t blob, int level0)
755 {
756 asn1_parser_t *parser;
757 chunk_t object;
758 int objectID;
759 time_t utc_time = 0;
760
761 parser= asn1_parser_create(timeObjects, blob);
762 parser->set_top_level(parser, level0);
763
764 while (parser->iterate(parser, &objectID, &object))
765 {
766 if (objectID == TIME_UTC || objectID == TIME_GENERALIZED)
767 {
768 utc_time = asn1_to_time(&object, (objectID == TIME_UTC)
769 ? ASN1_UTCTIME : ASN1_GENERALIZEDTIME);
770 }
771 }
772 parser->destroy(parser);
773 return utc_time;
774 }