Annotation of embedaddon/strongswan/src/libstrongswan/plugins/x509/x509_cert.c, revision 1.1
1.1 ! misho 1: /*
! 2: * Copyright (C) 2000 Andreas Hess, Patric Lichtsteiner, Roger Wegmann
! 3: * Copyright (C) 2001 Marco Bertossa, Andreas Schleiss
! 4: * Copyright (C) 2002 Mario Strasser
! 5: * Copyright (C) 2000-2017 Andreas Steffen
! 6: * Copyright (C) 2006-2009 Martin Willi
! 7: * Copyright (C) 2008-2017 Tobias Brunner
! 8: * HSR Hochschule fuer Technik Rapperswil
! 9: *
! 10: * This program is free software; you can redistribute it and/or modify it
! 11: * under the terms of the GNU General Public License as published by the
! 12: * Free Software Foundation; either version 2 of the License, or (at your
! 13: * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
! 14: *
! 15: * This program is distributed in the hope that it will be useful, but
! 16: * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
! 17: * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
! 18: * for more details.
! 19: */
! 20:
! 21: #define _GNU_SOURCE
! 22:
! 23: #include <sys/stat.h>
! 24: #include <time.h>
! 25: #include <unistd.h>
! 26: #include <string.h>
! 27: #include <stdio.h>
! 28:
! 29: #include "x509_cert.h"
! 30:
! 31: #include <library.h>
! 32: #include <utils/debug.h>
! 33: #include <asn1/oid.h>
! 34: #include <asn1/asn1.h>
! 35: #include <asn1/asn1_parser.h>
! 36: #include <crypto/hashers/hasher.h>
! 37: #include <credentials/keys/private_key.h>
! 38: #include <collections/linked_list.h>
! 39: #include <utils/identification.h>
! 40: #include <selectors/traffic_selector.h>
! 41:
! 42: /**
! 43: * Different kinds of generalNames
! 44: */
! 45: typedef enum {
! 46: GN_OTHER_NAME = 0,
! 47: GN_RFC822_NAME = 1,
! 48: GN_DNS_NAME = 2,
! 49: GN_X400_ADDRESS = 3,
! 50: GN_DIRECTORY_NAME = 4,
! 51: GN_EDI_PARTY_NAME = 5,
! 52: GN_URI = 6,
! 53: GN_IP_ADDRESS = 7,
! 54: GN_REGISTERED_ID = 8,
! 55: } generalNames_t;
! 56:
! 57:
! 58: typedef struct private_x509_cert_t private_x509_cert_t;
! 59:
! 60: /**
! 61: * Private data of a x509_cert_t object.
! 62: */
! 63: struct private_x509_cert_t {
! 64: /**
! 65: * Public interface for this certificate.
! 66: */
! 67: x509_cert_t public;
! 68:
! 69: /**
! 70: * X.509 certificate encoding in ASN.1 DER format
! 71: */
! 72: chunk_t encoding;
! 73:
! 74: /**
! 75: * SHA1 hash of the DER encoding of this X.509 certificate
! 76: */
! 77: chunk_t encoding_hash;
! 78:
! 79: /**
! 80: * X.509 certificate body over which signature is computed
! 81: */
! 82: chunk_t tbsCertificate;
! 83:
! 84: /**
! 85: * Version of the X.509 certificate
! 86: */
! 87: u_int version;
! 88:
! 89: /**
! 90: * Serial number of the X.509 certificate
! 91: */
! 92: chunk_t serialNumber;
! 93:
! 94: /**
! 95: * ID representing the certificate issuer
! 96: */
! 97: identification_t *issuer;
! 98:
! 99: /**
! 100: * Start time of certificate validity
! 101: */
! 102: time_t notBefore;
! 103:
! 104: /**
! 105: * End time of certificate validity
! 106: */
! 107: time_t notAfter;
! 108:
! 109: /**
! 110: * ID representing the certificate subject
! 111: */
! 112: identification_t *subject;
! 113:
! 114: /**
! 115: * List of subjectAltNames as identification_t
! 116: */
! 117: linked_list_t *subjectAltNames;
! 118:
! 119: /**
! 120: * List of crlDistributionPoints as x509_cdp_t*
! 121: */
! 122: linked_list_t *crl_uris;
! 123:
! 124: /**
! 125: * List of ocspAccessLocations as allocated char*
! 126: */
! 127: linked_list_t *ocsp_uris;
! 128:
! 129: /**
! 130: * List of ipAddrBlocks as traffic_selector_t
! 131: */
! 132: linked_list_t *ipAddrBlocks;
! 133:
! 134: /**
! 135: * List of permitted name constraints
! 136: */
! 137: linked_list_t *permitted_names;
! 138:
! 139: /**
! 140: * List of excluded name constraints
! 141: */
! 142: linked_list_t *excluded_names;
! 143:
! 144: /**
! 145: * List of certificatePolicies, as x509_cert_policy_t
! 146: */
! 147: linked_list_t *cert_policies;
! 148:
! 149: /**
! 150: * List of policyMappings, as x509_policy_mapping_t
! 151: */
! 152: linked_list_t *policy_mappings;
! 153:
! 154: /**
! 155: * certificate's embedded public key
! 156: */
! 157: public_key_t *public_key;
! 158:
! 159: /**
! 160: * Subject Key Identifier
! 161: */
! 162: chunk_t subjectKeyIdentifier;
! 163:
! 164: /**
! 165: * Authority Key Identifier
! 166: */
! 167: chunk_t authKeyIdentifier;
! 168:
! 169: /**
! 170: * Authority Key Serial Number
! 171: */
! 172: chunk_t authKeySerialNumber;
! 173:
! 174: /**
! 175: * Optional OID of an [unsupported] critical extension
! 176: */
! 177: chunk_t critical_extension_oid;
! 178:
! 179: /**
! 180: * Path Length Constraint
! 181: */
! 182: u_char pathLenConstraint;
! 183:
! 184: /**
! 185: * requireExplicitPolicy Constraint
! 186: */
! 187: u_char require_explicit;
! 188:
! 189: /**
! 190: * inhibitPolicyMapping Constraint
! 191: */
! 192: u_char inhibit_mapping;
! 193:
! 194: /**
! 195: * inhibitAnyPolicy Constraint
! 196: */
! 197: u_char inhibit_any;
! 198:
! 199: /**
! 200: * x509 constraints and other flags
! 201: */
! 202: x509_flag_t flags;
! 203:
! 204: /**
! 205: * Signature scheme
! 206: */
! 207: signature_params_t *scheme;
! 208:
! 209: /**
! 210: * Signature
! 211: */
! 212: chunk_t signature;
! 213:
! 214: /**
! 215: * Certificate parsed from blob/file?
! 216: */
! 217: bool parsed;
! 218:
! 219: /**
! 220: * reference count
! 221: */
! 222: refcount_t ref;
! 223: };
! 224:
! 225: /**
! 226: * Convert a generalName to a string
! 227: */
! 228: static bool gn_to_string(identification_t *id, char **uri)
! 229: {
! 230: int len;
! 231:
! 232: #ifdef USE_FUZZING
! 233: chunk_t proper;
! 234: chunk_printable(id->get_encoding(id), &proper, '?');
! 235: len = asprintf(uri, "%.*s", (int)proper.len, proper.ptr);
! 236: chunk_free(&proper);
! 237: #else
! 238: len = asprintf(uri, "%Y", id);
! 239: #endif
! 240: if (!len)
! 241: {
! 242: free(*uri);
! 243: return FALSE;
! 244: }
! 245: return len > 0;
! 246: }
! 247:
! 248: /**
! 249: * Destroy a CertificatePolicy
! 250: */
! 251: static void cert_policy_destroy(x509_cert_policy_t *this)
! 252: {
! 253: free(this->oid.ptr);
! 254: free(this->cps_uri);
! 255: free(this->unotice_text);
! 256: free(this);
! 257: }
! 258:
! 259: /**
! 260: * Free policy mapping
! 261: */
! 262: static void policy_mapping_destroy(x509_policy_mapping_t *mapping)
! 263: {
! 264: free(mapping->issuer.ptr);
! 265: free(mapping->subject.ptr);
! 266: free(mapping);
! 267: }
! 268:
! 269: /**
! 270: * Parse a length constraint from an unwrapped integer
! 271: */
! 272: static u_int parse_constraint(chunk_t object)
! 273: {
! 274: switch (object.len)
! 275: {
! 276: case 0:
! 277: return 0;
! 278: case 1:
! 279: return (object.ptr[0] & 0x80) ? X509_NO_CONSTRAINT : object.ptr[0];
! 280: default:
! 281: return X509_NO_CONSTRAINT;
! 282: }
! 283: }
! 284:
! 285: /**
! 286: * ASN.1 definition of a basicConstraints extension
! 287: */
! 288: static const asn1Object_t basicConstraintsObjects[] = {
! 289: { 0, "basicConstraints", ASN1_SEQUENCE, ASN1_NONE }, /* 0 */
! 290: { 1, "CA", ASN1_BOOLEAN, ASN1_DEF|ASN1_BODY }, /* 1 */
! 291: { 1, "pathLenConstraint", ASN1_INTEGER, ASN1_OPT|ASN1_BODY }, /* 2 */
! 292: { 1, "end opt", ASN1_EOC, ASN1_END }, /* 3 */
! 293: { 0, "exit", ASN1_EOC, ASN1_EXIT }
! 294: };
! 295: #define BASIC_CONSTRAINTS_CA 1
! 296: #define BASIC_CONSTRAINTS_PATH_LEN 2
! 297:
! 298: /**
! 299: * Extracts the basicConstraints extension
! 300: */
! 301: static bool parse_basicConstraints(chunk_t blob, int level0,
! 302: private_x509_cert_t *this)
! 303: {
! 304: asn1_parser_t *parser;
! 305: chunk_t object;
! 306: int objectID;
! 307: bool isCA = FALSE;
! 308: bool success;
! 309:
! 310: parser = asn1_parser_create(basicConstraintsObjects, blob);
! 311: parser->set_top_level(parser, level0);
! 312:
! 313: while (parser->iterate(parser, &objectID, &object))
! 314: {
! 315: switch (objectID)
! 316: {
! 317: case BASIC_CONSTRAINTS_CA:
! 318: isCA = object.len && *object.ptr;
! 319: DBG2(DBG_ASN, " %s", isCA ? "TRUE" : "FALSE");
! 320: if (isCA)
! 321: {
! 322: this->flags |= X509_CA;
! 323: }
! 324: break;
! 325: case BASIC_CONSTRAINTS_PATH_LEN:
! 326: if (isCA)
! 327: {
! 328: this->pathLenConstraint = parse_constraint(object);
! 329: }
! 330: break;
! 331: default:
! 332: break;
! 333: }
! 334: }
! 335: success = parser->success(parser);
! 336: parser->destroy(parser);
! 337:
! 338: return success;
! 339: }
! 340:
! 341: /**
! 342: * ASN.1 definition of otherName
! 343: */
! 344: static const asn1Object_t otherNameObjects[] = {
! 345: {0, "type-id", ASN1_OID, ASN1_BODY }, /* 0 */
! 346: {0, "value", ASN1_CONTEXT_C_0, ASN1_BODY }, /* 1 */
! 347: {0, "exit", ASN1_EOC, ASN1_EXIT }
! 348: };
! 349: #define ON_OBJ_ID_TYPE 0
! 350: #define ON_OBJ_VALUE 1
! 351:
! 352: /**
! 353: * Extracts an otherName
! 354: */
! 355: static bool parse_otherName(chunk_t *blob, int level0, id_type_t *type)
! 356: {
! 357: asn1_parser_t *parser;
! 358: chunk_t object;
! 359: int objectID;
! 360: int oid = OID_UNKNOWN;
! 361: bool success = FALSE;
! 362:
! 363: parser = asn1_parser_create(otherNameObjects, *blob);
! 364: parser->set_top_level(parser, level0);
! 365:
! 366: while (parser->iterate(parser, &objectID, &object))
! 367: {
! 368: switch (objectID)
! 369: {
! 370: case ON_OBJ_ID_TYPE:
! 371: oid = asn1_known_oid(object);
! 372: break;
! 373: case ON_OBJ_VALUE:
! 374: switch (oid)
! 375: {
! 376: case OID_XMPP_ADDR:
! 377: if (asn1_parse_simple_object(&object, ASN1_UTF8STRING,
! 378: parser->get_level(parser)+1, "xmppAddr"))
! 379: { /* we handle xmppAddr as RFC822 addr */
! 380: *blob = object;
! 381: *type = ID_RFC822_ADDR;
! 382: }
! 383: else
! 384: {
! 385: goto end;
! 386: }
! 387: break;
! 388: case OID_USER_PRINCIPAL_NAME:
! 389: if (asn1_parse_simple_object(&object, ASN1_UTF8STRING,
! 390: parser->get_level(parser)+1, "msUPN"))
! 391: { /* we handle UPNs as RFC822 addr */
! 392: *blob = object;
! 393: *type = ID_RFC822_ADDR;
! 394: }
! 395: else
! 396: {
! 397: goto end;
! 398: }
! 399: break;
! 400: }
! 401: break;
! 402: default:
! 403: break;
! 404: }
! 405: }
! 406: success = parser->success(parser);
! 407:
! 408: end:
! 409: parser->destroy(parser);
! 410: return success;
! 411: }
! 412:
! 413: /**
! 414: * ASN.1 definition of generalName
! 415: */
! 416: static const asn1Object_t generalNameObjects[] = {
! 417: { 0, "otherName", ASN1_CONTEXT_C_0, ASN1_OPT|ASN1_BODY }, /* 0 */
! 418: { 0, "end choice", ASN1_EOC, ASN1_END }, /* 1 */
! 419: { 0, "rfc822Name", ASN1_CONTEXT_S_1, ASN1_OPT|ASN1_BODY }, /* 2 */
! 420: { 0, "end choice", ASN1_EOC, ASN1_END }, /* 3 */
! 421: { 0, "dnsName", ASN1_CONTEXT_S_2, ASN1_OPT|ASN1_BODY }, /* 4 */
! 422: { 0, "end choice", ASN1_EOC, ASN1_END }, /* 5 */
! 423: { 0, "x400Address", ASN1_CONTEXT_S_3, ASN1_OPT|ASN1_BODY }, /* 6 */
! 424: { 0, "end choice", ASN1_EOC, ASN1_END }, /* 7 */
! 425: { 0, "directoryName", ASN1_CONTEXT_C_4, ASN1_OPT|ASN1_BODY }, /* 8 */
! 426: { 0, "end choice", ASN1_EOC, ASN1_END }, /* 9 */
! 427: { 0, "ediPartyName", ASN1_CONTEXT_C_5, ASN1_OPT|ASN1_BODY }, /* 10 */
! 428: { 0, "end choice", ASN1_EOC, ASN1_END }, /* 11 */
! 429: { 0, "URI", ASN1_CONTEXT_S_6, ASN1_OPT|ASN1_BODY }, /* 12 */
! 430: { 0, "end choice", ASN1_EOC, ASN1_END }, /* 13 */
! 431: { 0, "ipAddress", ASN1_CONTEXT_S_7, ASN1_OPT|ASN1_BODY }, /* 14 */
! 432: { 0, "end choice", ASN1_EOC, ASN1_END }, /* 15 */
! 433: { 0, "registeredID", ASN1_CONTEXT_S_8, ASN1_OPT|ASN1_BODY }, /* 16 */
! 434: { 0, "end choice", ASN1_EOC, ASN1_END }, /* 17 */
! 435: { 0, "exit", ASN1_EOC, ASN1_EXIT }
! 436: };
! 437: #define GN_OBJ_OTHER_NAME 0
! 438: #define GN_OBJ_RFC822_NAME 2
! 439: #define GN_OBJ_DNS_NAME 4
! 440: #define GN_OBJ_X400_ADDRESS 6
! 441: #define GN_OBJ_DIRECTORY_NAME 8
! 442: #define GN_OBJ_EDI_PARTY_NAME 10
! 443: #define GN_OBJ_URI 12
! 444: #define GN_OBJ_IP_ADDRESS 14
! 445: #define GN_OBJ_REGISTERED_ID 16
! 446:
! 447: /**
! 448: * Extracts a generalName
! 449: */
! 450: static identification_t *parse_generalName(chunk_t blob, int level0)
! 451: {
! 452: asn1_parser_t *parser;
! 453: chunk_t object;
! 454: int objectID ;
! 455:
! 456: identification_t *gn = NULL;
! 457:
! 458: parser = asn1_parser_create(generalNameObjects, blob);
! 459: parser->set_top_level(parser, level0);
! 460:
! 461: while (parser->iterate(parser, &objectID, &object))
! 462: {
! 463: id_type_t id_type = ID_ANY;
! 464:
! 465: switch (objectID)
! 466: {
! 467: case GN_OBJ_RFC822_NAME:
! 468: id_type = ID_RFC822_ADDR;
! 469: break;
! 470: case GN_OBJ_DNS_NAME:
! 471: id_type = ID_FQDN;
! 472: break;
! 473: case GN_OBJ_URI:
! 474: id_type = ID_DER_ASN1_GN_URI;
! 475: break;
! 476: case GN_OBJ_DIRECTORY_NAME:
! 477: id_type = ID_DER_ASN1_DN;
! 478: break;
! 479: case GN_OBJ_IP_ADDRESS:
! 480: switch (object.len)
! 481: {
! 482: case 4:
! 483: id_type = ID_IPV4_ADDR;
! 484: break;
! 485: case 16:
! 486: id_type = ID_IPV6_ADDR;
! 487: break;
! 488: default:
! 489: break;
! 490: }
! 491: break;
! 492: case GN_OBJ_OTHER_NAME:
! 493: if (!parse_otherName(&object, parser->get_level(parser)+1,
! 494: &id_type))
! 495: {
! 496: goto end;
! 497: }
! 498: break;
! 499: case GN_OBJ_X400_ADDRESS:
! 500: case GN_OBJ_EDI_PARTY_NAME:
! 501: case GN_OBJ_REGISTERED_ID:
! 502: default:
! 503: break;
! 504: }
! 505: if (id_type != ID_ANY)
! 506: {
! 507: gn = identification_create_from_encoding(id_type, object);
! 508: DBG2(DBG_ASN, " '%Y'", gn);
! 509: goto end;
! 510: }
! 511: }
! 512:
! 513: end:
! 514: parser->destroy(parser);
! 515: return gn;
! 516: }
! 517:
! 518: /**
! 519: * ASN.1 definition of generalNames
! 520: */
! 521: static const asn1Object_t generalNamesObjects[] = {
! 522: { 0, "generalNames", ASN1_SEQUENCE, ASN1_LOOP }, /* 0 */
! 523: { 1, "generalName", ASN1_EOC, ASN1_RAW }, /* 1 */
! 524: { 0, "end loop", ASN1_EOC, ASN1_END }, /* 2 */
! 525: { 0, "exit", ASN1_EOC, ASN1_EXIT }
! 526: };
! 527: #define GENERAL_NAMES_GN 1
! 528:
! 529: /**
! 530: * Extracts one or several GNs and puts them into a chained list
! 531: */
! 532: bool x509_parse_generalNames(chunk_t blob, int level0, bool implicit,
! 533: linked_list_t *list)
! 534: {
! 535: asn1_parser_t *parser;
! 536: chunk_t object;
! 537: identification_t *gn;
! 538: int objectID;
! 539: bool success = FALSE;
! 540:
! 541: parser = asn1_parser_create(generalNamesObjects, blob);
! 542: parser->set_top_level(parser, level0);
! 543: parser->set_flags(parser, implicit, FALSE);
! 544:
! 545: while (parser->iterate(parser, &objectID, &object))
! 546: {
! 547: if (objectID == GENERAL_NAMES_GN)
! 548: {
! 549: gn = parse_generalName(object, parser->get_level(parser)+1);
! 550: if (!gn)
! 551: {
! 552: goto end;
! 553: }
! 554: list->insert_last(list, (void *)gn);
! 555: }
! 556: }
! 557: success = parser->success(parser);
! 558:
! 559: end:
! 560: parser->destroy(parser);
! 561:
! 562: return success;
! 563: }
! 564:
! 565: /**
! 566: * ASN.1 definition of a authorityKeyIdentifier extension
! 567: */
! 568: static const asn1Object_t authKeyIdentifierObjects[] = {
! 569: { 0, "authorityKeyIdentifier", ASN1_SEQUENCE, ASN1_NONE }, /* 0 */
! 570: { 1, "keyIdentifier", ASN1_CONTEXT_S_0, ASN1_OPT|ASN1_BODY }, /* 1 */
! 571: { 1, "end opt", ASN1_EOC, ASN1_END }, /* 2 */
! 572: { 1, "authorityCertIssuer", ASN1_CONTEXT_C_1, ASN1_OPT|ASN1_OBJ }, /* 3 */
! 573: { 1, "end opt", ASN1_EOC, ASN1_END }, /* 4 */
! 574: { 1, "authorityCertSerialNumber", ASN1_CONTEXT_S_2, ASN1_OPT|ASN1_BODY }, /* 5 */
! 575: { 1, "end opt", ASN1_EOC, ASN1_END }, /* 6 */
! 576: { 0, "exit", ASN1_EOC, ASN1_EXIT }
! 577: };
! 578: #define AUTH_KEY_ID_KEY_ID 1
! 579: #define AUTH_KEY_ID_CERT_ISSUER 3
! 580: #define AUTH_KEY_ID_CERT_SERIAL 5
! 581:
! 582: /**
! 583: * Extracts an authoritykeyIdentifier
! 584: */
! 585: chunk_t x509_parse_authorityKeyIdentifier(chunk_t blob, int level0,
! 586: chunk_t *authKeySerialNumber)
! 587: {
! 588: asn1_parser_t *parser;
! 589: chunk_t object;
! 590: int objectID;
! 591: chunk_t authKeyIdentifier = chunk_empty;
! 592:
! 593: *authKeySerialNumber = chunk_empty;
! 594:
! 595: parser = asn1_parser_create(authKeyIdentifierObjects, blob);
! 596: parser->set_top_level(parser, level0);
! 597:
! 598: while (parser->iterate(parser, &objectID, &object))
! 599: {
! 600: switch (objectID)
! 601: {
! 602: case AUTH_KEY_ID_KEY_ID:
! 603: authKeyIdentifier = chunk_clone(object);
! 604: break;
! 605: case AUTH_KEY_ID_CERT_ISSUER:
! 606: /* TODO: x509_parse_generalNames(object, level+1, TRUE); */
! 607: break;
! 608: case AUTH_KEY_ID_CERT_SERIAL:
! 609: *authKeySerialNumber = object;
! 610: break;
! 611: default:
! 612: break;
! 613: }
! 614: }
! 615: parser->destroy(parser);
! 616:
! 617: return authKeyIdentifier;
! 618: }
! 619:
! 620: /**
! 621: * ASN.1 definition of a authorityInfoAccess extension
! 622: */
! 623: static const asn1Object_t authInfoAccessObjects[] = {
! 624: { 0, "authorityInfoAccess", ASN1_SEQUENCE, ASN1_LOOP }, /* 0 */
! 625: { 1, "accessDescription", ASN1_SEQUENCE, ASN1_NONE }, /* 1 */
! 626: { 2, "accessMethod", ASN1_OID, ASN1_BODY }, /* 2 */
! 627: { 2, "accessLocation", ASN1_EOC, ASN1_RAW }, /* 3 */
! 628: { 0, "end loop", ASN1_EOC, ASN1_END }, /* 4 */
! 629: { 0, "exit", ASN1_EOC, ASN1_EXIT }
! 630: };
! 631: #define AUTH_INFO_ACCESS_METHOD 2
! 632: #define AUTH_INFO_ACCESS_LOCATION 3
! 633:
! 634: /**
! 635: * Extracts an authorityInfoAcess location
! 636: */
! 637: static bool parse_authorityInfoAccess(chunk_t blob, int level0,
! 638: private_x509_cert_t *this)
! 639: {
! 640: asn1_parser_t *parser;
! 641: chunk_t object;
! 642: int objectID;
! 643: int accessMethod = OID_UNKNOWN;
! 644: bool success = FALSE;
! 645:
! 646: parser = asn1_parser_create(authInfoAccessObjects, blob);
! 647: parser->set_top_level(parser, level0);
! 648:
! 649: while (parser->iterate(parser, &objectID, &object))
! 650: {
! 651: switch (objectID)
! 652: {
! 653: case AUTH_INFO_ACCESS_METHOD:
! 654: accessMethod = asn1_known_oid(object);
! 655: break;
! 656: case AUTH_INFO_ACCESS_LOCATION:
! 657: {
! 658: switch (accessMethod)
! 659: {
! 660: case OID_OCSP:
! 661: case OID_CA_ISSUERS:
! 662: {
! 663: identification_t *id;
! 664: char *uri;
! 665:
! 666: id = parse_generalName(object,
! 667: parser->get_level(parser)+1);
! 668: if (id == NULL)
! 669: {
! 670: /* parsing went wrong - abort */
! 671: goto end;
! 672: }
! 673: DBG2(DBG_ASN, " '%Y'", id);
! 674: if (accessMethod == OID_OCSP &&
! 675: gn_to_string(id, &uri))
! 676: {
! 677: this->ocsp_uris->insert_last(this->ocsp_uris, uri);
! 678: }
! 679: id->destroy(id);
! 680: }
! 681: break;
! 682: default:
! 683: /* unknown accessMethod, ignoring */
! 684: break;
! 685: }
! 686: break;
! 687: }
! 688: default:
! 689: break;
! 690: }
! 691: }
! 692: success = parser->success(parser);
! 693:
! 694: end:
! 695: parser->destroy(parser);
! 696:
! 697: return success;
! 698: }
! 699:
! 700: /**
! 701: * Extract KeyUsage flags
! 702: */
! 703: static void parse_keyUsage(chunk_t blob, private_x509_cert_t *this)
! 704: {
! 705: enum {
! 706: KU_DIGITAL_SIGNATURE = 0,
! 707: KU_NON_REPUDIATION = 1,
! 708: KU_KEY_ENCIPHERMENT = 2,
! 709: KU_DATA_ENCIPHERMENT = 3,
! 710: KU_KEY_AGREEMENT = 4,
! 711: KU_KEY_CERT_SIGN = 5,
! 712: KU_CRL_SIGN = 6,
! 713: KU_ENCIPHER_ONLY = 7,
! 714: KU_DECIPHER_ONLY = 8,
! 715: };
! 716:
! 717: /* to be compliant with RFC 4945 specific KUs have to be included */
! 718: this->flags &= ~X509_IKE_COMPLIANT;
! 719:
! 720: if (asn1_unwrap(&blob, &blob) == ASN1_BIT_STRING && blob.len)
! 721: {
! 722: int bit, byte, unused = blob.ptr[0];
! 723:
! 724: blob = chunk_skip(blob, 1);
! 725: for (byte = 0; byte < blob.len; byte++)
! 726: {
! 727: for (bit = 0; bit < 8; bit++)
! 728: {
! 729: if (byte == blob.len - 1 && bit > (7 - unused))
! 730: {
! 731: break;
! 732: }
! 733: if (blob.ptr[byte] & 1 << (7 - bit))
! 734: {
! 735: switch (byte * 8 + bit)
! 736: {
! 737: case KU_CRL_SIGN:
! 738: this->flags |= X509_CRL_SIGN;
! 739: break;
! 740: case KU_DIGITAL_SIGNATURE:
! 741: case KU_NON_REPUDIATION:
! 742: this->flags |= X509_IKE_COMPLIANT;
! 743: break;
! 744: case KU_KEY_CERT_SIGN:
! 745: /* we use the caBasicConstraint, MUST be set */
! 746: case KU_KEY_ENCIPHERMENT:
! 747: case KU_DATA_ENCIPHERMENT:
! 748: case KU_KEY_AGREEMENT:
! 749: case KU_ENCIPHER_ONLY:
! 750: case KU_DECIPHER_ONLY:
! 751: break;
! 752: }
! 753: }
! 754: }
! 755: }
! 756: }
! 757: }
! 758:
! 759: /**
! 760: * ASN.1 definition of a extendedKeyUsage extension
! 761: */
! 762: static const asn1Object_t extendedKeyUsageObjects[] = {
! 763: { 0, "extendedKeyUsage", ASN1_SEQUENCE, ASN1_LOOP }, /* 0 */
! 764: { 1, "keyPurposeID", ASN1_OID, ASN1_BODY }, /* 1 */
! 765: { 0, "end loop", ASN1_EOC, ASN1_END }, /* 2 */
! 766: { 0, "exit", ASN1_EOC, ASN1_EXIT }
! 767: };
! 768: #define EXT_KEY_USAGE_PURPOSE_ID 1
! 769:
! 770: /**
! 771: * Extracts extendedKeyUsage OIDs
! 772: */
! 773: static bool parse_extendedKeyUsage(chunk_t blob, int level0,
! 774: private_x509_cert_t *this)
! 775: {
! 776: asn1_parser_t *parser;
! 777: chunk_t object;
! 778: int objectID;
! 779: bool success;
! 780:
! 781: parser = asn1_parser_create(extendedKeyUsageObjects, blob);
! 782: parser->set_top_level(parser, level0);
! 783:
! 784: while (parser->iterate(parser, &objectID, &object))
! 785: {
! 786: if (objectID == EXT_KEY_USAGE_PURPOSE_ID)
! 787: {
! 788: switch (asn1_known_oid(object))
! 789: {
! 790: case OID_SERVER_AUTH:
! 791: this->flags |= X509_SERVER_AUTH;
! 792: break;
! 793: case OID_CLIENT_AUTH:
! 794: this->flags |= X509_CLIENT_AUTH;
! 795: break;
! 796: case OID_IKE_INTERMEDIATE:
! 797: this->flags |= X509_IKE_INTERMEDIATE;
! 798: break;
! 799: case OID_OCSP_SIGNING:
! 800: this->flags |= X509_OCSP_SIGNER;
! 801: break;
! 802: case OID_MS_SMARTCARD_LOGON:
! 803: this->flags |= X509_MS_SMARTCARD_LOGON;
! 804: break;
! 805: default:
! 806: break;
! 807: }
! 808: }
! 809: }
! 810: success = parser->success(parser);
! 811: parser->destroy(parser);
! 812:
! 813: return success;
! 814: }
! 815:
! 816: /**
! 817: * ASN.1 definition of crlDistributionPoints
! 818: */
! 819: static const asn1Object_t crlDistributionPointsObjects[] = {
! 820: { 0, "crlDistributionPoints", ASN1_SEQUENCE, ASN1_LOOP }, /* 0 */
! 821: { 1, "DistributionPoint", ASN1_SEQUENCE, ASN1_NONE }, /* 1 */
! 822: { 2, "distributionPoint", ASN1_CONTEXT_C_0, ASN1_OPT|ASN1_CHOICE }, /* 2 */
! 823: { 3, "fullName", ASN1_CONTEXT_C_0, ASN1_OPT|ASN1_OBJ }, /* 3 */
! 824: { 3, "end choice", ASN1_EOC, ASN1_END|ASN1_CH }, /* 4 */
! 825: { 3, "nameRelToCRLIssuer",ASN1_CONTEXT_C_1, ASN1_OPT|ASN1_BODY }, /* 5 */
! 826: { 3, "end choice", ASN1_EOC, ASN1_END|ASN1_CH }, /* 6 */
! 827: { 2, "end opt/choices", ASN1_EOC, ASN1_END|ASN1_CHOICE }, /* 7 */
! 828: { 2, "reasons", ASN1_CONTEXT_C_1, ASN1_OPT|ASN1_BODY }, /* 8 */
! 829: { 2, "end opt", ASN1_EOC, ASN1_END }, /* 9 */
! 830: { 2, "crlIssuer", ASN1_CONTEXT_C_2, ASN1_OPT|ASN1_OBJ }, /* 10 */
! 831: { 2, "end opt", ASN1_EOC, ASN1_END }, /* 11 */
! 832: { 0, "end loop", ASN1_EOC, ASN1_END }, /* 12 */
! 833: { 0, "exit", ASN1_EOC, ASN1_EXIT }
! 834: };
! 835: #define CRL_DIST_POINTS 1
! 836: #define CRL_DIST_POINTS_FULLNAME 3
! 837: #define CRL_DIST_POINTS_ISSUER 10
! 838:
! 839: /**
! 840: * Add entry to the list of each pairing of URI and Issuer
! 841: */
! 842: static void add_cdps(linked_list_t *list, linked_list_t *uris,
! 843: linked_list_t *issuers)
! 844: {
! 845: identification_t *issuer, *id;
! 846: enumerator_t *enumerator;
! 847: x509_cdp_t *cdp;
! 848: char *uri;
! 849:
! 850: while (uris->remove_last(uris, (void**)&id) == SUCCESS)
! 851: {
! 852: if (gn_to_string(id, &uri))
! 853: {
! 854: if (issuers->get_count(issuers))
! 855: {
! 856: enumerator = issuers->create_enumerator(issuers);
! 857: while (enumerator->enumerate(enumerator, &issuer))
! 858: {
! 859: INIT(cdp,
! 860: .uri = strdup(uri),
! 861: .issuer = issuer->clone(issuer),
! 862: );
! 863: list->insert_last(list, cdp);
! 864: }
! 865: enumerator->destroy(enumerator);
! 866: free(uri);
! 867: }
! 868: else
! 869: {
! 870: INIT(cdp,
! 871: .uri = uri,
! 872: );
! 873: list->insert_last(list, cdp);
! 874: }
! 875: }
! 876: id->destroy(id);
! 877: }
! 878: while (issuers->remove_last(issuers, (void**)&id) == SUCCESS)
! 879: {
! 880: id->destroy(id);
! 881: }
! 882: }
! 883:
! 884: /**
! 885: * Extracts one or several crlDistributionPoints into a list
! 886: */
! 887: bool x509_parse_crlDistributionPoints(chunk_t blob, int level0,
! 888: linked_list_t *list)
! 889: {
! 890: linked_list_t *uris, *issuers;
! 891: asn1_parser_t *parser;
! 892: chunk_t object;
! 893: int objectID;
! 894: bool success = FALSE;
! 895:
! 896: uris = linked_list_create();
! 897: issuers = linked_list_create();
! 898: parser = asn1_parser_create(crlDistributionPointsObjects, blob);
! 899: parser->set_top_level(parser, level0);
! 900:
! 901: while (parser->iterate(parser, &objectID, &object))
! 902: {
! 903: switch (objectID)
! 904: {
! 905: case CRL_DIST_POINTS:
! 906: add_cdps(list, uris, issuers);
! 907: break;
! 908: case CRL_DIST_POINTS_FULLNAME:
! 909: if (!x509_parse_generalNames(object,
! 910: parser->get_level(parser) + 1, TRUE, uris))
! 911: {
! 912: goto end;
! 913: }
! 914: break;
! 915: case CRL_DIST_POINTS_ISSUER:
! 916: if (!x509_parse_generalNames(object,
! 917: parser->get_level(parser) + 1, TRUE, issuers))
! 918: {
! 919: goto end;
! 920: }
! 921: break;
! 922: default:
! 923: break;
! 924: }
! 925: }
! 926: success = parser->success(parser);
! 927: add_cdps(list, uris, issuers);
! 928:
! 929: end:
! 930: parser->destroy(parser);
! 931: uris->destroy_offset(uris, offsetof(identification_t, destroy));
! 932: issuers->destroy_offset(issuers, offsetof(identification_t, destroy));
! 933:
! 934: return success;
! 935: }
! 936:
! 937: /**
! 938: * ASN.1 definition of nameConstraints
! 939: */
! 940: static const asn1Object_t nameConstraintsObjects[] = {
! 941: { 0, "nameConstraints", ASN1_SEQUENCE, ASN1_NONE }, /* 0 */
! 942: { 1, "permittedSubtrees", ASN1_CONTEXT_C_0, ASN1_OPT|ASN1_LOOP }, /* 1 */
! 943: { 2, "generalSubtree", ASN1_SEQUENCE, ASN1_BODY }, /* 2 */
! 944: { 1, "end loop", ASN1_EOC, ASN1_END }, /* 3 */
! 945: { 1, "excludedSubtrees", ASN1_CONTEXT_C_1, ASN1_OPT|ASN1_LOOP }, /* 4 */
! 946: { 2, "generalSubtree", ASN1_SEQUENCE, ASN1_BODY }, /* 5 */
! 947: { 1, "end loop", ASN1_EOC, ASN1_END }, /* 6 */
! 948: { 0, "exit", ASN1_EOC, ASN1_EXIT }
! 949: };
! 950: #define NAME_CONSTRAINT_PERMITTED 2
! 951: #define NAME_CONSTRAINT_EXCLUDED 5
! 952:
! 953: /**
! 954: * Parse permitted/excluded nameConstraints
! 955: */
! 956: static bool parse_nameConstraints(chunk_t blob, int level0,
! 957: private_x509_cert_t *this)
! 958: {
! 959: asn1_parser_t *parser;
! 960: identification_t *id;
! 961: chunk_t object;
! 962: int objectID;
! 963: bool success = FALSE;
! 964:
! 965: parser = asn1_parser_create(nameConstraintsObjects, blob);
! 966: parser->set_top_level(parser, level0);
! 967:
! 968: while (parser->iterate(parser, &objectID, &object))
! 969: {
! 970: switch (objectID)
! 971: {
! 972: case NAME_CONSTRAINT_PERMITTED:
! 973: id = parse_generalName(object, parser->get_level(parser) + 1);
! 974: if (!id)
! 975: {
! 976: goto end;
! 977: }
! 978: this->permitted_names->insert_last(this->permitted_names, id);
! 979: break;
! 980: case NAME_CONSTRAINT_EXCLUDED:
! 981: id = parse_generalName(object, parser->get_level(parser) + 1);
! 982: if (!id)
! 983: {
! 984: goto end;
! 985: }
! 986: this->excluded_names->insert_last(this->excluded_names, id);
! 987: break;
! 988: default:
! 989: break;
! 990: }
! 991: }
! 992: success = parser->success(parser);
! 993:
! 994: end:
! 995: parser->destroy(parser);
! 996:
! 997: return success;
! 998: }
! 999:
! 1000: /**
! 1001: * ASN.1 definition of a certificatePolicies extension
! 1002: */
! 1003: static const asn1Object_t certificatePoliciesObject[] = {
! 1004: { 0, "certificatePolicies", ASN1_SEQUENCE, ASN1_LOOP }, /* 0 */
! 1005: { 1, "policyInformation", ASN1_SEQUENCE, ASN1_NONE }, /* 1 */
! 1006: { 2, "policyId", ASN1_OID, ASN1_BODY }, /* 2 */
! 1007: { 2, "qualifiers", ASN1_SEQUENCE, ASN1_OPT|ASN1_LOOP }, /* 3 */
! 1008: { 3, "qualifierInfo", ASN1_SEQUENCE, ASN1_NONE }, /* 4 */
! 1009: { 4, "qualifierId", ASN1_OID, ASN1_BODY }, /* 5 */
! 1010: { 4, "qualifier", ASN1_EOC, ASN1_CHOICE }, /* 6 */
! 1011: { 5, "cPSuri", ASN1_IA5STRING, ASN1_OPT|ASN1_BODY }, /* 7 */
! 1012: { 5, "end choice", ASN1_EOC, ASN1_END|ASN1_CH }, /* 8 */
! 1013: { 5, "userNotice", ASN1_SEQUENCE, ASN1_OPT|ASN1_BODY }, /* 9 */
! 1014: { 6, "explicitText", ASN1_EOC, ASN1_RAW }, /* 10 */
! 1015: { 5, "end choice", ASN1_EOC, ASN1_END|ASN1_CH }, /* 11 */
! 1016: { 4, "end choices", ASN1_EOC, ASN1_END|ASN1_CHOICE }, /* 12 */
! 1017: { 2, "end opt/loop", ASN1_EOC, ASN1_END }, /* 13 */
! 1018: { 0, "end loop", ASN1_EOC, ASN1_END }, /* 14 */
! 1019: { 0, "exit", ASN1_EOC, ASN1_EXIT }
! 1020: };
! 1021: #define CERT_POLICY_ID 2
! 1022: #define CERT_POLICY_QUALIFIER_ID 5
! 1023: #define CERT_POLICY_CPS_URI 7
! 1024: #define CERT_POLICY_EXPLICIT_TEXT 10
! 1025:
! 1026: /**
! 1027: * Parse certificatePolicies
! 1028: */
! 1029: static bool parse_certificatePolicies(chunk_t blob, int level0,
! 1030: private_x509_cert_t *this)
! 1031: {
! 1032: x509_cert_policy_t *policy = NULL;
! 1033: asn1_parser_t *parser;
! 1034: chunk_t object;
! 1035: int objectID, qualifier = OID_UNKNOWN;
! 1036: bool success;
! 1037:
! 1038: parser = asn1_parser_create(certificatePoliciesObject, blob);
! 1039: parser->set_top_level(parser, level0);
! 1040:
! 1041: while (parser->iterate(parser, &objectID, &object))
! 1042: {
! 1043: switch (objectID)
! 1044: {
! 1045: case CERT_POLICY_ID:
! 1046: INIT(policy,
! 1047: .oid = chunk_clone(object),
! 1048: );
! 1049: this->cert_policies->insert_last(this->cert_policies, policy);
! 1050: break;
! 1051: case CERT_POLICY_QUALIFIER_ID:
! 1052: qualifier = asn1_known_oid(object);
! 1053: break;
! 1054: case CERT_POLICY_CPS_URI:
! 1055: if (policy && !policy->cps_uri && object.len &&
! 1056: qualifier == OID_POLICY_QUALIFIER_CPS &&
! 1057: chunk_printable(object, NULL, 0))
! 1058: {
! 1059: policy->cps_uri = strndup(object.ptr, object.len);
! 1060: }
! 1061: break;
! 1062: case CERT_POLICY_EXPLICIT_TEXT:
! 1063: /* TODO */
! 1064: break;
! 1065: default:
! 1066: break;
! 1067: }
! 1068: }
! 1069: success = parser->success(parser);
! 1070: parser->destroy(parser);
! 1071:
! 1072: return success;
! 1073: }
! 1074:
! 1075: /**
! 1076: * ASN.1 definition of a policyMappings extension
! 1077: */
! 1078: static const asn1Object_t policyMappingsObjects[] = {
! 1079: { 0, "policyMappings", ASN1_SEQUENCE, ASN1_LOOP }, /* 0 */
! 1080: { 1, "policyMapping", ASN1_SEQUENCE, ASN1_NONE }, /* 1 */
! 1081: { 2, "issuerPolicy", ASN1_OID, ASN1_BODY }, /* 2 */
! 1082: { 2, "subjectPolicy", ASN1_OID, ASN1_BODY }, /* 3 */
! 1083: { 0, "end loop", ASN1_EOC, ASN1_END }, /* 4 */
! 1084: { 0, "exit", ASN1_EOC, ASN1_EXIT }
! 1085: };
! 1086: #define POLICY_MAPPING 1
! 1087: #define POLICY_MAPPING_ISSUER 2
! 1088: #define POLICY_MAPPING_SUBJECT 3
! 1089:
! 1090: /**
! 1091: * Parse policyMappings
! 1092: */
! 1093: static bool parse_policyMappings(chunk_t blob, int level0,
! 1094: private_x509_cert_t *this)
! 1095: {
! 1096: x509_policy_mapping_t *map = NULL;
! 1097: asn1_parser_t *parser;
! 1098: chunk_t object;
! 1099: int objectID;
! 1100: bool success;
! 1101:
! 1102: parser = asn1_parser_create(policyMappingsObjects, blob);
! 1103: parser->set_top_level(parser, level0);
! 1104:
! 1105: while (parser->iterate(parser, &objectID, &object))
! 1106: {
! 1107: switch (objectID)
! 1108: {
! 1109: case POLICY_MAPPING:
! 1110: INIT(map);
! 1111: this->policy_mappings->insert_last(this->policy_mappings, map);
! 1112: break;
! 1113: case POLICY_MAPPING_ISSUER:
! 1114: if (map && !map->issuer.len)
! 1115: {
! 1116: map->issuer = chunk_clone(object);
! 1117: }
! 1118: break;
! 1119: case POLICY_MAPPING_SUBJECT:
! 1120: if (map && !map->subject.len)
! 1121: {
! 1122: map->subject = chunk_clone(object);
! 1123: }
! 1124: break;
! 1125: default:
! 1126: break;
! 1127: }
! 1128: }
! 1129: success = parser->success(parser);
! 1130: parser->destroy(parser);
! 1131:
! 1132: return success;
! 1133: }
! 1134:
! 1135: /**
! 1136: * ASN.1 definition of a policyConstraints extension
! 1137: */
! 1138: static const asn1Object_t policyConstraintsObjects[] = {
! 1139: { 0, "policyConstraints", ASN1_SEQUENCE, ASN1_NONE }, /* 0 */
! 1140: { 1, "requireExplicitPolicy", ASN1_CONTEXT_C_0, ASN1_OPT|ASN1_NONE }, /* 1 */
! 1141: { 2, "SkipCerts", ASN1_INTEGER, ASN1_BODY }, /* 2 */
! 1142: { 1, "end opt", ASN1_EOC, ASN1_END }, /* 3 */
! 1143: { 1, "inhibitPolicyMapping", ASN1_CONTEXT_C_1, ASN1_OPT|ASN1_NONE }, /* 4 */
! 1144: { 2, "SkipCerts", ASN1_INTEGER, ASN1_BODY }, /* 5 */
! 1145: { 1, "end opt", ASN1_EOC, ASN1_END }, /* 6 */
! 1146: { 0, "exit", ASN1_EOC, ASN1_EXIT }
! 1147: };
! 1148: #define POLICY_CONSTRAINT_EXPLICIT 2
! 1149: #define POLICY_CONSTRAINT_INHIBIT 5
! 1150:
! 1151: /**
! 1152: * Parse policyConstraints
! 1153: */
! 1154: static bool parse_policyConstraints(chunk_t blob, int level0,
! 1155: private_x509_cert_t *this)
! 1156: {
! 1157: asn1_parser_t *parser;
! 1158: chunk_t object;
! 1159: int objectID;
! 1160: bool success;
! 1161:
! 1162: parser = asn1_parser_create(policyConstraintsObjects, blob);
! 1163: parser->set_top_level(parser, level0);
! 1164:
! 1165: while (parser->iterate(parser, &objectID, &object))
! 1166: {
! 1167: switch (objectID)
! 1168: {
! 1169: case POLICY_CONSTRAINT_EXPLICIT:
! 1170: this->require_explicit = parse_constraint(object);
! 1171: break;
! 1172: case POLICY_CONSTRAINT_INHIBIT:
! 1173: this->inhibit_mapping = parse_constraint(object);
! 1174: break;
! 1175: default:
! 1176: break;
! 1177: }
! 1178: }
! 1179: success = parser->success(parser);
! 1180: parser->destroy(parser);
! 1181:
! 1182: return success;
! 1183: }
! 1184:
! 1185: /**
! 1186: * ASN.1 definition of ipAddrBlocks according to RFC 3779
! 1187: */
! 1188: static const asn1Object_t ipAddrBlocksObjects[] = {
! 1189: { 0, "ipAddrBlocks", ASN1_SEQUENCE, ASN1_LOOP }, /* 0 */
! 1190: { 1, "ipAddressFamily", ASN1_SEQUENCE, ASN1_NONE }, /* 1 */
! 1191: { 2, "addressFamily", ASN1_OCTET_STRING, ASN1_BODY }, /* 2 */
! 1192: { 2, "ipAddressChoice", ASN1_EOC, ASN1_CHOICE }, /* 3 */
! 1193: { 3, "inherit", ASN1_NULL, ASN1_OPT }, /* 4 */
! 1194: { 3, "end choice", ASN1_EOC, ASN1_END|ASN1_CH }, /* 5 */
! 1195: { 3, "addressesOrRanges", ASN1_SEQUENCE, ASN1_OPT|ASN1_LOOP }, /* 6 */
! 1196: { 4, "addressOrRange", ASN1_EOC, ASN1_CHOICE }, /* 7 */
! 1197: { 5, "addressPrefix", ASN1_BIT_STRING, ASN1_OPT|ASN1_BODY }, /* 8 */
! 1198: { 5, "end choice", ASN1_EOC, ASN1_END|ASN1_CH }, /* 9 */
! 1199: { 5, "addressRange", ASN1_SEQUENCE, ASN1_OPT }, /* 10 */
! 1200: { 6, "min", ASN1_BIT_STRING, ASN1_BODY }, /* 11 */
! 1201: { 6, "max", ASN1_BIT_STRING, ASN1_BODY }, /* 12 */
! 1202: { 5, "end choice", ASN1_EOC, ASN1_END|ASN1_CH }, /* 13 */
! 1203: { 4, "end choices", ASN1_EOC, ASN1_END|ASN1_CHOICE }, /* 14 */
! 1204: { 3, "end loop/choice", ASN1_EOC, ASN1_END|ASN1_CH }, /* 15 */
! 1205: { 2, "end choices", ASN1_EOC, ASN1_END|ASN1_CHOICE }, /* 16 */
! 1206: { 0, "end loop", ASN1_EOC, ASN1_END }, /* 17 */
! 1207: { 0, "exit", ASN1_EOC, ASN1_EXIT }
! 1208: };
! 1209: #define IP_ADDR_BLOCKS_FAMILY 2
! 1210: #define IP_ADDR_BLOCKS_INHERIT 4
! 1211: #define IP_ADDR_BLOCKS_PREFIX 8
! 1212: #define IP_ADDR_BLOCKS_MIN 11
! 1213: #define IP_ADDR_BLOCKS_MAX 12
! 1214:
! 1215: static bool check_address_object(ts_type_t ts_type, chunk_t object)
! 1216: {
! 1217: switch (ts_type)
! 1218: {
! 1219: case TS_IPV4_ADDR_RANGE:
! 1220: if (object.len > 5)
! 1221: {
! 1222: DBG1(DBG_ASN, "IPv4 address object is larger than 5 octets");
! 1223: return FALSE;
! 1224: }
! 1225: break;
! 1226: case TS_IPV6_ADDR_RANGE:
! 1227: if (object.len > 17)
! 1228: {
! 1229: DBG1(DBG_ASN, "IPv6 address object is larger than 17 octets");
! 1230: return FALSE;
! 1231: }
! 1232: break;
! 1233: default:
! 1234: DBG1(DBG_ASN, "unknown address family");
! 1235: return FALSE;
! 1236: }
! 1237: if (object.len == 0)
! 1238: {
! 1239: DBG1(DBG_ASN, "An ASN.1 bit string must contain at least the "
! 1240: "initial octet");
! 1241: return FALSE;
! 1242: }
! 1243: if (object.len == 1 && object.ptr[0] != 0)
! 1244: {
! 1245: DBG1(DBG_ASN, "An empty ASN.1 bit string must contain a zero "
! 1246: "initial octet");
! 1247: return FALSE;
! 1248: }
! 1249: if (object.ptr[0] > 7)
! 1250: {
! 1251: DBG1(DBG_ASN, "number of unused bits is too large");
! 1252: return FALSE;
! 1253: }
! 1254: return TRUE;
! 1255: }
! 1256:
! 1257: static bool parse_ipAddrBlocks(chunk_t blob, int level0,
! 1258: private_x509_cert_t *this)
! 1259: {
! 1260: asn1_parser_t *parser;
! 1261: chunk_t object, min_object;
! 1262: ts_type_t ts_type = 0;
! 1263: traffic_selector_t *ts;
! 1264: int objectID;
! 1265: bool success = FALSE;
! 1266:
! 1267: parser = asn1_parser_create(ipAddrBlocksObjects, blob);
! 1268: parser->set_top_level(parser, level0);
! 1269:
! 1270: while (parser->iterate(parser, &objectID, &object))
! 1271: {
! 1272: switch (objectID)
! 1273: {
! 1274: case IP_ADDR_BLOCKS_FAMILY:
! 1275: ts_type = 0;
! 1276: if (object.len == 2 && object.ptr[0] == 0)
! 1277: {
! 1278: if (object.ptr[1] == 1)
! 1279: {
! 1280: ts_type = TS_IPV4_ADDR_RANGE;
! 1281: }
! 1282: else if (object.ptr[1] == 2)
! 1283: {
! 1284: ts_type = TS_IPV6_ADDR_RANGE;
! 1285: }
! 1286: else
! 1287: {
! 1288: break;
! 1289: }
! 1290: DBG2(DBG_ASN, " %N", ts_type_name, ts_type);
! 1291: }
! 1292: break;
! 1293: case IP_ADDR_BLOCKS_INHERIT:
! 1294: DBG1(DBG_ASN, "inherit choice is not supported");
! 1295: break;
! 1296: case IP_ADDR_BLOCKS_PREFIX:
! 1297: if (!check_address_object(ts_type, object))
! 1298: {
! 1299: goto end;
! 1300: }
! 1301: ts = traffic_selector_create_from_rfc3779_format(ts_type,
! 1302: object, object);
! 1303: DBG2(DBG_ASN, " %R", ts);
! 1304: this->ipAddrBlocks->insert_last(this->ipAddrBlocks, ts);
! 1305: break;
! 1306: case IP_ADDR_BLOCKS_MIN:
! 1307: if (!check_address_object(ts_type, object))
! 1308: {
! 1309: goto end;
! 1310: }
! 1311: min_object = object;
! 1312: break;
! 1313: case IP_ADDR_BLOCKS_MAX:
! 1314: if (!check_address_object(ts_type, object))
! 1315: {
! 1316: goto end;
! 1317: }
! 1318: ts = traffic_selector_create_from_rfc3779_format(ts_type,
! 1319: min_object, object);
! 1320: DBG2(DBG_ASN, " %R", ts);
! 1321: this->ipAddrBlocks->insert_last(this->ipAddrBlocks, ts);
! 1322: break;
! 1323: default:
! 1324: break;
! 1325: }
! 1326: }
! 1327: success = parser->success(parser);
! 1328: this->flags |= X509_IP_ADDR_BLOCKS;
! 1329:
! 1330: end:
! 1331: parser->destroy(parser);
! 1332:
! 1333: return success;
! 1334: }
! 1335:
! 1336: /**
! 1337: * ASN.1 definition of an X.509v3 x509_cert
! 1338: */
! 1339: static const asn1Object_t certObjects[] = {
! 1340: { 0, "x509", ASN1_SEQUENCE, ASN1_OBJ }, /* 0 */
! 1341: { 1, "tbsCertificate", ASN1_SEQUENCE, ASN1_OBJ }, /* 1 */
! 1342: { 2, "DEFAULT v1", ASN1_CONTEXT_C_0, ASN1_DEF }, /* 2 */
! 1343: { 3, "version", ASN1_INTEGER, ASN1_BODY }, /* 3 */
! 1344: { 2, "serialNumber", ASN1_INTEGER, ASN1_BODY }, /* 4 */
! 1345: { 2, "signature", ASN1_EOC, ASN1_RAW }, /* 5 */
! 1346: { 2, "issuer", ASN1_SEQUENCE, ASN1_OBJ }, /* 6 */
! 1347: { 2, "validity", ASN1_SEQUENCE, ASN1_NONE }, /* 7 */
! 1348: { 3, "notBefore", ASN1_EOC, ASN1_RAW }, /* 8 */
! 1349: { 3, "notAfter", ASN1_EOC, ASN1_RAW }, /* 9 */
! 1350: { 2, "subject", ASN1_SEQUENCE, ASN1_OBJ }, /* 10 */
! 1351: { 2, "subjectPublicKeyInfo",ASN1_SEQUENCE, ASN1_RAW }, /* 11 */
! 1352: { 2, "issuerUniqueID", ASN1_CONTEXT_C_1, ASN1_OPT }, /* 12 */
! 1353: { 2, "end opt", ASN1_EOC, ASN1_END }, /* 13 */
! 1354: { 2, "subjectUniqueID", ASN1_CONTEXT_C_2, ASN1_OPT }, /* 14 */
! 1355: { 2, "end opt", ASN1_EOC, ASN1_END }, /* 15 */
! 1356: { 2, "optional extensions", ASN1_CONTEXT_C_3, ASN1_OPT }, /* 16 */
! 1357: { 3, "extensions", ASN1_SEQUENCE, ASN1_LOOP }, /* 17 */
! 1358: { 4, "extension", ASN1_SEQUENCE, ASN1_NONE }, /* 18 */
! 1359: { 5, "extnID", ASN1_OID, ASN1_BODY }, /* 19 */
! 1360: { 5, "critical", ASN1_BOOLEAN, ASN1_DEF|ASN1_BODY }, /* 20 */
! 1361: { 5, "extnValue", ASN1_OCTET_STRING, ASN1_BODY }, /* 21 */
! 1362: { 3, "end loop", ASN1_EOC, ASN1_END }, /* 22 */
! 1363: { 2, "end opt", ASN1_EOC, ASN1_END }, /* 23 */
! 1364: { 1, "signatureAlgorithm", ASN1_EOC, ASN1_RAW }, /* 24 */
! 1365: { 1, "signatureValue", ASN1_BIT_STRING, ASN1_BODY }, /* 25 */
! 1366: { 0, "exit", ASN1_EOC, ASN1_EXIT }
! 1367: };
! 1368: #define X509_OBJ_TBS_CERTIFICATE 1
! 1369: #define X509_OBJ_VERSION 3
! 1370: #define X509_OBJ_SERIAL_NUMBER 4
! 1371: #define X509_OBJ_SIG_ALG 5
! 1372: #define X509_OBJ_ISSUER 6
! 1373: #define X509_OBJ_NOT_BEFORE 8
! 1374: #define X509_OBJ_NOT_AFTER 9
! 1375: #define X509_OBJ_SUBJECT 10
! 1376: #define X509_OBJ_SUBJECT_PUBLIC_KEY_INFO 11
! 1377: #define X509_OBJ_OPTIONAL_EXTENSIONS 16
! 1378: #define X509_OBJ_EXTN_ID 19
! 1379: #define X509_OBJ_CRITICAL 20
! 1380: #define X509_OBJ_EXTN_VALUE 21
! 1381: #define X509_OBJ_ALGORITHM 24
! 1382: #define X509_OBJ_SIGNATURE 25
! 1383:
! 1384: /**
! 1385: * Parses an X.509v3 certificate
! 1386: */
! 1387: static bool parse_certificate(private_x509_cert_t *this)
! 1388: {
! 1389: asn1_parser_t *parser;
! 1390: chunk_t object;
! 1391: int objectID;
! 1392: int extn_oid = OID_UNKNOWN;
! 1393: signature_params_t sig_alg = {};
! 1394: bool success = FALSE;
! 1395: bool critical = FALSE;
! 1396:
! 1397: parser = asn1_parser_create(certObjects, this->encoding);
! 1398:
! 1399: /* unless we see a keyUsage extension we are compliant with RFC 4945 */
! 1400: this->flags |= X509_IKE_COMPLIANT;
! 1401:
! 1402: while (parser->iterate(parser, &objectID, &object))
! 1403: {
! 1404: u_int level = parser->get_level(parser)+1;
! 1405:
! 1406: switch (objectID)
! 1407: {
! 1408: case X509_OBJ_TBS_CERTIFICATE:
! 1409: this->tbsCertificate = object;
! 1410: break;
! 1411: case X509_OBJ_VERSION:
! 1412: this->version = (object.len) ? (1+(u_int)*object.ptr) : 1;
! 1413: if (this->version < 1 || this->version > 3)
! 1414: {
! 1415: DBG1(DBG_ASN, "X.509v%d not supported", this->version);
! 1416: goto end;
! 1417: }
! 1418: else
! 1419: {
! 1420: DBG2(DBG_ASN, " X.509v%d", this->version);
! 1421: }
! 1422: break;
! 1423: case X509_OBJ_SERIAL_NUMBER:
! 1424: this->serialNumber = object;
! 1425: break;
! 1426: case X509_OBJ_SIG_ALG:
! 1427: if (!signature_params_parse(object, level, &sig_alg))
! 1428: {
! 1429: DBG1(DBG_ASN, " unable to parse signature algorithm");
! 1430: goto end;
! 1431: }
! 1432: break;
! 1433: case X509_OBJ_ISSUER:
! 1434: this->issuer = identification_create_from_encoding(ID_DER_ASN1_DN, object);
! 1435: DBG2(DBG_ASN, " '%Y'", this->issuer);
! 1436: break;
! 1437: case X509_OBJ_NOT_BEFORE:
! 1438: this->notBefore = asn1_parse_time(object, level);
! 1439: break;
! 1440: case X509_OBJ_NOT_AFTER:
! 1441: this->notAfter = asn1_parse_time(object, level);
! 1442: break;
! 1443: case X509_OBJ_SUBJECT:
! 1444: this->subject = identification_create_from_encoding(ID_DER_ASN1_DN, object);
! 1445: DBG2(DBG_ASN, " '%Y'", this->subject);
! 1446: break;
! 1447: case X509_OBJ_SUBJECT_PUBLIC_KEY_INFO:
! 1448: DBG2(DBG_ASN, "-- > --");
! 1449: this->public_key = lib->creds->create(lib->creds, CRED_PUBLIC_KEY,
! 1450: KEY_ANY, BUILD_BLOB_ASN1_DER, object, BUILD_END);
! 1451: DBG2(DBG_ASN, "-- < --");
! 1452: if (this->public_key == NULL)
! 1453: {
! 1454: goto end;
! 1455: }
! 1456: break;
! 1457: case X509_OBJ_OPTIONAL_EXTENSIONS:
! 1458: if (this->version != 3)
! 1459: {
! 1460: DBG1(DBG_ASN, "Only X.509v3 certificates have extensions");
! 1461: goto end;
! 1462: }
! 1463: break;
! 1464: case X509_OBJ_EXTN_ID:
! 1465: extn_oid = asn1_known_oid(object);
! 1466: break;
! 1467: case X509_OBJ_CRITICAL:
! 1468: critical = object.len && *object.ptr;
! 1469: DBG2(DBG_ASN, " %s", critical ? "TRUE" : "FALSE");
! 1470: break;
! 1471: case X509_OBJ_EXTN_VALUE:
! 1472: {
! 1473: switch (extn_oid)
! 1474: {
! 1475: case OID_SUBJECT_KEY_ID:
! 1476: if (!asn1_parse_simple_object(&object, ASN1_OCTET_STRING,
! 1477: level, "keyIdentifier"))
! 1478: {
! 1479: goto end;
! 1480: }
! 1481: this->subjectKeyIdentifier = object;
! 1482: break;
! 1483: case OID_SUBJECT_ALT_NAME:
! 1484: if (!x509_parse_generalNames(object, level, FALSE,
! 1485: this->subjectAltNames))
! 1486: {
! 1487: goto end;
! 1488: }
! 1489: break;
! 1490: case OID_BASIC_CONSTRAINTS:
! 1491: if (!parse_basicConstraints(object, level, this))
! 1492: {
! 1493: goto end;
! 1494: }
! 1495: break;
! 1496: case OID_CRL_DISTRIBUTION_POINTS:
! 1497: if (!x509_parse_crlDistributionPoints(object, level,
! 1498: this->crl_uris))
! 1499: {
! 1500: goto end;
! 1501: }
! 1502: break;
! 1503: case OID_AUTHORITY_KEY_ID:
! 1504: chunk_free(&this->authKeyIdentifier);
! 1505: this->authKeyIdentifier = x509_parse_authorityKeyIdentifier(
! 1506: object, level, &this->authKeySerialNumber);
! 1507: break;
! 1508: case OID_AUTHORITY_INFO_ACCESS:
! 1509: if (!parse_authorityInfoAccess(object, level, this))
! 1510: {
! 1511: goto end;
! 1512: }
! 1513: break;
! 1514: case OID_KEY_USAGE:
! 1515: parse_keyUsage(object, this);
! 1516: break;
! 1517: case OID_EXTENDED_KEY_USAGE:
! 1518: if (!parse_extendedKeyUsage(object, level, this))
! 1519: {
! 1520: goto end;
! 1521: }
! 1522: break;
! 1523: case OID_IP_ADDR_BLOCKS:
! 1524: if (!parse_ipAddrBlocks(object, level, this))
! 1525: {
! 1526: goto end;
! 1527: }
! 1528: break;
! 1529: case OID_NAME_CONSTRAINTS:
! 1530: if (!parse_nameConstraints(object, level, this))
! 1531: {
! 1532: goto end;
! 1533: }
! 1534: break;
! 1535: case OID_CERTIFICATE_POLICIES:
! 1536: if (!parse_certificatePolicies(object, level, this))
! 1537: {
! 1538: goto end;
! 1539: }
! 1540: break;
! 1541: case OID_POLICY_MAPPINGS:
! 1542: if (!parse_policyMappings(object, level, this))
! 1543: {
! 1544: goto end;
! 1545: }
! 1546: break;
! 1547: case OID_POLICY_CONSTRAINTS:
! 1548: if (!parse_policyConstraints(object, level, this))
! 1549: {
! 1550: goto end;
! 1551: }
! 1552: break;
! 1553: case OID_INHIBIT_ANY_POLICY:
! 1554: if (!asn1_parse_simple_object(&object, ASN1_INTEGER,
! 1555: level, "inhibitAnyPolicy"))
! 1556: {
! 1557: goto end;
! 1558: }
! 1559: this->inhibit_any = parse_constraint(object);
! 1560: break;
! 1561: case OID_NS_REVOCATION_URL:
! 1562: case OID_NS_CA_REVOCATION_URL:
! 1563: case OID_NS_CA_POLICY_URL:
! 1564: case OID_NS_COMMENT:
! 1565: if (!asn1_parse_simple_object(&object, ASN1_IA5STRING,
! 1566: level, oid_names[extn_oid].name))
! 1567: {
! 1568: goto end;
! 1569: }
! 1570: break;
! 1571: default:
! 1572: if (critical && lib->settings->get_bool(lib->settings,
! 1573: "%s.x509.enforce_critical", TRUE, lib->ns))
! 1574: {
! 1575: DBG1(DBG_ASN, "critical '%s' extension not supported",
! 1576: (extn_oid == OID_UNKNOWN) ? "unknown" :
! 1577: (char*)oid_names[extn_oid].name);
! 1578: goto end;
! 1579: }
! 1580: break;
! 1581: }
! 1582: break;
! 1583: }
! 1584: case X509_OBJ_ALGORITHM:
! 1585: INIT(this->scheme);
! 1586: if (!signature_params_parse(object, level, this->scheme))
! 1587: {
! 1588: DBG1(DBG_ASN, " unable to parse signature algorithm");
! 1589: goto end;
! 1590: }
! 1591: if (!signature_params_equal(this->scheme, &sig_alg))
! 1592: {
! 1593: DBG1(DBG_ASN, " signature algorithms do not agree");
! 1594: goto end;
! 1595: }
! 1596: break;
! 1597: case X509_OBJ_SIGNATURE:
! 1598: this->signature = chunk_skip(object, 1);
! 1599: break;
! 1600: default:
! 1601: break;
! 1602: }
! 1603: }
! 1604: success = parser->success(parser);
! 1605:
! 1606: end:
! 1607: parser->destroy(parser);
! 1608: signature_params_clear(&sig_alg);
! 1609: if (success)
! 1610: {
! 1611: hasher_t *hasher;
! 1612:
! 1613: /* check if the certificate is self-signed */
! 1614: if (this->public.interface.interface.issued_by(
! 1615: &this->public.interface.interface,
! 1616: &this->public.interface.interface,
! 1617: NULL))
! 1618: {
! 1619: this->flags |= X509_SELF_SIGNED;
! 1620: }
! 1621: /* create certificate hash */
! 1622: hasher = lib->crypto->create_hasher(lib->crypto, HASH_SHA1);
! 1623: if (!hasher ||
! 1624: !hasher->allocate_hash(hasher, this->encoding, &this->encoding_hash))
! 1625: {
! 1626: DESTROY_IF(hasher);
! 1627: DBG1(DBG_ASN, " unable to create hash of certificate, SHA1 not supported");
! 1628: return FALSE;
! 1629: }
! 1630: hasher->destroy(hasher);
! 1631: }
! 1632: return success;
! 1633: }
! 1634:
! 1635: METHOD(certificate_t, get_type, certificate_type_t,
! 1636: private_x509_cert_t *this)
! 1637: {
! 1638: return CERT_X509;
! 1639: }
! 1640:
! 1641: METHOD(certificate_t, get_subject, identification_t*,
! 1642: private_x509_cert_t *this)
! 1643: {
! 1644: return this->subject;
! 1645: }
! 1646:
! 1647: METHOD(certificate_t, get_issuer, identification_t*,
! 1648: private_x509_cert_t *this)
! 1649: {
! 1650: return this->issuer;
! 1651: }
! 1652:
! 1653: METHOD(certificate_t, has_subject, id_match_t,
! 1654: private_x509_cert_t *this, identification_t *subject)
! 1655: {
! 1656: identification_t *current;
! 1657: enumerator_t *enumerator;
! 1658: id_match_t match, best;
! 1659: chunk_t encoding;
! 1660:
! 1661: if (subject->get_type(subject) == ID_KEY_ID)
! 1662: {
! 1663: encoding = subject->get_encoding(subject);
! 1664:
! 1665: if (this->encoding_hash.len &&
! 1666: chunk_equals(this->encoding_hash, encoding))
! 1667: {
! 1668: return ID_MATCH_PERFECT;
! 1669: }
! 1670: if (this->subjectKeyIdentifier.len &&
! 1671: chunk_equals(this->subjectKeyIdentifier, encoding))
! 1672: {
! 1673: return ID_MATCH_PERFECT;
! 1674: }
! 1675: if (this->public_key &&
! 1676: this->public_key->has_fingerprint(this->public_key, encoding))
! 1677: {
! 1678: return ID_MATCH_PERFECT;
! 1679: }
! 1680: if (chunk_equals(this->serialNumber, encoding))
! 1681: {
! 1682: return ID_MATCH_PERFECT;
! 1683: }
! 1684: }
! 1685: best = this->subject->matches(this->subject, subject);
! 1686: enumerator = this->subjectAltNames->create_enumerator(this->subjectAltNames);
! 1687: while (enumerator->enumerate(enumerator, ¤t))
! 1688: {
! 1689: match = current->matches(current, subject);
! 1690: if (match > best)
! 1691: {
! 1692: best = match;
! 1693: }
! 1694: }
! 1695: enumerator->destroy(enumerator);
! 1696: return best;
! 1697: }
! 1698:
! 1699: METHOD(certificate_t, has_issuer, id_match_t,
! 1700: private_x509_cert_t *this, identification_t *issuer)
! 1701: {
! 1702: /* issuerAltNames currently not supported */
! 1703: return this->issuer->matches(this->issuer, issuer);
! 1704: }
! 1705:
! 1706: METHOD(certificate_t, issued_by, bool,
! 1707: private_x509_cert_t *this, certificate_t *issuer,
! 1708: signature_params_t **scheme)
! 1709: {
! 1710: public_key_t *key;
! 1711: bool valid;
! 1712: x509_t *x509 = (x509_t*)issuer;
! 1713:
! 1714: if (&this->public.interface.interface == issuer)
! 1715: {
! 1716: if (this->flags & X509_SELF_SIGNED)
! 1717: {
! 1718: if (scheme)
! 1719: {
! 1720: *scheme = signature_params_clone(this->scheme);
! 1721: }
! 1722: return TRUE;
! 1723: }
! 1724: }
! 1725: else
! 1726: {
! 1727: if (issuer->get_type(issuer) != CERT_X509)
! 1728: {
! 1729: return FALSE;
! 1730: }
! 1731: if (!(x509->get_flags(x509) & X509_CA))
! 1732: {
! 1733: return FALSE;
! 1734: }
! 1735: }
! 1736: if (!this->issuer->equals(this->issuer, issuer->get_subject(issuer)))
! 1737: {
! 1738: return FALSE;
! 1739: }
! 1740:
! 1741: /* get the public key of the issuer */
! 1742: key = issuer->get_public_key(issuer);
! 1743: if (!key)
! 1744: {
! 1745: return FALSE;
! 1746: }
! 1747: valid = key->verify(key, this->scheme->scheme, this->scheme->params,
! 1748: this->tbsCertificate, this->signature);
! 1749: key->destroy(key);
! 1750: if (valid && scheme)
! 1751: {
! 1752: *scheme = signature_params_clone(this->scheme);
! 1753: }
! 1754: return valid;
! 1755: }
! 1756:
! 1757: METHOD(certificate_t, get_public_key, public_key_t*,
! 1758: private_x509_cert_t *this)
! 1759: {
! 1760: this->public_key->get_ref(this->public_key);
! 1761: return this->public_key;
! 1762: }
! 1763:
! 1764: METHOD(certificate_t, get_ref, certificate_t*,
! 1765: private_x509_cert_t *this)
! 1766: {
! 1767: ref_get(&this->ref);
! 1768: return &this->public.interface.interface;
! 1769: }
! 1770:
! 1771: METHOD(certificate_t, get_validity, bool,
! 1772: private_x509_cert_t *this, time_t *when, time_t *not_before,
! 1773: time_t *not_after)
! 1774: {
! 1775: time_t t = when ? *when : time(NULL);
! 1776:
! 1777: if (not_before)
! 1778: {
! 1779: *not_before = this->notBefore;
! 1780: }
! 1781: if (not_after)
! 1782: {
! 1783: *not_after = this->notAfter;
! 1784: }
! 1785: return (t >= this->notBefore && t <= this->notAfter);
! 1786: }
! 1787:
! 1788: METHOD(certificate_t, get_encoding, bool,
! 1789: private_x509_cert_t *this, cred_encoding_type_t type, chunk_t *encoding)
! 1790: {
! 1791: if (type == CERT_ASN1_DER)
! 1792: {
! 1793: *encoding = chunk_clone(this->encoding);
! 1794: return TRUE;
! 1795: }
! 1796: return lib->encoding->encode(lib->encoding, type, NULL, encoding,
! 1797: CRED_PART_X509_ASN1_DER, this->encoding, CRED_PART_END);
! 1798: }
! 1799:
! 1800: METHOD(certificate_t, equals, bool,
! 1801: private_x509_cert_t *this, certificate_t *other)
! 1802: {
! 1803: chunk_t encoding;
! 1804: bool equal;
! 1805:
! 1806: if (this == (private_x509_cert_t*)other)
! 1807: {
! 1808: return TRUE;
! 1809: }
! 1810: if (other->get_type(other) != CERT_X509)
! 1811: {
! 1812: return FALSE;
! 1813: }
! 1814: if (other->equals == (void*)equals)
! 1815: { /* skip allocation if we have the same implementation */
! 1816: return chunk_equals(this->encoding, ((private_x509_cert_t*)other)->encoding);
! 1817: }
! 1818: if (!other->get_encoding(other, CERT_ASN1_DER, &encoding))
! 1819: {
! 1820: return FALSE;
! 1821: }
! 1822: equal = chunk_equals(this->encoding, encoding);
! 1823: free(encoding.ptr);
! 1824: return equal;
! 1825: }
! 1826:
! 1827: METHOD(x509_t, get_flags, x509_flag_t,
! 1828: private_x509_cert_t *this)
! 1829: {
! 1830: return this->flags;
! 1831: }
! 1832:
! 1833: METHOD(x509_t, get_serial, chunk_t,
! 1834: private_x509_cert_t *this)
! 1835: {
! 1836: return this->serialNumber;
! 1837: }
! 1838:
! 1839: METHOD(x509_t, get_subjectKeyIdentifier, chunk_t,
! 1840: private_x509_cert_t *this)
! 1841: {
! 1842: if (this->subjectKeyIdentifier.ptr)
! 1843: {
! 1844: return this->subjectKeyIdentifier;
! 1845: }
! 1846: else
! 1847: {
! 1848: chunk_t fingerprint;
! 1849:
! 1850: if (this->public_key->get_fingerprint(this->public_key,
! 1851: KEYID_PUBKEY_SHA1, &fingerprint))
! 1852: {
! 1853: return fingerprint;
! 1854: }
! 1855: else
! 1856: {
! 1857: return chunk_empty;
! 1858: }
! 1859: }
! 1860: }
! 1861:
! 1862: METHOD(x509_t, get_authKeyIdentifier, chunk_t,
! 1863: private_x509_cert_t *this)
! 1864: {
! 1865: return this->authKeyIdentifier;
! 1866: }
! 1867:
! 1868: METHOD(x509_t, get_constraint, u_int,
! 1869: private_x509_cert_t *this, x509_constraint_t type)
! 1870: {
! 1871: switch (type)
! 1872: {
! 1873: case X509_PATH_LEN:
! 1874: return this->pathLenConstraint;
! 1875: case X509_REQUIRE_EXPLICIT_POLICY:
! 1876: return this->require_explicit;
! 1877: case X509_INHIBIT_POLICY_MAPPING:
! 1878: return this->inhibit_mapping;
! 1879: case X509_INHIBIT_ANY_POLICY:
! 1880: return this->inhibit_any;
! 1881: default:
! 1882: return X509_NO_CONSTRAINT;
! 1883: }
! 1884: }
! 1885:
! 1886: METHOD(x509_t, create_subjectAltName_enumerator, enumerator_t*,
! 1887: private_x509_cert_t *this)
! 1888: {
! 1889: return this->subjectAltNames->create_enumerator(this->subjectAltNames);
! 1890: }
! 1891:
! 1892: METHOD(x509_t, create_ocsp_uri_enumerator, enumerator_t*,
! 1893: private_x509_cert_t *this)
! 1894: {
! 1895: return this->ocsp_uris->create_enumerator(this->ocsp_uris);
! 1896: }
! 1897:
! 1898: METHOD(x509_t, create_crl_uri_enumerator, enumerator_t*,
! 1899: private_x509_cert_t *this)
! 1900: {
! 1901: return this->crl_uris->create_enumerator(this->crl_uris);
! 1902: }
! 1903:
! 1904: METHOD(x509_t, create_ipAddrBlock_enumerator, enumerator_t*,
! 1905: private_x509_cert_t *this)
! 1906: {
! 1907: return this->ipAddrBlocks->create_enumerator(this->ipAddrBlocks);
! 1908: }
! 1909:
! 1910: METHOD(x509_t, create_name_constraint_enumerator, enumerator_t*,
! 1911: private_x509_cert_t *this, bool perm)
! 1912: {
! 1913: if (perm)
! 1914: {
! 1915: return this->permitted_names->create_enumerator(this->permitted_names);
! 1916: }
! 1917: return this->excluded_names->create_enumerator(this->excluded_names);
! 1918: }
! 1919:
! 1920: METHOD(x509_t, create_cert_policy_enumerator, enumerator_t*,
! 1921: private_x509_cert_t *this)
! 1922: {
! 1923: return this->cert_policies->create_enumerator(this->cert_policies);
! 1924: }
! 1925:
! 1926: METHOD(x509_t, create_policy_mapping_enumerator, enumerator_t*,
! 1927: private_x509_cert_t *this)
! 1928: {
! 1929: return this->policy_mappings->create_enumerator(this->policy_mappings);
! 1930: }
! 1931:
! 1932: METHOD(certificate_t, destroy, void,
! 1933: private_x509_cert_t *this)
! 1934: {
! 1935: if (ref_put(&this->ref))
! 1936: {
! 1937: this->subjectAltNames->destroy_offset(this->subjectAltNames,
! 1938: offsetof(identification_t, destroy));
! 1939: this->crl_uris->destroy_function(this->crl_uris,
! 1940: (void*)x509_cdp_destroy);
! 1941: this->ocsp_uris->destroy_function(this->ocsp_uris, free);
! 1942: this->ipAddrBlocks->destroy_offset(this->ipAddrBlocks,
! 1943: offsetof(traffic_selector_t, destroy));
! 1944: this->permitted_names->destroy_offset(this->permitted_names,
! 1945: offsetof(identification_t, destroy));
! 1946: this->excluded_names->destroy_offset(this->excluded_names,
! 1947: offsetof(identification_t, destroy));
! 1948: this->cert_policies->destroy_function(this->cert_policies,
! 1949: (void*)cert_policy_destroy);
! 1950: this->policy_mappings->destroy_function(this->policy_mappings,
! 1951: (void*)policy_mapping_destroy);
! 1952: signature_params_destroy(this->scheme);
! 1953: DESTROY_IF(this->issuer);
! 1954: DESTROY_IF(this->subject);
! 1955: DESTROY_IF(this->public_key);
! 1956: chunk_free(&this->authKeyIdentifier);
! 1957: chunk_free(&this->encoding);
! 1958: chunk_free(&this->encoding_hash);
! 1959: chunk_free(&this->critical_extension_oid);
! 1960: if (!this->parsed)
! 1961: { /* only parsed certificates point these fields to "encoded" */
! 1962: chunk_free(&this->signature);
! 1963: chunk_free(&this->serialNumber);
! 1964: chunk_free(&this->tbsCertificate);
! 1965: }
! 1966: free(this);
! 1967: }
! 1968: }
! 1969:
! 1970: /**
! 1971: * create an empty but initialized X.509 certificate
! 1972: */
! 1973: static private_x509_cert_t* create_empty(void)
! 1974: {
! 1975: private_x509_cert_t *this;
! 1976:
! 1977: INIT(this,
! 1978: .public = {
! 1979: .interface = {
! 1980: .interface = {
! 1981: .get_type = _get_type,
! 1982: .get_subject = _get_subject,
! 1983: .get_issuer = _get_issuer,
! 1984: .has_subject = _has_subject,
! 1985: .has_issuer = _has_issuer,
! 1986: .issued_by = _issued_by,
! 1987: .get_public_key = _get_public_key,
! 1988: .get_validity = _get_validity,
! 1989: .get_encoding = _get_encoding,
! 1990: .equals = _equals,
! 1991: .get_ref = _get_ref,
! 1992: .destroy = _destroy,
! 1993: },
! 1994: .get_flags = _get_flags,
! 1995: .get_serial = _get_serial,
! 1996: .get_subjectKeyIdentifier = _get_subjectKeyIdentifier,
! 1997: .get_authKeyIdentifier = _get_authKeyIdentifier,
! 1998: .get_constraint = _get_constraint,
! 1999: .create_subjectAltName_enumerator = _create_subjectAltName_enumerator,
! 2000: .create_crl_uri_enumerator = _create_crl_uri_enumerator,
! 2001: .create_ocsp_uri_enumerator = _create_ocsp_uri_enumerator,
! 2002: .create_ipAddrBlock_enumerator = _create_ipAddrBlock_enumerator,
! 2003: .create_name_constraint_enumerator = _create_name_constraint_enumerator,
! 2004: .create_cert_policy_enumerator = _create_cert_policy_enumerator,
! 2005: .create_policy_mapping_enumerator = _create_policy_mapping_enumerator,
! 2006: },
! 2007: },
! 2008: .version = 1,
! 2009: .subjectAltNames = linked_list_create(),
! 2010: .crl_uris = linked_list_create(),
! 2011: .ocsp_uris = linked_list_create(),
! 2012: .ipAddrBlocks = linked_list_create(),
! 2013: .permitted_names = linked_list_create(),
! 2014: .excluded_names = linked_list_create(),
! 2015: .cert_policies = linked_list_create(),
! 2016: .policy_mappings = linked_list_create(),
! 2017: .pathLenConstraint = X509_NO_CONSTRAINT,
! 2018: .require_explicit = X509_NO_CONSTRAINT,
! 2019: .inhibit_mapping = X509_NO_CONSTRAINT,
! 2020: .inhibit_any = X509_NO_CONSTRAINT,
! 2021: .ref = 1,
! 2022: );
! 2023: return this;
! 2024: }
! 2025:
! 2026: /**
! 2027: * Build a generalName from an id
! 2028: */
! 2029: chunk_t build_generalName(identification_t *id)
! 2030: {
! 2031: int context;
! 2032:
! 2033: switch (id->get_type(id))
! 2034: {
! 2035: case ID_DER_ASN1_GN:
! 2036: return chunk_clone(id->get_encoding(id));
! 2037: case ID_RFC822_ADDR:
! 2038: context = ASN1_CONTEXT_S_1;
! 2039: break;
! 2040: case ID_FQDN:
! 2041: context = ASN1_CONTEXT_S_2;
! 2042: break;
! 2043: case ID_DER_ASN1_DN:
! 2044: context = ASN1_CONTEXT_C_4;
! 2045: break;
! 2046: case ID_IPV4_ADDR:
! 2047: case ID_IPV6_ADDR:
! 2048: context = ASN1_CONTEXT_S_7;
! 2049: break;
! 2050: default:
! 2051: DBG1(DBG_ASN, "encoding %N as generalName not supported",
! 2052: id_type_names, id->get_type(id));
! 2053: return chunk_empty;
! 2054: }
! 2055: return asn1_wrap(context, "c", id->get_encoding(id));
! 2056: }
! 2057:
! 2058: /**
! 2059: * Encode a linked list of subjectAltNames
! 2060: */
! 2061: chunk_t x509_build_subjectAltNames(linked_list_t *list)
! 2062: {
! 2063: chunk_t subjectAltNames = chunk_empty, name;
! 2064: enumerator_t *enumerator;
! 2065: identification_t *id;
! 2066:
! 2067: if (list->get_count(list) == 0)
! 2068: {
! 2069: return chunk_empty;
! 2070: }
! 2071:
! 2072: enumerator = list->create_enumerator(list);
! 2073: while (enumerator->enumerate(enumerator, &id))
! 2074: {
! 2075: name = build_generalName(id);
! 2076: subjectAltNames = chunk_cat("mm", subjectAltNames, name);
! 2077: }
! 2078: enumerator->destroy(enumerator);
! 2079:
! 2080: return asn1_wrap(ASN1_SEQUENCE, "mm",
! 2081: asn1_build_known_oid(OID_SUBJECT_ALT_NAME),
! 2082: asn1_wrap(ASN1_OCTET_STRING, "m",
! 2083: asn1_wrap(ASN1_SEQUENCE, "m", subjectAltNames)
! 2084: )
! 2085: );
! 2086: }
! 2087:
! 2088: /**
! 2089: * Encode CRL distribution points extension from a x509_cdp_t list
! 2090: */
! 2091: chunk_t x509_build_crlDistributionPoints(linked_list_t *list, int extn)
! 2092: {
! 2093: chunk_t crlDistributionPoints = chunk_empty;
! 2094: enumerator_t *enumerator;
! 2095: x509_cdp_t *cdp;
! 2096:
! 2097: if (list->get_count(list) == 0)
! 2098: {
! 2099: return chunk_empty;
! 2100: }
! 2101:
! 2102: enumerator = list->create_enumerator(list);
! 2103: while (enumerator->enumerate(enumerator, &cdp))
! 2104: {
! 2105: chunk_t distributionPoint, crlIssuer = chunk_empty;
! 2106:
! 2107: if (cdp->issuer)
! 2108: {
! 2109: crlIssuer = asn1_wrap(ASN1_CONTEXT_C_2, "m",
! 2110: build_generalName(cdp->issuer));
! 2111: }
! 2112: distributionPoint = asn1_wrap(ASN1_SEQUENCE, "mm",
! 2113: asn1_wrap(ASN1_CONTEXT_C_0, "m",
! 2114: asn1_wrap(ASN1_CONTEXT_C_0, "m",
! 2115: asn1_wrap(ASN1_CONTEXT_S_6, "c",
! 2116: chunk_create(cdp->uri, strlen(cdp->uri))))),
! 2117: crlIssuer);
! 2118: crlDistributionPoints = chunk_cat("mm", crlDistributionPoints,
! 2119: distributionPoint);
! 2120: }
! 2121: enumerator->destroy(enumerator);
! 2122:
! 2123: return asn1_wrap(ASN1_SEQUENCE, "mm",
! 2124: asn1_build_known_oid(extn),
! 2125: asn1_wrap(ASN1_OCTET_STRING, "m",
! 2126: asn1_wrap(ASN1_SEQUENCE, "m", crlDistributionPoints)));
! 2127: }
! 2128:
! 2129: static chunk_t generate_ts(traffic_selector_t *ts)
! 2130: {
! 2131: chunk_t from, to;
! 2132: uint8_t minbits = 0, maxbits = 0, unused;
! 2133: host_t *net;
! 2134: int bit, byte;
! 2135:
! 2136: if (ts->to_subnet(ts, &net, &minbits))
! 2137: {
! 2138: unused = round_up(minbits, BITS_PER_BYTE) - minbits;
! 2139: from = asn1_wrap(ASN1_BIT_STRING, "m",
! 2140: chunk_cat("cc", chunk_from_thing(unused),
! 2141: chunk_create(net->get_address(net).ptr,
! 2142: (minbits + unused) / BITS_PER_BYTE)));
! 2143: net->destroy(net);
! 2144: return from;
! 2145: }
! 2146: net->destroy(net);
! 2147:
! 2148: from = ts->get_from_address(ts);
! 2149: for (byte = from.len - 1; byte >= 0; byte--)
! 2150: {
! 2151: if (from.ptr[byte] != 0)
! 2152: {
! 2153: minbits = byte * BITS_PER_BYTE + BITS_PER_BYTE;
! 2154: for (bit = 0; bit < BITS_PER_BYTE; bit++)
! 2155: {
! 2156: if (from.ptr[byte] & 1 << bit)
! 2157: {
! 2158: break;
! 2159: }
! 2160: minbits--;
! 2161: }
! 2162: break;
! 2163: }
! 2164: }
! 2165: to = ts->get_to_address(ts);
! 2166: for (byte = to.len - 1; byte >= 0; byte--)
! 2167: {
! 2168: if (to.ptr[byte] != 0xFF)
! 2169: {
! 2170: maxbits = byte * BITS_PER_BYTE + BITS_PER_BYTE;
! 2171: for (bit = 0; bit < BITS_PER_BYTE; bit++)
! 2172: {
! 2173: if ((to.ptr[byte] & 1 << bit) == 0)
! 2174: {
! 2175: break;
! 2176: }
! 2177: maxbits--;
! 2178: }
! 2179: break;
! 2180: }
! 2181: }
! 2182: unused = round_up(minbits, BITS_PER_BYTE) - minbits;
! 2183: from = asn1_wrap(ASN1_BIT_STRING, "m",
! 2184: chunk_cat("cc", chunk_from_thing(unused),
! 2185: chunk_create(from.ptr,
! 2186: (minbits + unused) / BITS_PER_BYTE)));
! 2187: unused = round_up(maxbits, BITS_PER_BYTE) - maxbits;
! 2188: to = asn1_wrap(ASN1_BIT_STRING, "m",
! 2189: chunk_cat("cc", chunk_from_thing(unused),
! 2190: chunk_create(to.ptr,
! 2191: (maxbits + unused) / BITS_PER_BYTE)));
! 2192: return asn1_wrap(ASN1_SEQUENCE, "mm", from, to);
! 2193: }
! 2194:
! 2195: /**
! 2196: * Generate and sign a new certificate
! 2197: */
! 2198: static bool generate(private_x509_cert_t *cert, certificate_t *sign_cert,
! 2199: private_key_t *sign_key, int digest_alg)
! 2200: {
! 2201: const chunk_t keyUsageCrlSign = chunk_from_chars(0x01, 0x02);
! 2202: const chunk_t keyUsageCertSignCrlSign = chunk_from_chars(0x01, 0x06);
! 2203: chunk_t extensions = chunk_empty, extendedKeyUsage = chunk_empty;
! 2204: chunk_t serverAuth = chunk_empty, clientAuth = chunk_empty;
! 2205: chunk_t ocspSigning = chunk_empty, certPolicies = chunk_empty;
! 2206: chunk_t basicConstraints = chunk_empty, nameConstraints = chunk_empty;
! 2207: chunk_t keyUsage = chunk_empty, keyUsageBits = chunk_empty;
! 2208: chunk_t subjectAltNames = chunk_empty, policyMappings = chunk_empty;
! 2209: chunk_t subjectKeyIdentifier = chunk_empty, authKeyIdentifier = chunk_empty;
! 2210: chunk_t crlDistributionPoints = chunk_empty, authorityInfoAccess = chunk_empty;
! 2211: chunk_t policyConstraints = chunk_empty, inhibitAnyPolicy = chunk_empty;
! 2212: chunk_t ikeIntermediate = chunk_empty, msSmartcardLogon = chunk_empty;
! 2213: chunk_t ipAddrBlocks = chunk_empty, sig_scheme = chunk_empty;
! 2214: chunk_t criticalExtension = chunk_empty;
! 2215: identification_t *issuer, *subject;
! 2216: chunk_t key_info;
! 2217: hasher_t *hasher;
! 2218: enumerator_t *enumerator;
! 2219: char *uri;
! 2220:
! 2221: subject = cert->subject;
! 2222: if (sign_cert)
! 2223: {
! 2224: issuer = sign_cert->get_subject(sign_cert);
! 2225: if (!cert->public_key)
! 2226: {
! 2227: return FALSE;
! 2228: }
! 2229: }
! 2230: else
! 2231: { /* self signed */
! 2232: issuer = subject;
! 2233: if (!cert->public_key)
! 2234: {
! 2235: cert->public_key = sign_key->get_public_key(sign_key);
! 2236: }
! 2237: cert->flags |= X509_SELF_SIGNED;
! 2238: }
! 2239: cert->issuer = issuer->clone(issuer);
! 2240: if (!cert->notBefore)
! 2241: {
! 2242: cert->notBefore = time(NULL);
! 2243: }
! 2244: if (!cert->notAfter)
! 2245: { /* defaults to 1 year from now */
! 2246: cert->notAfter = cert->notBefore + 60 * 60 * 24 * 365;
! 2247: }
! 2248:
! 2249: /* select signature scheme, if not already specified */
! 2250: if (!cert->scheme)
! 2251: {
! 2252: INIT(cert->scheme,
! 2253: .scheme = signature_scheme_from_oid(
! 2254: hasher_signature_algorithm_to_oid(digest_alg,
! 2255: sign_key->get_type(sign_key))),
! 2256: );
! 2257: }
! 2258: if (cert->scheme->scheme == SIGN_UNKNOWN)
! 2259: {
! 2260: return FALSE;
! 2261: }
! 2262: if (!signature_params_build(cert->scheme, &sig_scheme))
! 2263: {
! 2264: return FALSE;
! 2265: }
! 2266:
! 2267: if (!cert->public_key->get_encoding(cert->public_key,
! 2268: PUBKEY_SPKI_ASN1_DER, &key_info))
! 2269: {
! 2270: chunk_free(&sig_scheme);
! 2271: return FALSE;
! 2272: }
! 2273:
! 2274: /* encode subjectAltNames */
! 2275: subjectAltNames = x509_build_subjectAltNames(cert->subjectAltNames);
! 2276:
! 2277: crlDistributionPoints = x509_build_crlDistributionPoints(cert->crl_uris,
! 2278: OID_CRL_DISTRIBUTION_POINTS);
! 2279:
! 2280: /* encode OCSP URIs in authorityInfoAccess extension */
! 2281: enumerator = cert->ocsp_uris->create_enumerator(cert->ocsp_uris);
! 2282: while (enumerator->enumerate(enumerator, &uri))
! 2283: {
! 2284: chunk_t accessDescription;
! 2285:
! 2286: accessDescription = asn1_wrap(ASN1_SEQUENCE, "mm",
! 2287: asn1_build_known_oid(OID_OCSP),
! 2288: asn1_wrap(ASN1_CONTEXT_S_6, "c",
! 2289: chunk_create(uri, strlen(uri))));
! 2290: authorityInfoAccess = chunk_cat("mm", authorityInfoAccess,
! 2291: accessDescription);
! 2292: }
! 2293: enumerator->destroy(enumerator);
! 2294: if (authorityInfoAccess.ptr)
! 2295: {
! 2296: authorityInfoAccess = asn1_wrap(ASN1_SEQUENCE, "mm",
! 2297: asn1_build_known_oid(OID_AUTHORITY_INFO_ACCESS),
! 2298: asn1_wrap(ASN1_OCTET_STRING, "m",
! 2299: asn1_wrap(ASN1_SEQUENCE, "m", authorityInfoAccess)));
! 2300: }
! 2301:
! 2302: /* build CA basicConstraint and keyUsage flags for CA certificates */
! 2303: if (cert->flags & X509_CA)
! 2304: {
! 2305: chunk_t pathLenConstraint = chunk_empty;
! 2306:
! 2307: if (cert->pathLenConstraint != X509_NO_CONSTRAINT)
! 2308: {
! 2309: pathLenConstraint = asn1_integer("c",
! 2310: chunk_from_thing(cert->pathLenConstraint));
! 2311: }
! 2312: basicConstraints = asn1_wrap(ASN1_SEQUENCE, "mmm",
! 2313: asn1_build_known_oid(OID_BASIC_CONSTRAINTS),
! 2314: asn1_wrap(ASN1_BOOLEAN, "c",
! 2315: chunk_from_chars(0xFF)),
! 2316: asn1_wrap(ASN1_OCTET_STRING, "m",
! 2317: asn1_wrap(ASN1_SEQUENCE, "mm",
! 2318: asn1_wrap(ASN1_BOOLEAN, "c",
! 2319: chunk_from_chars(0xFF)),
! 2320: pathLenConstraint)));
! 2321: /* set CertificateSign and implicitly CRLsign */
! 2322: keyUsageBits = keyUsageCertSignCrlSign;
! 2323: }
! 2324: else if (cert->flags & X509_CRL_SIGN)
! 2325: {
! 2326: keyUsageBits = keyUsageCrlSign;
! 2327: }
! 2328: if (keyUsageBits.len)
! 2329: {
! 2330: keyUsage = asn1_wrap(ASN1_SEQUENCE, "mmm",
! 2331: asn1_build_known_oid(OID_KEY_USAGE),
! 2332: asn1_wrap(ASN1_BOOLEAN, "c", chunk_from_chars(0xFF)),
! 2333: asn1_wrap(ASN1_OCTET_STRING, "m",
! 2334: asn1_wrap(ASN1_BIT_STRING, "c", keyUsageBits)));
! 2335: }
! 2336:
! 2337: /* add extendedKeyUsage flags */
! 2338: if (cert->flags & X509_SERVER_AUTH)
! 2339: {
! 2340: serverAuth = asn1_build_known_oid(OID_SERVER_AUTH);
! 2341: }
! 2342: if (cert->flags & X509_CLIENT_AUTH)
! 2343: {
! 2344: clientAuth = asn1_build_known_oid(OID_CLIENT_AUTH);
! 2345: }
! 2346: if (cert->flags & X509_IKE_INTERMEDIATE)
! 2347: {
! 2348: ikeIntermediate = asn1_build_known_oid(OID_IKE_INTERMEDIATE);
! 2349: }
! 2350: if (cert->flags & X509_OCSP_SIGNER)
! 2351: {
! 2352: ocspSigning = asn1_build_known_oid(OID_OCSP_SIGNING);
! 2353: }
! 2354: if (cert->flags & X509_MS_SMARTCARD_LOGON)
! 2355: {
! 2356: msSmartcardLogon = asn1_build_known_oid(OID_MS_SMARTCARD_LOGON);
! 2357: }
! 2358:
! 2359: if (serverAuth.ptr || clientAuth.ptr || ikeIntermediate.ptr ||
! 2360: ocspSigning.ptr || msSmartcardLogon.ptr)
! 2361: {
! 2362: extendedKeyUsage = asn1_wrap(ASN1_SEQUENCE, "mm",
! 2363: asn1_build_known_oid(OID_EXTENDED_KEY_USAGE),
! 2364: asn1_wrap(ASN1_OCTET_STRING, "m",
! 2365: asn1_wrap(ASN1_SEQUENCE, "mmmmm",
! 2366: serverAuth, clientAuth, ikeIntermediate,
! 2367: ocspSigning, msSmartcardLogon)));
! 2368: }
! 2369:
! 2370: /* add subjectKeyIdentifier to CA and OCSP signer certificates */
! 2371: if (cert->flags & (X509_CA | X509_OCSP_SIGNER | X509_CRL_SIGN))
! 2372: {
! 2373: chunk_t keyid;
! 2374:
! 2375: if (cert->public_key->get_fingerprint(cert->public_key,
! 2376: KEYID_PUBKEY_SHA1, &keyid))
! 2377: {
! 2378: subjectKeyIdentifier = asn1_wrap(ASN1_SEQUENCE, "mm",
! 2379: asn1_build_known_oid(OID_SUBJECT_KEY_ID),
! 2380: asn1_wrap(ASN1_OCTET_STRING, "m",
! 2381: asn1_wrap(ASN1_OCTET_STRING, "c", keyid)));
! 2382: }
! 2383: }
! 2384:
! 2385: /* add the keyid authKeyIdentifier for non self-signed certificates */
! 2386: if (sign_cert)
! 2387: {
! 2388: chunk_t keyid;
! 2389:
! 2390: if (sign_key->get_fingerprint(sign_key, KEYID_PUBKEY_SHA1, &keyid))
! 2391: {
! 2392: authKeyIdentifier = asn1_wrap(ASN1_SEQUENCE, "mm",
! 2393: asn1_build_known_oid(OID_AUTHORITY_KEY_ID),
! 2394: asn1_wrap(ASN1_OCTET_STRING, "m",
! 2395: asn1_wrap(ASN1_SEQUENCE, "m",
! 2396: asn1_wrap(ASN1_CONTEXT_S_0, "c", keyid))));
! 2397: }
! 2398: }
! 2399:
! 2400: if (cert->ipAddrBlocks->get_count(cert->ipAddrBlocks))
! 2401: {
! 2402: chunk_t v4blocks = chunk_empty, v6blocks = chunk_empty, block;
! 2403: traffic_selector_t *ts;
! 2404:
! 2405: enumerator = cert->ipAddrBlocks->create_enumerator(cert->ipAddrBlocks);
! 2406: while (enumerator->enumerate(enumerator, &ts))
! 2407: {
! 2408: switch (ts->get_type(ts))
! 2409: {
! 2410: case TS_IPV4_ADDR_RANGE:
! 2411: block = generate_ts(ts);
! 2412: v4blocks = chunk_cat("mm", v4blocks, block);
! 2413: break;
! 2414: case TS_IPV6_ADDR_RANGE:
! 2415: block = generate_ts(ts);
! 2416: v6blocks = chunk_cat("mm", v6blocks, block);
! 2417: break;
! 2418: default:
! 2419: break;
! 2420: }
! 2421: }
! 2422: enumerator->destroy(enumerator);
! 2423:
! 2424: if (v4blocks.ptr)
! 2425: {
! 2426: v4blocks = asn1_wrap(ASN1_SEQUENCE, "mm",
! 2427: asn1_wrap(ASN1_OCTET_STRING, "c",
! 2428: chunk_from_chars(0x00,0x01)),
! 2429: asn1_wrap(ASN1_SEQUENCE, "m", v4blocks));
! 2430: }
! 2431: if (v6blocks.ptr)
! 2432: {
! 2433: v6blocks = asn1_wrap(ASN1_SEQUENCE, "mm",
! 2434: asn1_wrap(ASN1_OCTET_STRING, "c",
! 2435: chunk_from_chars(0x00,0x02)),
! 2436: asn1_wrap(ASN1_SEQUENCE, "m", v6blocks));
! 2437: }
! 2438: ipAddrBlocks = asn1_wrap(ASN1_SEQUENCE, "mm",
! 2439: asn1_build_known_oid(OID_IP_ADDR_BLOCKS),
! 2440: asn1_wrap(ASN1_OCTET_STRING, "m",
! 2441: asn1_wrap(ASN1_SEQUENCE, "mm",
! 2442: v4blocks, v6blocks)));
! 2443: cert->flags |= X509_IP_ADDR_BLOCKS;
! 2444: }
! 2445:
! 2446: if (cert->permitted_names->get_count(cert->permitted_names) ||
! 2447: cert->excluded_names->get_count(cert->excluded_names))
! 2448: {
! 2449: chunk_t permitted = chunk_empty, excluded = chunk_empty, subtree;
! 2450: identification_t *id;
! 2451:
! 2452: enumerator = create_name_constraint_enumerator(cert, TRUE);
! 2453: while (enumerator->enumerate(enumerator, &id))
! 2454: {
! 2455: subtree = asn1_wrap(ASN1_SEQUENCE, "m", build_generalName(id));
! 2456: permitted = chunk_cat("mm", permitted, subtree);
! 2457: }
! 2458: enumerator->destroy(enumerator);
! 2459: if (permitted.ptr)
! 2460: {
! 2461: permitted = asn1_wrap(ASN1_CONTEXT_C_0, "m", permitted);
! 2462: }
! 2463:
! 2464: enumerator = create_name_constraint_enumerator(cert, FALSE);
! 2465: while (enumerator->enumerate(enumerator, &id))
! 2466: {
! 2467: subtree = asn1_wrap(ASN1_SEQUENCE, "m", build_generalName(id));
! 2468: excluded = chunk_cat("mm", excluded, subtree);
! 2469: }
! 2470: enumerator->destroy(enumerator);
! 2471: if (excluded.ptr)
! 2472: {
! 2473: excluded = asn1_wrap(ASN1_CONTEXT_C_1, "m", excluded);
! 2474: }
! 2475:
! 2476: nameConstraints = asn1_wrap(ASN1_SEQUENCE, "mm",
! 2477: asn1_build_known_oid(OID_NAME_CONSTRAINTS),
! 2478: asn1_wrap(ASN1_OCTET_STRING, "m",
! 2479: asn1_wrap(ASN1_SEQUENCE, "mm",
! 2480: permitted, excluded)));
! 2481: }
! 2482:
! 2483: if (cert->cert_policies->get_count(cert->cert_policies))
! 2484: {
! 2485: x509_cert_policy_t *policy;
! 2486:
! 2487: enumerator = create_cert_policy_enumerator(cert);
! 2488: while (enumerator->enumerate(enumerator, &policy))
! 2489: {
! 2490: chunk_t chunk = chunk_empty, cps = chunk_empty, notice = chunk_empty;
! 2491:
! 2492: if (policy->cps_uri)
! 2493: {
! 2494: cps = asn1_wrap(ASN1_SEQUENCE, "mm",
! 2495: asn1_build_known_oid(OID_POLICY_QUALIFIER_CPS),
! 2496: asn1_wrap(ASN1_IA5STRING, "c",
! 2497: chunk_create(policy->cps_uri,
! 2498: strlen(policy->cps_uri))));
! 2499: }
! 2500: if (policy->unotice_text)
! 2501: {
! 2502: notice = asn1_wrap(ASN1_SEQUENCE, "mm",
! 2503: asn1_build_known_oid(OID_POLICY_QUALIFIER_UNOTICE),
! 2504: asn1_wrap(ASN1_SEQUENCE, "m",
! 2505: asn1_wrap(ASN1_VISIBLESTRING, "c",
! 2506: chunk_create(policy->unotice_text,
! 2507: strlen(policy->unotice_text)))));
! 2508: }
! 2509: if (cps.len || notice.len)
! 2510: {
! 2511: chunk = asn1_wrap(ASN1_SEQUENCE, "mm", cps, notice);
! 2512: }
! 2513: chunk = asn1_wrap(ASN1_SEQUENCE, "mm",
! 2514: asn1_wrap(ASN1_OID, "c", policy->oid), chunk);
! 2515: certPolicies = chunk_cat("mm", certPolicies, chunk);
! 2516: }
! 2517: enumerator->destroy(enumerator);
! 2518:
! 2519: certPolicies = asn1_wrap(ASN1_SEQUENCE, "mm",
! 2520: asn1_build_known_oid(OID_CERTIFICATE_POLICIES),
! 2521: asn1_wrap(ASN1_OCTET_STRING, "m",
! 2522: asn1_wrap(ASN1_SEQUENCE, "m", certPolicies)));
! 2523: }
! 2524:
! 2525: if (cert->policy_mappings->get_count(cert->policy_mappings))
! 2526: {
! 2527: x509_policy_mapping_t *mapping;
! 2528:
! 2529: enumerator = create_policy_mapping_enumerator(cert);
! 2530: while (enumerator->enumerate(enumerator, &mapping))
! 2531: {
! 2532: chunk_t chunk;
! 2533:
! 2534: chunk = asn1_wrap(ASN1_SEQUENCE, "mm",
! 2535: asn1_wrap(ASN1_OID, "c", mapping->issuer),
! 2536: asn1_wrap(ASN1_OID, "c", mapping->subject));
! 2537: policyMappings = chunk_cat("mm", policyMappings, chunk);
! 2538: }
! 2539: enumerator->destroy(enumerator);
! 2540:
! 2541: policyMappings = asn1_wrap(ASN1_SEQUENCE, "mm",
! 2542: asn1_build_known_oid(OID_POLICY_MAPPINGS),
! 2543: asn1_wrap(ASN1_OCTET_STRING, "m",
! 2544: asn1_wrap(ASN1_SEQUENCE, "m", policyMappings)));
! 2545: }
! 2546:
! 2547: if (cert->inhibit_mapping != X509_NO_CONSTRAINT ||
! 2548: cert->require_explicit != X509_NO_CONSTRAINT)
! 2549: {
! 2550: chunk_t inhibit = chunk_empty, explicit = chunk_empty;
! 2551:
! 2552: if (cert->require_explicit != X509_NO_CONSTRAINT)
! 2553: {
! 2554: explicit = asn1_wrap(ASN1_CONTEXT_C_0, "m",
! 2555: asn1_integer("c",
! 2556: chunk_from_thing(cert->require_explicit)));
! 2557: }
! 2558: if (cert->inhibit_mapping != X509_NO_CONSTRAINT)
! 2559: {
! 2560: inhibit = asn1_wrap(ASN1_CONTEXT_C_1, "m",
! 2561: asn1_integer("c",
! 2562: chunk_from_thing(cert->inhibit_mapping)));
! 2563: }
! 2564: policyConstraints = asn1_wrap(ASN1_SEQUENCE, "mmm",
! 2565: asn1_build_known_oid(OID_POLICY_CONSTRAINTS),
! 2566: asn1_wrap(ASN1_BOOLEAN, "c", chunk_from_chars(0xFF)),
! 2567: asn1_wrap(ASN1_OCTET_STRING, "m",
! 2568: asn1_wrap(ASN1_SEQUENCE, "mm",
! 2569: explicit, inhibit)));
! 2570: }
! 2571:
! 2572: if (cert->inhibit_any != X509_NO_CONSTRAINT)
! 2573: {
! 2574: inhibitAnyPolicy = asn1_wrap(ASN1_SEQUENCE, "mmm",
! 2575: asn1_build_known_oid(OID_INHIBIT_ANY_POLICY),
! 2576: asn1_wrap(ASN1_BOOLEAN, "c", chunk_from_chars(0xFF)),
! 2577: asn1_wrap(ASN1_OCTET_STRING, "m",
! 2578: asn1_integer("c",
! 2579: chunk_from_thing(cert->inhibit_any))));
! 2580: }
! 2581:
! 2582: if (cert->critical_extension_oid.len > 0)
! 2583: {
! 2584: criticalExtension = asn1_wrap(ASN1_SEQUENCE, "mmm",
! 2585: asn1_simple_object(ASN1_OID, cert->critical_extension_oid),
! 2586: asn1_simple_object(ASN1_BOOLEAN, chunk_from_chars(0xFF)),
! 2587: asn1_simple_object(ASN1_OCTET_STRING, chunk_empty));
! 2588: }
! 2589:
! 2590: if (basicConstraints.ptr || subjectAltNames.ptr || authKeyIdentifier.ptr ||
! 2591: crlDistributionPoints.ptr || nameConstraints.ptr || ipAddrBlocks.ptr)
! 2592: {
! 2593: extensions = asn1_wrap(ASN1_CONTEXT_C_3, "m",
! 2594: asn1_wrap(ASN1_SEQUENCE, "mmmmmmmmmmmmmmm",
! 2595: basicConstraints, keyUsage, subjectKeyIdentifier,
! 2596: authKeyIdentifier, subjectAltNames,
! 2597: extendedKeyUsage, crlDistributionPoints,
! 2598: authorityInfoAccess, nameConstraints, certPolicies,
! 2599: policyMappings, policyConstraints, inhibitAnyPolicy,
! 2600: ipAddrBlocks, criticalExtension));
! 2601: }
! 2602:
! 2603: cert->tbsCertificate = asn1_wrap(ASN1_SEQUENCE, "mmccmcmm",
! 2604: asn1_simple_object(ASN1_CONTEXT_C_0, ASN1_INTEGER_2),
! 2605: asn1_integer("c", cert->serialNumber),
! 2606: sig_scheme,
! 2607: issuer->get_encoding(issuer),
! 2608: asn1_wrap(ASN1_SEQUENCE, "mm",
! 2609: asn1_from_time(&cert->notBefore, ASN1_UTCTIME),
! 2610: asn1_from_time(&cert->notAfter, ASN1_UTCTIME)),
! 2611: subject->get_encoding(subject),
! 2612: key_info, extensions);
! 2613:
! 2614: if (!sign_key->sign(sign_key, cert->scheme->scheme, cert->scheme->params,
! 2615: cert->tbsCertificate, &cert->signature))
! 2616: {
! 2617: chunk_free(&sig_scheme);
! 2618: return FALSE;
! 2619: }
! 2620: cert->encoding = asn1_wrap(ASN1_SEQUENCE, "cmm", cert->tbsCertificate,
! 2621: sig_scheme,
! 2622: asn1_bitstring("c", cert->signature));
! 2623:
! 2624: hasher = lib->crypto->create_hasher(lib->crypto, HASH_SHA1);
! 2625: if (!hasher ||
! 2626: !hasher->allocate_hash(hasher, cert->encoding, &cert->encoding_hash))
! 2627: {
! 2628: DESTROY_IF(hasher);
! 2629: return FALSE;
! 2630: }
! 2631: hasher->destroy(hasher);
! 2632: return TRUE;
! 2633: }
! 2634:
! 2635: /**
! 2636: * See header.
! 2637: */
! 2638: x509_cert_t *x509_cert_load(certificate_type_t type, va_list args)
! 2639: {
! 2640: x509_flag_t flags = 0;
! 2641: chunk_t blob = chunk_empty;
! 2642:
! 2643: while (TRUE)
! 2644: {
! 2645: switch (va_arg(args, builder_part_t))
! 2646: {
! 2647: case BUILD_BLOB_ASN1_DER:
! 2648: blob = va_arg(args, chunk_t);
! 2649: continue;
! 2650: case BUILD_X509_FLAG:
! 2651: flags |= va_arg(args, x509_flag_t);
! 2652: continue;
! 2653: case BUILD_END:
! 2654: break;
! 2655: default:
! 2656: return NULL;
! 2657: }
! 2658: break;
! 2659: }
! 2660:
! 2661: if (blob.ptr)
! 2662: {
! 2663: private_x509_cert_t *cert = create_empty();
! 2664:
! 2665: cert->encoding = chunk_clone(blob);
! 2666: cert->parsed = TRUE;
! 2667: if (parse_certificate(cert))
! 2668: {
! 2669: cert->flags |= flags;
! 2670: return &cert->public;
! 2671: }
! 2672: destroy(cert);
! 2673: }
! 2674: return NULL;
! 2675: }
! 2676:
! 2677: /**
! 2678: * See header.
! 2679: */
! 2680: x509_cert_t *x509_cert_gen(certificate_type_t type, va_list args)
! 2681: {
! 2682: private_x509_cert_t *cert;
! 2683: certificate_t *sign_cert = NULL;
! 2684: private_key_t *sign_key = NULL;
! 2685: hash_algorithm_t digest_alg = HASH_SHA256;
! 2686: u_int constraint;
! 2687:
! 2688: cert = create_empty();
! 2689: while (TRUE)
! 2690: {
! 2691: switch (va_arg(args, builder_part_t))
! 2692: {
! 2693: case BUILD_X509_FLAG:
! 2694: cert->flags |= va_arg(args, x509_flag_t);
! 2695: continue;
! 2696: case BUILD_SIGNING_KEY:
! 2697: sign_key = va_arg(args, private_key_t*);
! 2698: continue;
! 2699: case BUILD_SIGNING_CERT:
! 2700: sign_cert = va_arg(args, certificate_t*);
! 2701: continue;
! 2702: case BUILD_PUBLIC_KEY:
! 2703: cert->public_key = va_arg(args, public_key_t*);
! 2704: cert->public_key->get_ref(cert->public_key);
! 2705: continue;
! 2706: case BUILD_SUBJECT:
! 2707: cert->subject = va_arg(args, identification_t*);
! 2708: cert->subject = cert->subject->clone(cert->subject);
! 2709: continue;
! 2710: case BUILD_SUBJECT_ALTNAMES:
! 2711: {
! 2712: enumerator_t *enumerator;
! 2713: identification_t *id;
! 2714: linked_list_t *list;
! 2715:
! 2716: list = va_arg(args, linked_list_t*);
! 2717: enumerator = list->create_enumerator(list);
! 2718: while (enumerator->enumerate(enumerator, &id))
! 2719: {
! 2720: cert->subjectAltNames->insert_last(cert->subjectAltNames,
! 2721: id->clone(id));
! 2722: }
! 2723: enumerator->destroy(enumerator);
! 2724: continue;
! 2725: }
! 2726: case BUILD_CRL_DISTRIBUTION_POINTS:
! 2727: {
! 2728: enumerator_t *enumerator;
! 2729: linked_list_t *list;
! 2730: x509_cdp_t *in, *cdp;
! 2731:
! 2732: list = va_arg(args, linked_list_t*);
! 2733: enumerator = list->create_enumerator(list);
! 2734: while (enumerator->enumerate(enumerator, &in))
! 2735: {
! 2736: INIT(cdp,
! 2737: .uri = strdup(in->uri),
! 2738: .issuer = in->issuer ? in->issuer->clone(in->issuer) : NULL,
! 2739: );
! 2740: cert->crl_uris->insert_last(cert->crl_uris, cdp);
! 2741: }
! 2742: enumerator->destroy(enumerator);
! 2743: continue;
! 2744: }
! 2745: case BUILD_OCSP_ACCESS_LOCATIONS:
! 2746: {
! 2747: enumerator_t *enumerator;
! 2748: linked_list_t *list;
! 2749: char *uri;
! 2750:
! 2751: list = va_arg(args, linked_list_t*);
! 2752: enumerator = list->create_enumerator(list);
! 2753: while (enumerator->enumerate(enumerator, &uri))
! 2754: {
! 2755: cert->ocsp_uris->insert_last(cert->ocsp_uris, strdup(uri));
! 2756: }
! 2757: enumerator->destroy(enumerator);
! 2758: continue;
! 2759: }
! 2760: case BUILD_PATHLEN:
! 2761: constraint = va_arg(args, u_int);
! 2762: cert->pathLenConstraint = (constraint < 128) ?
! 2763: constraint : X509_NO_CONSTRAINT;
! 2764: continue;
! 2765: case BUILD_ADDRBLOCKS:
! 2766: {
! 2767: enumerator_t *enumerator;
! 2768: traffic_selector_t *ts;
! 2769: linked_list_t *list;
! 2770:
! 2771: list = va_arg(args, linked_list_t*);
! 2772: enumerator = list->create_enumerator(list);
! 2773: while (enumerator->enumerate(enumerator, &ts))
! 2774: {
! 2775: cert->ipAddrBlocks->insert_last(cert->ipAddrBlocks,
! 2776: ts->clone(ts));
! 2777: }
! 2778: enumerator->destroy(enumerator);
! 2779: continue;
! 2780: }
! 2781: case BUILD_PERMITTED_NAME_CONSTRAINTS:
! 2782: {
! 2783: enumerator_t *enumerator;
! 2784: linked_list_t *list;
! 2785: identification_t *constraint;
! 2786:
! 2787: list = va_arg(args, linked_list_t*);
! 2788: enumerator = list->create_enumerator(list);
! 2789: while (enumerator->enumerate(enumerator, &constraint))
! 2790: {
! 2791: cert->permitted_names->insert_last(cert->permitted_names,
! 2792: constraint->clone(constraint));
! 2793: }
! 2794: enumerator->destroy(enumerator);
! 2795: continue;
! 2796: }
! 2797: case BUILD_EXCLUDED_NAME_CONSTRAINTS:
! 2798: {
! 2799: enumerator_t *enumerator;
! 2800: linked_list_t *list;
! 2801: identification_t *constraint;
! 2802:
! 2803: list = va_arg(args, linked_list_t*);
! 2804: enumerator = list->create_enumerator(list);
! 2805: while (enumerator->enumerate(enumerator, &constraint))
! 2806: {
! 2807: cert->excluded_names->insert_last(cert->excluded_names,
! 2808: constraint->clone(constraint));
! 2809: }
! 2810: enumerator->destroy(enumerator);
! 2811: continue;
! 2812: }
! 2813: case BUILD_CERTIFICATE_POLICIES:
! 2814: {
! 2815: enumerator_t *enumerator;
! 2816: linked_list_t *list;
! 2817: x509_cert_policy_t *policy, *in;
! 2818:
! 2819: list = va_arg(args, linked_list_t*);
! 2820: enumerator = list->create_enumerator(list);
! 2821: while (enumerator->enumerate(enumerator, &in))
! 2822: {
! 2823: INIT(policy,
! 2824: .oid = chunk_clone(in->oid),
! 2825: .cps_uri = strdupnull(in->cps_uri),
! 2826: .unotice_text = strdupnull(in->unotice_text),
! 2827: );
! 2828: cert->cert_policies->insert_last(cert->cert_policies, policy);
! 2829: }
! 2830: enumerator->destroy(enumerator);
! 2831: continue;
! 2832: }
! 2833: case BUILD_POLICY_MAPPINGS:
! 2834: {
! 2835: enumerator_t *enumerator;
! 2836: linked_list_t *list;
! 2837: x509_policy_mapping_t* mapping, *in;
! 2838:
! 2839: list = va_arg(args, linked_list_t*);
! 2840: enumerator = list->create_enumerator(list);
! 2841: while (enumerator->enumerate(enumerator, &in))
! 2842: {
! 2843: INIT(mapping,
! 2844: .issuer = chunk_clone(in->issuer),
! 2845: .subject = chunk_clone(in->subject),
! 2846: );
! 2847: cert->policy_mappings->insert_last(cert->policy_mappings,
! 2848: mapping);
! 2849: }
! 2850: enumerator->destroy(enumerator);
! 2851: continue;
! 2852: }
! 2853: case BUILD_POLICY_REQUIRE_EXPLICIT:
! 2854: constraint = va_arg(args, u_int);
! 2855: cert->require_explicit = (constraint < 128) ?
! 2856: constraint : X509_NO_CONSTRAINT;
! 2857: continue;
! 2858: case BUILD_POLICY_INHIBIT_MAPPING:
! 2859: constraint = va_arg(args, u_int);
! 2860: cert->inhibit_mapping = (constraint < 128) ?
! 2861: constraint : X509_NO_CONSTRAINT;
! 2862: continue;
! 2863: case BUILD_POLICY_INHIBIT_ANY:
! 2864: constraint = va_arg(args, u_int);
! 2865: cert->inhibit_any = (constraint < 128) ?
! 2866: constraint : X509_NO_CONSTRAINT;
! 2867: continue;
! 2868: case BUILD_NOT_BEFORE_TIME:
! 2869: cert->notBefore = va_arg(args, time_t);
! 2870: continue;
! 2871: case BUILD_NOT_AFTER_TIME:
! 2872: cert->notAfter = va_arg(args, time_t);
! 2873: continue;
! 2874: case BUILD_SERIAL:
! 2875: cert->serialNumber = chunk_clone(va_arg(args, chunk_t));
! 2876: continue;
! 2877: case BUILD_SIGNATURE_SCHEME:
! 2878: cert->scheme = va_arg(args, signature_params_t*);
! 2879: cert->scheme = signature_params_clone(cert->scheme);
! 2880: continue;
! 2881: case BUILD_DIGEST_ALG:
! 2882: digest_alg = va_arg(args, int);
! 2883: continue;
! 2884: case BUILD_CRITICAL_EXTENSION:
! 2885: cert->critical_extension_oid = chunk_clone(va_arg(args, chunk_t));
! 2886: continue;
! 2887: case BUILD_END:
! 2888: break;
! 2889: default:
! 2890: destroy(cert);
! 2891: return NULL;
! 2892: }
! 2893: break;
! 2894: }
! 2895:
! 2896: if (sign_key && generate(cert, sign_cert, sign_key, digest_alg))
! 2897: {
! 2898: return &cert->public;
! 2899: }
! 2900: destroy(cert);
! 2901: return NULL;
! 2902: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>