1/* 2 * Copyright (c) 2006 - 2007 Kungliga Tekniska Högskolan 3 * (Royal Institute of Technology, Stockholm, Sweden). 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 17 * 3. Neither the name of the Institute nor the names of its contributors 18 * may be used to endorse or promote products derived from this software 19 * without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND 22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE 25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 * SUCH DAMAGE. 32 */ 33 34/** 35 * @page page_revoke Revocation methods 36 * 37 * There are two revocation method for PKIX/X.509: CRL and OCSP. 38 * Revocation is needed if the private key is lost and 39 * stolen. Depending on how picky you are, you might want to make 40 * revocation for destroyed private keys too (smartcard broken), but 41 * that should not be a problem. 42 * 43 * CRL is a list of certifiates that have expired. 44 * 45 * OCSP is an online checking method where the requestor sends a list 46 * of certificates to the OCSP server to return a signed reply if they 47 * are valid or not. Some services sends a OCSP reply as part of the 48 * hand-shake to make the revoktion decision simpler/faster for the 49 * client. 50 */ 51 52#include "hx_locl.h" 53 54struct revoke_crl { 55 char *path; 56 time_t last_modfied; 57 CRLCertificateList crl; 58 int verified; 59 int failed_verify; 60}; 61 62struct revoke_ocsp { 63 char *path; 64 time_t last_modfied; 65 OCSPBasicOCSPResponse ocsp; 66 hx509_certs certs; 67 hx509_cert signer; 68}; 69 70 71struct hx509_revoke_ctx_data { 72 struct heim_base_uniq base; 73 struct { 74 struct revoke_crl *val; 75 size_t len; 76 } crls; 77 struct { 78 struct revoke_ocsp *val; 79 size_t len; 80 } ocsps; 81}; 82 83static void 84free_ocsp(struct revoke_ocsp *ocsp) 85{ 86 free(ocsp->path); 87 free_OCSPBasicOCSPResponse(&ocsp->ocsp); 88 hx509_certs_free(&ocsp->certs); 89 hx509_cert_free(ocsp->signer); 90} 91 92static void 93revoke_free(void *ptr) 94{ 95 hx509_revoke_ctx ctx = ptr; 96 size_t i; 97 98 for (i = 0; i < ctx->crls.len; i++) { 99 free(ctx->crls.val[i].path); 100 free_CRLCertificateList(&ctx->crls.val[i].crl); 101 } 102 103 for (i = 0; i < ctx->ocsps.len; i++) 104 free_ocsp(&ctx->ocsps.val[i]); 105 free(ctx->ocsps.val); 106 107 free(ctx->crls.val); 108} 109 110 111/** 112 * Allocate a revokation context. Free with hx509_revoke_free(). 113 * 114 * @param context A hx509 context. 115 * @param ctx returns a newly allocated revokation context. 116 * 117 * @return An hx509 error code, see hx509_get_error_string(). 118 * 119 * @ingroup hx509_revoke 120 */ 121 122int 123hx509_revoke_init(hx509_context context, hx509_revoke_ctx *ctx) 124{ 125 *ctx = heim_uniq_alloc(sizeof(**ctx), "hx509-revoke", revoke_free); 126 if (*ctx == NULL) 127 return ENOMEM; 128 129 (*ctx)->crls.len = 0; 130 (*ctx)->crls.val = NULL; 131 (*ctx)->ocsps.len = 0; 132 (*ctx)->ocsps.val = NULL; 133 134 return 0; 135} 136 137hx509_revoke_ctx 138_hx509_revoke_ref(hx509_revoke_ctx ctx) 139{ 140 return heim_retain(ctx); 141} 142 143/** 144 * Free a hx509 revokation context. 145 * 146 * @param ctx context to be freed 147 * 148 * @ingroup hx509_revoke 149 */ 150 151void 152hx509_revoke_free(hx509_revoke_ctx *ctx) 153{ 154 if (ctx == NULL) 155 return; 156 heim_release(*ctx); 157 *ctx = NULL; 158} 159 160static int 161verify_ocsp(hx509_context context, 162 struct revoke_ocsp *ocsp, 163 time_t time_now, 164 hx509_certs certs, 165 hx509_cert parent) 166{ 167 hx509_cert signer = NULL; 168 hx509_query q; 169 int ret; 170 171 _hx509_query_clear(&q); 172 173 /* 174 * Need to match on issuer too in case there are two CA that have 175 * issued the same name to a certificate. One example of this is 176 * the www.openvalidation.org test's ocsp validator. 177 */ 178 179 q.match = HX509_QUERY_MATCH_ISSUER_NAME; 180 q.issuer_name = &_hx509_get_cert(parent)->tbsCertificate.issuer; 181 182 switch(ocsp->ocsp.tbsResponseData.responderID.element) { 183 case choice_OCSPResponderID_byName: 184 q.match |= HX509_QUERY_MATCH_SUBJECT_NAME; 185 q.subject_name = &ocsp->ocsp.tbsResponseData.responderID.u.byName; 186 break; 187 case choice_OCSPResponderID_byKey: 188 q.match |= HX509_QUERY_MATCH_KEY_HASH_SHA1; 189 q.keyhash_sha1 = &ocsp->ocsp.tbsResponseData.responderID.u.byKey; 190 break; 191 case invalid_choice_OCSPResponderID: 192 return HX509_CERT_NOT_FOUND; 193 } 194 195 ret = hx509_certs_find(context, certs, &q, &signer); 196 if (ret && ocsp->certs) 197 ret = hx509_certs_find(context, ocsp->certs, &q, &signer); 198 if (ret) 199 goto out; 200 201 /* 202 * If signer certificate isn't the CA certificate, lets check the 203 * it is the CA that signed the signer certificate and the OCSP EKU 204 * is set. 205 */ 206 if (hx509_cert_cmp(signer, parent) != 0) { 207 Certificate *p = _hx509_get_cert(parent); 208 Certificate *s = _hx509_get_cert(signer); 209 210 ret = _hx509_cert_is_parent_cmp(s, p, 0); 211 if (ret != 0) { 212 ret = HX509_PARENT_NOT_CA; 213 hx509_set_error_string(context, 0, ret, "Revoke OCSP signer is " 214 "doesn't have CA as signer certificate"); 215 goto out; 216 } 217 218 ret = _hx509_verify_signature_bitstring(context, 219 parent, 220 &s->signatureAlgorithm, 221 &s->tbsCertificate._save, 222 &s->signatureValue); 223 if (ret) { 224 hx509_set_error_string(context, HX509_ERROR_APPEND, ret, 225 "OCSP signer signature invalid"); 226 goto out; 227 } 228 229 ret = hx509_cert_check_eku(context, signer, 230 &asn1_oid_id_pkix_kp_OCSPSigning, 0); 231 if (ret) 232 goto out; 233 } 234 235 ret = _hx509_verify_signature_bitstring(context, 236 signer, 237 &ocsp->ocsp.signatureAlgorithm, 238 &ocsp->ocsp.tbsResponseData._save, 239 &ocsp->ocsp.signature); 240 if (ret) { 241 hx509_set_error_string(context, HX509_ERROR_APPEND, ret, 242 "OCSP signature invalid"); 243 goto out; 244 } 245 246 ocsp->signer = signer; 247 signer = NULL; 248out: 249 if (signer) 250 hx509_cert_free(signer); 251 252 return ret; 253} 254 255/* 256 * 257 */ 258 259static int 260parse_ocsp_basic(const void *data, size_t length, OCSPBasicOCSPResponse *basic) 261{ 262 OCSPResponse resp; 263 size_t size; 264 int ret; 265 266 memset(basic, 0, sizeof(*basic)); 267 268 ret = decode_OCSPResponse(data, length, &resp, &size); 269 if (ret) 270 return ret; 271 if (length != size) { 272 free_OCSPResponse(&resp); 273 return ASN1_EXTRA_DATA; 274 } 275 276 switch (resp.responseStatus) { 277 case successful: 278 break; 279 default: 280 free_OCSPResponse(&resp); 281 return HX509_REVOKE_WRONG_DATA; 282 } 283 284 if (resp.responseBytes == NULL) { 285 free_OCSPResponse(&resp); 286 return EINVAL; 287 } 288 289 ret = der_heim_oid_cmp(&resp.responseBytes->responseType, 290 &asn1_oid_id_pkix_ocsp_basic); 291 if (ret != 0) { 292 free_OCSPResponse(&resp); 293 return HX509_REVOKE_WRONG_DATA; 294 } 295 296 ret = decode_OCSPBasicOCSPResponse(resp.responseBytes->response.data, 297 resp.responseBytes->response.length, 298 basic, 299 &size); 300 if (ret) { 301 free_OCSPResponse(&resp); 302 return ret; 303 } 304 if (size != resp.responseBytes->response.length) { 305 free_OCSPResponse(&resp); 306 free_OCSPBasicOCSPResponse(basic); 307 return ASN1_EXTRA_DATA; 308 } 309 free_OCSPResponse(&resp); 310 311 return 0; 312} 313 314/* 315 * 316 */ 317 318static int 319load_ocsp(hx509_context context, struct revoke_ocsp *ocsp) 320{ 321 OCSPBasicOCSPResponse basic; 322 hx509_certs certs = NULL; 323 size_t length; 324 struct stat sb; 325 void *data; 326 int ret; 327 328 ret = rk_undumpdata(ocsp->path, &data, &length); 329 if (ret) 330 return ret; 331 332 ret = stat(ocsp->path, &sb); 333 if (ret) 334 return errno; 335 336 ret = parse_ocsp_basic(data, length, &basic); 337 rk_xfree(data); 338 if (ret) { 339 hx509_set_error_string(context, 0, ret, 340 "Failed to parse OCSP response"); 341 return ret; 342 } 343 344 if (basic.certs) { 345 size_t i; 346 347 ret = hx509_certs_init(context, "MEMORY:ocsp-certs", 0, 348 NULL, &certs); 349 if (ret) { 350 free_OCSPBasicOCSPResponse(&basic); 351 return ret; 352 } 353 354 for (i = 0; i < basic.certs->len; i++) { 355 hx509_cert c; 356 357 ret = hx509_cert_init(context, &basic.certs->val[i], &c); 358 if (ret) 359 continue; 360 361 ret = hx509_certs_add(context, certs, c); 362 hx509_cert_free(c); 363 if (ret) 364 continue; 365 } 366 } 367 368 ocsp->last_modfied = sb.st_mtime; 369 370 free_OCSPBasicOCSPResponse(&ocsp->ocsp); 371 hx509_certs_free(&ocsp->certs); 372 hx509_cert_free(ocsp->signer); 373 374 ocsp->ocsp = basic; 375 ocsp->certs = certs; 376 ocsp->signer = NULL; 377 378 return 0; 379} 380 381/** 382 * Add a OCSP file to the revokation context. 383 * 384 * @param context hx509 context 385 * @param ctx hx509 revokation context 386 * @param path path to file that is going to be added to the context. 387 * 388 * @return An hx509 error code, see hx509_get_error_string(). 389 * 390 * @ingroup hx509_revoke 391 */ 392 393int 394hx509_revoke_add_ocsp(hx509_context context, 395 hx509_revoke_ctx ctx, 396 const char *path) 397{ 398 void *data; 399 int ret; 400 size_t i; 401 402 if (strncmp(path, "FILE:", 5) != 0) { 403 hx509_set_error_string(context, 0, HX509_UNSUPPORTED_OPERATION, 404 "unsupport type in %s", path); 405 return HX509_UNSUPPORTED_OPERATION; 406 } 407 408 path += 5; 409 410 for (i = 0; i < ctx->ocsps.len; i++) { 411 if (strcmp(ctx->ocsps.val[0].path, path) == 0) 412 return 0; 413 } 414 415 data = realloc(ctx->ocsps.val, 416 (ctx->ocsps.len + 1) * sizeof(ctx->ocsps.val[0])); 417 if (data == NULL) { 418 hx509_clear_error_string(context); 419 return ENOMEM; 420 } 421 422 ctx->ocsps.val = data; 423 424 memset(&ctx->ocsps.val[ctx->ocsps.len], 0, 425 sizeof(ctx->ocsps.val[0])); 426 427 ctx->ocsps.val[ctx->ocsps.len].path = strdup(path); 428 if (ctx->ocsps.val[ctx->ocsps.len].path == NULL) { 429 hx509_clear_error_string(context); 430 return ENOMEM; 431 } 432 433 ret = load_ocsp(context, &ctx->ocsps.val[ctx->ocsps.len]); 434 if (ret) { 435 free(ctx->ocsps.val[ctx->ocsps.len].path); 436 return ret; 437 } 438 ctx->ocsps.len++; 439 440 return ret; 441} 442 443/* 444 * 445 */ 446 447static int 448verify_crl(hx509_context context, 449 hx509_revoke_ctx ctx, 450 CRLCertificateList *crl, 451 time_t time_now, 452 hx509_certs certs, 453 hx509_cert parent) 454{ 455 hx509_cert signer; 456 hx509_query q; 457 time_t t; 458 int ret; 459 460 t = _hx509_Time2time_t(&crl->tbsCertList.thisUpdate); 461 if (t > time_now) { 462 hx509_set_error_string(context, 0, HX509_CRL_USED_BEFORE_TIME, 463 "CRL used before time"); 464 return HX509_CRL_USED_BEFORE_TIME; 465 } 466 467 if (crl->tbsCertList.nextUpdate == NULL) { 468 hx509_set_error_string(context, 0, HX509_CRL_INVALID_FORMAT, 469 "CRL missing nextUpdate"); 470 return HX509_CRL_INVALID_FORMAT; 471 } 472 473 t = _hx509_Time2time_t(crl->tbsCertList.nextUpdate); 474 if (t < time_now) { 475 hx509_set_error_string(context, 0, HX509_CRL_USED_AFTER_TIME, 476 "CRL used after time"); 477 return HX509_CRL_USED_AFTER_TIME; 478 } 479 480 _hx509_query_clear(&q); 481 482 /* 483 * If it's the signer have CRLSIGN bit set, use that as the signer 484 * cert for the certificate, otherwise, search for a certificate. 485 */ 486 if (_hx509_check_key_usage(context, parent, 1 << 6, FALSE) == 0) { 487 signer = hx509_cert_ref(parent); 488 } else { 489 q.match = HX509_QUERY_MATCH_SUBJECT_NAME; 490 q.match |= HX509_QUERY_KU_CRLSIGN; 491 q.subject_name = &crl->tbsCertList.issuer; 492 493 ret = hx509_certs_find(context, certs, &q, &signer); 494 if (ret) { 495 hx509_set_error_string(context, HX509_ERROR_APPEND, ret, 496 "Failed to find certificate for CRL"); 497 return ret; 498 } 499 } 500 501 ret = _hx509_verify_signature_bitstring(context, 502 signer, 503 &crl->signatureAlgorithm, 504 &crl->tbsCertList._save, 505 &crl->signatureValue); 506 if (ret) { 507 hx509_set_error_string(context, HX509_ERROR_APPEND, ret, 508 "CRL signature invalid"); 509 goto out; 510 } 511 512 /* 513 * If signer is not CA cert, need to check revoke status of this 514 * CRL signing cert too, this include all parent CRL signer cert 515 * up to the root *sigh*, assume root at least hve CERTSIGN flag 516 * set. 517 */ 518 while (_hx509_check_key_usage(context, signer, 1 << 5, TRUE)) { 519 hx509_cert crl_parent; 520 521 _hx509_query_clear(&q); 522 523 q.match = HX509_QUERY_MATCH_SUBJECT_NAME; 524 q.match |= HX509_QUERY_KU_CRLSIGN; 525 q.subject_name = &_hx509_get_cert(signer)->tbsCertificate.issuer; 526 527 ret = hx509_certs_find(context, certs, &q, &crl_parent); 528 if (ret) { 529 hx509_set_error_string(context, HX509_ERROR_APPEND, ret, 530 "Failed to find parent of CRL signer"); 531 goto out; 532 } 533 534 ret = hx509_revoke_verify(context, 535 ctx, 536 certs, 537 time_now, 538 signer, 539 crl_parent); 540 hx509_cert_free(signer); 541 signer = crl_parent; 542 if (ret) { 543 hx509_set_error_string(context, HX509_ERROR_APPEND, ret, 544 "Failed to verify revoke " 545 "status of CRL signer"); 546 goto out; 547 } 548 } 549 550out: 551 hx509_cert_free(signer); 552 553 return ret; 554} 555 556static int 557load_crl(const char *path, time_t *t, CRLCertificateList *crl) 558{ 559 size_t length, size; 560 struct stat sb; 561 void *data; 562 int ret; 563 564 memset(crl, 0, sizeof(*crl)); 565 566 ret = rk_undumpdata(path, &data, &length); 567 if (ret) 568 return ret; 569 570 ret = stat(path, &sb); 571 if (ret) 572 return errno; 573 574 *t = sb.st_mtime; 575 576 ret = decode_CRLCertificateList(data, length, crl, &size); 577 rk_xfree(data); 578 if (ret) 579 return ret; 580 581 /* check signature is aligned */ 582 if (crl->signatureValue.length & 7) { 583 free_CRLCertificateList(crl); 584 return HX509_CRYPTO_SIG_INVALID_FORMAT; 585 } 586 return 0; 587} 588 589/** 590 * Add a CRL file to the revokation context. 591 * 592 * @param context hx509 context 593 * @param ctx hx509 revokation context 594 * @param path path to file that is going to be added to the context. 595 * 596 * @return An hx509 error code, see hx509_get_error_string(). 597 * 598 * @ingroup hx509_revoke 599 */ 600 601int 602hx509_revoke_add_crl(hx509_context context, 603 hx509_revoke_ctx ctx, 604 const char *path) 605{ 606 void *data; 607 size_t i; 608 int ret; 609 610 if (strncmp(path, "FILE:", 5) != 0) { 611 hx509_set_error_string(context, 0, HX509_UNSUPPORTED_OPERATION, 612 "unsupport type in %s", path); 613 return HX509_UNSUPPORTED_OPERATION; 614 } 615 616 617 path += 5; 618 619 for (i = 0; i < ctx->crls.len; i++) { 620 if (strcmp(ctx->crls.val[0].path, path) == 0) 621 return 0; 622 } 623 624 data = realloc(ctx->crls.val, 625 (ctx->crls.len + 1) * sizeof(ctx->crls.val[0])); 626 if (data == NULL) { 627 hx509_clear_error_string(context); 628 return ENOMEM; 629 } 630 ctx->crls.val = data; 631 632 memset(&ctx->crls.val[ctx->crls.len], 0, sizeof(ctx->crls.val[0])); 633 634 ctx->crls.val[ctx->crls.len].path = strdup(path); 635 if (ctx->crls.val[ctx->crls.len].path == NULL) { 636 hx509_clear_error_string(context); 637 return ENOMEM; 638 } 639 640 ret = load_crl(path, 641 &ctx->crls.val[ctx->crls.len].last_modfied, 642 &ctx->crls.val[ctx->crls.len].crl); 643 if (ret) { 644 free(ctx->crls.val[ctx->crls.len].path); 645 return ret; 646 } 647 648 ctx->crls.len++; 649 650 return ret; 651} 652 653/** 654 * Check that a certificate is not expired according to a revokation 655 * context. Also need the parent certificte to the check OCSP 656 * parent identifier. 657 * 658 * @param context hx509 context 659 * @param ctx hx509 revokation context 660 * @param certs 661 * @param now 662 * @param cert 663 * @param parent_cert 664 * 665 * @return An hx509 error code, see hx509_get_error_string(). 666 * 667 * @ingroup hx509_revoke 668 */ 669 670 671int 672hx509_revoke_verify(hx509_context context, 673 hx509_revoke_ctx ctx, 674 hx509_certs certs, 675 time_t now, 676 hx509_cert cert, 677 hx509_cert parent_cert) 678{ 679 const Certificate *c = _hx509_get_cert(cert); 680 const Certificate *p = _hx509_get_cert(parent_cert); 681 unsigned long i, j, k; 682 int ret; 683 684 hx509_clear_error_string(context); 685 686 for (i = 0; i < ctx->ocsps.len; i++) { 687 struct revoke_ocsp *ocsp = &ctx->ocsps.val[i]; 688 struct stat sb; 689 690 /* check this ocsp apply to this cert */ 691 692 /* check if there is a newer version of the file */ 693 ret = stat(ocsp->path, &sb); 694 if (ret == 0 && ocsp->last_modfied != sb.st_mtime) { 695 ret = load_ocsp(context, ocsp); 696 if (ret) 697 continue; 698 } 699 700 /* verify signature in ocsp if not already done */ 701 if (ocsp->signer == NULL) { 702 ret = verify_ocsp(context, ocsp, now, certs, parent_cert); 703 if (ret) 704 continue; 705 } 706 707 for (j = 0; j < ocsp->ocsp.tbsResponseData.responses.len; j++) { 708 heim_octet_string os; 709 710 ret = der_heim_integer_cmp(&ocsp->ocsp.tbsResponseData.responses.val[j].certID.serialNumber, 711 &c->tbsCertificate.serialNumber); 712 if (ret != 0) 713 continue; 714 715 /* verify issuer hashes hash */ 716 ret = _hx509_verify_signature(context, 717 NULL, 718 &ocsp->ocsp.tbsResponseData.responses.val[i].certID.hashAlgorithm, 719 &c->tbsCertificate.issuer._save, 720 &ocsp->ocsp.tbsResponseData.responses.val[i].certID.issuerNameHash); 721 if (ret != 0) 722 continue; 723 724 os.data = p->tbsCertificate.subjectPublicKeyInfo.subjectPublicKey.data; 725 os.length = p->tbsCertificate.subjectPublicKeyInfo.subjectPublicKey.length / 8; 726 727 ret = _hx509_verify_signature(context, 728 NULL, 729 &ocsp->ocsp.tbsResponseData.responses.val[j].certID.hashAlgorithm, 730 &os, 731 &ocsp->ocsp.tbsResponseData.responses.val[j].certID.issuerKeyHash); 732 if (ret != 0) 733 continue; 734 735 switch (ocsp->ocsp.tbsResponseData.responses.val[j].certStatus.element) { 736 case choice_OCSPCertStatus_good: 737 break; 738 case invalid_choice_OCSPCertStatus: 739 case choice_OCSPCertStatus_revoked: 740 hx509_set_error_string(context, 0, 741 HX509_CERT_REVOKED, 742 "Certificate revoked by issuer in OCSP"); 743 return HX509_CERT_REVOKED; 744 case choice_OCSPCertStatus_unknown: 745 continue; 746 } 747 748 /* don't allow the update to be in the future */ 749 if (ocsp->ocsp.tbsResponseData.responses.val[j].thisUpdate > 750 now + context->ocsp_time_diff) 751 continue; 752 753 /* don't allow the next update to be in the past */ 754 if (ocsp->ocsp.tbsResponseData.responses.val[j].nextUpdate) { 755 if (*ocsp->ocsp.tbsResponseData.responses.val[j].nextUpdate < now) 756 continue; 757 } /* else should force a refetch, but can we ? */ 758 759 return 0; 760 } 761 } 762 763 for (i = 0; i < ctx->crls.len; i++) { 764 struct revoke_crl *crl = &ctx->crls.val[i]; 765 struct stat sb; 766 int diff; 767 768 /* check if cert.issuer == crls.val[i].crl.issuer */ 769 ret = _hx509_name_cmp(&c->tbsCertificate.issuer, 770 &crl->crl.tbsCertList.issuer, &diff); 771 if (ret || diff) 772 continue; 773 774 ret = stat(crl->path, &sb); 775 if (ret == 0 && crl->last_modfied != sb.st_mtime) { 776 CRLCertificateList cl; 777 778 ret = load_crl(crl->path, &crl->last_modfied, &cl); 779 if (ret == 0) { 780 free_CRLCertificateList(&crl->crl); 781 crl->crl = cl; 782 crl->verified = 0; 783 crl->failed_verify = 0; 784 } 785 } 786 if (crl->failed_verify) 787 continue; 788 789 /* verify signature in crl if not already done */ 790 if (crl->verified == 0) { 791 ret = verify_crl(context, ctx, &crl->crl, now, certs, parent_cert); 792 if (ret) { 793 crl->failed_verify = 1; 794 continue; 795 } 796 crl->verified = 1; 797 } 798 799 if (crl->crl.tbsCertList.crlExtensions) { 800 for (j = 0; j < crl->crl.tbsCertList.crlExtensions->len; j++) { 801 if (crl->crl.tbsCertList.crlExtensions->val[j].critical) { 802 hx509_set_error_string(context, 0, 803 HX509_CRL_UNKNOWN_EXTENSION, 804 "Unknown CRL extension"); 805 return HX509_CRL_UNKNOWN_EXTENSION; 806 } 807 } 808 } 809 810 if (crl->crl.tbsCertList.revokedCertificates == NULL) 811 return 0; 812 813 /* check if cert is in crl */ 814 for (j = 0; j < crl->crl.tbsCertList.revokedCertificates->len; j++) { 815 time_t t; 816 817 ret = der_heim_integer_cmp(&crl->crl.tbsCertList.revokedCertificates->val[j].userCertificate, 818 &c->tbsCertificate.serialNumber); 819 if (ret != 0) 820 continue; 821 822 t = _hx509_Time2time_t(&crl->crl.tbsCertList.revokedCertificates->val[j].revocationDate); 823 if (t > now) 824 continue; 825 826 if (crl->crl.tbsCertList.revokedCertificates->val[j].crlEntryExtensions) 827 for (k = 0; k < crl->crl.tbsCertList.revokedCertificates->val[j].crlEntryExtensions->len; k++) 828 if (crl->crl.tbsCertList.revokedCertificates->val[j].crlEntryExtensions->val[k].critical) 829 return HX509_CRL_UNKNOWN_EXTENSION; 830 831 hx509_set_error_string(context, 0, 832 HX509_CERT_REVOKED, 833 "Certificate revoked by issuer in CRL"); 834 return HX509_CERT_REVOKED; 835 } 836 837 return 0; 838 } 839 840 841 if (context->flags & HX509_CTX_VERIFY_MISSING_OK) 842 return 0; 843 hx509_set_error_string(context, HX509_ERROR_APPEND, 844 HX509_REVOKE_STATUS_MISSING, 845 "No revoke status found for " 846 "certificates"); 847 return HX509_REVOKE_STATUS_MISSING; 848} 849 850struct ocsp_add_ctx { 851 OCSPTBSRequest *req; 852 hx509_certs certs; 853 const AlgorithmIdentifier *digest; 854 hx509_cert parent; 855}; 856 857static int 858add_to_req(hx509_context context, void *ptr, hx509_cert cert) 859{ 860 struct ocsp_add_ctx *ctx = ptr; 861 OCSPInnerRequest *one; 862 hx509_cert parent = NULL; 863 Certificate *p, *c = _hx509_get_cert(cert); 864 heim_octet_string os; 865 int ret; 866 hx509_query q; 867 void *d; 868 869 d = realloc(ctx->req->requestList.val, 870 sizeof(ctx->req->requestList.val[0]) * 871 (ctx->req->requestList.len + 1)); 872 if (d == NULL) 873 return ENOMEM; 874 ctx->req->requestList.val = d; 875 876 one = &ctx->req->requestList.val[ctx->req->requestList.len]; 877 memset(one, 0, sizeof(*one)); 878 879 _hx509_query_clear(&q); 880 881 q.match |= HX509_QUERY_FIND_ISSUER_CERT; 882 q.subject = c; 883 884 ret = hx509_certs_find(context, ctx->certs, &q, &parent); 885 if (ret) 886 goto out; 887 888 if (ctx->parent) { 889 if (hx509_cert_cmp(ctx->parent, parent) != 0) { 890 ret = HX509_REVOKE_NOT_SAME_PARENT; 891 hx509_set_error_string(context, 0, ret, 892 "Not same parent certifate as " 893 "last certificate in request"); 894 goto out; 895 } 896 } else 897 ctx->parent = hx509_cert_ref(parent); 898 899 p = _hx509_get_cert(parent); 900 901 ret = copy_AlgorithmIdentifier(ctx->digest, &one->reqCert.hashAlgorithm); 902 if (ret) 903 goto out; 904 905 ret = _hx509_create_signature(context, 906 NULL, 907 &one->reqCert.hashAlgorithm, 908 &c->tbsCertificate.issuer._save, 909 NULL, 910 &one->reqCert.issuerNameHash); 911 if (ret) 912 goto out; 913 914 os.data = p->tbsCertificate.subjectPublicKeyInfo.subjectPublicKey.data; 915 os.length = 916 p->tbsCertificate.subjectPublicKeyInfo.subjectPublicKey.length / 8; 917 918 ret = _hx509_create_signature(context, 919 NULL, 920 &one->reqCert.hashAlgorithm, 921 &os, 922 NULL, 923 &one->reqCert.issuerKeyHash); 924 if (ret) 925 goto out; 926 927 ret = copy_CertificateSerialNumber(&c->tbsCertificate.serialNumber, 928 &one->reqCert.serialNumber); 929 if (ret) 930 goto out; 931 932 ctx->req->requestList.len++; 933out: 934 hx509_cert_free(parent); 935 if (ret) { 936 free_OCSPInnerRequest(one); 937 memset(one, 0, sizeof(*one)); 938 } 939 940 return ret; 941} 942 943/** 944 * Create an OCSP request for a set of certificates. 945 * 946 * @param context a hx509 context 947 * @param reqcerts list of certificates to request ocsp data for 948 * @param pool certificate pool to use when signing 949 * @param signer certificate to use to sign the request 950 * @param digest the signing algorithm in the request, if NULL use the 951 * default signature algorithm, 952 * @param request the encoded request, free with free_heim_octet_string(). 953 * @param nonce nonce in the request, free with free_heim_octet_string(). 954 * 955 * @return An hx509 error code, see hx509_get_error_string(). 956 * 957 * @ingroup hx509_revoke 958 */ 959 960int 961hx509_ocsp_request(hx509_context context, 962 hx509_certs reqcerts, 963 hx509_certs pool, 964 hx509_cert signer, 965 const AlgorithmIdentifier *digest, 966 heim_octet_string *request, 967 heim_octet_string *nonce) 968{ 969 OCSPRequest req; 970 size_t size; 971 int ret; 972 struct ocsp_add_ctx ctx; 973 Extensions *es; 974 975 memset(&req, 0, sizeof(req)); 976 977 if (digest == NULL) 978 digest = _hx509_crypto_default_digest_alg; 979 980 ctx.req = &req.tbsRequest; 981 ctx.certs = pool; 982 ctx.digest = digest; 983 ctx.parent = NULL; 984 985 ret = hx509_certs_iter_f(context, reqcerts, add_to_req, &ctx); 986 hx509_cert_free(ctx.parent); 987 if (ret) 988 goto out; 989 990 if (nonce) { 991 req.tbsRequest.requestExtensions = 992 calloc(1, sizeof(*req.tbsRequest.requestExtensions)); 993 if (req.tbsRequest.requestExtensions == NULL) { 994 ret = ENOMEM; 995 goto out; 996 } 997 998 es = req.tbsRequest.requestExtensions; 999 1000 es->val = calloc(es->len, sizeof(es->val[0])); 1001 if (es->val == NULL) { 1002 ret = ENOMEM; 1003 goto out; 1004 } 1005 es->len = 1; 1006 ret = der_copy_oid(&asn1_oid_id_pkix_ocsp_nonce, &es->val[0].extnID); 1007 if (ret) { 1008 free_OCSPRequest(&req); 1009 return ret; 1010 } 1011 1012 es->val[0].extnValue.data = malloc(10); 1013 if (es->val[0].extnValue.data == NULL) { 1014 ret = ENOMEM; 1015 goto out; 1016 } 1017 es->val[0].extnValue.length = 10; 1018 1019 ret = CCRandomCopyBytes(kCCRandomDefault, 1020 es->val[0].extnValue.data, 1021 es->val[0].extnValue.length); 1022 if (ret) { 1023 ret = HX509_CRYPTO_INTERNAL_ERROR; 1024 goto out; 1025 } 1026 ret = der_copy_octet_string(nonce, &es->val[0].extnValue); 1027 if (ret) { 1028 ret = ENOMEM; 1029 goto out; 1030 } 1031 } 1032 1033 ASN1_MALLOC_ENCODE(OCSPRequest, request->data, request->length, 1034 &req, &size, ret); 1035 free_OCSPRequest(&req); 1036 if (ret) 1037 goto out; 1038 if (size != request->length) 1039 _hx509_abort("internal ASN.1 encoder error"); 1040 1041 return 0; 1042 1043out: 1044 free_OCSPRequest(&req); 1045 return ret; 1046} 1047 1048static char * 1049printable_time(time_t t) 1050{ 1051 static char s[128]; 1052 char *p; 1053 if ((p = ctime(&t)) == NULL) 1054 strlcpy(s, "?", sizeof(s)); 1055 else { 1056 strlcpy(s, p + 4, sizeof(s)); 1057 s[20] = 0; 1058 } 1059 return s; 1060} 1061 1062/** 1063 * Print the OCSP reply stored in a file. 1064 * 1065 * @param context a hx509 context 1066 * @param path path to a file with a OCSP reply 1067 * @param out the out FILE descriptor to print the reply on 1068 * 1069 * @return An hx509 error code, see hx509_get_error_string(). 1070 * 1071 * @ingroup hx509_revoke 1072 */ 1073 1074int 1075hx509_revoke_ocsp_print(hx509_context context, const char *path, FILE *out) 1076{ 1077 struct revoke_ocsp ocsp; 1078 int ret; 1079 size_t i; 1080 1081 if (out == NULL) 1082 out = stdout; 1083 1084 memset(&ocsp, 0, sizeof(ocsp)); 1085 1086 ocsp.path = strdup(path); 1087 if (ocsp.path == NULL) 1088 return ENOMEM; 1089 1090 ret = load_ocsp(context, &ocsp); 1091 if (ret) { 1092 free_ocsp(&ocsp); 1093 return ret; 1094 } 1095 1096 fprintf(out, "signer: "); 1097 1098 switch(ocsp.ocsp.tbsResponseData.responderID.element) { 1099 case choice_OCSPResponderID_byName: { 1100 hx509_name n; 1101 char *s; 1102 hx509_name_from_Name(&ocsp.ocsp.tbsResponseData.responderID.u.byName, &n); 1103 hx509_name_to_string(n, &s); 1104 hx509_name_free(&n); 1105 fprintf(out, " byName: %s\n", s); 1106 free(s); 1107 break; 1108 } 1109 case choice_OCSPResponderID_byKey: { 1110 char *s; 1111 hex_encode(ocsp.ocsp.tbsResponseData.responderID.u.byKey.data, 1112 ocsp.ocsp.tbsResponseData.responderID.u.byKey.length, 1113 &s); 1114 fprintf(out, " byKey: %s\n", s); 1115 free(s); 1116 break; 1117 } 1118 default: 1119 _hx509_abort("choice_OCSPResponderID unknown"); 1120 break; 1121 } 1122 1123 fprintf(out, "producedAt: %s\n", 1124 printable_time(ocsp.ocsp.tbsResponseData.producedAt)); 1125 1126 fprintf(out, "replies: %d\n", ocsp.ocsp.tbsResponseData.responses.len); 1127 1128 for (i = 0; i < ocsp.ocsp.tbsResponseData.responses.len; i++) { 1129 const char *status; 1130 switch (ocsp.ocsp.tbsResponseData.responses.val[i].certStatus.element) { 1131 case choice_OCSPCertStatus_good: 1132 status = "good"; 1133 break; 1134 case choice_OCSPCertStatus_revoked: 1135 status = "revoked"; 1136 break; 1137 case choice_OCSPCertStatus_unknown: 1138 status = "unknown"; 1139 break; 1140 default: 1141 status = "element unknown"; 1142 } 1143 1144 fprintf(out, "\t%zu. status: %s\n", i, status); 1145 1146 fprintf(out, "\tthisUpdate: %s\n", 1147 printable_time(ocsp.ocsp.tbsResponseData.responses.val[i].thisUpdate)); 1148 if (ocsp.ocsp.tbsResponseData.responses.val[i].nextUpdate) 1149 fprintf(out, "\tproducedAt: %s\n", 1150 printable_time(ocsp.ocsp.tbsResponseData.responses.val[i].thisUpdate)); 1151 1152 } 1153 1154 fprintf(out, "appended certs:\n"); 1155 if (ocsp.certs) 1156 ret = hx509_certs_iter_f(context, ocsp.certs, hx509_ci_print_names, out); 1157 1158 free_ocsp(&ocsp); 1159 return ret; 1160} 1161 1162/** 1163 * Verify that the certificate is part of the OCSP reply and it's not 1164 * expired. Doesn't verify signature the OCSP reply or it's done by a 1165 * authorized sender, that is assumed to be already done. 1166 * 1167 * @param context a hx509 context 1168 * @param now the time right now, if 0, use the current time. 1169 * @param cert the certificate to verify 1170 * @param flags flags control the behavior 1171 * @param data pointer to the encode ocsp reply 1172 * @param length the length of the encode ocsp reply 1173 * @param expiration return the time the OCSP will expire and need to 1174 * be rechecked. 1175 * 1176 * @return An hx509 error code, see hx509_get_error_string(). 1177 * 1178 * @ingroup hx509_verify 1179 */ 1180 1181int 1182hx509_ocsp_verify(hx509_context context, 1183 time_t now, 1184 hx509_cert cert, 1185 int flags, 1186 const void *data, size_t length, 1187 time_t *expiration) 1188{ 1189 const Certificate *c = _hx509_get_cert(cert); 1190 OCSPBasicOCSPResponse basic; 1191 int ret; 1192 size_t i; 1193 1194 if (now == 0) 1195 now = time(NULL); 1196 1197 *expiration = 0; 1198 1199 ret = parse_ocsp_basic(data, length, &basic); 1200 if (ret) { 1201 hx509_set_error_string(context, 0, ret, 1202 "Failed to parse OCSP response"); 1203 return ret; 1204 } 1205 1206 for (i = 0; i < basic.tbsResponseData.responses.len; i++) { 1207 1208 ret = der_heim_integer_cmp(&basic.tbsResponseData.responses.val[i].certID.serialNumber, 1209 &c->tbsCertificate.serialNumber); 1210 if (ret != 0) 1211 continue; 1212 1213 /* verify issuer hashes hash */ 1214 ret = _hx509_verify_signature(context, 1215 NULL, 1216 &basic.tbsResponseData.responses.val[i].certID.hashAlgorithm, 1217 &c->tbsCertificate.issuer._save, 1218 &basic.tbsResponseData.responses.val[i].certID.issuerNameHash); 1219 if (ret != 0) 1220 continue; 1221 1222 switch (basic.tbsResponseData.responses.val[i].certStatus.element) { 1223 case choice_OCSPCertStatus_good: 1224 break; 1225 case choice_OCSPCertStatus_revoked: 1226 case choice_OCSPCertStatus_unknown: 1227 case invalid_choice_OCSPCertStatus: 1228 continue; 1229 } 1230 1231 /* don't allow the update to be in the future */ 1232 if (basic.tbsResponseData.responses.val[i].thisUpdate > 1233 now + context->ocsp_time_diff) 1234 continue; 1235 1236 /* don't allow the next update to be in the past */ 1237 if (basic.tbsResponseData.responses.val[i].nextUpdate) { 1238 if (*basic.tbsResponseData.responses.val[i].nextUpdate < now) 1239 continue; 1240 *expiration = *basic.tbsResponseData.responses.val[i].nextUpdate; 1241 } else 1242 *expiration = now; 1243 1244 free_OCSPBasicOCSPResponse(&basic); 1245 return 0; 1246 } 1247 1248 free_OCSPBasicOCSPResponse(&basic); 1249 1250 { 1251 hx509_name name; 1252 char *subject; 1253 1254 ret = hx509_cert_get_subject(cert, &name); 1255 if (ret) { 1256 hx509_clear_error_string(context); 1257 goto out; 1258 } 1259 ret = hx509_name_to_string(name, &subject); 1260 hx509_name_free(&name); 1261 if (ret) { 1262 hx509_clear_error_string(context); 1263 goto out; 1264 } 1265 hx509_set_error_string(context, 0, HX509_CERT_NOT_IN_OCSP, 1266 "Certificate %s not in OCSP response " 1267 "or not good", 1268 subject); 1269 free(subject); 1270 } 1271out: 1272 return HX509_CERT_NOT_IN_OCSP; 1273} 1274 1275struct hx509_crl { 1276 hx509_certs revoked; 1277 time_t expire; 1278}; 1279 1280/** 1281 * Create a CRL context. Use hx509_crl_free() to free the CRL context. 1282 * 1283 * @param context a hx509 context. 1284 * @param crl return pointer to a newly allocated CRL context. 1285 * 1286 * @return An hx509 error code, see hx509_get_error_string(). 1287 * 1288 * @ingroup hx509_verify 1289 */ 1290 1291int 1292hx509_crl_alloc(hx509_context context, hx509_crl *crl) 1293{ 1294 int ret; 1295 1296 *crl = calloc(1, sizeof(**crl)); 1297 if (*crl == NULL) { 1298 hx509_set_error_string(context, 0, ENOMEM, "out of memory"); 1299 return ENOMEM; 1300 } 1301 1302 ret = hx509_certs_init(context, "MEMORY:crl", 0, NULL, &(*crl)->revoked); 1303 if (ret) { 1304 free(*crl); 1305 *crl = NULL; 1306 return ret; 1307 } 1308 (*crl)->expire = 0; 1309 return ret; 1310} 1311 1312/** 1313 * Add revoked certificate to an CRL context. 1314 * 1315 * @param context a hx509 context. 1316 * @param crl the CRL to add the revoked certificate to. 1317 * @param certs keyset of certificate to revoke. 1318 * 1319 * @return An hx509 error code, see hx509_get_error_string(). 1320 * 1321 * @ingroup hx509_verify 1322 */ 1323 1324int 1325hx509_crl_add_revoked_certs(hx509_context context, 1326 hx509_crl crl, 1327 hx509_certs certs) 1328{ 1329 return hx509_certs_merge(context, crl->revoked, certs); 1330} 1331 1332/** 1333 * Set the lifetime of a CRL context. 1334 * 1335 * @param context a hx509 context. 1336 * @param crl a CRL context 1337 * @param delta delta time the certificate is valid, library adds the 1338 * current time to this. 1339 * 1340 * @return An hx509 error code, see hx509_get_error_string(). 1341 * 1342 * @ingroup hx509_verify 1343 */ 1344 1345int 1346hx509_crl_lifetime(hx509_context context, hx509_crl crl, int delta) 1347{ 1348 crl->expire = time(NULL) + delta; 1349 return 0; 1350} 1351 1352/** 1353 * Free a CRL context. 1354 * 1355 * @param context a hx509 context. 1356 * @param crl a CRL context to free. 1357 * 1358 * @ingroup hx509_verify 1359 */ 1360 1361void 1362hx509_crl_free(hx509_context context, hx509_crl *crl) 1363{ 1364 if (*crl == NULL) 1365 return; 1366 hx509_certs_free(&(*crl)->revoked); 1367 memset(*crl, 0, sizeof(**crl)); 1368 free(*crl); 1369 *crl = NULL; 1370} 1371 1372static int 1373add_revoked(hx509_context context, void *ctx, hx509_cert cert) 1374{ 1375 TBSCRLCertList *c = ctx; 1376 unsigned int num; 1377 void *ptr; 1378 int ret; 1379 1380 num = c->revokedCertificates->len; 1381 ptr = realloc(c->revokedCertificates->val, 1382 (num + 1) * sizeof(c->revokedCertificates->val[0])); 1383 if (ptr == NULL) { 1384 hx509_clear_error_string(context); 1385 return ENOMEM; 1386 } 1387 c->revokedCertificates->val = ptr; 1388 1389 ret = hx509_cert_get_serialnumber(cert, 1390 &c->revokedCertificates->val[num].userCertificate); 1391 if (ret) { 1392 hx509_clear_error_string(context); 1393 return ret; 1394 } 1395 c->revokedCertificates->val[num].revocationDate.element = 1396 choice_Time_generalTime; 1397 c->revokedCertificates->val[num].revocationDate.u.generalTime = 1398 time(NULL) - 3600 * 24; 1399 c->revokedCertificates->val[num].crlEntryExtensions = NULL; 1400 1401 c->revokedCertificates->len++; 1402 1403 return 0; 1404} 1405 1406/** 1407 * Sign a CRL and return an encode certificate. 1408 * 1409 * @param context a hx509 context. 1410 * @param signer certificate to sign the CRL with 1411 * @param crl the CRL to sign 1412 * @param os return the signed and encoded CRL, free with 1413 * free_heim_octet_string() 1414 * 1415 * @return An hx509 error code, see hx509_get_error_string(). 1416 * 1417 * @ingroup hx509_verify 1418 */ 1419 1420int 1421hx509_crl_sign(hx509_context context, 1422 hx509_cert signer, 1423 hx509_crl crl, 1424 heim_octet_string *os) 1425{ 1426 const AlgorithmIdentifier *sigalg = _hx509_crypto_default_sig_alg; 1427 CRLCertificateList c; 1428 size_t size; 1429 int ret; 1430 hx509_private_key signerkey; 1431 1432 memset(&c, 0, sizeof(c)); 1433 1434 signerkey = _hx509_cert_private_key(signer); 1435 if (signerkey == NULL) { 1436 ret = HX509_PRIVATE_KEY_MISSING; 1437 hx509_set_error_string(context, 0, ret, 1438 "Private key missing for CRL signing"); 1439 return ret; 1440 } 1441 1442 c.tbsCertList.version = malloc(sizeof(*c.tbsCertList.version)); 1443 if (c.tbsCertList.version == NULL) { 1444 hx509_set_error_string(context, 0, ENOMEM, "out of memory"); 1445 return ENOMEM; 1446 } 1447 1448 *c.tbsCertList.version = 1; 1449 1450 ret = copy_AlgorithmIdentifier(sigalg, &c.tbsCertList.signature); 1451 if (ret) { 1452 hx509_clear_error_string(context); 1453 goto out; 1454 } 1455 1456 ret = copy_Name(&_hx509_get_cert(signer)->tbsCertificate.issuer, 1457 &c.tbsCertList.issuer); 1458 if (ret) { 1459 hx509_clear_error_string(context); 1460 goto out; 1461 } 1462 1463 c.tbsCertList.thisUpdate.element = choice_Time_generalTime; 1464 c.tbsCertList.thisUpdate.u.generalTime = time(NULL) - 24 * 3600; 1465 1466 c.tbsCertList.nextUpdate = malloc(sizeof(*c.tbsCertList.nextUpdate)); 1467 if (c.tbsCertList.nextUpdate == NULL) { 1468 hx509_set_error_string(context, 0, ENOMEM, "out of memory"); 1469 ret = ENOMEM; 1470 goto out; 1471 } 1472 1473 { 1474 time_t next = crl->expire; 1475 if (next == 0) 1476 next = time(NULL) + 24 * 3600 * 365; 1477 1478 c.tbsCertList.nextUpdate->element = choice_Time_generalTime; 1479 c.tbsCertList.nextUpdate->u.generalTime = next; 1480 } 1481 1482 c.tbsCertList.revokedCertificates = 1483 calloc(1, sizeof(*c.tbsCertList.revokedCertificates)); 1484 if (c.tbsCertList.revokedCertificates == NULL) { 1485 hx509_set_error_string(context, 0, ENOMEM, "out of memory"); 1486 ret = ENOMEM; 1487 goto out; 1488 } 1489 c.tbsCertList.crlExtensions = NULL; 1490 1491 ret = hx509_certs_iter_f(context, crl->revoked, add_revoked, &c.tbsCertList); 1492 if (ret) 1493 goto out; 1494 1495 /* if not revoked certs, remove OPTIONAL entry */ 1496 if (c.tbsCertList.revokedCertificates->len == 0) { 1497 free(c.tbsCertList.revokedCertificates); 1498 c.tbsCertList.revokedCertificates = NULL; 1499 } 1500 1501 ASN1_MALLOC_ENCODE(TBSCRLCertList, os->data, os->length, 1502 &c.tbsCertList, &size, ret); 1503 if (ret) { 1504 hx509_set_error_string(context, 0, ret, "failed to encode tbsCRL"); 1505 goto out; 1506 } 1507 if (size != os->length) 1508 _hx509_abort("internal ASN.1 encoder error"); 1509 1510 1511 ret = _hx509_create_signature_bitstring(context, 1512 signerkey, 1513 sigalg, 1514 os, 1515 &c.signatureAlgorithm, 1516 &c.signatureValue); 1517 free(os->data); 1518 if (ret) { 1519 hx509_set_error_string(context, 0, ret, "Failed to sign CRL"); 1520 goto out; 1521 } 1522 1523 ASN1_MALLOC_ENCODE(CRLCertificateList, os->data, os->length, 1524 &c, &size, ret); 1525 if (ret) { 1526 hx509_set_error_string(context, 0, ret, "failed to encode CRL"); 1527 goto out; 1528 } 1529 if (size != os->length) 1530 _hx509_abort("internal ASN.1 encoder error"); 1531 1532 free_CRLCertificateList(&c); 1533 1534 return 0; 1535 1536out: 1537 free_CRLCertificateList(&c); 1538 return ret; 1539} 1540