asn1: Make sure not to exceed buffer for binary OID
[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
22 #include <utils/debug.h>
23
24 #include "oid.h"
25 #include "asn1.h"
26 #include "asn1_parser.h"
27
28 /**
29 * Commonly used ASN1 values.
30 */
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);
34
35 /*
36 * Defined in header.
37 */
38 chunk_t asn1_algorithmIdentifier(int oid)
39 {
40 chunk_t parameters;
41
42 /* some algorithmIdentifiers have a NULL parameters field and some do not */
43 switch (oid)
44 {
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;
51 break;
52 default:
53 parameters = asn1_simple_object(ASN1_NULL, chunk_empty);
54 break;
55 }
56 return asn1_wrap(ASN1_SEQUENCE, "mm", asn1_build_known_oid(oid), parameters);
57 }
58
59 /*
60 * Defined in header.
61 */
62 int asn1_known_oid(chunk_t object)
63 {
64 int oid = 0;
65
66 while (object.len)
67 {
68 if (oid_names[oid].octet == *object.ptr)
69 {
70 if (--object.len == 0 || oid_names[oid].down == 0)
71 {
72 return oid; /* found terminal symbol */
73 }
74 else
75 {
76 object.ptr++; oid++; /* advance to next hex octet */
77 }
78 }
79 else
80 {
81 if (oid_names[oid].next)
82 {
83 oid = oid_names[oid].next;
84 }
85 else
86 {
87 return OID_UNKNOWN;
88 }
89 }
90 }
91 return OID_UNKNOWN;
92 }
93
94 /*
95 * Defined in header.
96 */
97 chunk_t asn1_build_known_oid(int n)
98 {
99 chunk_t oid;
100 int i;
101
102 if (n < 0 || n >= OID_MAX)
103 {
104 return chunk_empty;
105 }
106
107 i = oid_names[n].level + 1;
108 oid = chunk_alloc(2 + i);
109 oid.ptr[0] = ASN1_OID;
110 oid.ptr[1] = i;
111
112 do
113 {
114 if (oid_names[n].level >= i)
115 {
116 n--;
117 continue;
118 }
119 oid.ptr[--i + 2] = oid_names[n--].octet;
120 }
121 while (i > 0);
122
123 return oid;
124 }
125
126 /*
127 * Defined in header.
128 */
129 chunk_t asn1_oid_from_string(char *str)
130 {
131 enumerator_t *enumerator;
132 size_t buf_len = 64;
133 u_char buf[buf_len];
134 char *end;
135 int i = 0, pos = 0, shift;
136 u_int val, shifted_val, first = 0;
137
138 enumerator = enumerator_create_token(str, ".", "");
139 while (enumerator->enumerate(enumerator, &str))
140 {
141 val = strtoul(str, &end, 10);
142 if (end == str || pos > buf_len-5)
143 {
144 pos = 0;
145 break;
146 }
147 switch (i++)
148 {
149 case 0:
150 first = val;
151 break;
152 case 1:
153 buf[pos++] = first * 40 + val;
154 break;
155 default:
156 shift = 28; /* sufficient to handle 32 bit node numbers */
157 while (shift)
158 {
159 shifted_val = val >> shift;
160 shift -= 7;
161 if (shifted_val) /* do not encode leading zeroes */
162 {
163 buf[pos++] = 0x80 | (shifted_val & 0x7F);
164 }
165 }
166 buf[pos++] = val & 0x7F;
167 }
168 }
169 enumerator->destroy(enumerator);
170
171 return chunk_clone(chunk_create(buf, pos));
172 }
173
174 /*
175 * Defined in header.
176 */
177 char *asn1_oid_to_string(chunk_t oid)
178 {
179 size_t len = 64;
180 char buf[len], *pos = buf;
181 int written;
182 u_int val;
183
184 if (!oid.len)
185 {
186 return NULL;
187 }
188 val = oid.ptr[0] / 40;
189 written = snprintf(buf, len, "%u.%u", val, oid.ptr[0] - val * 40);
190 oid = chunk_skip(oid, 1);
191 if (written < 0 || written >= len)
192 {
193 return NULL;
194 }
195 pos += written;
196 len -= written;
197 val = 0;
198
199 while (oid.len)
200 {
201 val = (val << 7) + (u_int)(oid.ptr[0] & 0x7f);
202
203 if (oid.ptr[0] < 128)
204 {
205 written = snprintf(pos, len, ".%u", val);
206 if (written < 0 || written >= len)
207 {
208 return NULL;
209 }
210 pos += written;
211 len -= written;
212 val = 0;
213 }
214 oid = chunk_skip(oid, 1);
215 }
216 return (val == 0) ? strdup(buf) : NULL;
217 }
218
219 /*
220 * Defined in header.
221 */
222 size_t asn1_length(chunk_t *blob)
223 {
224 u_char n;
225 size_t len;
226
227 if (blob->len < 2)
228 {
229 DBG2(DBG_ASN, "insufficient number of octets to parse ASN.1 length");
230 return ASN1_INVALID_LENGTH;
231 }
232
233 /* read length field, skip tag and length */
234 n = blob->ptr[1];
235 blob->ptr += 2;
236 blob->len -= 2;
237
238 if ((n & 0x80) == 0)
239 { /* single length octet */
240 if (n > blob->len)
241 {
242 DBG2(DBG_ASN, "length is larger than remaining blob size");
243 return ASN1_INVALID_LENGTH;
244 }
245 return n;
246 }
247
248 /* composite length, determine number of length octets */
249 n &= 0x7f;
250
251 if (n == 0 || n > blob->len)
252 {
253 DBG2(DBG_ASN, "number of length octets invalid");
254 return ASN1_INVALID_LENGTH;
255 }
256
257 if (n > sizeof(len))
258 {
259 DBG2(DBG_ASN, "number of length octets is larger than limit of"
260 " %d octets", (int)sizeof(len));
261 return ASN1_INVALID_LENGTH;
262 }
263
264 len = 0;
265
266 while (n-- > 0)
267 {
268 len = 256*len + *blob->ptr++;
269 blob->len--;
270 }
271 if (len > blob->len)
272 {
273 DBG2(DBG_ASN, "length is larger than remaining blob size");
274 return ASN1_INVALID_LENGTH;
275 }
276 return len;
277 }
278
279 /*
280 * See header.
281 */
282 int asn1_unwrap(chunk_t *blob, chunk_t *inner)
283 {
284 chunk_t res;
285 u_char len;
286 int type;
287
288 if (blob->len < 2)
289 {
290 return ASN1_INVALID;
291 }
292 type = blob->ptr[0];
293 len = blob->ptr[1];
294 *blob = chunk_skip(*blob, 2);
295
296 if ((len & 0x80) == 0)
297 { /* single length octet */
298 res.len = len;
299 }
300 else
301 { /* composite length, determine number of length octets */
302 len &= 0x7f;
303 if (len == 0 || len > blob->len || len > sizeof(res.len))
304 {
305 return ASN1_INVALID;
306 }
307 res.len = 0;
308 while (len-- > 0)
309 {
310 res.len = 256 * res.len + blob->ptr[0];
311 *blob = chunk_skip(*blob, 1);
312 }
313 }
314 if (res.len > blob->len)
315 {
316 return ASN1_INVALID;
317 }
318 res.ptr = blob->ptr;
319 *blob = chunk_skip(*blob, res.len);
320 /* updating inner not before we are finished allows a caller to pass
321 * blob = inner */
322 *inner = res;
323 return type;
324 }
325
326 static const int days[] = { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 };
327 static const int tm_leap_1970 = 477;
328
329 /**
330 * Converts ASN.1 UTCTIME or GENERALIZEDTIME into calender time
331 */
332 time_t asn1_to_time(const chunk_t *utctime, asn1_t type)
333 {
334 int tm_year, tm_mon, tm_day, tm_hour, tm_min, tm_sec;
335 int tm_leap_4, tm_leap_100, tm_leap_400, tm_leap;
336 int tz_hour, tz_min, tz_offset;
337 time_t tm_days, tm_secs;
338 u_char *eot = NULL;
339
340 if ((eot = memchr(utctime->ptr, 'Z', utctime->len)) != NULL)
341 {
342 tz_offset = 0; /* Zulu time with a zero time zone offset */
343 }
344 else if ((eot = memchr(utctime->ptr, '+', utctime->len)) != NULL)
345 {
346 if (sscanf(eot+1, "%2d%2d", &tz_hour, &tz_min) != 2)
347 {
348 return 0; /* error in positive timezone offset format */
349 }
350 tz_offset = 3600*tz_hour + 60*tz_min; /* positive time zone offset */
351 }
352 else if ((eot = memchr(utctime->ptr, '-', utctime->len)) != NULL)
353 {
354 if (sscanf(eot+1, "%2d%2d", &tz_hour, &tz_min) != 2)
355 {
356 return 0; /* error in negative timezone offset format */
357 }
358 tz_offset = -3600*tz_hour - 60*tz_min; /* negative time zone offset */
359 }
360 else
361 {
362 return 0; /* error in time format */
363 }
364
365 /* parse ASN.1 time string */
366 {
367 const char* format = (type == ASN1_UTCTIME)? "%2d%2d%2d%2d%2d":
368 "%4d%2d%2d%2d%2d";
369
370 if (sscanf(utctime->ptr, format, &tm_year, &tm_mon, &tm_day,
371 &tm_hour, &tm_min) != 5)
372 {
373 return 0; /* error in [yy]yymmddhhmm time format */
374 }
375 }
376
377 /* is there a seconds field? */
378 if ((eot - utctime->ptr) == ((type == ASN1_UTCTIME)?12:14))
379 {
380 if (sscanf(eot-2, "%2d", &tm_sec) != 1)
381 {
382 return 0; /* error in ss seconds field format */
383 }
384 }
385 else
386 {
387 tm_sec = 0;
388 }
389
390 /* representation of two-digit years */
391 if (type == ASN1_UTCTIME)
392 {
393 tm_year += (tm_year < 50) ? 2000 : 1900;
394 }
395
396 /* prevent obvious 32 bit integer overflows */
397 if (sizeof(time_t) == 4 && (tm_year > 2038 || tm_year < 1901))
398 {
399 return TIME_32_BIT_SIGNED_MAX;
400 }
401
402 /* representation of months as 0..11*/
403 if (tm_mon < 1 || tm_mon > 12)
404 {
405 return 0;
406 }
407 tm_mon--;
408
409 /* representation of days as 0..30 */
410 if (tm_day < 1 || tm_day > 31)
411 { /* we don't actually validate the day in relation to tm_year/tm_mon */
412 return 0;
413 }
414 tm_day--;
415
416 if (tm_hour < 0 || tm_hour > 23 ||
417 tm_min < 0 || tm_min > 59 ||
418 tm_sec < 0 || tm_sec > 60 /* allow leap seconds */)
419 {
420 return 0;
421 }
422
423 /* number of leap years between last year and 1970? */
424 tm_leap_4 = (tm_year - 1) / 4;
425 tm_leap_100 = tm_leap_4 / 25;
426 tm_leap_400 = tm_leap_100 / 4;
427 tm_leap = tm_leap_4 - tm_leap_100 + tm_leap_400 - tm_leap_1970;
428
429 /* if date later then February, is the current year a leap year? */
430 if (tm_mon > 1 && (tm_year % 4 == 0) &&
431 (tm_year % 100 != 0 || tm_year % 400 == 0))
432 {
433 tm_leap++;
434 }
435 tm_days = 365 * (tm_year - 1970) + days[tm_mon] + tm_day + tm_leap;
436 tm_secs = 60 * (60 * (24 * tm_days + tm_hour) + tm_min) + tm_sec - tz_offset;
437
438 if (sizeof(time_t) == 4)
439 { /* has a 32 bit signed integer overflow occurred? */
440 if (tm_year > 1970 && tm_secs < 0)
441 { /* depending on the time zone, the first days in 1970 may result in
442 * a negative value, but dates after 1970 never will */
443 return TIME_32_BIT_SIGNED_MAX;
444 }
445 if (tm_year < 1969 && tm_secs > 0)
446 { /* similarly, tm_secs is not positive for dates before 1970, except
447 * for the last days in 1969, depending on the time zone */
448 return TIME_32_BIT_SIGNED_MAX;
449 }
450 }
451 return tm_secs;
452 }
453
454 /**
455 * Convert a date into ASN.1 UTCTIME or GENERALIZEDTIME format
456 */
457 chunk_t asn1_from_time(const time_t *time, asn1_t type)
458 {
459 int offset;
460 const char *format;
461 char buf[BUF_LEN];
462 chunk_t formatted_time;
463 struct tm t = {};
464
465 gmtime_r(time, &t);
466 /* RFC 5280 says that dates through the year 2049 MUST be encoded as UTCTIME
467 * and dates in 2050 or later MUST be encoded as GENERALIZEDTIME. We only
468 * enforce the latter to avoid overflows but allow callers to force the
469 * encoding to GENERALIZEDTIME */
470 type = (t.tm_year >= 150) ? ASN1_GENERALIZEDTIME : type;
471 if (type == ASN1_GENERALIZEDTIME)
472 {
473 format = "%04d%02d%02d%02d%02d%02dZ";
474 offset = 1900;
475 }
476 else /* ASN1_UTCTIME */
477 {
478 format = "%02d%02d%02d%02d%02d%02dZ";
479 offset = (t.tm_year < 100) ? 0 : -100;
480 }
481 snprintf(buf, BUF_LEN, format, t.tm_year + offset,
482 t.tm_mon + 1, t.tm_mday, t.tm_hour, t.tm_min, t.tm_sec);
483 formatted_time.ptr = buf;
484 formatted_time.len = strlen(buf);
485 return asn1_simple_object(type, formatted_time);
486 }
487
488 /*
489 * Defined in header.
490 */
491 void asn1_debug_simple_object(chunk_t object, asn1_t type, bool private)
492 {
493 int oid;
494
495 switch (type)
496 {
497 case ASN1_OID:
498 oid = asn1_known_oid(object);
499 if (oid == OID_UNKNOWN)
500 {
501 char *oid_str = asn1_oid_to_string(object);
502
503 if (!oid_str)
504 {
505 break;
506 }
507 DBG2(DBG_ASN, " %s", oid_str);
508 free(oid_str);
509 }
510 else
511 {
512 DBG2(DBG_ASN, " '%s'", oid_names[oid].name);
513 }
514 return;
515 case ASN1_UTF8STRING:
516 case ASN1_IA5STRING:
517 case ASN1_PRINTABLESTRING:
518 case ASN1_T61STRING:
519 case ASN1_VISIBLESTRING:
520 DBG2(DBG_ASN, " '%.*s'", (int)object.len, object.ptr);
521 return;
522 case ASN1_UTCTIME:
523 case ASN1_GENERALIZEDTIME:
524 {
525 time_t time = asn1_to_time(&object, type);
526
527 DBG2(DBG_ASN, " '%T'", &time, TRUE);
528 }
529 return;
530 default:
531 break;
532 }
533 if (private)
534 {
535 DBG4(DBG_ASN, "%B", &object);
536 }
537 else
538 {
539 DBG3(DBG_ASN, "%B", &object);
540 }
541 }
542
543 /**
544 * parse an ASN.1 simple type
545 */
546 bool asn1_parse_simple_object(chunk_t *object, asn1_t type, u_int level, const char* name)
547 {
548 size_t len;
549
550 /* an ASN.1 object must possess at least a tag and length field */
551 if (object->len < 2)
552 {
553 DBG2(DBG_ASN, "L%d - %s: ASN.1 object smaller than 2 octets", level,
554 name);
555 return FALSE;
556 }
557
558 if (*object->ptr != type)
559 {
560 DBG2(DBG_ASN, "L%d - %s: ASN1 tag 0x%02x expected, but is 0x%02x",
561 level, name, type, *object->ptr);
562 return FALSE;
563 }
564
565 len = asn1_length(object);
566
567 if (len == ASN1_INVALID_LENGTH)
568 {
569 DBG2(DBG_ASN, "L%d - %s: length of ASN.1 object invalid or too large",
570 level, name);
571 return FALSE;
572 }
573
574 DBG2(DBG_ASN, "L%d - %s:", level, name);
575 asn1_debug_simple_object(*object, type, FALSE);
576 return TRUE;
577 }
578
579 /*
580 * Described in header
581 */
582 u_int64_t asn1_parse_integer_uint64(chunk_t blob)
583 {
584 u_int64_t val = 0;
585 int i;
586
587 for (i = 0; i < blob.len; i++)
588 { /* if it is longer than 8 bytes, we just use the 8 LSBs */
589 val <<= 8;
590 val |= (u_int64_t)blob.ptr[i];
591 }
592 return val;
593 }
594
595 /**
596 * ASN.1 definition of an algorithmIdentifier
597 */
598 static const asn1Object_t algorithmIdentifierObjects[] = {
599 { 0, "algorithmIdentifier", ASN1_SEQUENCE, ASN1_NONE }, /* 0 */
600 { 1, "algorithm", ASN1_OID, ASN1_BODY }, /* 1 */
601 { 1, "parameters", ASN1_OID, ASN1_RAW|ASN1_OPT }, /* 2 */
602 { 1, "end opt", ASN1_EOC, ASN1_END }, /* 3 */
603 { 1, "parameters", ASN1_SEQUENCE, ASN1_RAW|ASN1_OPT }, /* 4 */
604 { 1, "end opt", ASN1_EOC, ASN1_END }, /* 5 */
605 { 1, "parameters", ASN1_OCTET_STRING, ASN1_RAW|ASN1_OPT }, /* 6 */
606 { 1, "end opt", ASN1_EOC, ASN1_END }, /* 7 */
607 { 0, "exit", ASN1_EOC, ASN1_EXIT }
608 };
609 #define ALGORITHM_ID_ALG 1
610 #define ALGORITHM_ID_PARAMETERS_OID 2
611 #define ALGORITHM_ID_PARAMETERS_SEQ 4
612 #define ALGORITHM_ID_PARAMETERS_OCT 6
613
614 /*
615 * Defined in header
616 */
617 int asn1_parse_algorithmIdentifier(chunk_t blob, int level0, chunk_t *parameters)
618 {
619 asn1_parser_t *parser;
620 chunk_t object;
621 int objectID;
622 int alg = OID_UNKNOWN;
623
624 parser = asn1_parser_create(algorithmIdentifierObjects, blob);
625 parser->set_top_level(parser, level0);
626
627 while (parser->iterate(parser, &objectID, &object))
628 {
629 switch (objectID)
630 {
631 case ALGORITHM_ID_ALG:
632 alg = asn1_known_oid(object);
633 break;
634 case ALGORITHM_ID_PARAMETERS_OID:
635 case ALGORITHM_ID_PARAMETERS_SEQ:
636 case ALGORITHM_ID_PARAMETERS_OCT:
637 if (parameters != NULL)
638 {
639 *parameters = object;
640 }
641 break;
642 default:
643 break;
644 }
645 }
646 parser->destroy(parser);
647 return alg;
648 }
649
650 /*
651 * tests if a blob contains a valid ASN.1 set or sequence
652 */
653 bool is_asn1(chunk_t blob)
654 {
655 u_int len;
656 u_char tag;
657
658 if (!blob.len || !blob.ptr)
659 {
660 return FALSE;
661 }
662
663 tag = *blob.ptr;
664 if (tag != ASN1_SEQUENCE && tag != ASN1_SET && tag != ASN1_OCTET_STRING)
665 {
666 DBG2(DBG_ASN, " file content is not binary ASN.1");
667 return FALSE;
668 }
669
670 len = asn1_length(&blob);
671
672 if (len == ASN1_INVALID_LENGTH)
673 {
674 return FALSE;
675 }
676
677 /* exact match */
678 if (len == blob.len)
679 {
680 return TRUE;
681 }
682
683 /* some websites append a surplus newline character to the blob */
684 if (len + 1 == blob.len && *(blob.ptr + len) == '\n')
685 {
686 return TRUE;
687 }
688
689 DBG2(DBG_ASN, " file size does not match ASN.1 coded length");
690 return FALSE;
691 }
692
693 /*
694 * Defined in header.
695 */
696 bool asn1_is_printablestring(chunk_t str)
697 {
698 const char printablestring_charset[] =
699 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789 '()+,-./:=?";
700 u_int i;
701
702 for (i = 0; i < str.len; i++)
703 {
704 if (strchr(printablestring_charset, str.ptr[i]) == NULL)
705 {
706 return FALSE;
707 }
708 }
709 return TRUE;
710 }
711
712 /**
713 * codes ASN.1 lengths up to a size of 16'777'215 bytes
714 */
715 static void asn1_code_length(size_t length, chunk_t *code)
716 {
717 if (length < 128)
718 {
719 code->ptr[0] = length;
720 code->len = 1;
721 }
722 else if (length < 256)
723 {
724 code->ptr[0] = 0x81;
725 code->ptr[1] = (u_char) length;
726 code->len = 2;
727 }
728 else if (length < 65536)
729 {
730 code->ptr[0] = 0x82;
731 code->ptr[1] = length >> 8;
732 code->ptr[2] = length & 0x00ff;
733 code->len = 3;
734 }
735 else
736 {
737 code->ptr[0] = 0x83;
738 code->ptr[1] = length >> 16;
739 code->ptr[2] = (length >> 8) & 0x00ff;
740 code->ptr[3] = length & 0x0000ff;
741 code->len = 4;
742 }
743 }
744
745 /**
746 * build an empty asn.1 object with tag and length fields already filled in
747 */
748 u_char* asn1_build_object(chunk_t *object, asn1_t type, size_t datalen)
749 {
750 u_char length_buf[4];
751 chunk_t length = { length_buf, 0 };
752 u_char *pos;
753
754 /* code the asn.1 length field */
755 asn1_code_length(datalen, &length);
756
757 /* allocate memory for the asn.1 TLV object */
758 object->len = 1 + length.len + datalen;
759 object->ptr = malloc(object->len);
760
761 /* set position pointer at the start of the object */
762 pos = object->ptr;
763
764 /* copy the asn.1 tag field and advance the pointer */
765 *pos++ = type;
766
767 /* copy the asn.1 length field and advance the pointer */
768 memcpy(pos, length.ptr, length.len);
769 pos += length.len;
770
771 return pos;
772 }
773
774 /**
775 * Build a simple ASN.1 object
776 */
777 chunk_t asn1_simple_object(asn1_t tag, chunk_t content)
778 {
779 chunk_t object;
780
781 u_char *pos = asn1_build_object(&object, tag, content.len);
782 memcpy(pos, content.ptr, content.len);
783 pos += content.len;
784
785 return object;
786 }
787
788 /**
789 * Build an ASN.1 BIT_STRING object
790 */
791 chunk_t asn1_bitstring(const char *mode, chunk_t content)
792 {
793 chunk_t object;
794 u_char *pos = asn1_build_object(&object, ASN1_BIT_STRING, 1 + content.len);
795
796 *pos++ = 0x00;
797 memcpy(pos, content.ptr, content.len);
798 if (*mode == 'm')
799 {
800 free(content.ptr);
801 }
802 return object;
803 }
804
805 /**
806 * Build an ASN.1 INTEGER object
807 */
808 chunk_t asn1_integer(const char *mode, chunk_t content)
809 {
810 chunk_t object;
811 size_t len;
812 u_char *pos;
813 bool move;
814
815
816 if (content.len == 0)
817 { /* make sure 0 is encoded properly */
818 content = chunk_from_chars(0x00);
819 move = FALSE;
820 }
821 else
822 {
823 move = (*mode == 'm');
824 }
825
826 /* ASN.1 integers must be positive numbers in two's complement */
827 len = content.len + ((*content.ptr & 0x80) ? 1 : 0);
828 pos = asn1_build_object(&object, ASN1_INTEGER, len);
829 if (len > content.len)
830 {
831 *pos++ = 0x00;
832 }
833 memcpy(pos, content.ptr, content.len);
834
835 if (move)
836 {
837 free(content.ptr);
838 }
839 return object;
840 }
841
842 /**
843 * Build an ASN.1 object from a variable number of individual chunks.
844 * Depending on the mode, chunks either are moved ('m') or copied ('c').
845 */
846 chunk_t asn1_wrap(asn1_t type, const char *mode, ...)
847 {
848 chunk_t construct;
849 va_list chunks;
850 u_char *pos;
851 int i;
852 int count = strlen(mode);
853
854 /* sum up lengths of individual chunks */
855 va_start(chunks, mode);
856 construct.len = 0;
857 for (i = 0; i < count; i++)
858 {
859 chunk_t ch = va_arg(chunks, chunk_t);
860 construct.len += ch.len;
861 }
862 va_end(chunks);
863
864 /* allocate needed memory for construct */
865 pos = asn1_build_object(&construct, type, construct.len);
866
867 /* copy or move the chunks */
868 va_start(chunks, mode);
869 for (i = 0; i < count; i++)
870 {
871 chunk_t ch = va_arg(chunks, chunk_t);
872
873 memcpy(pos, ch.ptr, ch.len);
874 pos += ch.len;
875
876 switch (*mode++)
877 {
878 case 's':
879 chunk_clear(&ch);
880 break;
881 case 'm':
882 free(ch.ptr);
883 break;
884 default:
885 break;
886 }
887 }
888 va_end(chunks);
889
890 return construct;
891 }
892
893 /**
894 * ASN.1 definition of time
895 */
896 static const asn1Object_t timeObjects[] = {
897 { 0, "utcTime", ASN1_UTCTIME, ASN1_OPT|ASN1_BODY }, /* 0 */
898 { 0, "end opt", ASN1_EOC, ASN1_END }, /* 1 */
899 { 0, "generalizeTime", ASN1_GENERALIZEDTIME, ASN1_OPT|ASN1_BODY }, /* 2 */
900 { 0, "end opt", ASN1_EOC, ASN1_END }, /* 3 */
901 { 0, "exit", ASN1_EOC, ASN1_EXIT }
902 };
903 #define TIME_UTC 0
904 #define TIME_GENERALIZED 2
905
906 /**
907 * extracts and converts a UTCTIME or GENERALIZEDTIME object
908 */
909 time_t asn1_parse_time(chunk_t blob, int level0)
910 {
911 asn1_parser_t *parser;
912 chunk_t object;
913 int objectID;
914 time_t utc_time = 0;
915
916 parser= asn1_parser_create(timeObjects, blob);
917 parser->set_top_level(parser, level0);
918
919 while (parser->iterate(parser, &objectID, &object))
920 {
921 if (objectID == TIME_UTC || objectID == TIME_GENERALIZED)
922 {
923 utc_time = asn1_to_time(&object, (objectID == TIME_UTC)
924 ? ASN1_UTCTIME : ASN1_GENERALIZEDTIME);
925 }
926 }
927 parser->destroy(parser);
928 return utc_time;
929 }