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 case internalError: 280 case malformedRequest: 281 case sigRequired: 282 case tryLater: 283 case unauthorized: 284 free_OCSPResponse(&resp); 285 return HX509_REVOKE_WRONG_DATA; 286 } 287 288 if (resp.responseBytes == NULL) { 289 free_OCSPResponse(&resp); 290 return EINVAL; 291 } 292 293 ret = der_heim_oid_cmp(&resp.responseBytes->responseType, 294 &asn1_oid_id_pkix_ocsp_basic); 295 if (ret != 0) { 296 free_OCSPResponse(&resp); 297 return HX509_REVOKE_WRONG_DATA; 298 } 299 300 ret = decode_OCSPBasicOCSPResponse(resp.responseBytes->response.data, 301 resp.responseBytes->response.length, 302 basic, 303 &size); 304 if (ret) { 305 free_OCSPResponse(&resp); 306 return ret; 307 } 308 if (size != resp.responseBytes->response.length) { 309 free_OCSPResponse(&resp); 310 free_OCSPBasicOCSPResponse(basic); 311 return ASN1_EXTRA_DATA; 312 } 313 free_OCSPResponse(&resp); 314 315 return 0; 316} 317 318/* 319 * 320 */ 321 322static int 323load_ocsp(hx509_context context, struct revoke_ocsp *ocsp) 324{ 325 OCSPBasicOCSPResponse basic; 326 hx509_certs certs = NULL; 327 size_t length; 328 struct stat sb; 329 void *data; 330 int ret; 331 332 ret = rk_undumpdata(ocsp->path, &data, &length); 333 if (ret) 334 return ret; 335 336 ret = stat(ocsp->path, &sb); 337 if (ret) 338 return errno; 339 340 ret = parse_ocsp_basic(data, length, &basic); 341 rk_xfree(data); 342 if (ret) { 343 hx509_set_error_string(context, 0, ret, 344 "Failed to parse OCSP response"); 345 return ret; 346 } 347 348 if (basic.certs) { 349 size_t i; 350 351 ret = hx509_certs_init(context, "MEMORY:ocsp-certs", 0, 352 NULL, &certs); 353 if (ret) { 354 free_OCSPBasicOCSPResponse(&basic); 355 return ret; 356 } 357 358 for (i = 0; i < basic.certs->len; i++) { 359 hx509_cert c; 360 361 ret = hx509_cert_init(context, &basic.certs->val[i], &c); 362 if (ret) 363 continue; 364 365 ret = hx509_certs_add(context, certs, c); 366 hx509_cert_free(c); 367 if (ret) 368 continue; 369 } 370 } 371 372 ocsp->last_modfied = sb.st_mtime; 373 374 free_OCSPBasicOCSPResponse(&ocsp->ocsp); 375 hx509_certs_free(&ocsp->certs); 376 hx509_cert_free(ocsp->signer); 377 378 ocsp->ocsp = basic; 379 ocsp->certs = certs; 380 ocsp->signer = NULL; 381 382 return 0; 383} 384 385/** 386 * Add a OCSP file to the revokation context. 387 * 388 * @param context hx509 context 389 * @param ctx hx509 revokation context 390 * @param path path to file that is going to be added to the context. 391 * 392 * @return An hx509 error code, see hx509_get_error_string(). 393 * 394 * @ingroup hx509_revoke 395 */ 396 397int 398hx509_revoke_add_ocsp(hx509_context context, 399 hx509_revoke_ctx ctx, 400 const char *path) 401{ 402 void *data; 403 int ret; 404 size_t i; 405 406 if (strncmp(path, "FILE:", 5) != 0) { 407 hx509_set_error_string(context, 0, HX509_UNSUPPORTED_OPERATION, 408 "unsupport type in %s", path); 409 return HX509_UNSUPPORTED_OPERATION; 410 } 411 412 path += 5; 413 414 for (i = 0; i < ctx->ocsps.len; i++) { 415 if (strcmp(ctx->ocsps.val[0].path, path) == 0) 416 return 0; 417 } 418 419 data = realloc(ctx->ocsps.val, 420 (ctx->ocsps.len + 1) * sizeof(ctx->ocsps.val[0])); 421 if (data == NULL) { 422 hx509_clear_error_string(context); 423 return ENOMEM; 424 } 425 426 ctx->ocsps.val = data; 427 428 memset(&ctx->ocsps.val[ctx->ocsps.len], 0, 429 sizeof(ctx->ocsps.val[0])); 430 431 ctx->ocsps.val[ctx->ocsps.len].path = strdup(path); 432 if (ctx->ocsps.val[ctx->ocsps.len].path == NULL) { 433 hx509_clear_error_string(context); 434 return ENOMEM; 435 } 436 437 ret = load_ocsp(context, &ctx->ocsps.val[ctx->ocsps.len]); 438 if (ret) { 439 free(ctx->ocsps.val[ctx->ocsps.len].path); 440 return ret; 441 } 442 ctx->ocsps.len++; 443 444 return ret; 445} 446 447/* 448 * 449 */ 450 451static int 452verify_crl(hx509_context context, 453 hx509_revoke_ctx ctx, 454 CRLCertificateList *crl, 455 time_t time_now, 456 hx509_certs certs, 457 hx509_cert parent) 458{ 459 hx509_cert signer; 460 hx509_query q; 461 time_t t; 462 int ret; 463 464 t = _hx509_Time2time_t(&crl->tbsCertList.thisUpdate); 465 if (t > time_now) { 466 hx509_set_error_string(context, 0, HX509_CRL_USED_BEFORE_TIME, 467 "CRL used before time"); 468 return HX509_CRL_USED_BEFORE_TIME; 469 } 470 471 if (crl->tbsCertList.nextUpdate == NULL) { 472 hx509_set_error_string(context, 0, HX509_CRL_INVALID_FORMAT, 473 "CRL missing nextUpdate"); 474 return HX509_CRL_INVALID_FORMAT; 475 } 476 477 t = _hx509_Time2time_t(crl->tbsCertList.nextUpdate); 478 if (t < time_now) { 479 hx509_set_error_string(context, 0, HX509_CRL_USED_AFTER_TIME, 480 "CRL used after time"); 481 return HX509_CRL_USED_AFTER_TIME; 482 } 483 484 _hx509_query_clear(&q); 485 486 /* 487 * If it's the signer have CRLSIGN bit set, use that as the signer 488 * cert for the certificate, otherwise, search for a certificate. 489 */ 490 if (_hx509_check_key_usage(context, parent, 1 << 6, FALSE) == 0) { 491 signer = hx509_cert_ref(parent); 492 } else { 493 q.match = HX509_QUERY_MATCH_SUBJECT_NAME; 494 q.match |= HX509_QUERY_KU_CRLSIGN; 495 q.subject_name = &crl->tbsCertList.issuer; 496 497 ret = hx509_certs_find(context, certs, &q, &signer); 498 if (ret) { 499 hx509_set_error_string(context, HX509_ERROR_APPEND, ret, 500 "Failed to find certificate for CRL"); 501 return ret; 502 } 503 } 504 505 ret = _hx509_verify_signature_bitstring(context, 506 signer, 507 &crl->signatureAlgorithm, 508 &crl->tbsCertList._save, 509 &crl->signatureValue); 510 if (ret) { 511 hx509_set_error_string(context, HX509_ERROR_APPEND, ret, 512 "CRL signature invalid"); 513 goto out; 514 } 515 516 /* 517 * If signer is not CA cert, need to check revoke status of this 518 * CRL signing cert too, this include all parent CRL signer cert 519 * up to the root *sigh*, assume root at least hve CERTSIGN flag 520 * set. 521 */ 522 while (_hx509_check_key_usage(context, signer, 1 << 5, TRUE)) { 523 hx509_cert crl_parent; 524 525 _hx509_query_clear(&q); 526 527 q.match = HX509_QUERY_MATCH_SUBJECT_NAME; 528 q.match |= HX509_QUERY_KU_CRLSIGN; 529 q.subject_name = &_hx509_get_cert(signer)->tbsCertificate.issuer; 530 531 ret = hx509_certs_find(context, certs, &q, &crl_parent); 532 if (ret) { 533 hx509_set_error_string(context, HX509_ERROR_APPEND, ret, 534 "Failed to find parent of CRL signer"); 535 goto out; 536 } 537 538 ret = hx509_revoke_verify(context, 539 ctx, 540 certs, 541 time_now, 542 signer, 543 crl_parent); 544 hx509_cert_free(signer); 545 signer = crl_parent; 546 if (ret) { 547 hx509_set_error_string(context, HX509_ERROR_APPEND, ret, 548 "Failed to verify revoke " 549 "status of CRL signer"); 550 goto out; 551 } 552 } 553 554out: 555 hx509_cert_free(signer); 556 557 return ret; 558} 559 560static int 561load_crl(const char *path, time_t *t, CRLCertificateList *crl) 562{ 563 size_t length, size; 564 struct stat sb; 565 void *data; 566 int ret; 567 568 memset(crl, 0, sizeof(*crl)); 569 570 ret = rk_undumpdata(path, &data, &length); 571 if (ret) 572 return ret; 573 574 ret = stat(path, &sb); 575 if (ret) 576 return errno; 577 578 *t = sb.st_mtime; 579 580 ret = decode_CRLCertificateList(data, length, crl, &size); 581 rk_xfree(data); 582 if (ret) 583 return ret; 584 585 /* check signature is aligned */ 586 if (crl->signatureValue.length & 7) { 587 free_CRLCertificateList(crl); 588 return HX509_CRYPTO_SIG_INVALID_FORMAT; 589 } 590 return 0; 591} 592 593/** 594 * Add a CRL file to the revokation context. 595 * 596 * @param context hx509 context 597 * @param ctx hx509 revokation context 598 * @param path path to file that is going to be added to the context. 599 * 600 * @return An hx509 error code, see hx509_get_error_string(). 601 * 602 * @ingroup hx509_revoke 603 */ 604 605int 606hx509_revoke_add_crl(hx509_context context, 607 hx509_revoke_ctx ctx, 608 const char *path) 609{ 610 void *data; 611 size_t i; 612 int ret; 613 614 if (strncmp(path, "FILE:", 5) != 0) { 615 hx509_set_error_string(context, 0, HX509_UNSUPPORTED_OPERATION, 616 "unsupport type in %s", path); 617 return HX509_UNSUPPORTED_OPERATION; 618 } 619 620 621 path += 5; 622 623 for (i = 0; i < ctx->crls.len; i++) { 624 if (strcmp(ctx->crls.val[0].path, path) == 0) 625 return 0; 626 } 627 628 data = realloc(ctx->crls.val, 629 (ctx->crls.len + 1) * sizeof(ctx->crls.val[0])); 630 if (data == NULL) { 631 hx509_clear_error_string(context); 632 return ENOMEM; 633 } 634 ctx->crls.val = data; 635 636 memset(&ctx->crls.val[ctx->crls.len], 0, sizeof(ctx->crls.val[0])); 637 638 ctx->crls.val[ctx->crls.len].path = strdup(path); 639 if (ctx->crls.val[ctx->crls.len].path == NULL) { 640 hx509_clear_error_string(context); 641 return ENOMEM; 642 } 643 644 ret = load_crl(path, 645 &ctx->crls.val[ctx->crls.len].last_modfied, 646 &ctx->crls.val[ctx->crls.len].crl); 647 if (ret) { 648 free(ctx->crls.val[ctx->crls.len].path); 649 return ret; 650 } 651 652 ctx->crls.len++; 653 654 return ret; 655} 656 657/** 658 * Check that a certificate is not expired according to a revokation 659 * context. Also need the parent certificte to the check OCSP 660 * parent identifier. 661 * 662 * @param context hx509 context 663 * @param ctx hx509 revokation context 664 * @param certs certifiate pool t use 665 * @param now time now, 0 for current time 666 * @param cert cert to check 667 * @param parent_cert parent certificate 668 * 669 * @return An hx509 error code, see hx509_get_error_string(). 670 * 671 * @ingroup hx509_revoke 672 */ 673 674 675int 676hx509_revoke_verify(hx509_context context, 677 hx509_revoke_ctx ctx, 678 hx509_certs certs, 679 time_t now, 680 hx509_cert cert, 681 hx509_cert parent_cert) 682{ 683 const Certificate *c = _hx509_get_cert(cert); 684 const Certificate *p = _hx509_get_cert(parent_cert); 685 unsigned long i, j, k; 686 int ret; 687 688 hx509_clear_error_string(context); 689 690 for (i = 0; i < ctx->ocsps.len; i++) { 691 struct revoke_ocsp *ocsp = &ctx->ocsps.val[i]; 692 struct stat sb; 693 694 /* check this ocsp apply to this cert */ 695 696 /* check if there is a newer version of the file */ 697 ret = stat(ocsp->path, &sb); 698 if (ret == 0 && ocsp->last_modfied != sb.st_mtime) { 699 ret = load_ocsp(context, ocsp); 700 if (ret) 701 continue; 702 } 703 704 /* verify signature in ocsp if not already done */ 705 if (ocsp->signer == NULL) { 706 ret = verify_ocsp(context, ocsp, now, certs, parent_cert); 707 if (ret) 708 continue; 709 } 710 711 for (j = 0; j < ocsp->ocsp.tbsResponseData.responses.len; j++) { 712 heim_octet_string os; 713 714 ret = der_heim_integer_cmp(&ocsp->ocsp.tbsResponseData.responses.val[j].certID.serialNumber, 715 &c->tbsCertificate.serialNumber); 716 if (ret != 0) 717 continue; 718 719 /* verify issuer hashes hash */ 720 ret = _hx509_verify_signature(context, 721 NULL, 722 &ocsp->ocsp.tbsResponseData.responses.val[i].certID.hashAlgorithm, 723 &c->tbsCertificate.issuer._save, 724 &ocsp->ocsp.tbsResponseData.responses.val[i].certID.issuerNameHash); 725 if (ret != 0) 726 continue; 727 728 os.data = p->tbsCertificate.subjectPublicKeyInfo.subjectPublicKey.data; 729 os.length = p->tbsCertificate.subjectPublicKeyInfo.subjectPublicKey.length / 8; 730 731 ret = _hx509_verify_signature(context, 732 NULL, 733 &ocsp->ocsp.tbsResponseData.responses.val[j].certID.hashAlgorithm, 734 &os, 735 &ocsp->ocsp.tbsResponseData.responses.val[j].certID.issuerKeyHash); 736 if (ret != 0) 737 continue; 738 739 switch (ocsp->ocsp.tbsResponseData.responses.val[j].certStatus.element) { 740 case choice_OCSPCertStatus_good: 741 break; 742 case invalid_choice_OCSPCertStatus: 743 case choice_OCSPCertStatus_revoked: 744 hx509_set_error_string(context, 0, 745 HX509_CERT_REVOKED, 746 "Certificate revoked by issuer in OCSP"); 747 return HX509_CERT_REVOKED; 748 case choice_OCSPCertStatus_unknown: 749 continue; 750 } 751 752 /* don't allow the update to be in the future */ 753 if (ocsp->ocsp.tbsResponseData.responses.val[j].thisUpdate > 754 now + context->ocsp_time_diff) 755 continue; 756 757 /* don't allow the next update to be in the past */ 758 if (ocsp->ocsp.tbsResponseData.responses.val[j].nextUpdate) { 759 if (*ocsp->ocsp.tbsResponseData.responses.val[j].nextUpdate < now) 760 continue; 761 } /* else should force a refetch, but can we ? */ 762 763 return 0; 764 } 765 } 766 767 for (i = 0; i < ctx->crls.len; i++) { 768 struct revoke_crl *crl = &ctx->crls.val[i]; 769 struct stat sb; 770 int diff; 771 772 /* check if cert.issuer == crls.val[i].crl.issuer */ 773 ret = _hx509_name_cmp(&c->tbsCertificate.issuer, 774 &crl->crl.tbsCertList.issuer, &diff); 775 if (ret || diff) 776 continue; 777 778 ret = stat(crl->path, &sb); 779 if (ret == 0 && crl->last_modfied != sb.st_mtime) { 780 CRLCertificateList cl; 781 782 ret = load_crl(crl->path, &crl->last_modfied, &cl); 783 if (ret == 0) { 784 free_CRLCertificateList(&crl->crl); 785 crl->crl = cl; 786 crl->verified = 0; 787 crl->failed_verify = 0; 788 } 789 } 790 if (crl->failed_verify) 791 continue; 792 793 /* verify signature in crl if not already done */ 794 if (crl->verified == 0) { 795 ret = verify_crl(context, ctx, &crl->crl, now, certs, parent_cert); 796 if (ret) { 797 crl->failed_verify = 1; 798 continue; 799 } 800 crl->verified = 1; 801 } 802 803 if (crl->crl.tbsCertList.crlExtensions) { 804 for (j = 0; j < crl->crl.tbsCertList.crlExtensions->len; j++) { 805 if (crl->crl.tbsCertList.crlExtensions->val[j].critical) { 806 hx509_set_error_string(context, 0, 807 HX509_CRL_UNKNOWN_EXTENSION, 808 "Unknown CRL extension"); 809 return HX509_CRL_UNKNOWN_EXTENSION; 810 } 811 } 812 } 813 814 if (crl->crl.tbsCertList.revokedCertificates == NULL) 815 return 0; 816 817 /* check if cert is in crl */ 818 for (j = 0; j < crl->crl.tbsCertList.revokedCertificates->len; j++) { 819 time_t t; 820 821 ret = der_heim_integer_cmp(&crl->crl.tbsCertList.revokedCertificates->val[j].userCertificate, 822 &c->tbsCertificate.serialNumber); 823 if (ret != 0) 824 continue; 825 826 t = _hx509_Time2time_t(&crl->crl.tbsCertList.revokedCertificates->val[j].revocationDate); 827 if (t > now) 828 continue; 829 830 if (crl->crl.tbsCertList.revokedCertificates->val[j].crlEntryExtensions) 831 for (k = 0; k < crl->crl.tbsCertList.revokedCertificates->val[j].crlEntryExtensions->len; k++) 832 if (crl->crl.tbsCertList.revokedCertificates->val[j].crlEntryExtensions->val[k].critical) 833 return HX509_CRL_UNKNOWN_EXTENSION; 834 835 hx509_set_error_string(context, 0, 836 HX509_CERT_REVOKED, 837 "Certificate revoked by issuer in CRL"); 838 return HX509_CERT_REVOKED; 839 } 840 841 return 0; 842 } 843 844 845 if (context->flags & HX509_CTX_VERIFY_MISSING_OK) 846 return 0; 847 hx509_set_error_string(context, HX509_ERROR_APPEND, 848 HX509_REVOKE_STATUS_MISSING, 849 "No revoke status found for " 850 "certificates"); 851 return HX509_REVOKE_STATUS_MISSING; 852} 853 854struct ocsp_add_ctx { 855 OCSPTBSRequest *req; 856 hx509_certs certs; 857 const AlgorithmIdentifier *digest; 858 hx509_cert parent; 859}; 860 861static int 862add_to_req(hx509_context context, void *ptr, hx509_cert cert) 863{ 864 struct ocsp_add_ctx *ctx = ptr; 865 OCSPInnerRequest *one; 866 hx509_cert parent = NULL; 867 Certificate *p, *c = _hx509_get_cert(cert); 868 heim_octet_string os; 869 int ret; 870 hx509_query q; 871 void *d; 872 873 d = realloc(ctx->req->requestList.val, 874 sizeof(ctx->req->requestList.val[0]) * 875 (ctx->req->requestList.len + 1)); 876 if (d == NULL) 877 return ENOMEM; 878 ctx->req->requestList.val = d; 879 880 one = &ctx->req->requestList.val[ctx->req->requestList.len]; 881 memset(one, 0, sizeof(*one)); 882 883 _hx509_query_clear(&q); 884 885 q.match |= HX509_QUERY_FIND_ISSUER_CERT; 886 q.subject = c; 887 888 ret = hx509_certs_find(context, ctx->certs, &q, &parent); 889 if (ret) 890 goto out; 891 892 if (ctx->parent) { 893 if (hx509_cert_cmp(ctx->parent, parent) != 0) { 894 ret = HX509_REVOKE_NOT_SAME_PARENT; 895 hx509_set_error_string(context, 0, ret, 896 "Not same parent certifate as " 897 "last certificate in request"); 898 goto out; 899 } 900 } else 901 ctx->parent = hx509_cert_ref(parent); 902 903 p = _hx509_get_cert(parent); 904 905 ret = copy_AlgorithmIdentifier(ctx->digest, &one->reqCert.hashAlgorithm); 906 if (ret) 907 goto out; 908 909 ret = _hx509_create_signature(context, 910 NULL, 911 &one->reqCert.hashAlgorithm, 912 &c->tbsCertificate.issuer._save, 913 NULL, 914 &one->reqCert.issuerNameHash); 915 if (ret) 916 goto out; 917 918 os.data = p->tbsCertificate.subjectPublicKeyInfo.subjectPublicKey.data; 919 os.length = 920 p->tbsCertificate.subjectPublicKeyInfo.subjectPublicKey.length / 8; 921 922 ret = _hx509_create_signature(context, 923 NULL, 924 &one->reqCert.hashAlgorithm, 925 &os, 926 NULL, 927 &one->reqCert.issuerKeyHash); 928 if (ret) 929 goto out; 930 931 ret = copy_CertificateSerialNumber(&c->tbsCertificate.serialNumber, 932 &one->reqCert.serialNumber); 933 if (ret) 934 goto out; 935 936 ctx->req->requestList.len++; 937out: 938 hx509_cert_free(parent); 939 if (ret) { 940 free_OCSPInnerRequest(one); 941 memset(one, 0, sizeof(*one)); 942 } 943 944 return ret; 945} 946 947/** 948 * Create an OCSP request for a set of certificates. 949 * 950 * @param context a hx509 context 951 * @param reqcerts list of certificates to request ocsp data for 952 * @param pool certificate pool to use when signing 953 * @param signer certificate to use to sign the request 954 * @param digest the signing algorithm in the request, if NULL use the 955 * default signature algorithm, 956 * @param request the encoded request, free with free_heim_octet_string(). 957 * @param nonce nonce in the request, free with free_heim_octet_string(). 958 * 959 * @return An hx509 error code, see hx509_get_error_string(). 960 * 961 * @ingroup hx509_revoke 962 */ 963 964int 965hx509_ocsp_request(hx509_context context, 966 hx509_certs reqcerts, 967 hx509_certs pool, 968 hx509_cert signer, 969 const AlgorithmIdentifier *digest, 970 heim_octet_string *request, 971 heim_octet_string *nonce) 972{ 973 OCSPRequest req; 974 size_t size = 0; 975 int ret; 976 struct ocsp_add_ctx ctx; 977 Extensions *es; 978 979 memset(&req, 0, sizeof(req)); 980 981 if (digest == NULL) 982 digest = _hx509_crypto_default_digest_alg; 983 984 ctx.req = &req.tbsRequest; 985 ctx.certs = pool; 986 ctx.digest = digest; 987 ctx.parent = NULL; 988 989 ret = hx509_certs_iter_f(context, reqcerts, add_to_req, &ctx); 990 hx509_cert_free(ctx.parent); 991 if (ret) 992 goto out; 993 994 if (nonce) { 995 req.tbsRequest.requestExtensions = 996 calloc(1, sizeof(*req.tbsRequest.requestExtensions)); 997 if (req.tbsRequest.requestExtensions == NULL) { 998 ret = ENOMEM; 999 goto out; 1000 } 1001 1002 es = req.tbsRequest.requestExtensions; 1003 1004 es->len = 1; 1005 es->val = calloc(es->len, sizeof(es->val[0])); 1006 if (es->val == NULL) { 1007 es->len = 0; 1008 ret = ENOMEM; 1009 goto out; 1010 } 1011 ret = der_copy_oid(&asn1_oid_id_pkix_ocsp_nonce, &es->val[0].extnID); 1012 if (ret) { 1013 free_OCSPRequest(&req); 1014 return ret; 1015 } 1016 1017 es->val[0].extnValue.data = malloc(10); 1018 if (es->val[0].extnValue.data == NULL) { 1019 ret = ENOMEM; 1020 goto out; 1021 } 1022 es->val[0].extnValue.length = 10; 1023 1024 ret = CCRandomCopyBytes(kCCRandomDefault, 1025 es->val[0].extnValue.data, 1026 es->val[0].extnValue.length); 1027 if (ret) { 1028 ret = HX509_CRYPTO_INTERNAL_ERROR; 1029 goto out; 1030 } 1031 ret = der_copy_octet_string(nonce, &es->val[0].extnValue); 1032 if (ret) { 1033 ret = ENOMEM; 1034 goto out; 1035 } 1036 } 1037 1038 ASN1_MALLOC_ENCODE(OCSPRequest, request->data, request->length, 1039 &req, &size, ret); 1040 free_OCSPRequest(&req); 1041 if (ret) 1042 goto out; 1043 if (size != request->length) 1044 _hx509_abort("internal ASN.1 encoder error"); 1045 1046 return 0; 1047 1048out: 1049 free_OCSPRequest(&req); 1050 return ret; 1051} 1052 1053static char * 1054printable_time(time_t t) 1055{ 1056 static char s[128]; 1057 char *p; 1058 if ((p = ctime(&t)) == NULL) 1059 strlcpy(s, "?", sizeof(s)); 1060 else { 1061 strlcpy(s, p + 4, sizeof(s)); 1062 s[20] = 0; 1063 } 1064 return s; 1065} 1066 1067/** 1068 * Print the OCSP reply stored in a file. 1069 * 1070 * @param context a hx509 context 1071 * @param path path to a file with a OCSP reply 1072 * @param out the out FILE descriptor to print the reply on 1073 * 1074 * @return An hx509 error code, see hx509_get_error_string(). 1075 * 1076 * @ingroup hx509_revoke 1077 */ 1078 1079int 1080hx509_revoke_ocsp_print(hx509_context context, const char *path, FILE *out) 1081{ 1082 struct revoke_ocsp ocsp; 1083 int ret; 1084 size_t i; 1085 1086 if (out == NULL) 1087 out = stdout; 1088 1089 memset(&ocsp, 0, sizeof(ocsp)); 1090 1091 ocsp.path = strdup(path); 1092 if (ocsp.path == NULL) 1093 return ENOMEM; 1094 1095 ret = load_ocsp(context, &ocsp); 1096 if (ret) { 1097 free_ocsp(&ocsp); 1098 return ret; 1099 } 1100 1101 fprintf(out, "signer: "); 1102 1103 switch(ocsp.ocsp.tbsResponseData.responderID.element) { 1104 case choice_OCSPResponderID_byName: { 1105 hx509_name n; 1106 char *s; 1107 hx509_name_from_Name(&ocsp.ocsp.tbsResponseData.responderID.u.byName, &n); 1108 hx509_name_to_string(n, &s); 1109 hx509_name_free(&n); 1110 fprintf(out, " byName: %s\n", s); 1111 free(s); 1112 break; 1113 } 1114 case choice_OCSPResponderID_byKey: { 1115 char *s; 1116 hex_encode(ocsp.ocsp.tbsResponseData.responderID.u.byKey.data, 1117 ocsp.ocsp.tbsResponseData.responderID.u.byKey.length, 1118 &s); 1119 fprintf(out, " byKey: %s\n", s); 1120 free(s); 1121 break; 1122 } 1123 case invalid_choice_OCSPResponderID: 1124 _hx509_abort("choice_OCSPResponderID unknown"); 1125 } 1126 1127 fprintf(out, "producedAt: %s\n", 1128 printable_time(ocsp.ocsp.tbsResponseData.producedAt)); 1129 1130 fprintf(out, "replies: %d\n", ocsp.ocsp.tbsResponseData.responses.len); 1131 1132 for (i = 0; i < ocsp.ocsp.tbsResponseData.responses.len; i++) { 1133 const char *status; 1134 switch (ocsp.ocsp.tbsResponseData.responses.val[i].certStatus.element) { 1135 case choice_OCSPCertStatus_good: 1136 status = "good"; 1137 break; 1138 case choice_OCSPCertStatus_revoked: 1139 status = "revoked"; 1140 break; 1141 case choice_OCSPCertStatus_unknown: 1142 status = "unknown"; 1143 break; 1144 case invalid_choice_OCSPCertStatus: 1145 status = "element unknown"; 1146 break; 1147 } 1148 1149 fprintf(out, "\t%zu. status: %s\n", i, status); 1150 1151 fprintf(out, "\tthisUpdate: %s\n", 1152 printable_time(ocsp.ocsp.tbsResponseData.responses.val[i].thisUpdate)); 1153 if (ocsp.ocsp.tbsResponseData.responses.val[i].nextUpdate) 1154 fprintf(out, "\tproducedAt: %s\n", 1155 printable_time(ocsp.ocsp.tbsResponseData.responses.val[i].thisUpdate)); 1156 1157 } 1158 1159 fprintf(out, "appended certs:\n"); 1160 if (ocsp.certs) 1161 ret = hx509_certs_iter_f(context, ocsp.certs, hx509_ci_print_names, out); 1162 1163 free_ocsp(&ocsp); 1164 return ret; 1165} 1166 1167/** 1168 * Verify that the certificate is part of the OCSP reply and it's not 1169 * expired. Doesn't verify signature the OCSP reply or it's done by a 1170 * authorized sender, that is assumed to be already done. 1171 * 1172 * @param context a hx509 context 1173 * @param now the time right now, if 0, use the current time. 1174 * @param cert the certificate to verify 1175 * @param flags flags control the behavior 1176 * @param data pointer to the encode ocsp reply 1177 * @param length the length of the encode ocsp reply 1178 * @param expiration return the time the OCSP will expire and need to 1179 * be rechecked. 1180 * 1181 * @return An hx509 error code, see hx509_get_error_string(). 1182 * 1183 * @ingroup hx509_verify 1184 */ 1185 1186int 1187hx509_ocsp_verify(hx509_context context, 1188 time_t now, 1189 hx509_cert cert, 1190 int flags, 1191 const void *data, size_t length, 1192 time_t *expiration) 1193{ 1194 const Certificate *c = _hx509_get_cert(cert); 1195 OCSPBasicOCSPResponse basic; 1196 int ret; 1197 size_t i; 1198 1199 if (now == 0) 1200 now = time(NULL); 1201 1202 *expiration = 0; 1203 1204 ret = parse_ocsp_basic(data, length, &basic); 1205 if (ret) { 1206 hx509_set_error_string(context, 0, ret, 1207 "Failed to parse OCSP response"); 1208 return ret; 1209 } 1210 1211 for (i = 0; i < basic.tbsResponseData.responses.len; i++) { 1212 1213 ret = der_heim_integer_cmp(&basic.tbsResponseData.responses.val[i].certID.serialNumber, 1214 &c->tbsCertificate.serialNumber); 1215 if (ret != 0) 1216 continue; 1217 1218 /* verify issuer hashes hash */ 1219 ret = _hx509_verify_signature(context, 1220 NULL, 1221 &basic.tbsResponseData.responses.val[i].certID.hashAlgorithm, 1222 &c->tbsCertificate.issuer._save, 1223 &basic.tbsResponseData.responses.val[i].certID.issuerNameHash); 1224 if (ret != 0) 1225 continue; 1226 1227 switch (basic.tbsResponseData.responses.val[i].certStatus.element) { 1228 case choice_OCSPCertStatus_good: 1229 break; 1230 case choice_OCSPCertStatus_revoked: 1231 case choice_OCSPCertStatus_unknown: 1232 case invalid_choice_OCSPCertStatus: 1233 continue; 1234 } 1235 1236 /* don't allow the update to be in the future */ 1237 if (basic.tbsResponseData.responses.val[i].thisUpdate > 1238 now + context->ocsp_time_diff) 1239 continue; 1240 1241 /* don't allow the next update to be in the past */ 1242 if (basic.tbsResponseData.responses.val[i].nextUpdate) { 1243 if (*basic.tbsResponseData.responses.val[i].nextUpdate < now) 1244 continue; 1245 *expiration = *basic.tbsResponseData.responses.val[i].nextUpdate; 1246 } else 1247 *expiration = now; 1248 1249 free_OCSPBasicOCSPResponse(&basic); 1250 return 0; 1251 } 1252 1253 free_OCSPBasicOCSPResponse(&basic); 1254 1255 { 1256 hx509_name name; 1257 char *subject; 1258 1259 ret = hx509_cert_get_subject(cert, &name); 1260 if (ret) { 1261 hx509_clear_error_string(context); 1262 goto out; 1263 } 1264 ret = hx509_name_to_string(name, &subject); 1265 hx509_name_free(&name); 1266 if (ret) { 1267 hx509_clear_error_string(context); 1268 goto out; 1269 } 1270 hx509_set_error_string(context, 0, HX509_CERT_NOT_IN_OCSP, 1271 "Certificate %s not in OCSP response " 1272 "or not good", 1273 subject); 1274 free(subject); 1275 } 1276out: 1277 return HX509_CERT_NOT_IN_OCSP; 1278} 1279 1280struct hx509_crl { 1281 hx509_certs revoked; 1282 time_t expire; 1283}; 1284 1285/** 1286 * Create a CRL context. Use hx509_crl_free() to free the CRL context. 1287 * 1288 * @param context a hx509 context. 1289 * @param crl return pointer to a newly allocated CRL context. 1290 * 1291 * @return An hx509 error code, see hx509_get_error_string(). 1292 * 1293 * @ingroup hx509_verify 1294 */ 1295 1296int 1297hx509_crl_alloc(hx509_context context, hx509_crl *crl) 1298{ 1299 int ret; 1300 1301 *crl = calloc(1, sizeof(**crl)); 1302 if (*crl == NULL) { 1303 hx509_set_error_string(context, 0, ENOMEM, "out of memory"); 1304 return ENOMEM; 1305 } 1306 1307 ret = hx509_certs_init(context, "MEMORY:crl", 0, NULL, &(*crl)->revoked); 1308 if (ret) { 1309 free(*crl); 1310 *crl = NULL; 1311 return ret; 1312 } 1313 (*crl)->expire = 0; 1314 return ret; 1315} 1316 1317/** 1318 * Add revoked certificate to an CRL context. 1319 * 1320 * @param context a hx509 context. 1321 * @param crl the CRL to add the revoked certificate to. 1322 * @param certs keyset of certificate to revoke. 1323 * 1324 * @return An hx509 error code, see hx509_get_error_string(). 1325 * 1326 * @ingroup hx509_verify 1327 */ 1328 1329int 1330hx509_crl_add_revoked_certs(hx509_context context, 1331 hx509_crl crl, 1332 hx509_certs certs) 1333{ 1334 return hx509_certs_merge(context, crl->revoked, certs); 1335} 1336 1337/** 1338 * Set the lifetime of a CRL context. 1339 * 1340 * @param context a hx509 context. 1341 * @param crl a CRL context 1342 * @param delta delta time the certificate is valid, library adds the 1343 * current time to this. 1344 * 1345 * @return An hx509 error code, see hx509_get_error_string(). 1346 * 1347 * @ingroup hx509_verify 1348 */ 1349 1350int 1351hx509_crl_lifetime(hx509_context context, hx509_crl crl, int delta) 1352{ 1353 crl->expire = time(NULL) + delta; 1354 return 0; 1355} 1356 1357/** 1358 * Free a CRL context. 1359 * 1360 * @param context a hx509 context. 1361 * @param crl a CRL context to free. 1362 * 1363 * @ingroup hx509_verify 1364 */ 1365 1366void 1367hx509_crl_free(hx509_context context, hx509_crl *crl) 1368{ 1369 if (*crl == NULL) 1370 return; 1371 hx509_certs_free(&(*crl)->revoked); 1372 memset(*crl, 0, sizeof(**crl)); 1373 free(*crl); 1374 *crl = NULL; 1375} 1376 1377static int 1378add_revoked(hx509_context context, void *ctx, hx509_cert cert) 1379{ 1380 TBSCRLCertList *c = ctx; 1381 unsigned int num; 1382 void *ptr; 1383 int ret; 1384 1385 num = c->revokedCertificates->len; 1386 ptr = realloc(c->revokedCertificates->val, 1387 (num + 1) * sizeof(c->revokedCertificates->val[0])); 1388 if (ptr == NULL) { 1389 hx509_clear_error_string(context); 1390 return ENOMEM; 1391 } 1392 c->revokedCertificates->val = ptr; 1393 1394 ret = hx509_cert_get_serialnumber(cert, 1395 &c->revokedCertificates->val[num].userCertificate); 1396 if (ret) { 1397 hx509_clear_error_string(context); 1398 return ret; 1399 } 1400 c->revokedCertificates->val[num].revocationDate.element = 1401 choice_Time_generalTime; 1402 c->revokedCertificates->val[num].revocationDate.u.generalTime = 1403 time(NULL) - 3600 * 24; 1404 c->revokedCertificates->val[num].crlEntryExtensions = NULL; 1405 1406 c->revokedCertificates->len++; 1407 1408 return 0; 1409} 1410 1411/** 1412 * Sign a CRL and return an encode certificate. 1413 * 1414 * @param context a hx509 context. 1415 * @param signer certificate to sign the CRL with 1416 * @param crl the CRL to sign 1417 * @param os return the signed and encoded CRL, free with 1418 * free_heim_octet_string() 1419 * 1420 * @return An hx509 error code, see hx509_get_error_string(). 1421 * 1422 * @ingroup hx509_verify 1423 */ 1424 1425int 1426hx509_crl_sign(hx509_context context, 1427 hx509_cert signer, 1428 hx509_crl crl, 1429 heim_octet_string *os) 1430{ 1431 const AlgorithmIdentifier *sigalg = _hx509_crypto_default_sig_alg; 1432 CRLCertificateList c; 1433 size_t size = 0; 1434 int ret; 1435 hx509_private_key signerkey; 1436 1437 memset(&c, 0, sizeof(c)); 1438 1439 signerkey = _hx509_cert_private_key(signer); 1440 if (signerkey == NULL) { 1441 ret = HX509_PRIVATE_KEY_MISSING; 1442 hx509_set_error_string(context, 0, ret, 1443 "Private key missing for CRL signing"); 1444 return ret; 1445 } 1446 1447 c.tbsCertList.version = malloc(sizeof(*c.tbsCertList.version)); 1448 if (c.tbsCertList.version == NULL) { 1449 hx509_set_error_string(context, 0, ENOMEM, "out of memory"); 1450 return ENOMEM; 1451 } 1452 1453 *c.tbsCertList.version = 1; 1454 1455 ret = copy_AlgorithmIdentifier(sigalg, &c.tbsCertList.signature); 1456 if (ret) { 1457 hx509_clear_error_string(context); 1458 goto out; 1459 } 1460 1461 ret = copy_Name(&_hx509_get_cert(signer)->tbsCertificate.issuer, 1462 &c.tbsCertList.issuer); 1463 if (ret) { 1464 hx509_clear_error_string(context); 1465 goto out; 1466 } 1467 1468 c.tbsCertList.thisUpdate.element = choice_Time_generalTime; 1469 c.tbsCertList.thisUpdate.u.generalTime = time(NULL) - 24 * 3600; 1470 1471 c.tbsCertList.nextUpdate = malloc(sizeof(*c.tbsCertList.nextUpdate)); 1472 if (c.tbsCertList.nextUpdate == NULL) { 1473 hx509_set_error_string(context, 0, ENOMEM, "out of memory"); 1474 ret = ENOMEM; 1475 goto out; 1476 } 1477 1478 { 1479 time_t next = crl->expire; 1480 if (next == 0) 1481 next = time(NULL) + 24 * 3600 * 365; 1482 1483 c.tbsCertList.nextUpdate->element = choice_Time_generalTime; 1484 c.tbsCertList.nextUpdate->u.generalTime = next; 1485 } 1486 1487 c.tbsCertList.revokedCertificates = 1488 calloc(1, sizeof(*c.tbsCertList.revokedCertificates)); 1489 if (c.tbsCertList.revokedCertificates == NULL) { 1490 hx509_set_error_string(context, 0, ENOMEM, "out of memory"); 1491 ret = ENOMEM; 1492 goto out; 1493 } 1494 c.tbsCertList.crlExtensions = NULL; 1495 1496 ret = hx509_certs_iter_f(context, crl->revoked, add_revoked, &c.tbsCertList); 1497 if (ret) 1498 goto out; 1499 1500 /* if not revoked certs, remove OPTIONAL entry */ 1501 if (c.tbsCertList.revokedCertificates->len == 0) { 1502 free(c.tbsCertList.revokedCertificates); 1503 c.tbsCertList.revokedCertificates = NULL; 1504 } 1505 1506 ASN1_MALLOC_ENCODE(TBSCRLCertList, os->data, os->length, 1507 &c.tbsCertList, &size, ret); 1508 if (ret) { 1509 hx509_set_error_string(context, 0, ret, "failed to encode tbsCRL"); 1510 goto out; 1511 } 1512 if (size != os->length) 1513 _hx509_abort("internal ASN.1 encoder error"); 1514 1515 1516 ret = _hx509_create_signature_bitstring(context, 1517 signerkey, 1518 sigalg, 1519 os, 1520 &c.signatureAlgorithm, 1521 &c.signatureValue); 1522 free(os->data); 1523 if (ret) { 1524 hx509_set_error_string(context, 0, ret, "Failed to sign CRL"); 1525 goto out; 1526 } 1527 1528 ASN1_MALLOC_ENCODE(CRLCertificateList, os->data, os->length, 1529 &c, &size, ret); 1530 if (ret) { 1531 hx509_set_error_string(context, 0, ret, "failed to encode CRL"); 1532 goto out; 1533 } 1534 if (size != os->length) 1535 _hx509_abort("internal ASN.1 encoder error"); 1536 1537 free_CRLCertificateList(&c); 1538 1539 return 0; 1540 1541out: 1542 free_CRLCertificateList(&c); 1543 return ret; 1544} 1545