1 /* $NetBSD: revoke.c,v 1.3 2014/04/24 13:45:34 pettai 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 56 struct revoke_crl { 57 char *path; 58 time_t last_modfied; 59 CRLCertificateList crl; 60 int verified; 61 int failed_verify; 62 }; 63 64 struct revoke_ocsp { 65 char *path; 66 time_t last_modfied; 67 OCSPBasicOCSPResponse ocsp; 68 hx509_certs certs; 69 hx509_cert signer; 70 }; 71 72 73 struct 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 96 int 97 hx509_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 112 hx509_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 125 static void 126 free_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 142 void 143 hx509_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 171 static int 172 verify_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; 257 out: 258 if (signer) 259 hx509_cert_free(signer); 260 261 return ret; 262 } 263 264 /* 265 * 266 */ 267 268 static int 269 parse_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 327 static int 328 load_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 size_t 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 402 int 403 hx509_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 456 static int 457 verify_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 559 out: 560 hx509_cert_free(signer); 561 562 return ret; 563 } 564 565 static int 566 load_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 610 int 611 hx509_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[i].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 680 int 681 hx509_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 should force a refetch, but can we ? */ 766 767 return 0; 768 } 769 } 770 771 for (i = 0; i < ctx->crls.len; i++) { 772 struct revoke_crl *crl = &ctx->crls.val[i]; 773 struct stat sb; 774 int diff; 775 776 /* check if cert.issuer == crls.val[i].crl.issuer */ 777 ret = _hx509_name_cmp(&c->tbsCertificate.issuer, 778 &crl->crl.tbsCertList.issuer, &diff); 779 if (ret || diff) 780 continue; 781 782 ret = stat(crl->path, &sb); 783 if (ret == 0 && crl->last_modfied != sb.st_mtime) { 784 CRLCertificateList cl; 785 786 ret = load_crl(crl->path, &crl->last_modfied, &cl); 787 if (ret == 0) { 788 free_CRLCertificateList(&crl->crl); 789 crl->crl = cl; 790 crl->verified = 0; 791 crl->failed_verify = 0; 792 } 793 } 794 if (crl->failed_verify) 795 continue; 796 797 /* verify signature in crl if not already done */ 798 if (crl->verified == 0) { 799 ret = verify_crl(context, ctx, &crl->crl, now, certs, parent_cert); 800 if (ret) { 801 crl->failed_verify = 1; 802 continue; 803 } 804 crl->verified = 1; 805 } 806 807 if (crl->crl.tbsCertList.crlExtensions) { 808 for (j = 0; j < crl->crl.tbsCertList.crlExtensions->len; j++) { 809 if (crl->crl.tbsCertList.crlExtensions->val[j].critical) { 810 hx509_set_error_string(context, 0, 811 HX509_CRL_UNKNOWN_EXTENSION, 812 "Unknown CRL extension"); 813 return HX509_CRL_UNKNOWN_EXTENSION; 814 } 815 } 816 } 817 818 if (crl->crl.tbsCertList.revokedCertificates == NULL) 819 return 0; 820 821 /* check if cert is in crl */ 822 for (j = 0; j < crl->crl.tbsCertList.revokedCertificates->len; j++) { 823 time_t t; 824 825 ret = der_heim_integer_cmp(&crl->crl.tbsCertList.revokedCertificates->val[j].userCertificate, 826 &c->tbsCertificate.serialNumber); 827 if (ret != 0) 828 continue; 829 830 t = _hx509_Time2time_t(&crl->crl.tbsCertList.revokedCertificates->val[j].revocationDate); 831 if (t > now) 832 continue; 833 834 if (crl->crl.tbsCertList.revokedCertificates->val[j].crlEntryExtensions) 835 for (k = 0; k < crl->crl.tbsCertList.revokedCertificates->val[j].crlEntryExtensions->len; k++) 836 if (crl->crl.tbsCertList.revokedCertificates->val[j].crlEntryExtensions->val[k].critical) 837 return HX509_CRL_UNKNOWN_EXTENSION; 838 839 hx509_set_error_string(context, 0, 840 HX509_CERT_REVOKED, 841 "Certificate revoked by issuer in CRL"); 842 return HX509_CERT_REVOKED; 843 } 844 845 return 0; 846 } 847 848 849 if (context->flags & HX509_CTX_VERIFY_MISSING_OK) 850 return 0; 851 hx509_set_error_string(context, HX509_ERROR_APPEND, 852 HX509_REVOKE_STATUS_MISSING, 853 "No revoke status found for " 854 "certificates"); 855 return HX509_REVOKE_STATUS_MISSING; 856 } 857 858 struct ocsp_add_ctx { 859 OCSPTBSRequest *req; 860 hx509_certs certs; 861 const AlgorithmIdentifier *digest; 862 hx509_cert parent; 863 }; 864 865 static int 866 add_to_req(hx509_context context, void *ptr, hx509_cert cert) 867 { 868 struct ocsp_add_ctx *ctx = ptr; 869 OCSPInnerRequest *one; 870 hx509_cert parent = NULL; 871 Certificate *p, *c = _hx509_get_cert(cert); 872 heim_octet_string os; 873 int ret; 874 hx509_query q; 875 void *d; 876 877 d = realloc(ctx->req->requestList.val, 878 sizeof(ctx->req->requestList.val[0]) * 879 (ctx->req->requestList.len + 1)); 880 if (d == NULL) 881 return ENOMEM; 882 ctx->req->requestList.val = d; 883 884 one = &ctx->req->requestList.val[ctx->req->requestList.len]; 885 memset(one, 0, sizeof(*one)); 886 887 _hx509_query_clear(&q); 888 889 q.match |= HX509_QUERY_FIND_ISSUER_CERT; 890 q.subject = c; 891 892 ret = hx509_certs_find(context, ctx->certs, &q, &parent); 893 if (ret) 894 goto out; 895 896 if (ctx->parent) { 897 if (hx509_cert_cmp(ctx->parent, parent) != 0) { 898 ret = HX509_REVOKE_NOT_SAME_PARENT; 899 hx509_set_error_string(context, 0, ret, 900 "Not same parent certifate as " 901 "last certificate in request"); 902 goto out; 903 } 904 } else 905 ctx->parent = hx509_cert_ref(parent); 906 907 p = _hx509_get_cert(parent); 908 909 ret = copy_AlgorithmIdentifier(ctx->digest, &one->reqCert.hashAlgorithm); 910 if (ret) 911 goto out; 912 913 ret = _hx509_create_signature(context, 914 NULL, 915 &one->reqCert.hashAlgorithm, 916 &c->tbsCertificate.issuer._save, 917 NULL, 918 &one->reqCert.issuerNameHash); 919 if (ret) 920 goto out; 921 922 os.data = p->tbsCertificate.subjectPublicKeyInfo.subjectPublicKey.data; 923 os.length = 924 p->tbsCertificate.subjectPublicKeyInfo.subjectPublicKey.length / 8; 925 926 ret = _hx509_create_signature(context, 927 NULL, 928 &one->reqCert.hashAlgorithm, 929 &os, 930 NULL, 931 &one->reqCert.issuerKeyHash); 932 if (ret) 933 goto out; 934 935 ret = copy_CertificateSerialNumber(&c->tbsCertificate.serialNumber, 936 &one->reqCert.serialNumber); 937 if (ret) 938 goto out; 939 940 ctx->req->requestList.len++; 941 out: 942 hx509_cert_free(parent); 943 if (ret) { 944 free_OCSPInnerRequest(one); 945 memset(one, 0, sizeof(*one)); 946 } 947 948 return ret; 949 } 950 951 /** 952 * Create an OCSP request for a set of certificates. 953 * 954 * @param context a hx509 context 955 * @param reqcerts list of certificates to request ocsp data for 956 * @param pool certificate pool to use when signing 957 * @param signer certificate to use to sign the request 958 * @param digest the signing algorithm in the request, if NULL use the 959 * default signature algorithm, 960 * @param request the encoded request, free with free_heim_octet_string(). 961 * @param nonce nonce in the request, free with free_heim_octet_string(). 962 * 963 * @return An hx509 error code, see hx509_get_error_string(). 964 * 965 * @ingroup hx509_revoke 966 */ 967 968 int 969 hx509_ocsp_request(hx509_context context, 970 hx509_certs reqcerts, 971 hx509_certs pool, 972 hx509_cert signer, 973 const AlgorithmIdentifier *digest, 974 heim_octet_string *request, 975 heim_octet_string *nonce) 976 { 977 OCSPRequest req; 978 size_t size; 979 int ret; 980 struct ocsp_add_ctx ctx; 981 Extensions *es; 982 983 memset(&req, 0, sizeof(req)); 984 985 if (digest == NULL) 986 digest = _hx509_crypto_default_digest_alg; 987 988 ctx.req = &req.tbsRequest; 989 ctx.certs = pool; 990 ctx.digest = digest; 991 ctx.parent = NULL; 992 993 ret = hx509_certs_iter_f(context, reqcerts, add_to_req, &ctx); 994 hx509_cert_free(ctx.parent); 995 if (ret) 996 goto out; 997 998 if (nonce) { 999 req.tbsRequest.requestExtensions = 1000 calloc(1, sizeof(*req.tbsRequest.requestExtensions)); 1001 if (req.tbsRequest.requestExtensions == NULL) { 1002 ret = ENOMEM; 1003 goto out; 1004 } 1005 1006 es = req.tbsRequest.requestExtensions; 1007 1008 es->val = calloc(es->len, sizeof(es->val[0])); 1009 if (es->val == NULL) { 1010 ret = ENOMEM; 1011 goto out; 1012 } 1013 es->len = 1; 1014 ret = der_copy_oid(&asn1_oid_id_pkix_ocsp_nonce, &es->val[0].extnID); 1015 if (ret) { 1016 free_OCSPRequest(&req); 1017 return ret; 1018 } 1019 1020 es->val[0].extnValue.data = malloc(10); 1021 if (es->val[0].extnValue.data == NULL) { 1022 ret = ENOMEM; 1023 goto out; 1024 } 1025 es->val[0].extnValue.length = 10; 1026 1027 ret = RAND_bytes(es->val[0].extnValue.data, 1028 es->val[0].extnValue.length); 1029 if (ret != 1) { 1030 ret = HX509_CRYPTO_INTERNAL_ERROR; 1031 goto out; 1032 } 1033 ret = der_copy_octet_string(nonce, &es->val[0].extnValue); 1034 if (ret) { 1035 ret = ENOMEM; 1036 goto out; 1037 } 1038 } 1039 1040 ASN1_MALLOC_ENCODE(OCSPRequest, request->data, request->length, 1041 &req, &size, ret); 1042 free_OCSPRequest(&req); 1043 if (ret) 1044 goto out; 1045 if (size != request->length) 1046 _hx509_abort("internal ASN.1 encoder error"); 1047 1048 return 0; 1049 1050 out: 1051 free_OCSPRequest(&req); 1052 return ret; 1053 } 1054 1055 static char * 1056 printable_time(time_t t) 1057 { 1058 static char s[128]; 1059 char *p; 1060 if ((p = ctime(&t)) == NULL) 1061 strlcpy(s, "?", sizeof(s)); 1062 else { 1063 strlcpy(s, p + 4, sizeof(s)); 1064 s[20] = 0; 1065 } 1066 return s; 1067 } 1068 1069 /** 1070 * Print the OCSP reply stored in a file. 1071 * 1072 * @param context a hx509 context 1073 * @param path path to a file with a OCSP reply 1074 * @param out the out FILE descriptor to print the reply on 1075 * 1076 * @return An hx509 error code, see hx509_get_error_string(). 1077 * 1078 * @ingroup hx509_revoke 1079 */ 1080 1081 int 1082 hx509_revoke_ocsp_print(hx509_context context, const char *path, FILE *out) 1083 { 1084 struct revoke_ocsp ocsp; 1085 int ret; 1086 size_t 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%zu. 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 1188 int 1189 hx509_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; 1199 size_t i; 1200 1201 if (now == 0) 1202 now = time(NULL); 1203 1204 *expiration = 0; 1205 1206 ret = parse_ocsp_basic(data, length, &basic); 1207 if (ret) { 1208 hx509_set_error_string(context, 0, ret, 1209 "Failed to parse OCSP response"); 1210 return ret; 1211 } 1212 1213 for (i = 0; i < basic.tbsResponseData.responses.len; i++) { 1214 1215 ret = der_heim_integer_cmp(&basic.tbsResponseData.responses.val[i].certID.serialNumber, 1216 &c->tbsCertificate.serialNumber); 1217 if (ret != 0) 1218 continue; 1219 1220 /* verify issuer hashes hash */ 1221 ret = _hx509_verify_signature(context, 1222 NULL, 1223 &basic.tbsResponseData.responses.val[i].certID.hashAlgorithm, 1224 &c->tbsCertificate.issuer._save, 1225 &basic.tbsResponseData.responses.val[i].certID.issuerNameHash); 1226 if (ret != 0) 1227 continue; 1228 1229 switch (basic.tbsResponseData.responses.val[i].certStatus.element) { 1230 case choice_OCSPCertStatus_good: 1231 break; 1232 case choice_OCSPCertStatus_revoked: 1233 case choice_OCSPCertStatus_unknown: 1234 continue; 1235 } 1236 1237 /* don't allow the update to be in the future */ 1238 if (basic.tbsResponseData.responses.val[i].thisUpdate > 1239 now + context->ocsp_time_diff) 1240 continue; 1241 1242 /* don't allow the next update to be in the past */ 1243 if (basic.tbsResponseData.responses.val[i].nextUpdate) { 1244 if (*basic.tbsResponseData.responses.val[i].nextUpdate < now) 1245 continue; 1246 *expiration = *basic.tbsResponseData.responses.val[i].nextUpdate; 1247 } else 1248 *expiration = now; 1249 1250 free_OCSPBasicOCSPResponse(&basic); 1251 return 0; 1252 } 1253 1254 free_OCSPBasicOCSPResponse(&basic); 1255 1256 { 1257 hx509_name name; 1258 char *subject; 1259 1260 ret = hx509_cert_get_subject(cert, &name); 1261 if (ret) { 1262 hx509_clear_error_string(context); 1263 goto out; 1264 } 1265 ret = hx509_name_to_string(name, &subject); 1266 hx509_name_free(&name); 1267 if (ret) { 1268 hx509_clear_error_string(context); 1269 goto out; 1270 } 1271 hx509_set_error_string(context, 0, HX509_CERT_NOT_IN_OCSP, 1272 "Certificate %s not in OCSP response " 1273 "or not good", 1274 subject); 1275 free(subject); 1276 } 1277 out: 1278 return HX509_CERT_NOT_IN_OCSP; 1279 } 1280 1281 struct hx509_crl { 1282 hx509_certs revoked; 1283 time_t expire; 1284 }; 1285 1286 /** 1287 * Create a CRL context. Use hx509_crl_free() to free the CRL context. 1288 * 1289 * @param context a hx509 context. 1290 * @param crl return pointer to a newly allocated CRL context. 1291 * 1292 * @return An hx509 error code, see hx509_get_error_string(). 1293 * 1294 * @ingroup hx509_verify 1295 */ 1296 1297 int 1298 hx509_crl_alloc(hx509_context context, hx509_crl *crl) 1299 { 1300 int ret; 1301 1302 *crl = calloc(1, sizeof(**crl)); 1303 if (*crl == NULL) { 1304 hx509_set_error_string(context, 0, ENOMEM, "out of memory"); 1305 return ENOMEM; 1306 } 1307 1308 ret = hx509_certs_init(context, "MEMORY:crl", 0, NULL, &(*crl)->revoked); 1309 if (ret) { 1310 free(*crl); 1311 *crl = NULL; 1312 return ret; 1313 } 1314 (*crl)->expire = 0; 1315 return ret; 1316 } 1317 1318 /** 1319 * Add revoked certificate to an CRL context. 1320 * 1321 * @param context a hx509 context. 1322 * @param crl the CRL to add the revoked certificate to. 1323 * @param certs keyset of certificate to revoke. 1324 * 1325 * @return An hx509 error code, see hx509_get_error_string(). 1326 * 1327 * @ingroup hx509_verify 1328 */ 1329 1330 int 1331 hx509_crl_add_revoked_certs(hx509_context context, 1332 hx509_crl crl, 1333 hx509_certs certs) 1334 { 1335 return hx509_certs_merge(context, crl->revoked, certs); 1336 } 1337 1338 /** 1339 * Set the lifetime of a CRL context. 1340 * 1341 * @param context a hx509 context. 1342 * @param crl a CRL context 1343 * @param delta delta time the certificate is valid, library adds the 1344 * current time to this. 1345 * 1346 * @return An hx509 error code, see hx509_get_error_string(). 1347 * 1348 * @ingroup hx509_verify 1349 */ 1350 1351 int 1352 hx509_crl_lifetime(hx509_context context, hx509_crl crl, int delta) 1353 { 1354 crl->expire = time(NULL) + delta; 1355 return 0; 1356 } 1357 1358 /** 1359 * Free a CRL context. 1360 * 1361 * @param context a hx509 context. 1362 * @param crl a CRL context to free. 1363 * 1364 * @ingroup hx509_verify 1365 */ 1366 1367 void 1368 hx509_crl_free(hx509_context context, hx509_crl *crl) 1369 { 1370 if (*crl == NULL) 1371 return; 1372 hx509_certs_free(&(*crl)->revoked); 1373 memset(*crl, 0, sizeof(**crl)); 1374 free(*crl); 1375 *crl = NULL; 1376 } 1377 1378 static int 1379 add_revoked(hx509_context context, void *ctx, hx509_cert cert) 1380 { 1381 TBSCRLCertList *c = ctx; 1382 unsigned int num; 1383 void *ptr; 1384 int ret; 1385 1386 num = c->revokedCertificates->len; 1387 ptr = realloc(c->revokedCertificates->val, 1388 (num + 1) * sizeof(c->revokedCertificates->val[0])); 1389 if (ptr == NULL) { 1390 hx509_clear_error_string(context); 1391 return ENOMEM; 1392 } 1393 c->revokedCertificates->val = ptr; 1394 1395 ret = hx509_cert_get_serialnumber(cert, 1396 &c->revokedCertificates->val[num].userCertificate); 1397 if (ret) { 1398 hx509_clear_error_string(context); 1399 return ret; 1400 } 1401 c->revokedCertificates->val[num].revocationDate.element = 1402 choice_Time_generalTime; 1403 c->revokedCertificates->val[num].revocationDate.u.generalTime = 1404 time(NULL) - 3600 * 24; 1405 c->revokedCertificates->val[num].crlEntryExtensions = NULL; 1406 1407 c->revokedCertificates->len++; 1408 1409 return 0; 1410 } 1411 1412 /** 1413 * Sign a CRL and return an encode certificate. 1414 * 1415 * @param context a hx509 context. 1416 * @param signer certificate to sign the CRL with 1417 * @param crl the CRL to sign 1418 * @param os return the signed and encoded CRL, free with 1419 * free_heim_octet_string() 1420 * 1421 * @return An hx509 error code, see hx509_get_error_string(). 1422 * 1423 * @ingroup hx509_verify 1424 */ 1425 1426 int 1427 hx509_crl_sign(hx509_context context, 1428 hx509_cert signer, 1429 hx509_crl crl, 1430 heim_octet_string *os) 1431 { 1432 const AlgorithmIdentifier *sigalg = _hx509_crypto_default_sig_alg; 1433 CRLCertificateList c; 1434 size_t size; 1435 int ret; 1436 hx509_private_key signerkey; 1437 1438 memset(&c, 0, sizeof(c)); 1439 1440 signerkey = _hx509_cert_private_key(signer); 1441 if (signerkey == NULL) { 1442 ret = HX509_PRIVATE_KEY_MISSING; 1443 hx509_set_error_string(context, 0, ret, 1444 "Private key missing for CRL signing"); 1445 return ret; 1446 } 1447 1448 c.tbsCertList.version = malloc(sizeof(*c.tbsCertList.version)); 1449 if (c.tbsCertList.version == NULL) { 1450 hx509_set_error_string(context, 0, ENOMEM, "out of memory"); 1451 return ENOMEM; 1452 } 1453 1454 *c.tbsCertList.version = 1; 1455 1456 ret = copy_AlgorithmIdentifier(sigalg, &c.tbsCertList.signature); 1457 if (ret) { 1458 hx509_clear_error_string(context); 1459 goto out; 1460 } 1461 1462 ret = copy_Name(&_hx509_get_cert(signer)->tbsCertificate.issuer, 1463 &c.tbsCertList.issuer); 1464 if (ret) { 1465 hx509_clear_error_string(context); 1466 goto out; 1467 } 1468 1469 c.tbsCertList.thisUpdate.element = choice_Time_generalTime; 1470 c.tbsCertList.thisUpdate.u.generalTime = time(NULL) - 24 * 3600; 1471 1472 c.tbsCertList.nextUpdate = malloc(sizeof(*c.tbsCertList.nextUpdate)); 1473 if (c.tbsCertList.nextUpdate == NULL) { 1474 hx509_set_error_string(context, 0, ENOMEM, "out of memory"); 1475 ret = ENOMEM; 1476 goto out; 1477 } 1478 1479 { 1480 time_t next = crl->expire; 1481 if (next == 0) 1482 next = time(NULL) + 24 * 3600 * 365; 1483 1484 c.tbsCertList.nextUpdate->element = choice_Time_generalTime; 1485 c.tbsCertList.nextUpdate->u.generalTime = next; 1486 } 1487 1488 c.tbsCertList.revokedCertificates = 1489 calloc(1, sizeof(*c.tbsCertList.revokedCertificates)); 1490 if (c.tbsCertList.revokedCertificates == NULL) { 1491 hx509_set_error_string(context, 0, ENOMEM, "out of memory"); 1492 ret = ENOMEM; 1493 goto out; 1494 } 1495 c.tbsCertList.crlExtensions = NULL; 1496 1497 ret = hx509_certs_iter_f(context, crl->revoked, add_revoked, &c.tbsCertList); 1498 if (ret) 1499 goto out; 1500 1501 /* if not revoked certs, remove OPTIONAL entry */ 1502 if (c.tbsCertList.revokedCertificates->len == 0) { 1503 free(c.tbsCertList.revokedCertificates); 1504 c.tbsCertList.revokedCertificates = NULL; 1505 } 1506 1507 ASN1_MALLOC_ENCODE(TBSCRLCertList, os->data, os->length, 1508 &c.tbsCertList, &size, ret); 1509 if (ret) { 1510 hx509_set_error_string(context, 0, ret, "failed to encode tbsCRL"); 1511 goto out; 1512 } 1513 if (size != os->length) 1514 _hx509_abort("internal ASN.1 encoder error"); 1515 1516 1517 ret = _hx509_create_signature_bitstring(context, 1518 signerkey, 1519 sigalg, 1520 os, 1521 &c.signatureAlgorithm, 1522 &c.signatureValue); 1523 free(os->data); 1524 if (ret) { 1525 hx509_set_error_string(context, 0, ret, "Failed to sign CRL"); 1526 goto out; 1527 } 1528 1529 ASN1_MALLOC_ENCODE(CRLCertificateList, os->data, os->length, 1530 &c, &size, ret); 1531 if (ret) { 1532 hx509_set_error_string(context, 0, ret, "failed to encode CRL"); 1533 goto out; 1534 } 1535 if (size != os->length) 1536 _hx509_abort("internal ASN.1 encoder error"); 1537 1538 free_CRLCertificateList(&c); 1539 1540 return 0; 1541 1542 out: 1543 free_CRLCertificateList(&c); 1544 return ret; 1545 } 1546