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