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