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