Annotation of embedaddon/strongswan/src/libstrongswan/plugins/x509/x509_crl.c, revision 1.1
1.1 ! misho 1: /*
! 2: * Copyright (C) 2014-2017 Tobias Brunner
! 3: * Copyright (C) 2008-2009 Martin Willi
! 4: * Copyright (C) 2017 Andreas Steffen
! 5: * HSR Hochschule fuer Technik Rapperswil
! 6: *
! 7: * This program is free software; you can redistribute it and/or modify it
! 8: * under the terms of the GNU General Public License as published by the
! 9: * Free Software Foundation; either version 2 of the License, or (at your
! 10: * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
! 11: *
! 12: * This program is distributed in the hope that it will be useful, but
! 13: * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
! 14: * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
! 15: * for more details.
! 16: */
! 17:
! 18: #include "x509_crl.h"
! 19:
! 20: typedef struct private_x509_crl_t private_x509_crl_t;
! 21: typedef struct revoked_t revoked_t;
! 22:
! 23: #include <time.h>
! 24:
! 25: #include <utils/debug.h>
! 26: #include <library.h>
! 27: #include <asn1/oid.h>
! 28: #include <asn1/asn1.h>
! 29: #include <asn1/asn1_parser.h>
! 30: #include <credentials/certificates/x509.h>
! 31: #include <credentials/keys/private_key.h>
! 32: #include <collections/linked_list.h>
! 33:
! 34: /**
! 35: * entry for a revoked certificate
! 36: */
! 37: struct revoked_t {
! 38: /**
! 39: * serial of the revoked certificate
! 40: */
! 41: chunk_t serial;
! 42:
! 43: /**
! 44: * date of revocation
! 45: */
! 46: time_t date;
! 47:
! 48: /**
! 49: * reason for revocation
! 50: */
! 51: crl_reason_t reason;
! 52: };
! 53:
! 54: /**
! 55: * private data of x509_crl
! 56: */
! 57: struct private_x509_crl_t {
! 58:
! 59: /**
! 60: * public functions
! 61: */
! 62: x509_crl_t public;
! 63:
! 64: /**
! 65: * X.509 crl encoding in ASN.1 DER format
! 66: */
! 67: chunk_t encoding;
! 68:
! 69: /**
! 70: * X.509 crl body over which signature is computed
! 71: */
! 72: chunk_t tbsCertList;
! 73:
! 74: /**
! 75: * Version of the X.509 crl
! 76: */
! 77: u_int version;
! 78:
! 79: /**
! 80: * ID representing the crl issuer
! 81: */
! 82: identification_t *issuer;
! 83:
! 84: /**
! 85: * CRL number
! 86: */
! 87: chunk_t crlNumber;
! 88:
! 89: /**
! 90: * Time when the crl was generated
! 91: */
! 92: time_t thisUpdate;
! 93:
! 94: /**
! 95: * Time when an update crl will be available
! 96: */
! 97: time_t nextUpdate;
! 98:
! 99: /**
! 100: * list of revoked certificates as revoked_t
! 101: */
! 102: linked_list_t *revoked;
! 103:
! 104: /**
! 105: * List of Freshest CRL distribution points
! 106: */
! 107: linked_list_t *crl_uris;
! 108:
! 109: /**
! 110: * Authority Key Identifier
! 111: */
! 112: chunk_t authKeyIdentifier;
! 113:
! 114: /**
! 115: * Authority Key Serial Number
! 116: */
! 117: chunk_t authKeySerialNumber;
! 118:
! 119: /**
! 120: * Optional OID of an [unsupported] critical extension
! 121: */
! 122: chunk_t critical_extension_oid;
! 123:
! 124: /**
! 125: * Number of BaseCRL, if a delta CRL
! 126: */
! 127: chunk_t baseCrlNumber;
! 128:
! 129: /**
! 130: * Signature scheme
! 131: */
! 132: signature_params_t *scheme;
! 133:
! 134: /**
! 135: * Signature
! 136: */
! 137: chunk_t signature;
! 138:
! 139: /**
! 140: * has this CRL been generated
! 141: */
! 142: bool generated;
! 143:
! 144: /**
! 145: * reference counter
! 146: */
! 147: refcount_t ref;
! 148: };
! 149:
! 150: /**
! 151: * from x509_cert
! 152: */
! 153: extern chunk_t x509_parse_authorityKeyIdentifier(chunk_t blob, int level0,
! 154: chunk_t *authKeySerialNumber);
! 155:
! 156: /**
! 157: * from x509_cert
! 158: */
! 159: extern bool x509_parse_crlDistributionPoints(chunk_t blob, int level0,
! 160: linked_list_t *list);
! 161:
! 162: /**
! 163: * from x509_cert
! 164: */
! 165: extern chunk_t x509_build_crlDistributionPoints(linked_list_t *list, int extn);
! 166:
! 167: /**
! 168: * ASN.1 definition of an X.509 certificate revocation list
! 169: */
! 170: static const asn1Object_t crlObjects[] = {
! 171: { 0, "certificateList", ASN1_SEQUENCE, ASN1_OBJ }, /* 0 */
! 172: { 1, "tbsCertList", ASN1_SEQUENCE, ASN1_OBJ }, /* 1 */
! 173: { 2, "version", ASN1_INTEGER, ASN1_OPT |
! 174: ASN1_BODY }, /* 2 */
! 175: { 2, "end opt", ASN1_EOC, ASN1_END }, /* 3 */
! 176: { 2, "signature", ASN1_EOC, ASN1_RAW }, /* 4 */
! 177: { 2, "issuer", ASN1_SEQUENCE, ASN1_OBJ }, /* 5 */
! 178: { 2, "thisUpdate", ASN1_EOC, ASN1_RAW }, /* 6 */
! 179: { 2, "nextUpdate", ASN1_EOC, ASN1_RAW }, /* 7 */
! 180: { 2, "revokedCertificates", ASN1_SEQUENCE, ASN1_OPT |
! 181: ASN1_LOOP }, /* 8 */
! 182: { 3, "certList", ASN1_SEQUENCE, ASN1_NONE }, /* 9 */
! 183: { 4, "userCertificate", ASN1_INTEGER, ASN1_BODY }, /* 10 */
! 184: { 4, "revocationDate", ASN1_EOC, ASN1_RAW }, /* 11 */
! 185: { 4, "crlEntryExtensions", ASN1_SEQUENCE, ASN1_OPT |
! 186: ASN1_LOOP }, /* 12 */
! 187: { 5, "extension", ASN1_SEQUENCE, ASN1_NONE }, /* 13 */
! 188: { 6, "extnID", ASN1_OID, ASN1_BODY }, /* 14 */
! 189: { 6, "critical", ASN1_BOOLEAN, ASN1_DEF |
! 190: ASN1_BODY }, /* 15 */
! 191: { 6, "extnValue", ASN1_OCTET_STRING, ASN1_BODY }, /* 16 */
! 192: { 4, "end opt or loop", ASN1_EOC, ASN1_END }, /* 17 */
! 193: { 2, "end opt or loop", ASN1_EOC, ASN1_END }, /* 18 */
! 194: { 2, "optional extensions", ASN1_CONTEXT_C_0, ASN1_OPT }, /* 19 */
! 195: { 3, "crlExtensions", ASN1_SEQUENCE, ASN1_LOOP }, /* 20 */
! 196: { 4, "extension", ASN1_SEQUENCE, ASN1_NONE }, /* 21 */
! 197: { 5, "extnID", ASN1_OID, ASN1_BODY }, /* 22 */
! 198: { 5, "critical", ASN1_BOOLEAN, ASN1_DEF |
! 199: ASN1_BODY }, /* 23 */
! 200: { 5, "extnValue", ASN1_OCTET_STRING, ASN1_BODY }, /* 24 */
! 201: { 3, "end loop", ASN1_EOC, ASN1_END }, /* 25 */
! 202: { 2, "end opt", ASN1_EOC, ASN1_END }, /* 26 */
! 203: { 1, "signatureAlgorithm", ASN1_EOC, ASN1_RAW }, /* 27 */
! 204: { 1, "signatureValue", ASN1_BIT_STRING, ASN1_BODY }, /* 28 */
! 205: { 0, "exit", ASN1_EOC, ASN1_EXIT }
! 206: };
! 207: #define CRL_OBJ_TBS_CERT_LIST 1
! 208: #define CRL_OBJ_VERSION 2
! 209: #define CRL_OBJ_SIG_ALG 4
! 210: #define CRL_OBJ_ISSUER 5
! 211: #define CRL_OBJ_THIS_UPDATE 6
! 212: #define CRL_OBJ_NEXT_UPDATE 7
! 213: #define CRL_OBJ_USER_CERTIFICATE 10
! 214: #define CRL_OBJ_REVOCATION_DATE 11
! 215: #define CRL_OBJ_CRL_ENTRY_EXTN_ID 14
! 216: #define CRL_OBJ_CRL_ENTRY_CRITICAL 15
! 217: #define CRL_OBJ_CRL_ENTRY_EXTN_VALUE 16
! 218: #define CRL_OBJ_EXTN_ID 22
! 219: #define CRL_OBJ_CRITICAL 23
! 220: #define CRL_OBJ_EXTN_VALUE 24
! 221: #define CRL_OBJ_ALGORITHM 27
! 222: #define CRL_OBJ_SIGNATURE 28
! 223:
! 224: /**
! 225: * Parses an X.509 Certificate Revocation List (CRL)
! 226: */
! 227: static bool parse(private_x509_crl_t *this)
! 228: {
! 229: asn1_parser_t *parser;
! 230: chunk_t object;
! 231: chunk_t extnID = chunk_empty;
! 232: chunk_t userCertificate = chunk_empty;
! 233: int objectID;
! 234: signature_params_t sig_alg = {};
! 235: bool success = FALSE;
! 236: bool critical = FALSE;
! 237: revoked_t *revoked = NULL;
! 238:
! 239: parser = asn1_parser_create(crlObjects, this->encoding);
! 240:
! 241: while (parser->iterate(parser, &objectID, &object))
! 242: {
! 243: u_int level = parser->get_level(parser)+1;
! 244:
! 245: switch (objectID)
! 246: {
! 247: case CRL_OBJ_TBS_CERT_LIST:
! 248: this->tbsCertList = object;
! 249: break;
! 250: case CRL_OBJ_VERSION:
! 251: this->version = (object.len) ? (1+(u_int)*object.ptr) : 1;
! 252: DBG2(DBG_ASN, " v%d", this->version);
! 253: break;
! 254: case CRL_OBJ_SIG_ALG:
! 255: if (!signature_params_parse(object, level, &sig_alg))
! 256: {
! 257: DBG1(DBG_ASN, " unable to parse signature algorithm");
! 258: goto end;
! 259: }
! 260: break;
! 261: case CRL_OBJ_ISSUER:
! 262: this->issuer = identification_create_from_encoding(ID_DER_ASN1_DN, object);
! 263: DBG2(DBG_ASN, " '%Y'", this->issuer);
! 264: break;
! 265: case CRL_OBJ_THIS_UPDATE:
! 266: this->thisUpdate = asn1_parse_time(object, level);
! 267: break;
! 268: case CRL_OBJ_NEXT_UPDATE:
! 269: this->nextUpdate = asn1_parse_time(object, level);
! 270: break;
! 271: case CRL_OBJ_USER_CERTIFICATE:
! 272: userCertificate = object;
! 273: break;
! 274: case CRL_OBJ_REVOCATION_DATE:
! 275: revoked = malloc_thing(revoked_t);
! 276: revoked->serial = chunk_clone(userCertificate);
! 277: revoked->date = asn1_parse_time(object, level);
! 278: revoked->reason = CRL_REASON_UNSPECIFIED;
! 279: this->revoked->insert_last(this->revoked, (void *)revoked);
! 280: break;
! 281: case CRL_OBJ_CRL_ENTRY_EXTN_ID:
! 282: case CRL_OBJ_EXTN_ID:
! 283: extnID = object;
! 284: break;
! 285: case CRL_OBJ_CRL_ENTRY_CRITICAL:
! 286: case CRL_OBJ_CRITICAL:
! 287: critical = object.len && *object.ptr;
! 288: DBG2(DBG_ASN, " %s", critical ? "TRUE" : "FALSE");
! 289: break;
! 290: case CRL_OBJ_CRL_ENTRY_EXTN_VALUE:
! 291: case CRL_OBJ_EXTN_VALUE:
! 292: {
! 293: int extn_oid = asn1_known_oid(extnID);
! 294:
! 295: switch (extn_oid)
! 296: {
! 297: case OID_CRL_REASON_CODE:
! 298: if (revoked)
! 299: {
! 300: if (object.len && *object.ptr == ASN1_ENUMERATED &&
! 301: asn1_length(&object) == 1)
! 302: {
! 303: revoked->reason = *object.ptr;
! 304: }
! 305: DBG2(DBG_ASN, " '%N'", crl_reason_names,
! 306: revoked->reason);
! 307: }
! 308: break;
! 309: case OID_AUTHORITY_KEY_ID:
! 310: chunk_free(&this->authKeyIdentifier);
! 311: this->authKeyIdentifier =
! 312: x509_parse_authorityKeyIdentifier(
! 313: object, level, &this->authKeySerialNumber);
! 314: break;
! 315: case OID_CRL_NUMBER:
! 316: if (!asn1_parse_simple_object(&object, ASN1_INTEGER,
! 317: level, "crlNumber"))
! 318: {
! 319: goto end;
! 320: }
! 321: this->crlNumber = object;
! 322: break;
! 323: case OID_FRESHEST_CRL:
! 324: if (!x509_parse_crlDistributionPoints(object, level,
! 325: this->crl_uris))
! 326: {
! 327: goto end;
! 328: }
! 329: break;
! 330: case OID_DELTA_CRL_INDICATOR:
! 331: if (!asn1_parse_simple_object(&object, ASN1_INTEGER,
! 332: level, "deltaCrlIndicator"))
! 333: {
! 334: goto end;
! 335: }
! 336: this->baseCrlNumber = object;
! 337: break;
! 338: case OID_ISSUING_DIST_POINT:
! 339: /* TODO support of IssuingDistributionPoints */
! 340: break;
! 341: default:
! 342: if (critical && lib->settings->get_bool(lib->settings,
! 343: "%s.x509.enforce_critical", TRUE, lib->ns))
! 344: {
! 345: DBG1(DBG_ASN, "critical '%s' extension not supported",
! 346: (extn_oid == OID_UNKNOWN) ? "unknown" :
! 347: (char*)oid_names[extn_oid].name);
! 348: goto end;
! 349: }
! 350: break;
! 351: }
! 352: break;
! 353: }
! 354: case CRL_OBJ_ALGORITHM:
! 355: {
! 356: INIT(this->scheme);
! 357: if (!signature_params_parse(object, level, this->scheme))
! 358: {
! 359: DBG1(DBG_ASN, " unable to parse signature algorithm");
! 360: goto end;
! 361: }
! 362: if (!signature_params_equal(this->scheme, &sig_alg))
! 363: {
! 364: DBG1(DBG_ASN, " signature algorithms do not agree");
! 365: goto end;
! 366: }
! 367: break;
! 368: }
! 369: case CRL_OBJ_SIGNATURE:
! 370: this->signature = chunk_skip(object, 1);
! 371: break;
! 372: default:
! 373: break;
! 374: }
! 375: }
! 376: success = parser->success(parser);
! 377:
! 378: end:
! 379: parser->destroy(parser);
! 380: signature_params_clear(&sig_alg);
! 381: return success;
! 382: }
! 383:
! 384: CALLBACK(filter, bool,
! 385: void *data, enumerator_t *orig, va_list args)
! 386: {
! 387: revoked_t *revoked;
! 388: crl_reason_t *reason;
! 389: chunk_t *serial;
! 390: time_t *date;
! 391:
! 392: VA_ARGS_VGET(args, serial, date, reason);
! 393:
! 394: if (orig->enumerate(orig, &revoked))
! 395: {
! 396: if (serial)
! 397: {
! 398: *serial = revoked->serial;
! 399: }
! 400: if (date)
! 401: {
! 402: *date = revoked->date;
! 403: }
! 404: if (reason)
! 405: {
! 406: *reason = revoked->reason;
! 407: }
! 408: return TRUE;
! 409: }
! 410: return FALSE;
! 411: }
! 412:
! 413: METHOD(crl_t, get_serial, chunk_t,
! 414: private_x509_crl_t *this)
! 415: {
! 416: return this->crlNumber;
! 417: }
! 418:
! 419: METHOD(crl_t, get_authKeyIdentifier, chunk_t,
! 420: private_x509_crl_t *this)
! 421: {
! 422: return this->authKeyIdentifier;
! 423: }
! 424:
! 425: METHOD(crl_t, is_delta_crl, bool,
! 426: private_x509_crl_t *this, chunk_t *base_crl)
! 427: {
! 428: if (this->baseCrlNumber.len)
! 429: {
! 430: if (base_crl)
! 431: {
! 432: *base_crl = this->baseCrlNumber;
! 433: }
! 434: return TRUE;
! 435: }
! 436: return FALSE;
! 437: }
! 438:
! 439: METHOD(crl_t, create_delta_crl_uri_enumerator, enumerator_t*,
! 440: private_x509_crl_t *this)
! 441: {
! 442: return this->crl_uris->create_enumerator(this->crl_uris);
! 443: }
! 444:
! 445: METHOD(crl_t, create_enumerator, enumerator_t*,
! 446: private_x509_crl_t *this)
! 447: {
! 448: return enumerator_create_filter(
! 449: this->revoked->create_enumerator(this->revoked),
! 450: filter, NULL, NULL);
! 451: }
! 452:
! 453: METHOD(certificate_t, get_type, certificate_type_t,
! 454: private_x509_crl_t *this)
! 455: {
! 456: return CERT_X509_CRL;
! 457: }
! 458:
! 459: METHOD(certificate_t, get_issuer, identification_t*,
! 460: private_x509_crl_t *this)
! 461: {
! 462: return this->issuer;
! 463: }
! 464:
! 465: METHOD(certificate_t, has_issuer, id_match_t,
! 466: private_x509_crl_t *this, identification_t *issuer)
! 467: {
! 468: if (issuer->get_type(issuer) == ID_KEY_ID && this->authKeyIdentifier.ptr &&
! 469: chunk_equals(this->authKeyIdentifier, issuer->get_encoding(issuer)))
! 470: {
! 471: return ID_MATCH_PERFECT;
! 472: }
! 473: return this->issuer->matches(this->issuer, issuer);
! 474: }
! 475:
! 476: METHOD(certificate_t, issued_by, bool,
! 477: private_x509_crl_t *this, certificate_t *issuer,
! 478: signature_params_t **scheme)
! 479: {
! 480: public_key_t *key;
! 481: bool valid;
! 482: x509_t *x509 = (x509_t*)issuer;
! 483: chunk_t keyid = chunk_empty;
! 484:
! 485: /* check if issuer is an X.509 CA certificate */
! 486: if (issuer->get_type(issuer) != CERT_X509)
! 487: {
! 488: return FALSE;
! 489: }
! 490: if (!(x509->get_flags(x509) & (X509_CA | X509_CRL_SIGN)))
! 491: {
! 492: return FALSE;
! 493: }
! 494:
! 495: /* compare keyIdentifiers if available, otherwise use DNs */
! 496: if (this->authKeyIdentifier.ptr)
! 497: {
! 498: keyid = x509->get_subjectKeyIdentifier(x509);
! 499: if (keyid.len && !chunk_equals(keyid, this->authKeyIdentifier))
! 500: {
! 501: return FALSE;
! 502: }
! 503: }
! 504: if (!keyid.len)
! 505: {
! 506: if (!this->issuer->equals(this->issuer, issuer->get_subject(issuer)))
! 507: {
! 508: return FALSE;
! 509: }
! 510: }
! 511:
! 512: key = issuer->get_public_key(issuer);
! 513: if (!key)
! 514: {
! 515: return FALSE;
! 516: }
! 517: valid = key->verify(key, this->scheme->scheme, this->scheme->params,
! 518: this->tbsCertList, this->signature);
! 519: key->destroy(key);
! 520: if (valid && scheme)
! 521: {
! 522: *scheme = signature_params_clone(this->scheme);
! 523: }
! 524: return valid;
! 525: }
! 526:
! 527: METHOD(certificate_t, get_public_key, public_key_t*,
! 528: private_x509_crl_t *this)
! 529: {
! 530: return NULL;
! 531: }
! 532:
! 533: METHOD(certificate_t, get_ref, certificate_t*,
! 534: private_x509_crl_t *this)
! 535: {
! 536: ref_get(&this->ref);
! 537: return &this->public.crl.certificate;
! 538: }
! 539:
! 540: METHOD(certificate_t, get_validity, bool,
! 541: private_x509_crl_t *this, time_t *when,
! 542: time_t *not_before, time_t *not_after)
! 543: {
! 544: time_t t = when ? *when : time(NULL);
! 545:
! 546: if (not_before)
! 547: {
! 548: *not_before = this->thisUpdate;
! 549: }
! 550: if (not_after)
! 551: {
! 552: *not_after = this->nextUpdate;
! 553: }
! 554: return (t >= this->thisUpdate && t <= this->nextUpdate);
! 555: }
! 556:
! 557: METHOD(certificate_t, get_encoding, bool,
! 558: private_x509_crl_t *this, cred_encoding_type_t type, chunk_t *encoding)
! 559: {
! 560: if (type == CERT_ASN1_DER)
! 561: {
! 562: *encoding = chunk_clone(this->encoding);
! 563: return TRUE;
! 564: }
! 565: return lib->encoding->encode(lib->encoding, type, NULL, encoding,
! 566: CRED_PART_X509_CRL_ASN1_DER, this->encoding, CRED_PART_END);
! 567: }
! 568:
! 569: METHOD(certificate_t, equals, bool,
! 570: private_x509_crl_t *this, certificate_t *other)
! 571: {
! 572: chunk_t encoding;
! 573: bool equal;
! 574:
! 575: if ((certificate_t*)this == other)
! 576: {
! 577: return TRUE;
! 578: }
! 579: if (other->equals == (void*)equals)
! 580: { /* skip allocation if we have the same implementation */
! 581: return chunk_equals(this->encoding, ((private_x509_crl_t*)other)->encoding);
! 582: }
! 583: if (!other->get_encoding(other, CERT_ASN1_DER, &encoding))
! 584: {
! 585: return FALSE;
! 586: }
! 587: equal = chunk_equals(this->encoding, encoding);
! 588: free(encoding.ptr);
! 589: return equal;
! 590: }
! 591:
! 592: /**
! 593: * Destroy a revoked_t entry
! 594: */
! 595: static void revoked_destroy(revoked_t *revoked)
! 596: {
! 597: free(revoked->serial.ptr);
! 598: free(revoked);
! 599: }
! 600:
! 601: METHOD(certificate_t, destroy, void,
! 602: private_x509_crl_t *this)
! 603: {
! 604: if (ref_put(&this->ref))
! 605: {
! 606: this->revoked->destroy_function(this->revoked, (void*)revoked_destroy);
! 607: this->crl_uris->destroy_function(this->crl_uris,
! 608: (void*)x509_cdp_destroy);
! 609: signature_params_destroy(this->scheme);
! 610: DESTROY_IF(this->issuer);
! 611: free(this->authKeyIdentifier.ptr);
! 612: free(this->encoding.ptr);
! 613: free(this->critical_extension_oid.ptr);
! 614: if (this->generated)
! 615: {
! 616: free(this->crlNumber.ptr);
! 617: free(this->baseCrlNumber.ptr);
! 618: free(this->signature.ptr);
! 619: free(this->tbsCertList.ptr);
! 620: }
! 621: free(this);
! 622: }
! 623: }
! 624:
! 625: /**
! 626: * create an empty but initialized X.509 crl
! 627: */
! 628: static private_x509_crl_t* create_empty(void)
! 629: {
! 630: private_x509_crl_t *this;
! 631:
! 632: INIT(this,
! 633: .public = {
! 634: .crl = {
! 635: .certificate = {
! 636: .get_type = _get_type,
! 637: .get_subject = _get_issuer,
! 638: .get_issuer = _get_issuer,
! 639: .has_subject = _has_issuer,
! 640: .has_issuer = _has_issuer,
! 641: .issued_by = _issued_by,
! 642: .get_public_key = _get_public_key,
! 643: .get_validity = _get_validity,
! 644: .get_encoding = _get_encoding,
! 645: .equals = _equals,
! 646: .get_ref = _get_ref,
! 647: .destroy = _destroy,
! 648: },
! 649: .get_serial = _get_serial,
! 650: .get_authKeyIdentifier = _get_authKeyIdentifier,
! 651: .is_delta_crl = _is_delta_crl,
! 652: .create_delta_crl_uri_enumerator = _create_delta_crl_uri_enumerator,
! 653: .create_enumerator = _create_enumerator,
! 654: },
! 655: },
! 656: .revoked = linked_list_create(),
! 657: .crl_uris = linked_list_create(),
! 658: .ref = 1,
! 659: );
! 660: return this;
! 661: }
! 662:
! 663: /**
! 664: * See header.
! 665: */
! 666: x509_crl_t *x509_crl_load(certificate_type_t type, va_list args)
! 667: {
! 668: chunk_t blob = chunk_empty;
! 669:
! 670: while (TRUE)
! 671: {
! 672: switch (va_arg(args, builder_part_t))
! 673: {
! 674: case BUILD_BLOB_ASN1_DER:
! 675: blob = va_arg(args, chunk_t);
! 676: continue;
! 677: case BUILD_END:
! 678: break;
! 679: default:
! 680: return NULL;
! 681: }
! 682: break;
! 683: }
! 684: if (blob.ptr)
! 685: {
! 686: private_x509_crl_t *crl = create_empty();
! 687:
! 688: crl->encoding = chunk_clone(blob);
! 689: if (parse(crl))
! 690: {
! 691: return &crl->public;
! 692: }
! 693: destroy(crl);
! 694: }
! 695: return NULL;
! 696: };
! 697:
! 698: /**
! 699: * Read certificate status from enumerator, copy to crl
! 700: */
! 701: static void read_revoked(private_x509_crl_t *crl, enumerator_t *enumerator)
! 702: {
! 703: revoked_t *revoked;
! 704: chunk_t serial;
! 705: time_t date;
! 706: crl_reason_t reason;
! 707:
! 708: while (enumerator->enumerate(enumerator, &serial, &date, &reason))
! 709: {
! 710: INIT(revoked,
! 711: .serial = chunk_clone(serial),
! 712: .date = date,
! 713: .reason = reason,
! 714: );
! 715: crl->revoked->insert_last(crl->revoked, revoked);
! 716: }
! 717: }
! 718:
! 719: /**
! 720: * Generate CRL encoding, sign CRL
! 721: */
! 722: static bool generate(private_x509_crl_t *this, certificate_t *cert,
! 723: private_key_t *key, hash_algorithm_t digest_alg)
! 724: {
! 725: chunk_t extensions = chunk_empty, certList = chunk_empty, serial;
! 726: chunk_t crlDistributionPoints = chunk_empty, baseCrlNumber = chunk_empty;
! 727: chunk_t sig_scheme = chunk_empty, criticalExtension = chunk_empty;
! 728: enumerator_t *enumerator;
! 729: crl_reason_t reason;
! 730: time_t date;
! 731: x509_t *x509;
! 732:
! 733: x509 = (x509_t*)cert;
! 734:
! 735: this->issuer = cert->get_subject(cert);
! 736: this->issuer = this->issuer->clone(this->issuer);
! 737:
! 738: this->authKeyIdentifier = chunk_clone(x509->get_subjectKeyIdentifier(x509));
! 739:
! 740: /* select signature scheme, if not already specified */
! 741: if (!this->scheme)
! 742: {
! 743: INIT(this->scheme,
! 744: .scheme = signature_scheme_from_oid(
! 745: hasher_signature_algorithm_to_oid(digest_alg,
! 746: key->get_type(key))),
! 747: );
! 748: }
! 749: if (this->scheme->scheme == SIGN_UNKNOWN)
! 750: {
! 751: return FALSE;
! 752: }
! 753: if (!signature_params_build(this->scheme, &sig_scheme))
! 754: {
! 755: return FALSE;
! 756: }
! 757:
! 758: enumerator = create_enumerator(this);
! 759: while (enumerator->enumerate(enumerator, &serial, &date, &reason))
! 760: {
! 761: chunk_t revoked, entry_ext = chunk_empty;
! 762:
! 763: if (reason != CRL_REASON_UNSPECIFIED)
! 764: {
! 765: entry_ext = asn1_wrap(ASN1_SEQUENCE, "m",
! 766: asn1_wrap(ASN1_SEQUENCE, "mm",
! 767: asn1_build_known_oid(OID_CRL_REASON_CODE),
! 768: asn1_wrap(ASN1_OCTET_STRING, "m",
! 769: asn1_wrap(ASN1_ENUMERATED, "c",
! 770: chunk_from_chars(reason)))));
! 771: }
! 772: revoked = asn1_wrap(ASN1_SEQUENCE, "mmm",
! 773: asn1_integer("c", serial),
! 774: asn1_from_time(&date, ASN1_UTCTIME),
! 775: entry_ext);
! 776: certList = chunk_cat("mm", certList, revoked);
! 777: }
! 778: enumerator->destroy(enumerator);
! 779:
! 780: crlDistributionPoints = x509_build_crlDistributionPoints(this->crl_uris,
! 781: OID_FRESHEST_CRL);
! 782:
! 783: if (this->baseCrlNumber.len)
! 784: {
! 785: baseCrlNumber = asn1_wrap(ASN1_SEQUENCE, "mmm",
! 786: asn1_build_known_oid(OID_DELTA_CRL_INDICATOR),
! 787: asn1_wrap(ASN1_BOOLEAN, "c",
! 788: chunk_from_chars(0xFF)),
! 789: asn1_wrap(ASN1_OCTET_STRING, "m",
! 790: asn1_integer("c", this->baseCrlNumber)));
! 791: }
! 792:
! 793: if (this->critical_extension_oid.len > 0)
! 794: {
! 795: criticalExtension = asn1_wrap(ASN1_SEQUENCE, "mmm",
! 796: asn1_simple_object(ASN1_OID, this->critical_extension_oid),
! 797: asn1_simple_object(ASN1_BOOLEAN, chunk_from_chars(0xFF)),
! 798: asn1_simple_object(ASN1_OCTET_STRING, chunk_empty));
! 799: }
! 800:
! 801: extensions = asn1_wrap(ASN1_CONTEXT_C_0, "m",
! 802: asn1_wrap(ASN1_SEQUENCE, "mmmmm",
! 803: asn1_wrap(ASN1_SEQUENCE, "mm",
! 804: asn1_build_known_oid(OID_AUTHORITY_KEY_ID),
! 805: asn1_wrap(ASN1_OCTET_STRING, "m",
! 806: asn1_wrap(ASN1_SEQUENCE, "m",
! 807: asn1_wrap(ASN1_CONTEXT_S_0, "c",
! 808: this->authKeyIdentifier)))),
! 809: asn1_wrap(ASN1_SEQUENCE, "mm",
! 810: asn1_build_known_oid(OID_CRL_NUMBER),
! 811: asn1_wrap(ASN1_OCTET_STRING, "m",
! 812: asn1_integer("c", this->crlNumber))),
! 813: crlDistributionPoints, baseCrlNumber,
! 814: criticalExtension));
! 815:
! 816: this->tbsCertList = asn1_wrap(ASN1_SEQUENCE, "cccmmmm",
! 817: ASN1_INTEGER_1,
! 818: sig_scheme,
! 819: this->issuer->get_encoding(this->issuer),
! 820: asn1_from_time(&this->thisUpdate, ASN1_UTCTIME),
! 821: asn1_from_time(&this->nextUpdate, ASN1_UTCTIME),
! 822: asn1_wrap(ASN1_SEQUENCE, "m", certList),
! 823: extensions);
! 824:
! 825: if (!key->sign(key, this->scheme->scheme, this->scheme->params,
! 826: this->tbsCertList, &this->signature))
! 827: {
! 828: chunk_free(&sig_scheme);
! 829: return FALSE;
! 830: }
! 831: this->encoding = asn1_wrap(ASN1_SEQUENCE, "cmm",
! 832: this->tbsCertList,
! 833: sig_scheme,
! 834: asn1_bitstring("c", this->signature));
! 835: return TRUE;
! 836: }
! 837:
! 838: /**
! 839: * See header.
! 840: */
! 841: x509_crl_t *x509_crl_gen(certificate_type_t type, va_list args)
! 842: {
! 843: hash_algorithm_t digest_alg = HASH_SHA1;
! 844: private_x509_crl_t *crl;
! 845: certificate_t *cert = NULL;
! 846: private_key_t *key = NULL;
! 847:
! 848: crl = create_empty();
! 849: crl->generated = TRUE;
! 850: while (TRUE)
! 851: {
! 852: builder_part_t part = va_arg(args, builder_part_t);
! 853:
! 854: switch (part)
! 855: {
! 856: case BUILD_SIGNING_KEY:
! 857: key = va_arg(args, private_key_t*);
! 858: continue;
! 859: case BUILD_SIGNING_CERT:
! 860: cert = va_arg(args, certificate_t*);
! 861: continue;
! 862: case BUILD_NOT_BEFORE_TIME:
! 863: crl->thisUpdate = va_arg(args, time_t);
! 864: continue;
! 865: case BUILD_NOT_AFTER_TIME:
! 866: crl->nextUpdate = va_arg(args, time_t);
! 867: continue;
! 868: case BUILD_SERIAL:
! 869: crl->crlNumber = va_arg(args, chunk_t);
! 870: crl->crlNumber = chunk_clone(crl->crlNumber);
! 871: continue;
! 872: case BUILD_SIGNATURE_SCHEME:
! 873: crl->scheme = va_arg(args, signature_params_t*);
! 874: crl->scheme = signature_params_clone(crl->scheme);
! 875: continue;
! 876: case BUILD_DIGEST_ALG:
! 877: digest_alg = va_arg(args, int);
! 878: continue;
! 879: case BUILD_REVOKED_ENUMERATOR:
! 880: read_revoked(crl, va_arg(args, enumerator_t*));
! 881: continue;
! 882: case BUILD_BASE_CRL:
! 883: crl->baseCrlNumber = va_arg(args, chunk_t);
! 884: crl->baseCrlNumber = chunk_clone(crl->baseCrlNumber);
! 885: break;
! 886: case BUILD_CRL_DISTRIBUTION_POINTS:
! 887: {
! 888: enumerator_t *enumerator;
! 889: linked_list_t *list;
! 890: x509_cdp_t *in, *cdp;
! 891:
! 892: list = va_arg(args, linked_list_t*);
! 893: enumerator = list->create_enumerator(list);
! 894: while (enumerator->enumerate(enumerator, &in))
! 895: {
! 896: INIT(cdp,
! 897: .uri = strdup(in->uri),
! 898: .issuer = in->issuer ? in->issuer->clone(in->issuer) : NULL,
! 899: );
! 900: crl->crl_uris->insert_last(crl->crl_uris, cdp);
! 901: }
! 902: enumerator->destroy(enumerator);
! 903: continue;
! 904: }
! 905: case BUILD_CRITICAL_EXTENSION:
! 906: crl->critical_extension_oid = chunk_clone(va_arg(args, chunk_t));
! 907: continue;
! 908: case BUILD_END:
! 909: break;
! 910: default:
! 911: destroy(crl);
! 912: return NULL;
! 913: }
! 914: break;
! 915: }
! 916:
! 917: if (key && cert && cert->get_type(cert) == CERT_X509 &&
! 918: generate(crl, cert, key, digest_alg))
! 919: {
! 920: return &crl->public;
! 921: }
! 922: destroy(crl);
! 923: return NULL;
! 924: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>