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