Annotation of embedaddon/strongswan/src/libstrongswan/plugins/openssl/openssl_x509.c, revision 1.1
1.1 ! misho 1: /*
! 2: * Copyright (C) 2011-2017 Tobias Brunner
! 3: * HSR Hochschule fuer Technik Rapperswil
! 4: *
! 5: * Copyright (C) 2010 Martin Willi
! 6: * Copyright (C) 2010 revosec AG
! 7: *
! 8: * This program is free software; you can redistribute it and/or modify it
! 9: * under the terms of the GNU General Public License as published by the
! 10: * Free Software Foundation; either version 2 of the License, or (at your
! 11: * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
! 12: *
! 13: * This program is distributed in the hope that it will be useful, but
! 14: * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
! 15: * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
! 16: * for more details.
! 17: */
! 18:
! 19: /*
! 20: * Copyright (C) 2013 Michael Rossberg
! 21: * Copyright (C) 2013 Technische Universität Ilmenau
! 22: *
! 23: * Copyright (C) 2010 secunet Security Networks AG
! 24: * Copyright (C) 2010 Thomas Egerer
! 25: *
! 26: * Permission is hereby granted, free of charge, to any person obtaining a copy
! 27: * of this software and associated documentation files (the "Software"), to deal
! 28: * in the Software without restriction, including without limitation the rights
! 29: * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
! 30: * copies of the Software, and to permit persons to whom the Software is
! 31: * furnished to do so, subject to the following conditions:
! 32: *
! 33: * The above copyright notice and this permission notice shall be included in
! 34: * all copies or substantial portions of the Software.
! 35: *
! 36: * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
! 37: * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
! 38: * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
! 39: * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
! 40: * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
! 41: * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
! 42: * THE SOFTWARE.
! 43: */
! 44:
! 45: #define _GNU_SOURCE
! 46: #include <stdio.h>
! 47: #include <openssl/x509.h>
! 48: #include <openssl/x509v3.h>
! 49:
! 50: #include "openssl_x509.h"
! 51: #include "openssl_util.h"
! 52:
! 53: #include <utils/debug.h>
! 54: #include <asn1/oid.h>
! 55: #include <collections/linked_list.h>
! 56: #include <selectors/traffic_selector.h>
! 57:
! 58: /* IP Addr block extension support was introduced with 0.9.8e */
! 59: #if OPENSSL_VERSION_NUMBER < 0x0090805fL
! 60: #define OPENSSL_NO_RFC3779
! 61: #endif
! 62:
! 63: /* added with 1.0.2 */
! 64: #if OPENSSL_VERSION_NUMBER < 0x10002000L
! 65: static inline void X509_get0_signature(ASN1_BIT_STRING **psig, X509_ALGOR **palg, const X509 *x) {
! 66: if (psig) { *psig = x->signature; }
! 67: if (palg) { *palg = x->sig_alg; }
! 68: }
! 69: #endif
! 70:
! 71: /* added with 1.1.0 when X509 etc. was made opaque */
! 72: #if OPENSSL_VERSION_NUMBER < 0x10100000L
! 73: #define X509_get0_extensions(x509) ({ (x509)->cert_info->extensions; })
! 74: #define X509_get0_tbs_sigalg(x509) ({ (x509)->cert_info->signature; })
! 75: #define X509_ALGOR_get0(oid, ppt, ppv, alg) ({ *(oid) = (alg)->algorithm; })
! 76: #define X509_PUBKEY_get0_param(oid, pk, len, pa, pub) X509_ALGOR_get0(oid, NULL, NULL, (pub)->algor)
! 77: #define X509v3_addr_get_afi v3_addr_get_afi
! 78: #define X509v3_addr_get_range v3_addr_get_range
! 79: #define X509v3_addr_is_canonical v3_addr_is_canonical
! 80: #define X509_get0_notBefore X509_get_notBefore
! 81: #define X509_get0_notAfter X509_get_notAfter
! 82: #endif
! 83:
! 84: typedef struct private_openssl_x509_t private_openssl_x509_t;
! 85:
! 86: /**
! 87: * Private data of an openssl_x509_t object.
! 88: */
! 89: struct private_openssl_x509_t {
! 90:
! 91: /**
! 92: * Public openssl_x509_t interface.
! 93: */
! 94: openssl_x509_t public;
! 95:
! 96: /**
! 97: * OpenSSL certificate representation
! 98: */
! 99: X509 *x509;
! 100:
! 101: /**
! 102: * DER encoded certificate
! 103: */
! 104: chunk_t encoding;
! 105:
! 106: /**
! 107: * SHA1 hash of the certificate
! 108: */
! 109: chunk_t hash;
! 110:
! 111: /**
! 112: * X509 flags
! 113: */
! 114: x509_flag_t flags;
! 115:
! 116: /**
! 117: * Pathlen constraint
! 118: */
! 119: u_char pathlen;
! 120:
! 121: /**
! 122: * certificate subject
! 123: */
! 124: identification_t *subject;
! 125:
! 126: /**
! 127: * certificate issuer
! 128: */
! 129: identification_t *issuer;
! 130:
! 131: /**
! 132: * Certificates public key
! 133: */
! 134: public_key_t *pubkey;
! 135:
! 136: /**
! 137: * subjectKeyIdentifier as read from cert
! 138: */
! 139: chunk_t subjectKeyIdentifier;
! 140:
! 141: /**
! 142: * authorityKeyIdentifier as read from cert
! 143: */
! 144: chunk_t authKeyIdentifier;
! 145:
! 146: /**
! 147: * Start time of certificate validity
! 148: */
! 149: time_t notBefore;
! 150:
! 151: /**
! 152: * End time of certificate validity
! 153: */
! 154: time_t notAfter;
! 155:
! 156: /**
! 157: * Signature scheme of the certificate
! 158: */
! 159: signature_params_t *scheme;
! 160:
! 161: /**
! 162: * subjectAltNames
! 163: */
! 164: linked_list_t *subjectAltNames;
! 165:
! 166: /**
! 167: * issuerAltNames
! 168: */
! 169: linked_list_t *issuerAltNames;
! 170:
! 171: /**
! 172: * List of CRL URIs, as x509_cdp_t
! 173: */
! 174: linked_list_t *crl_uris;
! 175:
! 176: /**
! 177: * List of OCSP URIs
! 178: */
! 179: linked_list_t *ocsp_uris;
! 180:
! 181: /**
! 182: * List of ipAddrBlocks as traffic_selector_t
! 183: */
! 184: linked_list_t *ipAddrBlocks;
! 185:
! 186:
! 187: /**
! 188: * References to this cert
! 189: */
! 190: refcount_t ref;
! 191: };
! 192:
! 193: /**
! 194: * Convert a GeneralName to an identification_t.
! 195: */
! 196: static identification_t *general_name2id(GENERAL_NAME *name)
! 197: {
! 198: if (!name)
! 199: {
! 200: return NULL;
! 201: }
! 202: switch (name->type)
! 203: {
! 204: case GEN_EMAIL:
! 205: return identification_create_from_encoding(ID_RFC822_ADDR,
! 206: openssl_asn1_str2chunk(name->d.rfc822Name));
! 207: case GEN_DNS:
! 208: return identification_create_from_encoding(ID_FQDN,
! 209: openssl_asn1_str2chunk(name->d.dNSName));
! 210: case GEN_URI:
! 211: return identification_create_from_encoding(ID_DER_ASN1_GN_URI,
! 212: openssl_asn1_str2chunk(name->d.uniformResourceIdentifier));
! 213: case GEN_IPADD:
! 214: {
! 215: chunk_t chunk = openssl_asn1_str2chunk(name->d.iPAddress);
! 216: if (chunk.len == 4)
! 217: {
! 218: return identification_create_from_encoding(ID_IPV4_ADDR, chunk);
! 219: }
! 220: if (chunk.len == 16)
! 221: {
! 222: return identification_create_from_encoding(ID_IPV6_ADDR, chunk);
! 223: }
! 224: return NULL;
! 225: }
! 226: case GEN_DIRNAME :
! 227: return openssl_x509_name2id(name->d.directoryName);
! 228: case GEN_OTHERNAME:
! 229: if (OBJ_obj2nid(name->d.otherName->type_id) == NID_ms_upn &&
! 230: name->d.otherName->value->type == V_ASN1_UTF8STRING)
! 231: {
! 232: return identification_create_from_encoding(ID_RFC822_ADDR,
! 233: openssl_asn1_str2chunk(
! 234: name->d.otherName->value->value.utf8string));
! 235: }
! 236: return NULL;
! 237: default:
! 238: return NULL;
! 239: }
! 240: }
! 241:
! 242: METHOD(x509_t, get_flags, x509_flag_t,
! 243: private_openssl_x509_t *this)
! 244: {
! 245: return this->flags;
! 246: }
! 247:
! 248: METHOD(x509_t, get_serial, chunk_t,
! 249: private_openssl_x509_t *this)
! 250: {
! 251: return openssl_asn1_str2chunk(X509_get_serialNumber(this->x509));
! 252: }
! 253:
! 254: METHOD(x509_t, get_subjectKeyIdentifier, chunk_t,
! 255: private_openssl_x509_t *this)
! 256: {
! 257: chunk_t fingerprint;
! 258:
! 259: if (this->subjectKeyIdentifier.len)
! 260: {
! 261: return this->subjectKeyIdentifier;
! 262: }
! 263: if (this->pubkey->get_fingerprint(this->pubkey, KEYID_PUBKEY_SHA1,
! 264: &fingerprint))
! 265: {
! 266: return fingerprint;
! 267: }
! 268: return chunk_empty;
! 269: }
! 270:
! 271: METHOD(x509_t, get_authKeyIdentifier, chunk_t,
! 272: private_openssl_x509_t *this)
! 273: {
! 274: if (this->authKeyIdentifier.len)
! 275: {
! 276: return this->authKeyIdentifier;
! 277: }
! 278: return chunk_empty;
! 279: }
! 280:
! 281: METHOD(x509_t, get_constraint, u_int,
! 282: private_openssl_x509_t *this, x509_constraint_t type)
! 283: {
! 284: switch (type)
! 285: {
! 286: case X509_PATH_LEN:
! 287: return this->pathlen;
! 288: default:
! 289: return X509_NO_CONSTRAINT;
! 290: }
! 291: }
! 292:
! 293: METHOD(x509_t, create_subjectAltName_enumerator, enumerator_t*,
! 294: private_openssl_x509_t *this)
! 295: {
! 296: return this->subjectAltNames->create_enumerator(this->subjectAltNames);
! 297: }
! 298:
! 299: METHOD(x509_t, create_crl_uri_enumerator, enumerator_t*,
! 300: private_openssl_x509_t *this)
! 301: {
! 302: return this->crl_uris->create_enumerator(this->crl_uris);
! 303: }
! 304:
! 305: METHOD(x509_t, create_ocsp_uri_enumerator, enumerator_t*,
! 306: private_openssl_x509_t *this)
! 307: {
! 308: return this->ocsp_uris->create_enumerator(this->ocsp_uris);
! 309: }
! 310:
! 311: METHOD(x509_t, create_ipAddrBlock_enumerator, enumerator_t*,
! 312: private_openssl_x509_t *this)
! 313: {
! 314: return this->ipAddrBlocks->create_enumerator(this->ipAddrBlocks);
! 315: }
! 316:
! 317: METHOD(certificate_t, get_type, certificate_type_t,
! 318: private_openssl_x509_t *this)
! 319: {
! 320: return CERT_X509;
! 321: }
! 322:
! 323: METHOD(certificate_t, get_subject, identification_t*,
! 324: private_openssl_x509_t *this)
! 325: {
! 326: return this->subject;
! 327: }
! 328:
! 329: METHOD(certificate_t, get_issuer, identification_t*,
! 330: private_openssl_x509_t *this)
! 331: {
! 332: return this->issuer;
! 333: }
! 334:
! 335: METHOD(certificate_t, has_subject, id_match_t,
! 336: private_openssl_x509_t *this, identification_t *subject)
! 337: {
! 338: identification_t *current;
! 339: enumerator_t *enumerator;
! 340: id_match_t match, best;
! 341: chunk_t encoding;
! 342:
! 343: if (subject->get_type(subject) == ID_KEY_ID)
! 344: {
! 345: encoding = subject->get_encoding(subject);
! 346:
! 347: if (chunk_equals(this->hash, encoding))
! 348: {
! 349: return ID_MATCH_PERFECT;
! 350: }
! 351: if (this->subjectKeyIdentifier.len &&
! 352: chunk_equals(this->subjectKeyIdentifier, encoding))
! 353: {
! 354: return ID_MATCH_PERFECT;
! 355: }
! 356: if (this->pubkey &&
! 357: this->pubkey->has_fingerprint(this->pubkey, encoding))
! 358: {
! 359: return ID_MATCH_PERFECT;
! 360: }
! 361: if (chunk_equals(get_serial(this), encoding))
! 362: {
! 363: return ID_MATCH_PERFECT;
! 364: }
! 365: }
! 366: best = this->subject->matches(this->subject, subject);
! 367: enumerator = create_subjectAltName_enumerator(this);
! 368: while (enumerator->enumerate(enumerator, ¤t))
! 369: {
! 370: match = current->matches(current, subject);
! 371: if (match > best)
! 372: {
! 373: best = match;
! 374: }
! 375: }
! 376: enumerator->destroy(enumerator);
! 377: return best;
! 378: }
! 379:
! 380: METHOD(certificate_t, has_issuer, id_match_t,
! 381: private_openssl_x509_t *this, identification_t *issuer)
! 382: {
! 383: /* issuerAltNames currently not supported */
! 384: return this->issuer->matches(this->issuer, issuer);
! 385: }
! 386:
! 387: METHOD(certificate_t, issued_by, bool,
! 388: private_openssl_x509_t *this, certificate_t *issuer,
! 389: signature_params_t **scheme)
! 390: {
! 391: public_key_t *key;
! 392: bool valid;
! 393: x509_t *x509 = (x509_t*)issuer;
! 394: #if OPENSSL_VERSION_NUMBER >= 0x10100000L
! 395: const ASN1_BIT_STRING *sig;
! 396: #else
! 397: ASN1_BIT_STRING *sig;
! 398: #endif
! 399: chunk_t tbs;
! 400:
! 401: if (&this->public.x509.interface == issuer)
! 402: {
! 403: if (this->flags & X509_SELF_SIGNED)
! 404: {
! 405: valid = TRUE;
! 406: goto out;
! 407: }
! 408: }
! 409: else
! 410: {
! 411: if (issuer->get_type(issuer) != CERT_X509)
! 412: {
! 413: return FALSE;
! 414: }
! 415: if (!(x509->get_flags(x509) & X509_CA))
! 416: {
! 417: return FALSE;
! 418: }
! 419: }
! 420: if (!this->issuer->equals(this->issuer, issuer->get_subject(issuer)))
! 421: {
! 422: return FALSE;
! 423: }
! 424: key = issuer->get_public_key(issuer);
! 425: if (!key)
! 426: {
! 427: return FALSE;
! 428: }
! 429: /* i2d_re_X509_tbs() was added with 1.1.0 when X509 was made opaque */
! 430: #if OPENSSL_VERSION_NUMBER >= 0x10100000L
! 431: tbs = openssl_i2chunk(re_X509_tbs, this->x509);
! 432: #else
! 433: tbs = openssl_i2chunk(X509_CINF, this->x509->cert_info);
! 434: #endif
! 435: X509_get0_signature(&sig, NULL, this->x509);
! 436: valid = key->verify(key, this->scheme->scheme, this->scheme->params, tbs,
! 437: openssl_asn1_str2chunk(sig));
! 438: free(tbs.ptr);
! 439: key->destroy(key);
! 440:
! 441: out:
! 442: if (valid && scheme)
! 443: {
! 444: *scheme = signature_params_clone(this->scheme);
! 445: }
! 446: return valid;
! 447: }
! 448:
! 449: METHOD(certificate_t, get_public_key, public_key_t*,
! 450: private_openssl_x509_t *this)
! 451: {
! 452: return this->pubkey->get_ref(this->pubkey);
! 453: }
! 454:
! 455: METHOD(certificate_t, get_validity, bool,
! 456: private_openssl_x509_t *this,
! 457: time_t *when, time_t *not_before, time_t *not_after)
! 458: {
! 459: time_t t;
! 460:
! 461: if (when)
! 462: {
! 463: t = *when;
! 464: }
! 465: else
! 466: {
! 467: t = time(NULL);
! 468: }
! 469: if (not_before)
! 470: {
! 471: *not_before = this->notBefore;
! 472: }
! 473: if (not_after)
! 474: {
! 475: *not_after = this->notAfter;
! 476: }
! 477: return (t >= this->notBefore && t <= this->notAfter);
! 478: }
! 479:
! 480: METHOD(certificate_t, get_encoding, bool,
! 481: private_openssl_x509_t *this, cred_encoding_type_t type, chunk_t *encoding)
! 482: {
! 483: if (type == CERT_ASN1_DER)
! 484: {
! 485: *encoding = chunk_clone(this->encoding);
! 486: return TRUE;
! 487: }
! 488: return lib->encoding->encode(lib->encoding, type, NULL, encoding,
! 489: CRED_PART_X509_ASN1_DER, this->encoding, CRED_PART_END);
! 490: }
! 491:
! 492:
! 493: METHOD(certificate_t, equals, bool,
! 494: private_openssl_x509_t *this, certificate_t *other)
! 495: {
! 496: chunk_t encoding;
! 497: bool equal;
! 498:
! 499: if (this == (private_openssl_x509_t*)other)
! 500: {
! 501: return TRUE;
! 502: }
! 503: if (other->get_type(other) != CERT_X509)
! 504: {
! 505: return FALSE;
! 506: }
! 507: if (other->equals == (void*)equals)
! 508: { /* skip allocation if we have the same implementation */
! 509: encoding = ((private_openssl_x509_t*)other)->encoding;
! 510: return chunk_equals(this->encoding, encoding);
! 511: }
! 512: if (!other->get_encoding(other, CERT_ASN1_DER, &encoding))
! 513: {
! 514: return FALSE;
! 515: }
! 516: equal = chunk_equals(this->encoding, encoding);
! 517: free(encoding.ptr);
! 518: return equal;
! 519: }
! 520:
! 521: METHOD(certificate_t, get_ref, certificate_t*,
! 522: private_openssl_x509_t *this)
! 523: {
! 524: ref_get(&this->ref);
! 525: return &this->public.x509.interface;
! 526: }
! 527:
! 528: METHOD(certificate_t, destroy, void,
! 529: private_openssl_x509_t *this)
! 530: {
! 531: if (ref_put(&this->ref))
! 532: {
! 533: if (this->x509)
! 534: {
! 535: X509_free(this->x509);
! 536: }
! 537: signature_params_destroy(this->scheme);
! 538: DESTROY_IF(this->subject);
! 539: DESTROY_IF(this->issuer);
! 540: DESTROY_IF(this->pubkey);
! 541: free(this->subjectKeyIdentifier.ptr);
! 542: free(this->authKeyIdentifier.ptr);
! 543: free(this->encoding.ptr);
! 544: free(this->hash.ptr);
! 545: this->subjectAltNames->destroy_offset(this->subjectAltNames,
! 546: offsetof(identification_t, destroy));
! 547: this->issuerAltNames->destroy_offset(this->issuerAltNames,
! 548: offsetof(identification_t, destroy));
! 549: this->crl_uris->destroy_function(this->crl_uris,
! 550: (void*)x509_cdp_destroy);
! 551: this->ocsp_uris->destroy_function(this->ocsp_uris, free);
! 552: this->ipAddrBlocks->destroy_offset(this->ipAddrBlocks,
! 553: offsetof(traffic_selector_t, destroy));
! 554: free(this);
! 555: }
! 556: }
! 557:
! 558: /**
! 559: * Create an empty certificate
! 560: */
! 561: static private_openssl_x509_t *create_empty()
! 562: {
! 563: private_openssl_x509_t *this;
! 564:
! 565: INIT(this,
! 566: .public = {
! 567: .x509 = {
! 568: .interface = {
! 569: .get_type = _get_type,
! 570: .get_subject = _get_subject,
! 571: .get_issuer = _get_issuer,
! 572: .has_subject = _has_subject,
! 573: .has_issuer = _has_issuer,
! 574: .issued_by = _issued_by,
! 575: .get_public_key = _get_public_key,
! 576: .get_validity = _get_validity,
! 577: .get_encoding = _get_encoding,
! 578: .equals = _equals,
! 579: .get_ref = _get_ref,
! 580: .destroy = _destroy,
! 581: },
! 582: .get_flags = _get_flags,
! 583: .get_serial = _get_serial,
! 584: .get_subjectKeyIdentifier = _get_subjectKeyIdentifier,
! 585: .get_authKeyIdentifier = _get_authKeyIdentifier,
! 586: .get_constraint = _get_constraint,
! 587: .create_subjectAltName_enumerator = _create_subjectAltName_enumerator,
! 588: .create_crl_uri_enumerator = _create_crl_uri_enumerator,
! 589: .create_ocsp_uri_enumerator = _create_ocsp_uri_enumerator,
! 590: .create_ipAddrBlock_enumerator = _create_ipAddrBlock_enumerator,
! 591: .create_name_constraint_enumerator = (void*)enumerator_create_empty,
! 592: .create_cert_policy_enumerator = (void*)enumerator_create_empty,
! 593: .create_policy_mapping_enumerator = (void*)enumerator_create_empty,
! 594: },
! 595: },
! 596: .subjectAltNames = linked_list_create(),
! 597: .issuerAltNames = linked_list_create(),
! 598: .crl_uris = linked_list_create(),
! 599: .ocsp_uris = linked_list_create(),
! 600: .ipAddrBlocks = linked_list_create(),
! 601: .pathlen = X509_NO_CONSTRAINT,
! 602: .ref = 1,
! 603: );
! 604:
! 605: return this;
! 606: }
! 607:
! 608: /**
! 609: * parse an extension containing GENERAL_NAMES into a list
! 610: */
! 611: static bool parse_generalNames_ext(linked_list_t *list,
! 612: X509_EXTENSION *ext)
! 613: {
! 614: GENERAL_NAMES *names;
! 615: GENERAL_NAME *name;
! 616: identification_t *id;
! 617: int i, num;
! 618:
! 619: names = X509V3_EXT_d2i(ext);
! 620: if (!names)
! 621: {
! 622: return FALSE;
! 623: }
! 624:
! 625: num = sk_GENERAL_NAME_num(names);
! 626: for (i = 0; i < num; i++)
! 627: {
! 628: name = sk_GENERAL_NAME_value(names, i);
! 629: id = general_name2id(name);
! 630: if (id)
! 631: {
! 632: list->insert_last(list, id);
! 633: }
! 634: GENERAL_NAME_free(name);
! 635: }
! 636: sk_GENERAL_NAME_free(names);
! 637: return TRUE;
! 638: }
! 639:
! 640: /**
! 641: * parse basic constraints
! 642: */
! 643: static bool parse_basicConstraints_ext(private_openssl_x509_t *this,
! 644: X509_EXTENSION *ext)
! 645: {
! 646: BASIC_CONSTRAINTS *constraints;
! 647: long pathlen;
! 648:
! 649: constraints = (BASIC_CONSTRAINTS*)X509V3_EXT_d2i(ext);
! 650: if (constraints)
! 651: {
! 652: if (constraints->ca)
! 653: {
! 654: this->flags |= X509_CA;
! 655: }
! 656: if (constraints->pathlen)
! 657: {
! 658:
! 659: pathlen = ASN1_INTEGER_get(constraints->pathlen);
! 660: this->pathlen = (pathlen >= 0 && pathlen < 128) ?
! 661: pathlen : X509_NO_CONSTRAINT;
! 662: }
! 663: BASIC_CONSTRAINTS_free(constraints);
! 664: return TRUE;
! 665: }
! 666: return FALSE;
! 667: }
! 668:
! 669: /**
! 670: * parse key usage
! 671: */
! 672: static bool parse_keyUsage_ext(private_openssl_x509_t *this,
! 673: X509_EXTENSION *ext)
! 674: {
! 675: ASN1_BIT_STRING *usage;
! 676:
! 677: /* to be compliant with RFC 4945 specific KUs have to be included */
! 678: this->flags &= ~X509_IKE_COMPLIANT;
! 679:
! 680: usage = X509V3_EXT_d2i(ext);
! 681: if (usage)
! 682: {
! 683: if (usage->length > 0)
! 684: {
! 685: int flags = usage->data[0];
! 686: if (usage->length > 1)
! 687: {
! 688: flags |= usage->data[1] << 8;
! 689: }
! 690: if (flags & X509v3_KU_CRL_SIGN)
! 691: {
! 692: this->flags |= X509_CRL_SIGN;
! 693: }
! 694: if (flags & X509v3_KU_DIGITAL_SIGNATURE ||
! 695: flags & X509v3_KU_NON_REPUDIATION)
! 696: {
! 697: this->flags |= X509_IKE_COMPLIANT;
! 698: }
! 699: if (flags & X509v3_KU_KEY_CERT_SIGN)
! 700: {
! 701: /* we use the caBasicConstraint, MUST be set */
! 702: }
! 703: }
! 704: ASN1_BIT_STRING_free(usage);
! 705: return TRUE;
! 706: }
! 707: return FALSE;
! 708: }
! 709:
! 710: /**
! 711: * Parse ExtendedKeyUsage
! 712: */
! 713: static bool parse_extKeyUsage_ext(private_openssl_x509_t *this,
! 714: X509_EXTENSION *ext)
! 715: {
! 716: EXTENDED_KEY_USAGE *usage;
! 717: int i;
! 718:
! 719: usage = X509V3_EXT_d2i(ext);
! 720: if (usage)
! 721: {
! 722: for (i = 0; i < sk_ASN1_OBJECT_num(usage); i++)
! 723: {
! 724: switch (OBJ_obj2nid(sk_ASN1_OBJECT_value(usage, i)))
! 725: {
! 726: case NID_server_auth:
! 727: this->flags |= X509_SERVER_AUTH;
! 728: break;
! 729: case NID_client_auth:
! 730: this->flags |= X509_CLIENT_AUTH;
! 731: break;
! 732: case NID_OCSP_sign:
! 733: this->flags |= X509_OCSP_SIGNER;
! 734: break;
! 735: default:
! 736: break;
! 737: }
! 738: }
! 739: sk_ASN1_OBJECT_pop_free(usage, ASN1_OBJECT_free);
! 740: return TRUE;
! 741: }
! 742: return FALSE;
! 743: }
! 744:
! 745: /**
! 746: * Parse CRL distribution points
! 747: */
! 748: bool openssl_parse_crlDistributionPoints(X509_EXTENSION *ext,
! 749: linked_list_t *list)
! 750: {
! 751: CRL_DIST_POINTS *cdps;
! 752: DIST_POINT *cdp;
! 753: identification_t *id, *issuer;
! 754: x509_cdp_t *entry;
! 755: char *uri;
! 756: int i, j, k, point_num, name_num, issuer_num, len;
! 757:
! 758: cdps = X509V3_EXT_d2i(ext);
! 759: if (!cdps)
! 760: {
! 761: return FALSE;
! 762: }
! 763: point_num = sk_DIST_POINT_num(cdps);
! 764: for (i = 0; i < point_num; i++)
! 765: {
! 766: cdp = sk_DIST_POINT_value(cdps, i);
! 767: if (cdp)
! 768: {
! 769: if (cdp->distpoint && cdp->distpoint->type == 0 &&
! 770: cdp->distpoint->name.fullname)
! 771: {
! 772: name_num = sk_GENERAL_NAME_num(cdp->distpoint->name.fullname);
! 773: for (j = 0; j < name_num; j++)
! 774: {
! 775: id = general_name2id(sk_GENERAL_NAME_value(
! 776: cdp->distpoint->name.fullname, j));
! 777: if (id)
! 778: {
! 779: len = asprintf(&uri, "%Y", id);
! 780: if (!len)
! 781: {
! 782: free(uri);
! 783: }
! 784: else if (len > 0)
! 785: {
! 786: if (cdp->CRLissuer)
! 787: {
! 788: issuer_num = sk_GENERAL_NAME_num(cdp->CRLissuer);
! 789: for (k = 0; k < issuer_num; k++)
! 790: {
! 791: issuer = general_name2id(
! 792: sk_GENERAL_NAME_value(cdp->CRLissuer, k));
! 793: if (issuer)
! 794: {
! 795: INIT(entry,
! 796: .uri = strdup(uri),
! 797: .issuer = issuer,
! 798: );
! 799: list->insert_last(list, entry);
! 800: }
! 801: }
! 802: free(uri);
! 803: }
! 804: else
! 805: {
! 806: INIT(entry,
! 807: .uri = uri,
! 808: );
! 809: list->insert_last(list, entry);
! 810: }
! 811: }
! 812: id->destroy(id);
! 813: }
! 814: }
! 815: }
! 816:
! 817: DIST_POINT_free(cdp);
! 818: }
! 819: }
! 820: sk_DIST_POINT_free(cdps);
! 821: return TRUE;
! 822: }
! 823:
! 824: /**
! 825: * Parse authorityInfoAccess with OCSP URIs
! 826: */
! 827: static bool parse_authorityInfoAccess_ext(private_openssl_x509_t *this,
! 828: X509_EXTENSION *ext)
! 829: {
! 830: AUTHORITY_INFO_ACCESS *infos;
! 831: ACCESS_DESCRIPTION *desc;
! 832: identification_t *id;
! 833: int i, num, len;
! 834: char *uri;
! 835:
! 836: infos = X509V3_EXT_d2i(ext);
! 837: if (!infos)
! 838: {
! 839: return FALSE;
! 840: }
! 841: num = sk_ACCESS_DESCRIPTION_num(infos);
! 842: for (i = 0; i < num; i++)
! 843: {
! 844: desc = sk_ACCESS_DESCRIPTION_value(infos, i);
! 845: if (desc)
! 846: {
! 847: if (openssl_asn1_known_oid(desc->method) == OID_OCSP)
! 848: {
! 849: id = general_name2id(desc->location);
! 850: if (id)
! 851: {
! 852: len = asprintf(&uri, "%Y", id);
! 853: if (!len)
! 854: {
! 855: free(uri);
! 856: }
! 857: else if (len > 0)
! 858: {
! 859: this->ocsp_uris->insert_last(this->ocsp_uris, uri);
! 860: }
! 861: id->destroy(id);
! 862: }
! 863: }
! 864: ACCESS_DESCRIPTION_free(desc);
! 865: }
! 866: }
! 867: sk_ACCESS_DESCRIPTION_free(infos);
! 868: return TRUE;
! 869: }
! 870:
! 871: #ifndef OPENSSL_NO_RFC3779
! 872:
! 873: /**
! 874: * Parse a single block of ipAddrBlock extension
! 875: */
! 876: static void parse_ipAddrBlock_ext_fam(private_openssl_x509_t *this,
! 877: IPAddressFamily *fam)
! 878: {
! 879: const IPAddressOrRanges *list;
! 880: IPAddressOrRange *aor;
! 881: traffic_selector_t *ts;
! 882: ts_type_t type;
! 883: chunk_t from, to;
! 884: int i, afi;
! 885:
! 886: if (fam->ipAddressChoice->type != IPAddressChoice_addressesOrRanges)
! 887: {
! 888: return;
! 889: }
! 890:
! 891: afi = X509v3_addr_get_afi(fam);
! 892: switch (afi)
! 893: {
! 894: case IANA_AFI_IPV4:
! 895: from = chunk_alloca(4);
! 896: to = chunk_alloca(4);
! 897: type = TS_IPV4_ADDR_RANGE;
! 898: break;
! 899: case IANA_AFI_IPV6:
! 900: from = chunk_alloca(16);
! 901: to = chunk_alloca(16);
! 902: type = TS_IPV6_ADDR_RANGE;
! 903: break;
! 904: default:
! 905: return;
! 906: }
! 907:
! 908: list = fam->ipAddressChoice->u.addressesOrRanges;
! 909: for (i = 0; i < sk_IPAddressOrRange_num(list); i++)
! 910: {
! 911: aor = sk_IPAddressOrRange_value(list, i);
! 912: if (X509v3_addr_get_range(aor, afi, from.ptr, to.ptr, from.len) > 0)
! 913: {
! 914: ts = traffic_selector_create_from_bytes(0, type, from, 0, to, 65535);
! 915: if (ts)
! 916: {
! 917: this->ipAddrBlocks->insert_last(this->ipAddrBlocks, ts);
! 918: }
! 919: }
! 920: }
! 921: }
! 922:
! 923: /**
! 924: * Parse ipAddrBlock extension
! 925: */
! 926: static bool parse_ipAddrBlock_ext(private_openssl_x509_t *this,
! 927: X509_EXTENSION *ext)
! 928: {
! 929: STACK_OF(IPAddressFamily) *blocks;
! 930: IPAddressFamily *fam;
! 931:
! 932: blocks = (STACK_OF(IPAddressFamily)*)X509V3_EXT_d2i(ext);
! 933: if (!blocks)
! 934: {
! 935: return FALSE;
! 936: }
! 937:
! 938: if (!X509v3_addr_is_canonical(blocks))
! 939: {
! 940: sk_IPAddressFamily_free(blocks);
! 941: return FALSE;
! 942: }
! 943:
! 944: while (sk_IPAddressFamily_num(blocks) > 0)
! 945: {
! 946: fam = sk_IPAddressFamily_pop(blocks);
! 947: parse_ipAddrBlock_ext_fam(this, fam);
! 948: IPAddressFamily_free(fam);
! 949: }
! 950: sk_IPAddressFamily_free(blocks);
! 951:
! 952: this->flags |= X509_IP_ADDR_BLOCKS;
! 953: return TRUE;
! 954: }
! 955: #endif /* !OPENSSL_NO_RFC3779 */
! 956:
! 957: /**
! 958: * Parse authorityKeyIdentifier extension
! 959: */
! 960: static bool parse_authKeyIdentifier_ext(private_openssl_x509_t *this,
! 961: X509_EXTENSION *ext)
! 962: {
! 963: AUTHORITY_KEYID *keyid;
! 964:
! 965: keyid = (AUTHORITY_KEYID*)X509V3_EXT_d2i(ext);
! 966: if (keyid)
! 967: {
! 968: free(this->authKeyIdentifier.ptr);
! 969: this->authKeyIdentifier = chunk_clone(
! 970: openssl_asn1_str2chunk(keyid->keyid));
! 971: AUTHORITY_KEYID_free(keyid);
! 972: return TRUE;
! 973: }
! 974: return FALSE;
! 975: }
! 976:
! 977: /**
! 978: * Parse subjectKeyIdentifier extension
! 979: */
! 980: static bool parse_subjectKeyIdentifier_ext(private_openssl_x509_t *this,
! 981: X509_EXTENSION *ext)
! 982: {
! 983: chunk_t ostr;
! 984:
! 985: ostr = openssl_asn1_str2chunk(X509_EXTENSION_get_data(ext));
! 986: /* quick and dirty unwrap of octet string */
! 987: if (ostr.len > 2 &&
! 988: ostr.ptr[0] == V_ASN1_OCTET_STRING && ostr.ptr[1] == ostr.len - 2)
! 989: {
! 990: free(this->subjectKeyIdentifier.ptr);
! 991: this->subjectKeyIdentifier = chunk_clone(chunk_skip(ostr, 2));
! 992: return TRUE;
! 993: }
! 994: return FALSE;
! 995: }
! 996:
! 997: /**
! 998: * Parse X509 extensions we are interested in
! 999: */
! 1000: static bool parse_extensions(private_openssl_x509_t *this)
! 1001: {
! 1002: const STACK_OF(X509_EXTENSION) *extensions;
! 1003: int i, num;
! 1004:
! 1005: /* unless we see a keyUsage extension we are compliant with RFC 4945 */
! 1006: this->flags |= X509_IKE_COMPLIANT;
! 1007:
! 1008: extensions = X509_get0_extensions(this->x509);
! 1009: if (extensions)
! 1010: {
! 1011: num = sk_X509_EXTENSION_num(extensions);
! 1012:
! 1013: for (i = 0; i < num; i++)
! 1014: {
! 1015: X509_EXTENSION *ext;
! 1016: bool ok;
! 1017:
! 1018: ext = sk_X509_EXTENSION_value(extensions, i);
! 1019: switch (OBJ_obj2nid(X509_EXTENSION_get_object(ext)))
! 1020: {
! 1021: case NID_info_access:
! 1022: ok = parse_authorityInfoAccess_ext(this, ext);
! 1023: break;
! 1024: case NID_authority_key_identifier:
! 1025: ok = parse_authKeyIdentifier_ext(this, ext);
! 1026: break;
! 1027: case NID_subject_key_identifier:
! 1028: ok = parse_subjectKeyIdentifier_ext(this, ext);
! 1029: break;
! 1030: case NID_subject_alt_name:
! 1031: ok = parse_generalNames_ext(this->subjectAltNames, ext);
! 1032: break;
! 1033: case NID_issuer_alt_name:
! 1034: ok = parse_generalNames_ext(this->issuerAltNames, ext);
! 1035: break;
! 1036: case NID_basic_constraints:
! 1037: ok = parse_basicConstraints_ext(this, ext);
! 1038: break;
! 1039: case NID_key_usage:
! 1040: ok = parse_keyUsage_ext(this, ext);
! 1041: break;
! 1042: case NID_ext_key_usage:
! 1043: ok = parse_extKeyUsage_ext(this, ext);
! 1044: break;
! 1045: case NID_crl_distribution_points:
! 1046: ok = openssl_parse_crlDistributionPoints(ext, this->crl_uris);
! 1047: break;
! 1048: #ifndef OPENSSL_NO_RFC3779
! 1049: case NID_sbgp_ipAddrBlock:
! 1050: ok = parse_ipAddrBlock_ext(this, ext);
! 1051: break;
! 1052: #endif /* !OPENSSL_NO_RFC3779 */
! 1053: default:
! 1054: ok = X509_EXTENSION_get_critical(ext) == 0 ||
! 1055: !lib->settings->get_bool(lib->settings,
! 1056: "%s.x509.enforce_critical", TRUE, lib->ns);
! 1057: if (!ok)
! 1058: {
! 1059: char buf[80] = "";
! 1060:
! 1061: OBJ_obj2txt(buf, sizeof(buf),
! 1062: X509_EXTENSION_get_object(ext), 0);
! 1063: DBG1(DBG_LIB, "found unsupported critical X.509 "
! 1064: "extension: %s", buf);
! 1065: }
! 1066: break;
! 1067: }
! 1068: if (!ok)
! 1069: {
! 1070: return FALSE;
! 1071: }
! 1072: }
! 1073: }
! 1074: return TRUE;
! 1075: }
! 1076:
! 1077: /**
! 1078: * Parse a DER encoded x509 certificate
! 1079: */
! 1080: static bool parse_certificate(private_openssl_x509_t *this)
! 1081: {
! 1082: const unsigned char *ptr = this->encoding.ptr;
! 1083: hasher_t *hasher;
! 1084: chunk_t chunk, sig_scheme, sig_scheme_tbs;
! 1085: ASN1_OBJECT *oid;
! 1086: #if OPENSSL_VERSION_NUMBER >= 0x10100000L
! 1087: const X509_ALGOR *alg;
! 1088: #else
! 1089: X509_ALGOR *alg;
! 1090: #endif
! 1091: key_type_t ed_type = KEY_ED448;
! 1092:
! 1093: this->x509 = d2i_X509(NULL, &ptr, this->encoding.len);
! 1094: if (!this->x509)
! 1095: {
! 1096: return FALSE;
! 1097: }
! 1098: if (X509_get_version(this->x509) < 0 || X509_get_version(this->x509) > 2)
! 1099: {
! 1100: DBG1(DBG_LIB, "unsupported x509 version: %d",
! 1101: X509_get_version(this->x509) + 1);
! 1102: return FALSE;
! 1103: }
! 1104:
! 1105: this->subject = openssl_x509_name2id(X509_get_subject_name(this->x509));
! 1106: this->issuer = openssl_x509_name2id(X509_get_issuer_name(this->x509));
! 1107:
! 1108: if (!X509_PUBKEY_get0_param(&oid, NULL, NULL, NULL,
! 1109: X509_get_X509_PUBKEY(this->x509)))
! 1110: {
! 1111: return FALSE;
! 1112: }
! 1113: switch (openssl_asn1_known_oid(oid))
! 1114: {
! 1115: case OID_RSASSA_PSS:
! 1116: /* TODO: we should treat such keys special and use the params as
! 1117: * restrictions regarding the use of this key (or rather the
! 1118: * associated private key) */
! 1119: case OID_RSA_ENCRYPTION:
! 1120: this->pubkey = lib->creds->create(lib->creds,
! 1121: CRED_PUBLIC_KEY, KEY_RSA, BUILD_BLOB_ASN1_DER,
! 1122: openssl_asn1_str2chunk(X509_get0_pubkey_bitstr(this->x509)),
! 1123: BUILD_END);
! 1124: break;
! 1125: case OID_EC_PUBLICKEY:
! 1126: /* for ECDSA, we need the full subjectPublicKeyInfo, as it contains
! 1127: * the curve parameters. */
! 1128: chunk = openssl_i2chunk(X509_PUBKEY, X509_get_X509_PUBKEY(this->x509));
! 1129: this->pubkey = lib->creds->create(lib->creds,
! 1130: CRED_PUBLIC_KEY, KEY_ECDSA, BUILD_BLOB_ASN1_DER,
! 1131: chunk, BUILD_END);
! 1132: free(chunk.ptr);
! 1133: break;
! 1134: case OID_ED25519:
! 1135: ed_type = KEY_ED25519;
! 1136: /* fall-through */
! 1137: case OID_ED448:
! 1138: /* for EdDSA, the parsers expect the full subjectPublicKeyInfo */
! 1139: chunk = openssl_i2chunk(X509_PUBKEY, X509_get_X509_PUBKEY(this->x509));
! 1140: this->pubkey = lib->creds->create(lib->creds,
! 1141: CRED_PUBLIC_KEY, ed_type, BUILD_BLOB_ASN1_DER,
! 1142: chunk, BUILD_END);
! 1143: free(chunk.ptr);
! 1144: break;
! 1145: default:
! 1146: DBG1(DBG_LIB, "unsupported public key algorithm");
! 1147: break;
! 1148: }
! 1149: if (!this->subject || !this->issuer || !this->pubkey)
! 1150: {
! 1151: return FALSE;
! 1152: }
! 1153:
! 1154: this->notBefore = openssl_asn1_to_time(X509_get0_notBefore(this->x509));
! 1155: this->notAfter = openssl_asn1_to_time(X509_get0_notAfter(this->x509));
! 1156:
! 1157: /* while X509_ALGOR_cmp() is declared in the headers of older OpenSSL
! 1158: * versions, at least on Ubuntu 14.04 it is not actually defined */
! 1159: X509_get0_signature(NULL, &alg, this->x509);
! 1160: sig_scheme = openssl_i2chunk(X509_ALGOR, (X509_ALGOR*)alg);
! 1161: alg = X509_get0_tbs_sigalg(this->x509);
! 1162: sig_scheme_tbs = openssl_i2chunk(X509_ALGOR, (X509_ALGOR*)alg);
! 1163: if (!chunk_equals(sig_scheme, sig_scheme_tbs))
! 1164: {
! 1165: free(sig_scheme_tbs.ptr);
! 1166: free(sig_scheme.ptr);
! 1167: return FALSE;
! 1168: }
! 1169: free(sig_scheme_tbs.ptr);
! 1170:
! 1171: INIT(this->scheme);
! 1172: if (!signature_params_parse(sig_scheme, 0, this->scheme))
! 1173: {
! 1174: DBG1(DBG_ASN, "unable to parse signature algorithm");
! 1175: free(sig_scheme.ptr);
! 1176: return FALSE;
! 1177: }
! 1178: free(sig_scheme.ptr);
! 1179:
! 1180: if (!parse_extensions(this))
! 1181: {
! 1182: return FALSE;
! 1183: }
! 1184:
! 1185: hasher = lib->crypto->create_hasher(lib->crypto, HASH_SHA1);
! 1186: if (!hasher || !hasher->allocate_hash(hasher, this->encoding, &this->hash))
! 1187: {
! 1188: DESTROY_IF(hasher);
! 1189: return FALSE;
! 1190: }
! 1191: hasher->destroy(hasher);
! 1192:
! 1193: if (issued_by(this, &this->public.x509.interface, NULL))
! 1194: {
! 1195: this->flags |= X509_SELF_SIGNED;
! 1196: }
! 1197: return TRUE;
! 1198: }
! 1199:
! 1200: openssl_x509_t *openssl_x509_load(certificate_type_t type, va_list args)
! 1201: {
! 1202: chunk_t blob = chunk_empty;
! 1203: x509_flag_t flags = 0;
! 1204:
! 1205: while (TRUE)
! 1206: {
! 1207: switch (va_arg(args, builder_part_t))
! 1208: {
! 1209: case BUILD_BLOB_ASN1_DER:
! 1210: blob = va_arg(args, chunk_t);
! 1211: continue;
! 1212: case BUILD_X509_FLAG:
! 1213: flags |= va_arg(args, x509_flag_t);
! 1214: continue;
! 1215: case BUILD_END:
! 1216: break;
! 1217: default:
! 1218: return NULL;
! 1219: }
! 1220: break;
! 1221: }
! 1222:
! 1223: if (blob.ptr)
! 1224: {
! 1225: private_openssl_x509_t *this;
! 1226:
! 1227: this = create_empty();
! 1228: this->encoding = chunk_clone(blob);
! 1229: this->flags |= flags;
! 1230: if (parse_certificate(this))
! 1231: {
! 1232: return &this->public;
! 1233: }
! 1234: DBG1(DBG_LIB, "OpenSSL X.509 parsing failed");
! 1235: destroy(this);
! 1236: }
! 1237: return NULL;
! 1238: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>