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 54 struct revoke_crl { 55 char *path; 56 time_t last_modfied; 57 CRLCertificateList crl; 58 int verified; 59 int failed_verify; 60 }; 61 62 struct revoke_ocsp { 63 char *path; 64 time_t last_modfied; 65 OCSPBasicOCSPResponse ocsp; 66 hx509_certs certs; 67 hx509_cert signer; 68 }; 69 70 71 struct hx509_revoke_ctx_data { 72 unsigned int ref; 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 83 /** 84 * Allocate a revokation context. Free with hx509_revoke_free(). 85 * 86 * @param context A hx509 context. 87 * @param ctx returns a newly allocated revokation context. 88 * 89 * @return An hx509 error code, see hx509_get_error_string(). 90 * 91 * @ingroup hx509_revoke 92 */ 93 94 int 95 hx509_revoke_init(hx509_context context, hx509_revoke_ctx *ctx) 96 { 97 *ctx = calloc(1, sizeof(**ctx)); 98 if (*ctx == NULL) 99 return ENOMEM; 100 101 (*ctx)->ref = 1; 102 (*ctx)->crls.len = 0; 103 (*ctx)->crls.val = NULL; 104 (*ctx)->ocsps.len = 0; 105 (*ctx)->ocsps.val = NULL; 106 107 return 0; 108 } 109 110 hx509_revoke_ctx 111 _hx509_revoke_ref(hx509_revoke_ctx ctx) 112 { 113 if (ctx == NULL) 114 return NULL; 115 if (ctx->ref == 0) 116 _hx509_abort("revoke ctx refcount == 0 on ref"); 117 ctx->ref++; 118 if (ctx->ref == UINT_MAX) 119 _hx509_abort("revoke ctx refcount == UINT_MAX on ref"); 120 return ctx; 121 } 122 123 static void 124 free_ocsp(struct revoke_ocsp *ocsp) 125 { 126 free(ocsp->path); 127 free_OCSPBasicOCSPResponse(&ocsp->ocsp); 128 hx509_certs_free(&ocsp->certs); 129 hx509_cert_free(ocsp->signer); 130 } 131 132 /** 133 * Free a hx509 revokation context. 134 * 135 * @param ctx context to be freed 136 * 137 * @ingroup hx509_revoke 138 */ 139 140 void 141 hx509_revoke_free(hx509_revoke_ctx *ctx) 142 { 143 size_t i ; 144 145 if (ctx == NULL || *ctx == NULL) 146 return; 147 148 if ((*ctx)->ref == 0) 149 _hx509_abort("revoke ctx refcount == 0 on free"); 150 if (--(*ctx)->ref > 0) 151 return; 152 153 for (i = 0; i < (*ctx)->crls.len; i++) { 154 free((*ctx)->crls.val[i].path); 155 free_CRLCertificateList(&(*ctx)->crls.val[i].crl); 156 } 157 158 for (i = 0; i < (*ctx)->ocsps.len; i++) 159 free_ocsp(&(*ctx)->ocsps.val[i]); 160 free((*ctx)->ocsps.val); 161 162 free((*ctx)->crls.val); 163 164 memset(*ctx, 0, sizeof(**ctx)); 165 free(*ctx); 166 *ctx = NULL; 167 } 168 169 static int 170 verify_ocsp(hx509_context context, 171 struct revoke_ocsp *ocsp, 172 time_t time_now, 173 hx509_certs certs, 174 hx509_cert parent) 175 { 176 hx509_cert signer = NULL; 177 hx509_query q; 178 int ret; 179 180 _hx509_query_clear(&q); 181 182 /* 183 * Need to match on issuer too in case there are two CA that have 184 * issued the same name to a certificate. One example of this is 185 * the www.openvalidation.org test's ocsp validator. 186 */ 187 188 q.match = HX509_QUERY_MATCH_ISSUER_NAME; 189 q.issuer_name = &_hx509_get_cert(parent)->tbsCertificate.issuer; 190 191 switch(ocsp->ocsp.tbsResponseData.responderID.element) { 192 case choice_OCSPResponderID_byName: 193 q.match |= HX509_QUERY_MATCH_SUBJECT_NAME; 194 q.subject_name = &ocsp->ocsp.tbsResponseData.responderID.u.byName; 195 break; 196 case choice_OCSPResponderID_byKey: 197 q.match |= HX509_QUERY_MATCH_KEY_HASH_SHA1; 198 q.keyhash_sha1 = &ocsp->ocsp.tbsResponseData.responderID.u.byKey; 199 break; 200 } 201 202 ret = hx509_certs_find(context, certs, &q, &signer); 203 if (ret && ocsp->certs) 204 ret = hx509_certs_find(context, ocsp->certs, &q, &signer); 205 if (ret) 206 goto out; 207 208 /* 209 * If signer certificate isn't the CA certificate, lets check the 210 * it is the CA that signed the signer certificate and the OCSP EKU 211 * is set. 212 */ 213 if (hx509_cert_cmp(signer, parent) != 0) { 214 Certificate *p = _hx509_get_cert(parent); 215 Certificate *s = _hx509_get_cert(signer); 216 217 ret = _hx509_cert_is_parent_cmp(s, p, 0); 218 if (ret != 0) { 219 ret = HX509_PARENT_NOT_CA; 220 hx509_set_error_string(context, 0, ret, "Revoke OCSP signer is " 221 "doesn't have CA as signer certificate"); 222 goto out; 223 } 224 225 ret = _hx509_verify_signature_bitstring(context, 226 parent, 227 &s->signatureAlgorithm, 228 &s->tbsCertificate._save, 229 &s->signatureValue); 230 if (ret) { 231 hx509_set_error_string(context, HX509_ERROR_APPEND, ret, 232 "OCSP signer signature invalid"); 233 goto out; 234 } 235 236 ret = hx509_cert_check_eku(context, signer, 237 &asn1_oid_id_pkix_kp_OCSPSigning, 0); 238 if (ret) 239 goto out; 240 } 241 242 ret = _hx509_verify_signature_bitstring(context, 243 signer, 244 &ocsp->ocsp.signatureAlgorithm, 245 &ocsp->ocsp.tbsResponseData._save, 246 &ocsp->ocsp.signature); 247 if (ret) { 248 hx509_set_error_string(context, HX509_ERROR_APPEND, ret, 249 "OCSP signature invalid"); 250 goto out; 251 } 252 253 ocsp->signer = signer; 254 signer = NULL; 255 out: 256 if (signer) 257 hx509_cert_free(signer); 258 259 return ret; 260 } 261 262 /* 263 * 264 */ 265 266 static int 267 parse_ocsp_basic(const void *data, size_t length, OCSPBasicOCSPResponse *basic) 268 { 269 OCSPResponse resp; 270 size_t size; 271 int ret; 272 273 memset(basic, 0, sizeof(*basic)); 274 275 ret = decode_OCSPResponse(data, length, &resp, &size); 276 if (ret) 277 return ret; 278 if (length != size) { 279 free_OCSPResponse(&resp); 280 return ASN1_EXTRA_DATA; 281 } 282 283 switch (resp.responseStatus) { 284 case successful: 285 break; 286 default: 287 free_OCSPResponse(&resp); 288 return HX509_REVOKE_WRONG_DATA; 289 } 290 291 if (resp.responseBytes == NULL) { 292 free_OCSPResponse(&resp); 293 return EINVAL; 294 } 295 296 ret = der_heim_oid_cmp(&resp.responseBytes->responseType, 297 &asn1_oid_id_pkix_ocsp_basic); 298 if (ret != 0) { 299 free_OCSPResponse(&resp); 300 return HX509_REVOKE_WRONG_DATA; 301 } 302 303 ret = decode_OCSPBasicOCSPResponse(resp.responseBytes->response.data, 304 resp.responseBytes->response.length, 305 basic, 306 &size); 307 if (ret) { 308 free_OCSPResponse(&resp); 309 return ret; 310 } 311 if (size != resp.responseBytes->response.length) { 312 free_OCSPResponse(&resp); 313 free_OCSPBasicOCSPResponse(basic); 314 return ASN1_EXTRA_DATA; 315 } 316 free_OCSPResponse(&resp); 317 318 return 0; 319 } 320 321 /* 322 * 323 */ 324 325 static int 326 load_ocsp(hx509_context context, struct revoke_ocsp *ocsp) 327 { 328 OCSPBasicOCSPResponse basic; 329 hx509_certs certs = NULL; 330 size_t length; 331 struct stat sb; 332 void *data; 333 int ret; 334 335 ret = rk_undumpdata(ocsp->path, &data, &length); 336 if (ret) 337 return ret; 338 339 ret = stat(ocsp->path, &sb); 340 if (ret) 341 return errno; 342 343 ret = parse_ocsp_basic(data, length, &basic); 344 rk_xfree(data); 345 if (ret) { 346 hx509_set_error_string(context, 0, ret, 347 "Failed to parse OCSP response"); 348 return ret; 349 } 350 351 if (basic.certs) { 352 size_t i; 353 354 ret = hx509_certs_init(context, "MEMORY:ocsp-certs", 0, 355 NULL, &certs); 356 if (ret) { 357 free_OCSPBasicOCSPResponse(&basic); 358 return ret; 359 } 360 361 for (i = 0; i < basic.certs->len; i++) { 362 hx509_cert c; 363 364 ret = hx509_cert_init(context, &basic.certs->val[i], &c); 365 if (ret) 366 continue; 367 368 ret = hx509_certs_add(context, certs, c); 369 hx509_cert_free(c); 370 if (ret) 371 continue; 372 } 373 } 374 375 ocsp->last_modfied = sb.st_mtime; 376 377 free_OCSPBasicOCSPResponse(&ocsp->ocsp); 378 hx509_certs_free(&ocsp->certs); 379 hx509_cert_free(ocsp->signer); 380 381 ocsp->ocsp = basic; 382 ocsp->certs = certs; 383 ocsp->signer = NULL; 384 385 return 0; 386 } 387 388 /** 389 * Add a OCSP file to the revokation context. 390 * 391 * @param context hx509 context 392 * @param ctx hx509 revokation context 393 * @param path path to file that is going to be added to the context. 394 * 395 * @return An hx509 error code, see hx509_get_error_string(). 396 * 397 * @ingroup hx509_revoke 398 */ 399 400 int 401 hx509_revoke_add_ocsp(hx509_context context, 402 hx509_revoke_ctx ctx, 403 const char *path) 404 { 405 void *data; 406 int ret; 407 size_t i; 408 409 if (strncmp(path, "FILE:", 5) != 0) { 410 hx509_set_error_string(context, 0, HX509_UNSUPPORTED_OPERATION, 411 "unsupport type in %s", path); 412 return HX509_UNSUPPORTED_OPERATION; 413 } 414 415 path += 5; 416 417 for (i = 0; i < ctx->ocsps.len; i++) { 418 if (strcmp(ctx->ocsps.val[0].path, path) == 0) 419 return 0; 420 } 421 422 data = realloc(ctx->ocsps.val, 423 (ctx->ocsps.len + 1) * sizeof(ctx->ocsps.val[0])); 424 if (data == NULL) { 425 hx509_clear_error_string(context); 426 return ENOMEM; 427 } 428 429 ctx->ocsps.val = data; 430 431 memset(&ctx->ocsps.val[ctx->ocsps.len], 0, 432 sizeof(ctx->ocsps.val[0])); 433 434 ctx->ocsps.val[ctx->ocsps.len].path = strdup(path); 435 if (ctx->ocsps.val[ctx->ocsps.len].path == NULL) { 436 hx509_clear_error_string(context); 437 return ENOMEM; 438 } 439 440 ret = load_ocsp(context, &ctx->ocsps.val[ctx->ocsps.len]); 441 if (ret) { 442 free(ctx->ocsps.val[ctx->ocsps.len].path); 443 return ret; 444 } 445 ctx->ocsps.len++; 446 447 return ret; 448 } 449 450 /* 451 * 452 */ 453 454 static int 455 verify_crl(hx509_context context, 456 hx509_revoke_ctx ctx, 457 CRLCertificateList *crl, 458 time_t time_now, 459 hx509_certs certs, 460 hx509_cert parent) 461 { 462 hx509_cert signer; 463 hx509_query q; 464 time_t t; 465 int ret; 466 467 t = _hx509_Time2time_t(&crl->tbsCertList.thisUpdate); 468 if (t > time_now) { 469 hx509_set_error_string(context, 0, HX509_CRL_USED_BEFORE_TIME, 470 "CRL used before time"); 471 return HX509_CRL_USED_BEFORE_TIME; 472 } 473 474 if (crl->tbsCertList.nextUpdate == NULL) { 475 hx509_set_error_string(context, 0, HX509_CRL_INVALID_FORMAT, 476 "CRL missing nextUpdate"); 477 return HX509_CRL_INVALID_FORMAT; 478 } 479 480 t = _hx509_Time2time_t(crl->tbsCertList.nextUpdate); 481 if (t < time_now) { 482 hx509_set_error_string(context, 0, HX509_CRL_USED_AFTER_TIME, 483 "CRL used after time"); 484 return HX509_CRL_USED_AFTER_TIME; 485 } 486 487 _hx509_query_clear(&q); 488 489 /* 490 * If it's the signer have CRLSIGN bit set, use that as the signer 491 * cert for the certificate, otherwise, search for a certificate. 492 */ 493 if (_hx509_check_key_usage(context, parent, 1 << 6, FALSE) == 0) { 494 signer = hx509_cert_ref(parent); 495 } else { 496 q.match = HX509_QUERY_MATCH_SUBJECT_NAME; 497 q.match |= HX509_QUERY_KU_CRLSIGN; 498 q.subject_name = &crl->tbsCertList.issuer; 499 500 ret = hx509_certs_find(context, certs, &q, &signer); 501 if (ret) { 502 hx509_set_error_string(context, HX509_ERROR_APPEND, ret, 503 "Failed to find certificate for CRL"); 504 return ret; 505 } 506 } 507 508 ret = _hx509_verify_signature_bitstring(context, 509 signer, 510 &crl->signatureAlgorithm, 511 &crl->tbsCertList._save, 512 &crl->signatureValue); 513 if (ret) { 514 hx509_set_error_string(context, HX509_ERROR_APPEND, ret, 515 "CRL signature invalid"); 516 goto out; 517 } 518 519 /* 520 * If signer is not CA cert, need to check revoke status of this 521 * CRL signing cert too, this include all parent CRL signer cert 522 * up to the root *sigh*, assume root at least hve CERTSIGN flag 523 * set. 524 */ 525 while (_hx509_check_key_usage(context, signer, 1 << 5, TRUE)) { 526 hx509_cert crl_parent; 527 528 _hx509_query_clear(&q); 529 530 q.match = HX509_QUERY_MATCH_SUBJECT_NAME; 531 q.match |= HX509_QUERY_KU_CRLSIGN; 532 q.subject_name = &_hx509_get_cert(signer)->tbsCertificate.issuer; 533 534 ret = hx509_certs_find(context, certs, &q, &crl_parent); 535 if (ret) { 536 hx509_set_error_string(context, HX509_ERROR_APPEND, ret, 537 "Failed to find parent of CRL signer"); 538 goto out; 539 } 540 541 ret = hx509_revoke_verify(context, 542 ctx, 543 certs, 544 time_now, 545 signer, 546 crl_parent); 547 hx509_cert_free(signer); 548 signer = crl_parent; 549 if (ret) { 550 hx509_set_error_string(context, HX509_ERROR_APPEND, ret, 551 "Failed to verify revoke " 552 "status of CRL signer"); 553 goto out; 554 } 555 } 556 557 out: 558 hx509_cert_free(signer); 559 560 return ret; 561 } 562 563 static int 564 load_crl(const char *path, time_t *t, CRLCertificateList *crl) 565 { 566 size_t length, size; 567 struct stat sb; 568 void *data; 569 int ret; 570 571 memset(crl, 0, sizeof(*crl)); 572 573 ret = rk_undumpdata(path, &data, &length); 574 if (ret) 575 return ret; 576 577 ret = stat(path, &sb); 578 if (ret) 579 return errno; 580 581 *t = sb.st_mtime; 582 583 ret = decode_CRLCertificateList(data, length, crl, &size); 584 rk_xfree(data); 585 if (ret) 586 return ret; 587 588 /* check signature is aligned */ 589 if (crl->signatureValue.length & 7) { 590 free_CRLCertificateList(crl); 591 return HX509_CRYPTO_SIG_INVALID_FORMAT; 592 } 593 return 0; 594 } 595 596 /** 597 * Add a CRL file to the revokation context. 598 * 599 * @param context hx509 context 600 * @param ctx hx509 revokation context 601 * @param path path to file that is going to be added to the context. 602 * 603 * @return An hx509 error code, see hx509_get_error_string(). 604 * 605 * @ingroup hx509_revoke 606 */ 607 608 int 609 hx509_revoke_add_crl(hx509_context context, 610 hx509_revoke_ctx ctx, 611 const char *path) 612 { 613 void *data; 614 size_t i; 615 int ret; 616 617 if (strncmp(path, "FILE:", 5) != 0) { 618 hx509_set_error_string(context, 0, HX509_UNSUPPORTED_OPERATION, 619 "unsupport type in %s", path); 620 return HX509_UNSUPPORTED_OPERATION; 621 } 622 623 624 path += 5; 625 626 for (i = 0; i < ctx->crls.len; i++) { 627 if (strcmp(ctx->crls.val[0].path, path) == 0) 628 return 0; 629 } 630 631 data = realloc(ctx->crls.val, 632 (ctx->crls.len + 1) * sizeof(ctx->crls.val[0])); 633 if (data == NULL) { 634 hx509_clear_error_string(context); 635 return ENOMEM; 636 } 637 ctx->crls.val = data; 638 639 memset(&ctx->crls.val[ctx->crls.len], 0, sizeof(ctx->crls.val[0])); 640 641 ctx->crls.val[ctx->crls.len].path = strdup(path); 642 if (ctx->crls.val[ctx->crls.len].path == NULL) { 643 hx509_clear_error_string(context); 644 return ENOMEM; 645 } 646 647 ret = load_crl(path, 648 &ctx->crls.val[ctx->crls.len].last_modfied, 649 &ctx->crls.val[ctx->crls.len].crl); 650 if (ret) { 651 free(ctx->crls.val[ctx->crls.len].path); 652 return ret; 653 } 654 655 ctx->crls.len++; 656 657 return ret; 658 } 659 660 /** 661 * Check that a certificate is not expired according to a revokation 662 * context. Also need the parent certificte to the check OCSP 663 * parent identifier. 664 * 665 * @param context hx509 context 666 * @param ctx hx509 revokation context 667 * @param certs 668 * @param now 669 * @param cert 670 * @param parent_cert 671 * 672 * @return An hx509 error code, see hx509_get_error_string(). 673 * 674 * @ingroup hx509_revoke 675 */ 676 677 678 int 679 hx509_revoke_verify(hx509_context context, 680 hx509_revoke_ctx ctx, 681 hx509_certs certs, 682 time_t now, 683 hx509_cert cert, 684 hx509_cert parent_cert) 685 { 686 const Certificate *c = _hx509_get_cert(cert); 687 const Certificate *p = _hx509_get_cert(parent_cert); 688 unsigned long i, j, k; 689 int ret; 690 691 hx509_clear_error_string(context); 692 693 for (i = 0; i < ctx->ocsps.len; i++) { 694 struct revoke_ocsp *ocsp = &ctx->ocsps.val[i]; 695 struct stat sb; 696 697 /* check this ocsp apply to this cert */ 698 699 /* check if there is a newer version of the file */ 700 ret = stat(ocsp->path, &sb); 701 if (ret == 0 && ocsp->last_modfied != sb.st_mtime) { 702 ret = load_ocsp(context, ocsp); 703 if (ret) 704 continue; 705 } 706 707 /* verify signature in ocsp if not already done */ 708 if (ocsp->signer == NULL) { 709 ret = verify_ocsp(context, ocsp, now, certs, parent_cert); 710 if (ret) 711 continue; 712 } 713 714 for (j = 0; j < ocsp->ocsp.tbsResponseData.responses.len; j++) { 715 heim_octet_string os; 716 717 ret = der_heim_integer_cmp(&ocsp->ocsp.tbsResponseData.responses.val[j].certID.serialNumber, 718 &c->tbsCertificate.serialNumber); 719 if (ret != 0) 720 continue; 721 722 /* verify issuer hashes hash */ 723 ret = _hx509_verify_signature(context, 724 NULL, 725 &ocsp->ocsp.tbsResponseData.responses.val[i].certID.hashAlgorithm, 726 &c->tbsCertificate.issuer._save, 727 &ocsp->ocsp.tbsResponseData.responses.val[i].certID.issuerNameHash); 728 if (ret != 0) 729 continue; 730 731 os.data = p->tbsCertificate.subjectPublicKeyInfo.subjectPublicKey.data; 732 os.length = p->tbsCertificate.subjectPublicKeyInfo.subjectPublicKey.length / 8; 733 734 ret = _hx509_verify_signature(context, 735 NULL, 736 &ocsp->ocsp.tbsResponseData.responses.val[j].certID.hashAlgorithm, 737 &os, 738 &ocsp->ocsp.tbsResponseData.responses.val[j].certID.issuerKeyHash); 739 if (ret != 0) 740 continue; 741 742 switch (ocsp->ocsp.tbsResponseData.responses.val[j].certStatus.element) { 743 case choice_OCSPCertStatus_good: 744 break; 745 case choice_OCSPCertStatus_revoked: 746 hx509_set_error_string(context, 0, 747 HX509_CERT_REVOKED, 748 "Certificate revoked by issuer in OCSP"); 749 return HX509_CERT_REVOKED; 750 case choice_OCSPCertStatus_unknown: 751 continue; 752 } 753 754 /* don't allow the update to be in the future */ 755 if (ocsp->ocsp.tbsResponseData.responses.val[j].thisUpdate > 756 now + context->ocsp_time_diff) 757 continue; 758 759 /* don't allow the next update to be in the past */ 760 if (ocsp->ocsp.tbsResponseData.responses.val[j].nextUpdate) { 761 if (*ocsp->ocsp.tbsResponseData.responses.val[j].nextUpdate < now) 762 continue; 763 } /* else should force a refetch, but can we ? */ 764 765 return 0; 766 } 767 } 768 769 for (i = 0; i < ctx->crls.len; i++) { 770 struct revoke_crl *crl = &ctx->crls.val[i]; 771 struct stat sb; 772 int diff; 773 774 /* check if cert.issuer == crls.val[i].crl.issuer */ 775 ret = _hx509_name_cmp(&c->tbsCertificate.issuer, 776 &crl->crl.tbsCertList.issuer, &diff); 777 if (ret || diff) 778 continue; 779 780 ret = stat(crl->path, &sb); 781 if (ret == 0 && crl->last_modfied != sb.st_mtime) { 782 CRLCertificateList cl; 783 784 ret = load_crl(crl->path, &crl->last_modfied, &cl); 785 if (ret == 0) { 786 free_CRLCertificateList(&crl->crl); 787 crl->crl = cl; 788 crl->verified = 0; 789 crl->failed_verify = 0; 790 } 791 } 792 if (crl->failed_verify) 793 continue; 794 795 /* verify signature in crl if not already done */ 796 if (crl->verified == 0) { 797 ret = verify_crl(context, ctx, &crl->crl, now, certs, parent_cert); 798 if (ret) { 799 crl->failed_verify = 1; 800 continue; 801 } 802 crl->verified = 1; 803 } 804 805 if (crl->crl.tbsCertList.crlExtensions) { 806 for (j = 0; j < crl->crl.tbsCertList.crlExtensions->len; j++) { 807 if (crl->crl.tbsCertList.crlExtensions->val[j].critical) { 808 hx509_set_error_string(context, 0, 809 HX509_CRL_UNKNOWN_EXTENSION, 810 "Unknown CRL extension"); 811 return HX509_CRL_UNKNOWN_EXTENSION; 812 } 813 } 814 } 815 816 if (crl->crl.tbsCertList.revokedCertificates == NULL) 817 return 0; 818 819 /* check if cert is in crl */ 820 for (j = 0; j < crl->crl.tbsCertList.revokedCertificates->len; j++) { 821 time_t t; 822 823 ret = der_heim_integer_cmp(&crl->crl.tbsCertList.revokedCertificates->val[j].userCertificate, 824 &c->tbsCertificate.serialNumber); 825 if (ret != 0) 826 continue; 827 828 t = _hx509_Time2time_t(&crl->crl.tbsCertList.revokedCertificates->val[j].revocationDate); 829 if (t > now) 830 continue; 831 832 if (crl->crl.tbsCertList.revokedCertificates->val[j].crlEntryExtensions) 833 for (k = 0; k < crl->crl.tbsCertList.revokedCertificates->val[j].crlEntryExtensions->len; k++) 834 if (crl->crl.tbsCertList.revokedCertificates->val[j].crlEntryExtensions->val[k].critical) 835 return HX509_CRL_UNKNOWN_EXTENSION; 836 837 hx509_set_error_string(context, 0, 838 HX509_CERT_REVOKED, 839 "Certificate revoked by issuer in CRL"); 840 return HX509_CERT_REVOKED; 841 } 842 843 return 0; 844 } 845 846 847 if (context->flags & HX509_CTX_VERIFY_MISSING_OK) 848 return 0; 849 hx509_set_error_string(context, HX509_ERROR_APPEND, 850 HX509_REVOKE_STATUS_MISSING, 851 "No revoke status found for " 852 "certificates"); 853 return HX509_REVOKE_STATUS_MISSING; 854 } 855 856 struct ocsp_add_ctx { 857 OCSPTBSRequest *req; 858 hx509_certs certs; 859 const AlgorithmIdentifier *digest; 860 hx509_cert parent; 861 }; 862 863 static int 864 add_to_req(hx509_context context, void *ptr, hx509_cert cert) 865 { 866 struct ocsp_add_ctx *ctx = ptr; 867 OCSPInnerRequest *one; 868 hx509_cert parent = NULL; 869 Certificate *p, *c = _hx509_get_cert(cert); 870 heim_octet_string os; 871 int ret; 872 hx509_query q; 873 void *d; 874 875 d = realloc(ctx->req->requestList.val, 876 sizeof(ctx->req->requestList.val[0]) * 877 (ctx->req->requestList.len + 1)); 878 if (d == NULL) 879 return ENOMEM; 880 ctx->req->requestList.val = d; 881 882 one = &ctx->req->requestList.val[ctx->req->requestList.len]; 883 memset(one, 0, sizeof(*one)); 884 885 _hx509_query_clear(&q); 886 887 q.match |= HX509_QUERY_FIND_ISSUER_CERT; 888 q.subject = c; 889 890 ret = hx509_certs_find(context, ctx->certs, &q, &parent); 891 if (ret) 892 goto out; 893 894 if (ctx->parent) { 895 if (hx509_cert_cmp(ctx->parent, parent) != 0) { 896 ret = HX509_REVOKE_NOT_SAME_PARENT; 897 hx509_set_error_string(context, 0, ret, 898 "Not same parent certifate as " 899 "last certificate in request"); 900 goto out; 901 } 902 } else 903 ctx->parent = hx509_cert_ref(parent); 904 905 p = _hx509_get_cert(parent); 906 907 ret = copy_AlgorithmIdentifier(ctx->digest, &one->reqCert.hashAlgorithm); 908 if (ret) 909 goto out; 910 911 ret = _hx509_create_signature(context, 912 NULL, 913 &one->reqCert.hashAlgorithm, 914 &c->tbsCertificate.issuer._save, 915 NULL, 916 &one->reqCert.issuerNameHash); 917 if (ret) 918 goto out; 919 920 os.data = p->tbsCertificate.subjectPublicKeyInfo.subjectPublicKey.data; 921 os.length = 922 p->tbsCertificate.subjectPublicKeyInfo.subjectPublicKey.length / 8; 923 924 ret = _hx509_create_signature(context, 925 NULL, 926 &one->reqCert.hashAlgorithm, 927 &os, 928 NULL, 929 &one->reqCert.issuerKeyHash); 930 if (ret) 931 goto out; 932 933 ret = copy_CertificateSerialNumber(&c->tbsCertificate.serialNumber, 934 &one->reqCert.serialNumber); 935 if (ret) 936 goto out; 937 938 ctx->req->requestList.len++; 939 out: 940 hx509_cert_free(parent); 941 if (ret) { 942 free_OCSPInnerRequest(one); 943 memset(one, 0, sizeof(*one)); 944 } 945 946 return ret; 947 } 948 949 /** 950 * Create an OCSP request for a set of certificates. 951 * 952 * @param context a hx509 context 953 * @param reqcerts list of certificates to request ocsp data for 954 * @param pool certificate pool to use when signing 955 * @param signer certificate to use to sign the request 956 * @param digest the signing algorithm in the request, if NULL use the 957 * default signature algorithm, 958 * @param request the encoded request, free with free_heim_octet_string(). 959 * @param nonce nonce in the request, free with free_heim_octet_string(). 960 * 961 * @return An hx509 error code, see hx509_get_error_string(). 962 * 963 * @ingroup hx509_revoke 964 */ 965 966 int 967 hx509_ocsp_request(hx509_context context, 968 hx509_certs reqcerts, 969 hx509_certs pool, 970 hx509_cert signer, 971 const AlgorithmIdentifier *digest, 972 heim_octet_string *request, 973 heim_octet_string *nonce) 974 { 975 OCSPRequest req; 976 size_t size; 977 int ret; 978 struct ocsp_add_ctx ctx; 979 Extensions *es; 980 981 memset(&req, 0, sizeof(req)); 982 983 if (digest == NULL) 984 digest = _hx509_crypto_default_digest_alg; 985 986 ctx.req = &req.tbsRequest; 987 ctx.certs = pool; 988 ctx.digest = digest; 989 ctx.parent = NULL; 990 991 ret = hx509_certs_iter_f(context, reqcerts, add_to_req, &ctx); 992 hx509_cert_free(ctx.parent); 993 if (ret) 994 goto out; 995 996 if (nonce) { 997 req.tbsRequest.requestExtensions = 998 calloc(1, sizeof(*req.tbsRequest.requestExtensions)); 999 if (req.tbsRequest.requestExtensions == NULL) { 1000 ret = ENOMEM; 1001 goto out; 1002 } 1003 1004 es = req.tbsRequest.requestExtensions; 1005 1006 es->val = calloc(es->len, sizeof(es->val[0])); 1007 if (es->val == NULL) { 1008 ret = ENOMEM; 1009 goto out; 1010 } 1011 es->len = 1; 1012 ret = der_copy_oid(&asn1_oid_id_pkix_ocsp_nonce, &es->val[0].extnID); 1013 if (ret) { 1014 free_OCSPRequest(&req); 1015 return ret; 1016 } 1017 1018 es->val[0].extnValue.data = malloc(10); 1019 if (es->val[0].extnValue.data == NULL) { 1020 ret = ENOMEM; 1021 goto out; 1022 } 1023 es->val[0].extnValue.length = 10; 1024 1025 ret = RAND_bytes(es->val[0].extnValue.data, 1026 es->val[0].extnValue.length); 1027 if (ret != 1) { 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 1048 out: 1049 free_OCSPRequest(&req); 1050 return ret; 1051 } 1052 1053 static char * 1054 printable_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 1079 int 1080 hx509_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 default: 1124 _hx509_abort("choice_OCSPResponderID unknown"); 1125 break; 1126 } 1127 1128 fprintf(out, "producedAt: %s\n", 1129 printable_time(ocsp.ocsp.tbsResponseData.producedAt)); 1130 1131 fprintf(out, "replies: %d\n", ocsp.ocsp.tbsResponseData.responses.len); 1132 1133 for (i = 0; i < ocsp.ocsp.tbsResponseData.responses.len; i++) { 1134 const char *status; 1135 switch (ocsp.ocsp.tbsResponseData.responses.val[i].certStatus.element) { 1136 case choice_OCSPCertStatus_good: 1137 status = "good"; 1138 break; 1139 case choice_OCSPCertStatus_revoked: 1140 status = "revoked"; 1141 break; 1142 case choice_OCSPCertStatus_unknown: 1143 status = "unknown"; 1144 break; 1145 default: 1146 status = "element unknown"; 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 1186 int 1187 hx509_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 continue; 1233 } 1234 1235 /* don't allow the update to be in the future */ 1236 if (basic.tbsResponseData.responses.val[i].thisUpdate > 1237 now + context->ocsp_time_diff) 1238 continue; 1239 1240 /* don't allow the next update to be in the past */ 1241 if (basic.tbsResponseData.responses.val[i].nextUpdate) { 1242 if (*basic.tbsResponseData.responses.val[i].nextUpdate < now) 1243 continue; 1244 *expiration = *basic.tbsResponseData.responses.val[i].nextUpdate; 1245 } else 1246 *expiration = now; 1247 1248 free_OCSPBasicOCSPResponse(&basic); 1249 return 0; 1250 } 1251 1252 free_OCSPBasicOCSPResponse(&basic); 1253 1254 { 1255 hx509_name name; 1256 char *subject; 1257 1258 ret = hx509_cert_get_subject(cert, &name); 1259 if (ret) { 1260 hx509_clear_error_string(context); 1261 goto out; 1262 } 1263 ret = hx509_name_to_string(name, &subject); 1264 hx509_name_free(&name); 1265 if (ret) { 1266 hx509_clear_error_string(context); 1267 goto out; 1268 } 1269 hx509_set_error_string(context, 0, HX509_CERT_NOT_IN_OCSP, 1270 "Certificate %s not in OCSP response " 1271 "or not good", 1272 subject); 1273 free(subject); 1274 } 1275 out: 1276 return HX509_CERT_NOT_IN_OCSP; 1277 } 1278 1279 struct hx509_crl { 1280 hx509_certs revoked; 1281 time_t expire; 1282 }; 1283 1284 /** 1285 * Create a CRL context. Use hx509_crl_free() to free the CRL context. 1286 * 1287 * @param context a hx509 context. 1288 * @param crl return pointer to a newly allocated CRL context. 1289 * 1290 * @return An hx509 error code, see hx509_get_error_string(). 1291 * 1292 * @ingroup hx509_verify 1293 */ 1294 1295 int 1296 hx509_crl_alloc(hx509_context context, hx509_crl *crl) 1297 { 1298 int ret; 1299 1300 *crl = calloc(1, sizeof(**crl)); 1301 if (*crl == NULL) { 1302 hx509_set_error_string(context, 0, ENOMEM, "out of memory"); 1303 return ENOMEM; 1304 } 1305 1306 ret = hx509_certs_init(context, "MEMORY:crl", 0, NULL, &(*crl)->revoked); 1307 if (ret) { 1308 free(*crl); 1309 *crl = NULL; 1310 return ret; 1311 } 1312 (*crl)->expire = 0; 1313 return ret; 1314 } 1315 1316 /** 1317 * Add revoked certificate to an CRL context. 1318 * 1319 * @param context a hx509 context. 1320 * @param crl the CRL to add the revoked certificate to. 1321 * @param certs keyset of certificate to revoke. 1322 * 1323 * @return An hx509 error code, see hx509_get_error_string(). 1324 * 1325 * @ingroup hx509_verify 1326 */ 1327 1328 int 1329 hx509_crl_add_revoked_certs(hx509_context context, 1330 hx509_crl crl, 1331 hx509_certs certs) 1332 { 1333 return hx509_certs_merge(context, crl->revoked, certs); 1334 } 1335 1336 /** 1337 * Set the lifetime of a CRL context. 1338 * 1339 * @param context a hx509 context. 1340 * @param crl a CRL context 1341 * @param delta delta time the certificate is valid, library adds the 1342 * current time to this. 1343 * 1344 * @return An hx509 error code, see hx509_get_error_string(). 1345 * 1346 * @ingroup hx509_verify 1347 */ 1348 1349 int 1350 hx509_crl_lifetime(hx509_context context, hx509_crl crl, int delta) 1351 { 1352 crl->expire = time(NULL) + delta; 1353 return 0; 1354 } 1355 1356 /** 1357 * Free a CRL context. 1358 * 1359 * @param context a hx509 context. 1360 * @param crl a CRL context to free. 1361 * 1362 * @ingroup hx509_verify 1363 */ 1364 1365 void 1366 hx509_crl_free(hx509_context context, hx509_crl *crl) 1367 { 1368 if (*crl == NULL) 1369 return; 1370 hx509_certs_free(&(*crl)->revoked); 1371 memset(*crl, 0, sizeof(**crl)); 1372 free(*crl); 1373 *crl = NULL; 1374 } 1375 1376 static int 1377 add_revoked(hx509_context context, void *ctx, hx509_cert cert) 1378 { 1379 TBSCRLCertList *c = ctx; 1380 unsigned int num; 1381 void *ptr; 1382 int ret; 1383 1384 num = c->revokedCertificates->len; 1385 ptr = realloc(c->revokedCertificates->val, 1386 (num + 1) * sizeof(c->revokedCertificates->val[0])); 1387 if (ptr == NULL) { 1388 hx509_clear_error_string(context); 1389 return ENOMEM; 1390 } 1391 c->revokedCertificates->val = ptr; 1392 1393 ret = hx509_cert_get_serialnumber(cert, 1394 &c->revokedCertificates->val[num].userCertificate); 1395 if (ret) { 1396 hx509_clear_error_string(context); 1397 return ret; 1398 } 1399 c->revokedCertificates->val[num].revocationDate.element = 1400 choice_Time_generalTime; 1401 c->revokedCertificates->val[num].revocationDate.u.generalTime = 1402 time(NULL) - 3600 * 24; 1403 c->revokedCertificates->val[num].crlEntryExtensions = NULL; 1404 1405 c->revokedCertificates->len++; 1406 1407 return 0; 1408 } 1409 1410 /** 1411 * Sign a CRL and return an encode certificate. 1412 * 1413 * @param context a hx509 context. 1414 * @param signer certificate to sign the CRL with 1415 * @param crl the CRL to sign 1416 * @param os return the signed and encoded CRL, free with 1417 * free_heim_octet_string() 1418 * 1419 * @return An hx509 error code, see hx509_get_error_string(). 1420 * 1421 * @ingroup hx509_verify 1422 */ 1423 1424 int 1425 hx509_crl_sign(hx509_context context, 1426 hx509_cert signer, 1427 hx509_crl crl, 1428 heim_octet_string *os) 1429 { 1430 const AlgorithmIdentifier *sigalg = _hx509_crypto_default_sig_alg; 1431 CRLCertificateList c; 1432 size_t size; 1433 int ret; 1434 hx509_private_key signerkey; 1435 1436 memset(&c, 0, sizeof(c)); 1437 1438 signerkey = _hx509_cert_private_key(signer); 1439 if (signerkey == NULL) { 1440 ret = HX509_PRIVATE_KEY_MISSING; 1441 hx509_set_error_string(context, 0, ret, 1442 "Private key missing for CRL signing"); 1443 return ret; 1444 } 1445 1446 c.tbsCertList.version = malloc(sizeof(*c.tbsCertList.version)); 1447 if (c.tbsCertList.version == NULL) { 1448 hx509_set_error_string(context, 0, ENOMEM, "out of memory"); 1449 return ENOMEM; 1450 } 1451 1452 *c.tbsCertList.version = 1; 1453 1454 ret = copy_AlgorithmIdentifier(sigalg, &c.tbsCertList.signature); 1455 if (ret) { 1456 hx509_clear_error_string(context); 1457 goto out; 1458 } 1459 1460 ret = copy_Name(&_hx509_get_cert(signer)->tbsCertificate.issuer, 1461 &c.tbsCertList.issuer); 1462 if (ret) { 1463 hx509_clear_error_string(context); 1464 goto out; 1465 } 1466 1467 c.tbsCertList.thisUpdate.element = choice_Time_generalTime; 1468 c.tbsCertList.thisUpdate.u.generalTime = time(NULL) - 24 * 3600; 1469 1470 c.tbsCertList.nextUpdate = malloc(sizeof(*c.tbsCertList.nextUpdate)); 1471 if (c.tbsCertList.nextUpdate == NULL) { 1472 hx509_set_error_string(context, 0, ENOMEM, "out of memory"); 1473 ret = ENOMEM; 1474 goto out; 1475 } 1476 1477 { 1478 time_t next = crl->expire; 1479 if (next == 0) 1480 next = time(NULL) + 24 * 3600 * 365; 1481 1482 c.tbsCertList.nextUpdate->element = choice_Time_generalTime; 1483 c.tbsCertList.nextUpdate->u.generalTime = next; 1484 } 1485 1486 c.tbsCertList.revokedCertificates = 1487 calloc(1, sizeof(*c.tbsCertList.revokedCertificates)); 1488 if (c.tbsCertList.revokedCertificates == NULL) { 1489 hx509_set_error_string(context, 0, ENOMEM, "out of memory"); 1490 ret = ENOMEM; 1491 goto out; 1492 } 1493 c.tbsCertList.crlExtensions = NULL; 1494 1495 ret = hx509_certs_iter_f(context, crl->revoked, add_revoked, &c.tbsCertList); 1496 if (ret) 1497 goto out; 1498 1499 /* if not revoked certs, remove OPTIONAL entry */ 1500 if (c.tbsCertList.revokedCertificates->len == 0) { 1501 free(c.tbsCertList.revokedCertificates); 1502 c.tbsCertList.revokedCertificates = NULL; 1503 } 1504 1505 ASN1_MALLOC_ENCODE(TBSCRLCertList, os->data, os->length, 1506 &c.tbsCertList, &size, ret); 1507 if (ret) { 1508 hx509_set_error_string(context, 0, ret, "failed to encode tbsCRL"); 1509 goto out; 1510 } 1511 if (size != os->length) 1512 _hx509_abort("internal ASN.1 encoder error"); 1513 1514 1515 ret = _hx509_create_signature_bitstring(context, 1516 signerkey, 1517 sigalg, 1518 os, 1519 &c.signatureAlgorithm, 1520 &c.signatureValue); 1521 free(os->data); 1522 if (ret) { 1523 hx509_set_error_string(context, 0, ret, "Failed to sign CRL"); 1524 goto out; 1525 } 1526 1527 ASN1_MALLOC_ENCODE(CRLCertificateList, os->data, os->length, 1528 &c, &size, ret); 1529 if (ret) { 1530 hx509_set_error_string(context, 0, ret, "failed to encode CRL"); 1531 goto out; 1532 } 1533 if (size != os->length) 1534 _hx509_abort("internal ASN.1 encoder error"); 1535 1536 free_CRLCertificateList(&c); 1537 1538 return 0; 1539 1540 out: 1541 free_CRLCertificateList(&c); 1542 return ret; 1543 } 1544