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