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