Annotation of embedaddon/strongswan/src/libstrongswan/plugins/openssl/openssl_crl.c, revision 1.1
1.1 ! misho 1: /*
! 2: * Copyright (C) 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) 2010 secunet Security Networks AG
! 21: * Copyright (C) 2010 Thomas Egerer
! 22: *
! 23: * Permission is hereby granted, free of charge, to any person obtaining a copy
! 24: * of this software and associated documentation files (the "Software"), to deal
! 25: * in the Software without restriction, including without limitation the rights
! 26: * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
! 27: * copies of the Software, and to permit persons to whom the Software is
! 28: * furnished to do so, subject to the following conditions:
! 29: *
! 30: * The above copyright notice and this permission notice shall be included in
! 31: * all copies or substantial portions of the Software.
! 32: *
! 33: * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
! 34: * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
! 35: * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
! 36: * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
! 37: * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
! 38: * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
! 39: * THE SOFTWARE.
! 40: */
! 41:
! 42: #include "openssl_crl.h"
! 43: #include "openssl_util.h"
! 44:
! 45: #include <openssl/x509.h>
! 46: #include <openssl/x509v3.h>
! 47:
! 48: #include <utils/debug.h>
! 49: #include <collections/enumerator.h>
! 50: #include <credentials/certificates/x509.h>
! 51:
! 52: #if OPENSSL_VERSION_NUMBER < 0x10100000L
! 53: static inline void X509_CRL_get0_signature(const X509_CRL *crl, ASN1_BIT_STRING **psig, X509_ALGOR **palg) {
! 54: if (psig) { *psig = crl->signature; }
! 55: if (palg) { *palg = crl->sig_alg; }
! 56: }
! 57: #define X509_REVOKED_get0_serialNumber(r) ({ (r)->serialNumber; })
! 58: #define X509_REVOKED_get0_revocationDate(r) ({ (r)->revocationDate; })
! 59: #define X509_CRL_get0_extensions(c) ({ (c)->crl->extensions; })
! 60: #define ASN1_STRING_get0_data(a) ASN1_STRING_data(a)
! 61: #define X509_CRL_get0_lastUpdate(c) X509_CRL_get_lastUpdate(c)
! 62: #define X509_CRL_get0_nextUpdate(c) X509_CRL_get_nextUpdate(c)
! 63: #endif
! 64:
! 65: typedef struct private_openssl_crl_t private_openssl_crl_t;
! 66:
! 67: /**
! 68: * Private data of an openssl_crl_t object.
! 69: */
! 70: struct private_openssl_crl_t {
! 71:
! 72: /**
! 73: * Public openssl_crl_t interface.
! 74: */
! 75: openssl_crl_t public;
! 76:
! 77: /**
! 78: * OpenSSL representation of a CRL
! 79: */
! 80: X509_CRL *crl;
! 81:
! 82: /**
! 83: * DER encoding of the CRL
! 84: */
! 85: chunk_t encoding;
! 86:
! 87: /**
! 88: * Serial Number (crlNumber) of the CRL)
! 89: */
! 90: chunk_t serial;
! 91:
! 92: /**
! 93: * Number of base CRL (deltaCrlIndicator), if a delta CRL
! 94: */
! 95: chunk_t base;
! 96:
! 97: /**
! 98: * List of Freshest CRL distribution points
! 99: */
! 100: linked_list_t *crl_uris;
! 101:
! 102: /**
! 103: * AuthorityKeyIdentifier of the issuing CA
! 104: */
! 105: chunk_t authKeyIdentifier;
! 106:
! 107: /**
! 108: * Date of this CRL
! 109: */
! 110: time_t thisUpdate;
! 111:
! 112: /**
! 113: * Date of next CRL expected
! 114: */
! 115: time_t nextUpdate;
! 116:
! 117: /**
! 118: * Issuer of this CRL
! 119: */
! 120: identification_t *issuer;
! 121:
! 122: /**
! 123: * Signature scheme used in this CRL
! 124: */
! 125: signature_params_t *scheme;
! 126:
! 127: /**
! 128: * References to this CRL
! 129: */
! 130: refcount_t ref;
! 131: };
! 132:
! 133: /**
! 134: * Enumerator over revoked certificates
! 135: */
! 136: typedef struct {
! 137: /**
! 138: * Implements enumerator_t
! 139: */
! 140: enumerator_t public;
! 141:
! 142: /**
! 143: * stack of revoked certificates
! 144: */
! 145: STACK_OF(X509_REVOKED) *stack;
! 146:
! 147: /**
! 148: * Total number of revoked certificates
! 149: */
! 150: int num;
! 151:
! 152: /**
! 153: * Current position of enumerator
! 154: */
! 155: int i;
! 156: } crl_enumerator_t;
! 157:
! 158: /**
! 159: * from openssl_x509
! 160: */
! 161: bool openssl_parse_crlDistributionPoints(X509_EXTENSION *ext,
! 162: linked_list_t *list);
! 163:
! 164: METHOD(enumerator_t, crl_enumerate, bool,
! 165: crl_enumerator_t *this, va_list args)
! 166: {
! 167: crl_reason_t *reason;
! 168: chunk_t *serial;
! 169: time_t *date;
! 170:
! 171: VA_ARGS_VGET(args, serial, date, reason);
! 172:
! 173: if (this->i < this->num)
! 174: {
! 175: X509_REVOKED *revoked;
! 176: ASN1_ENUMERATED *crlrsn;
! 177:
! 178: revoked = sk_X509_REVOKED_value(this->stack, this->i);
! 179: if (serial)
! 180: {
! 181: *serial = openssl_asn1_str2chunk(
! 182: X509_REVOKED_get0_serialNumber(revoked));
! 183: }
! 184: if (date)
! 185: {
! 186: *date = openssl_asn1_to_time(
! 187: X509_REVOKED_get0_revocationDate(revoked));
! 188: }
! 189: if (reason)
! 190: {
! 191: *reason = CRL_REASON_UNSPECIFIED;
! 192: crlrsn = X509_REVOKED_get_ext_d2i(revoked, NID_crl_reason,
! 193: NULL, NULL);
! 194: if (crlrsn)
! 195: {
! 196: if (ASN1_STRING_type(crlrsn) == V_ASN1_ENUMERATED &&
! 197: ASN1_STRING_length(crlrsn) == 1)
! 198: {
! 199: *reason = *ASN1_STRING_get0_data(crlrsn);
! 200: }
! 201: ASN1_STRING_free(crlrsn);
! 202: }
! 203: }
! 204: this->i++;
! 205: return TRUE;
! 206: }
! 207: return FALSE;
! 208: }
! 209:
! 210: METHOD(crl_t, create_enumerator, enumerator_t*,
! 211: private_openssl_crl_t *this)
! 212: {
! 213: crl_enumerator_t *enumerator;
! 214:
! 215: INIT(enumerator,
! 216: .public = {
! 217: .enumerate = enumerator_enumerate_default,
! 218: .venumerate = _crl_enumerate,
! 219: .destroy = (void*)free,
! 220: },
! 221: .stack = X509_CRL_get_REVOKED(this->crl),
! 222: );
! 223: if (!enumerator->stack)
! 224: {
! 225: free(enumerator);
! 226: return enumerator_create_empty();
! 227: }
! 228: enumerator->num = sk_X509_REVOKED_num(enumerator->stack);
! 229: return &enumerator->public;
! 230: }
! 231:
! 232: METHOD(crl_t, get_serial, chunk_t,
! 233: private_openssl_crl_t *this)
! 234: {
! 235: return this->serial;
! 236: }
! 237:
! 238: METHOD(crl_t, is_delta_crl, bool,
! 239: private_openssl_crl_t *this, chunk_t *base_crl)
! 240: {
! 241: if (this->base.len)
! 242: {
! 243: if (base_crl)
! 244: {
! 245: *base_crl = this->base;
! 246: }
! 247: return TRUE;
! 248: }
! 249: return FALSE;
! 250: }
! 251:
! 252: METHOD(crl_t, create_delta_crl_uri_enumerator, enumerator_t*,
! 253: private_openssl_crl_t *this)
! 254: {
! 255: return this->crl_uris->create_enumerator(this->crl_uris);
! 256: }
! 257:
! 258: METHOD(crl_t, get_authKeyIdentifier, chunk_t,
! 259: private_openssl_crl_t *this)
! 260: {
! 261: return this->authKeyIdentifier;
! 262: }
! 263:
! 264: METHOD(certificate_t, get_type, certificate_type_t,
! 265: private_openssl_crl_t *this)
! 266: {
! 267: return CERT_X509_CRL;
! 268: }
! 269:
! 270: METHOD(certificate_t, get_subject_or_issuer, identification_t*,
! 271: private_openssl_crl_t *this)
! 272: {
! 273: return this->issuer;
! 274: }
! 275:
! 276: METHOD(certificate_t, has_subject_or_issuer, id_match_t,
! 277: private_openssl_crl_t *this, identification_t *id)
! 278: {
! 279: if (id->get_type(id) == ID_KEY_ID &&
! 280: chunk_equals(this->authKeyIdentifier, id->get_encoding(id)))
! 281: {
! 282: return ID_MATCH_PERFECT;
! 283: }
! 284: return this->issuer->matches(this->issuer, id);
! 285: }
! 286:
! 287: METHOD(certificate_t, issued_by, bool,
! 288: private_openssl_crl_t *this, certificate_t *issuer,
! 289: signature_params_t **scheme)
! 290: {
! 291: chunk_t fingerprint, tbs;
! 292: public_key_t *key;
! 293: x509_t *x509;
! 294: #if OPENSSL_VERSION_NUMBER >= 0x10100000L
! 295: const ASN1_BIT_STRING *sig;
! 296: #else
! 297: ASN1_BIT_STRING *sig;
! 298: #endif
! 299: bool valid;
! 300:
! 301: if (issuer->get_type(issuer) != CERT_X509)
! 302: {
! 303: return FALSE;
! 304: }
! 305: x509 = (x509_t*)issuer;
! 306: if (!(x509->get_flags(x509) & X509_CA))
! 307: {
! 308: return FALSE;
! 309: }
! 310: key = issuer->get_public_key(issuer);
! 311: if (!key)
! 312: {
! 313: return FALSE;
! 314: }
! 315: if (this->authKeyIdentifier.ptr && key)
! 316: {
! 317: if (!key->get_fingerprint(key, KEYID_PUBKEY_SHA1, &fingerprint) ||
! 318: !chunk_equals(fingerprint, this->authKeyIdentifier))
! 319: {
! 320: return FALSE;
! 321: }
! 322: }
! 323: else
! 324: {
! 325: if (!this->issuer->equals(this->issuer, issuer->get_subject(issuer)))
! 326: {
! 327: return FALSE;
! 328: }
! 329: }
! 330: /* i2d_re_X509_CRL_tbs() was added with 1.1.0 when X509_CRL became opaque */
! 331: #if OPENSSL_VERSION_NUMBER >= 0x10100000L
! 332: tbs = openssl_i2chunk(re_X509_CRL_tbs, this->crl);
! 333: #else
! 334: tbs = openssl_i2chunk(X509_CRL_INFO, this->crl->crl);
! 335: #endif
! 336: X509_CRL_get0_signature(this->crl, &sig, NULL);
! 337: valid = key->verify(key, this->scheme->scheme, this->scheme->params, tbs,
! 338: openssl_asn1_str2chunk(sig));
! 339: free(tbs.ptr);
! 340: key->destroy(key);
! 341: if (valid && scheme)
! 342: {
! 343: *scheme = signature_params_clone(this->scheme);
! 344: }
! 345: return valid;
! 346: }
! 347:
! 348: METHOD(certificate_t, get_public_key, public_key_t*,
! 349: private_openssl_crl_t *this)
! 350: {
! 351: return NULL;
! 352: }
! 353:
! 354: METHOD(certificate_t, get_validity, bool,
! 355: private_openssl_crl_t *this,
! 356: time_t *when, time_t *not_before, time_t *not_after)
! 357: {
! 358: time_t t = when ? *when : time(NULL);
! 359:
! 360: if (not_before)
! 361: {
! 362: *not_before = this->thisUpdate;
! 363: }
! 364: if (not_after)
! 365: {
! 366: *not_after = this->nextUpdate;
! 367: }
! 368: return (t >= this->thisUpdate && t <= this->nextUpdate);
! 369: }
! 370:
! 371: METHOD(certificate_t, get_encoding, bool,
! 372: private_openssl_crl_t *this, cred_encoding_type_t type, chunk_t *encoding)
! 373: {
! 374: if (type == CERT_ASN1_DER)
! 375: {
! 376: *encoding = chunk_clone(this->encoding);
! 377: return TRUE;
! 378: }
! 379: return lib->encoding->encode(lib->encoding, type, NULL, encoding,
! 380: CRED_PART_X509_CRL_ASN1_DER, this->encoding, CRED_PART_END);
! 381: }
! 382:
! 383: METHOD(certificate_t, equals, bool,
! 384: private_openssl_crl_t *this, certificate_t *other)
! 385: {
! 386: chunk_t encoding;
! 387: bool equal;
! 388:
! 389: if (&this->public.crl.certificate == other)
! 390: {
! 391: return TRUE;
! 392: }
! 393: if (other->equals == (void*)equals)
! 394: { /* skip allocation if we have the same implementation */
! 395: return chunk_equals(this->encoding,
! 396: ((private_openssl_crl_t*)other)->encoding);
! 397: }
! 398: if (!other->get_encoding(other, CERT_ASN1_DER, &encoding))
! 399: {
! 400: return FALSE;
! 401: }
! 402: equal = chunk_equals(this->encoding, encoding);
! 403: free(encoding.ptr);
! 404: return equal;
! 405: }
! 406:
! 407: METHOD(certificate_t, get_ref, certificate_t*,
! 408: private_openssl_crl_t *this)
! 409: {
! 410: ref_get(&this->ref);
! 411: return &this->public.crl.certificate;
! 412: }
! 413:
! 414: METHOD(certificate_t, destroy, void,
! 415: private_openssl_crl_t *this)
! 416: {
! 417: if (ref_put(&this->ref))
! 418: {
! 419: if (this->crl)
! 420: {
! 421: X509_CRL_free(this->crl);
! 422: }
! 423: signature_params_destroy(this->scheme);
! 424: this->crl_uris->destroy_function(this->crl_uris,
! 425: (void*)x509_cdp_destroy);
! 426: DESTROY_IF(this->issuer);
! 427: free(this->authKeyIdentifier.ptr);
! 428: free(this->base.ptr);
! 429: free(this->serial.ptr);
! 430: free(this->encoding.ptr);
! 431: free(this);
! 432: }
! 433: }
! 434:
! 435: /**
! 436: * Create an empty CRL.
! 437: */
! 438: static private_openssl_crl_t *create_empty()
! 439: {
! 440: private_openssl_crl_t *this;
! 441:
! 442: INIT(this,
! 443: .public = {
! 444: .crl = {
! 445: .certificate = {
! 446: .get_type = _get_type,
! 447: .get_subject = _get_subject_or_issuer,
! 448: .get_issuer = _get_subject_or_issuer,
! 449: .has_subject = _has_subject_or_issuer,
! 450: .has_issuer = _has_subject_or_issuer,
! 451: .issued_by = _issued_by,
! 452: .get_public_key = _get_public_key,
! 453: .get_validity = _get_validity,
! 454: .get_encoding = _get_encoding,
! 455: .equals = _equals,
! 456: .get_ref = _get_ref,
! 457: .destroy = _destroy,
! 458: },
! 459: .get_serial = _get_serial,
! 460: .get_authKeyIdentifier = _get_authKeyIdentifier,
! 461: .is_delta_crl = _is_delta_crl,
! 462: .create_delta_crl_uri_enumerator = _create_delta_crl_uri_enumerator,
! 463: .create_enumerator = _create_enumerator,
! 464: },
! 465: },
! 466: .crl_uris = linked_list_create(),
! 467: .ref = 1,
! 468: );
! 469: return this;
! 470: }
! 471:
! 472: /**
! 473: * Parse the authKeyIdentifier extension
! 474: */
! 475: static bool parse_authKeyIdentifier_ext(private_openssl_crl_t *this,
! 476: X509_EXTENSION *ext)
! 477: {
! 478: AUTHORITY_KEYID *keyid;
! 479:
! 480: keyid = (AUTHORITY_KEYID *)X509V3_EXT_d2i(ext);
! 481: if (keyid)
! 482: {
! 483: free(this->authKeyIdentifier.ptr);
! 484: this->authKeyIdentifier = chunk_clone(
! 485: openssl_asn1_str2chunk(keyid->keyid));
! 486: AUTHORITY_KEYID_free(keyid);
! 487: return TRUE;
! 488: }
! 489: return FALSE;
! 490: }
! 491:
! 492: /**
! 493: * Quick and dirty INTEGER unwrap for crlNumber/deltaCrlIndicator extensions
! 494: */
! 495: static bool parse_integer_ext(X509_EXTENSION *ext, chunk_t *out)
! 496: {
! 497: chunk_t chunk;
! 498:
! 499: chunk = openssl_asn1_str2chunk(X509_EXTENSION_get_data(ext));
! 500: if (chunk.len > 1 && chunk.ptr[0] == V_ASN1_INTEGER &&
! 501: chunk.ptr[1] == chunk.len - 2)
! 502: {
! 503: chunk = chunk_skip(chunk, 2);
! 504: free(out->ptr);
! 505: *out = chunk_clone(chunk);
! 506: return TRUE;
! 507: }
! 508: return FALSE;
! 509: }
! 510:
! 511: /**
! 512: * Parse X509 CRL extensions
! 513: */
! 514: static bool parse_extensions(private_openssl_crl_t *this)
! 515: {
! 516: bool ok;
! 517: int i, num;
! 518: X509_EXTENSION *ext;
! 519: const STACK_OF(X509_EXTENSION) *extensions;
! 520:
! 521: extensions = X509_CRL_get0_extensions(this->crl);
! 522: if (extensions)
! 523: {
! 524: num = sk_X509_EXTENSION_num(extensions);
! 525: for (i = 0; i < num; ++i)
! 526: {
! 527: ext = sk_X509_EXTENSION_value(extensions, i);
! 528:
! 529: switch (OBJ_obj2nid(X509_EXTENSION_get_object(ext)))
! 530: {
! 531: case NID_authority_key_identifier:
! 532: ok = parse_authKeyIdentifier_ext(this, ext);
! 533: break;
! 534: case NID_crl_number:
! 535: ok = parse_integer_ext(ext, &this->serial);
! 536: break;
! 537: case NID_delta_crl:
! 538: ok = parse_integer_ext(ext, &this->base);
! 539: break;
! 540: case NID_freshest_crl:
! 541: ok = openssl_parse_crlDistributionPoints(ext, this->crl_uris);
! 542: break;
! 543: case NID_issuing_distribution_point:
! 544: /* TODO support of IssuingDistributionPoints */
! 545: ok = TRUE;
! 546: break;
! 547: default:
! 548: ok = X509_EXTENSION_get_critical(ext) == 0 ||
! 549: !lib->settings->get_bool(lib->settings,
! 550: "%s.x509.enforce_critical", TRUE, lib->ns);
! 551: if (!ok)
! 552: {
! 553: DBG1(DBG_LIB, "found unsupported critical X.509 "
! 554: "CRL extension");
! 555: }
! 556: break;
! 557: }
! 558: if (!ok)
! 559: {
! 560: return FALSE;
! 561: }
! 562: }
! 563: }
! 564: return TRUE;
! 565: }
! 566:
! 567: /**
! 568: * Parse a X509 CRL
! 569: */
! 570: static bool parse_crl(private_openssl_crl_t *this)
! 571: {
! 572: const unsigned char *ptr = this->encoding.ptr;
! 573: chunk_t sig_scheme;
! 574: #if OPENSSL_VERSION_NUMBER >= 0x10100000L
! 575: const X509_ALGOR *alg;
! 576: #else
! 577: X509_ALGOR *alg;
! 578: #endif
! 579:
! 580: this->crl = d2i_X509_CRL(NULL, &ptr, this->encoding.len);
! 581: if (!this->crl)
! 582: {
! 583: return FALSE;
! 584: }
! 585:
! 586: X509_CRL_get0_signature(this->crl, NULL, &alg);
! 587: sig_scheme = openssl_i2chunk(X509_ALGOR, (X509_ALGOR*)alg);
! 588: INIT(this->scheme);
! 589: if (!signature_params_parse(sig_scheme, 0, this->scheme))
! 590: {
! 591: DBG1(DBG_ASN, "unable to parse signature algorithm");
! 592: free(sig_scheme.ptr);
! 593: return FALSE;
! 594: }
! 595: free(sig_scheme.ptr);
! 596:
! 597: this->issuer = openssl_x509_name2id(X509_CRL_get_issuer(this->crl));
! 598: if (!this->issuer)
! 599: {
! 600: return FALSE;
! 601: }
! 602: this->thisUpdate = openssl_asn1_to_time(X509_CRL_get0_lastUpdate(this->crl));
! 603: this->nextUpdate = openssl_asn1_to_time(X509_CRL_get0_nextUpdate(this->crl));
! 604:
! 605: return parse_extensions(this);
! 606: }
! 607:
! 608: /**
! 609: * Load the CRL.
! 610: */
! 611: openssl_crl_t *openssl_crl_load(certificate_type_t type, va_list args)
! 612: {
! 613: chunk_t blob = chunk_empty;
! 614:
! 615: while (TRUE)
! 616: {
! 617: switch (va_arg(args, builder_part_t))
! 618: {
! 619: case BUILD_BLOB_ASN1_DER:
! 620: blob = va_arg(args, chunk_t);
! 621: continue;
! 622: case BUILD_END:
! 623: break;
! 624: default:
! 625: return NULL;
! 626: }
! 627: break;
! 628: }
! 629: if (blob.ptr)
! 630: {
! 631: private_openssl_crl_t *this = create_empty();
! 632:
! 633: this->encoding = chunk_clone(blob);
! 634: if (parse_crl(this))
! 635: {
! 636: return &this->public;
! 637: }
! 638: destroy(this);
! 639: }
! 640: return NULL;
! 641: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>