diff options
| author | beck <> | 2021-11-04 23:52:34 +0000 |
|---|---|---|
| committer | beck <> | 2021-11-04 23:52:34 +0000 |
| commit | 87decea9a33c04cfad36679efd6678bbc21363cd (patch) | |
| tree | 3ca9bd91a3930e5f3e28873aa362dffdb8cf6227 /src/lib/libcrypto/x509/x509_verify.c | |
| parent | 427635c8217e5b9c6e458a39dac977cc6818582f (diff) | |
| download | openbsd-87decea9a33c04cfad36679efd6678bbc21363cd.tar.gz openbsd-87decea9a33c04cfad36679efd6678bbc21363cd.tar.bz2 openbsd-87decea9a33c04cfad36679efd6678bbc21363cd.zip | |
Cache sha512 hash and parsed not_before and not_after with X509 cert.
Replace sha1 hash use with sha512 for certificate comparisons internal
to the library. use the cached sha512 for the validator's verification
cache.
Reduces our recomputation of hashes, and heavy use of time1 time
conversion functions noticed bu claudio@ in rpki client.
ok jsing@ tb@
Diffstat (limited to 'src/lib/libcrypto/x509/x509_verify.c')
| -rw-r--r-- | src/lib/libcrypto/x509/x509_verify.c | 172 |
1 files changed, 78 insertions, 94 deletions
diff --git a/src/lib/libcrypto/x509/x509_verify.c b/src/lib/libcrypto/x509/x509_verify.c index 8bcc647149..b9ba2bee3c 100644 --- a/src/lib/libcrypto/x509/x509_verify.c +++ b/src/lib/libcrypto/x509/x509_verify.c | |||
| @@ -1,4 +1,4 @@ | |||
| 1 | /* $OpenBSD: x509_verify.c,v 1.50 2021/10/26 15:14:18 job Exp $ */ | 1 | /* $OpenBSD: x509_verify.c,v 1.51 2021/11/04 23:52:34 beck Exp $ */ |
| 2 | /* | 2 | /* |
| 3 | * Copyright (c) 2020-2021 Bob Beck <beck@openbsd.org> | 3 | * Copyright (c) 2020-2021 Bob Beck <beck@openbsd.org> |
| 4 | * | 4 | * |
| @@ -38,7 +38,58 @@ static int x509_verify_cert_error(struct x509_verify_ctx *ctx, X509 *cert, | |||
| 38 | size_t depth, int error, int ok); | 38 | size_t depth, int error, int ok); |
| 39 | static void x509_verify_chain_free(struct x509_verify_chain *chain); | 39 | static void x509_verify_chain_free(struct x509_verify_chain *chain); |
| 40 | 40 | ||
| 41 | #define X509_VERIFY_CERT_HASH (EVP_sha512()) | 41 | /* |
| 42 | * Parse an asn1 to a representable time_t as per RFC 5280 rules. | ||
| 43 | * Returns -1 if that can't be done for any reason. | ||
| 44 | */ | ||
| 45 | time_t | ||
| 46 | x509_verify_asn1_time_to_time_t(const ASN1_TIME *atime, int notAfter) | ||
| 47 | { | ||
| 48 | struct tm tm = { 0 }; | ||
| 49 | int type; | ||
| 50 | |||
| 51 | type = ASN1_time_parse(atime->data, atime->length, &tm, atime->type); | ||
| 52 | if (type == -1) | ||
| 53 | return -1; | ||
| 54 | |||
| 55 | /* RFC 5280 section 4.1.2.5 */ | ||
| 56 | if (tm.tm_year < 150 && type != V_ASN1_UTCTIME) | ||
| 57 | return -1; | ||
| 58 | if (tm.tm_year >= 150 && type != V_ASN1_GENERALIZEDTIME) | ||
| 59 | return -1; | ||
| 60 | |||
| 61 | if (notAfter) { | ||
| 62 | /* | ||
| 63 | * If we are a completely broken operating system with a | ||
| 64 | * 32 bit time_t, and we have been told this is a notAfter | ||
| 65 | * date, limit the date to a 32 bit representable value. | ||
| 66 | */ | ||
| 67 | if (!ASN1_time_tm_clamp_notafter(&tm)) | ||
| 68 | return -1; | ||
| 69 | } | ||
| 70 | |||
| 71 | /* | ||
| 72 | * Defensively fail if the time string is not representable as | ||
| 73 | * a time_t. A time_t must be sane if you care about times after | ||
| 74 | * Jan 19 2038. | ||
| 75 | */ | ||
| 76 | return timegm(&tm); | ||
| 77 | } | ||
| 78 | |||
| 79 | /* | ||
| 80 | * Cache certificate hash, and values parsed out of an X509. | ||
| 81 | * called from cache_extensions() | ||
| 82 | */ | ||
| 83 | void | ||
| 84 | x509_verify_cert_info_populate(X509 *cert) | ||
| 85 | { | ||
| 86 | /* | ||
| 87 | * Parse and save the cert times, or remember that they | ||
| 88 | * are unacceptable/unparsable. | ||
| 89 | */ | ||
| 90 | cert->not_before = x509_verify_asn1_time_to_time_t(X509_get_notBefore(cert), 0); | ||
| 91 | cert->not_after = x509_verify_asn1_time_to_time_t(X509_get_notAfter(cert), 1); | ||
| 92 | } | ||
| 42 | 93 | ||
| 43 | struct x509_verify_chain * | 94 | struct x509_verify_chain * |
| 44 | x509_verify_chain_new(void) | 95 | x509_verify_chain_new(void) |
| @@ -194,6 +245,7 @@ x509_verify_cert_cache_extensions(X509 *cert) { | |||
| 194 | } | 245 | } |
| 195 | if (cert->ex_flags & EXFLAG_INVALID) | 246 | if (cert->ex_flags & EXFLAG_INVALID) |
| 196 | return 0; | 247 | return 0; |
| 248 | |||
| 197 | return (cert->ex_flags & EXFLAG_SET); | 249 | return (cert->ex_flags & EXFLAG_SET); |
| 198 | } | 250 | } |
| 199 | 251 | ||
| @@ -455,22 +507,15 @@ x509_verify_potential_parent(struct x509_verify_ctx *ctx, X509 *parent, | |||
| 455 | } | 507 | } |
| 456 | 508 | ||
| 457 | static int | 509 | static int |
| 458 | x509_verify_parent_signature(X509 *parent, X509 *child, | 510 | x509_verify_parent_signature(X509 *parent, X509 *child, int *error) |
| 459 | unsigned char *child_md, int *error) | ||
| 460 | { | 511 | { |
| 461 | unsigned char parent_md[EVP_MAX_MD_SIZE] = { 0 }; | ||
| 462 | EVP_PKEY *pkey; | 512 | EVP_PKEY *pkey; |
| 463 | int cached; | 513 | int cached; |
| 464 | int ret = 0; | 514 | int ret = 0; |
| 465 | 515 | ||
| 466 | /* Use cached value if we have it */ | 516 | /* Use cached value if we have it */ |
| 467 | if (child_md != NULL) { | 517 | if ((cached = x509_issuer_cache_find(parent->hash, child->hash)) >= 0) |
| 468 | if (!X509_digest(parent, X509_VERIFY_CERT_HASH, parent_md, | 518 | return cached; |
| 469 | NULL)) | ||
| 470 | return 0; | ||
| 471 | if ((cached = x509_issuer_cache_find(parent_md, child_md)) >= 0) | ||
| 472 | return cached; | ||
| 473 | } | ||
| 474 | 519 | ||
| 475 | /* Check signature. Did parent sign child? */ | 520 | /* Check signature. Did parent sign child? */ |
| 476 | if ((pkey = X509_get_pubkey(parent)) == NULL) { | 521 | if ((pkey = X509_get_pubkey(parent)) == NULL) { |
| @@ -483,8 +528,7 @@ x509_verify_parent_signature(X509 *parent, X509 *child, | |||
| 483 | ret = 1; | 528 | ret = 1; |
| 484 | 529 | ||
| 485 | /* Add result to cache */ | 530 | /* Add result to cache */ |
| 486 | if (child_md != NULL) | 531 | x509_issuer_cache_add(parent->hash, child->hash, ret); |
| 487 | x509_issuer_cache_add(parent_md, child_md, ret); | ||
| 488 | 532 | ||
| 489 | EVP_PKEY_free(pkey); | 533 | EVP_PKEY_free(pkey); |
| 490 | 534 | ||
| @@ -493,8 +537,8 @@ x509_verify_parent_signature(X509 *parent, X509 *child, | |||
| 493 | 537 | ||
| 494 | static int | 538 | static int |
| 495 | x509_verify_consider_candidate(struct x509_verify_ctx *ctx, X509 *cert, | 539 | x509_verify_consider_candidate(struct x509_verify_ctx *ctx, X509 *cert, |
| 496 | unsigned char *cert_md, int is_root_cert, X509 *candidate, | 540 | int is_root_cert, X509 *candidate, struct x509_verify_chain *current_chain, |
| 497 | struct x509_verify_chain *current_chain, int full_chain) | 541 | int full_chain) |
| 498 | { | 542 | { |
| 499 | int depth = sk_X509_num(current_chain->certs); | 543 | int depth = sk_X509_num(current_chain->certs); |
| 500 | struct x509_verify_chain *new_chain; | 544 | struct x509_verify_chain *new_chain; |
| @@ -514,8 +558,7 @@ x509_verify_consider_candidate(struct x509_verify_ctx *ctx, X509 *cert, | |||
| 514 | return 0; | 558 | return 0; |
| 515 | } | 559 | } |
| 516 | 560 | ||
| 517 | if (!x509_verify_parent_signature(candidate, cert, cert_md, | 561 | if (!x509_verify_parent_signature(candidate, cert, &ctx->error)) { |
| 518 | &ctx->error)) { | ||
| 519 | if (!x509_verify_cert_error(ctx, candidate, depth, | 562 | if (!x509_verify_cert_error(ctx, candidate, depth, |
| 520 | ctx->error, 0)) | 563 | ctx->error, 0)) |
| 521 | return 0; | 564 | return 0; |
| @@ -579,7 +622,6 @@ static void | |||
| 579 | x509_verify_build_chains(struct x509_verify_ctx *ctx, X509 *cert, | 622 | x509_verify_build_chains(struct x509_verify_ctx *ctx, X509 *cert, |
| 580 | struct x509_verify_chain *current_chain, int full_chain) | 623 | struct x509_verify_chain *current_chain, int full_chain) |
| 581 | { | 624 | { |
| 582 | unsigned char cert_md[EVP_MAX_MD_SIZE] = { 0 }; | ||
| 583 | X509 *candidate; | 625 | X509 *candidate; |
| 584 | int i, depth, count, ret, is_root; | 626 | int i, depth, count, ret, is_root; |
| 585 | 627 | ||
| @@ -600,11 +642,6 @@ x509_verify_build_chains(struct x509_verify_ctx *ctx, X509 *cert, | |||
| 600 | X509_V_ERR_CERT_CHAIN_TOO_LONG, 0)) | 642 | X509_V_ERR_CERT_CHAIN_TOO_LONG, 0)) |
| 601 | return; | 643 | return; |
| 602 | 644 | ||
| 603 | if (!X509_digest(cert, X509_VERIFY_CERT_HASH, cert_md, NULL) && | ||
| 604 | !x509_verify_cert_error(ctx, cert, depth, | ||
| 605 | X509_V_ERR_UNSPECIFIED, 0)) | ||
| 606 | return; | ||
| 607 | |||
| 608 | count = ctx->chains_count; | 645 | count = ctx->chains_count; |
| 609 | 646 | ||
| 610 | ctx->error = X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY; | 647 | ctx->error = X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY; |
| @@ -640,7 +677,7 @@ x509_verify_build_chains(struct x509_verify_ctx *ctx, X509 *cert, | |||
| 640 | is_root = !full_chain || | 677 | is_root = !full_chain || |
| 641 | x509_verify_cert_self_signed(candidate); | 678 | x509_verify_cert_self_signed(candidate); |
| 642 | x509_verify_consider_candidate(ctx, cert, | 679 | x509_verify_consider_candidate(ctx, cert, |
| 643 | cert_md, is_root, candidate, current_chain, | 680 | is_root, candidate, current_chain, |
| 644 | full_chain); | 681 | full_chain); |
| 645 | } | 682 | } |
| 646 | X509_free(candidate); | 683 | X509_free(candidate); |
| @@ -653,7 +690,7 @@ x509_verify_build_chains(struct x509_verify_ctx *ctx, X509 *cert, | |||
| 653 | is_root = !full_chain || | 690 | is_root = !full_chain || |
| 654 | x509_verify_cert_self_signed(candidate); | 691 | x509_verify_cert_self_signed(candidate); |
| 655 | x509_verify_consider_candidate(ctx, cert, | 692 | x509_verify_consider_candidate(ctx, cert, |
| 656 | cert_md, is_root, candidate, current_chain, | 693 | is_root, candidate, current_chain, |
| 657 | full_chain); | 694 | full_chain); |
| 658 | } | 695 | } |
| 659 | } | 696 | } |
| @@ -665,7 +702,7 @@ x509_verify_build_chains(struct x509_verify_ctx *ctx, X509 *cert, | |||
| 665 | candidate = sk_X509_value(ctx->intermediates, i); | 702 | candidate = sk_X509_value(ctx->intermediates, i); |
| 666 | if (x509_verify_potential_parent(ctx, candidate, cert)) { | 703 | if (x509_verify_potential_parent(ctx, candidate, cert)) { |
| 667 | x509_verify_consider_candidate(ctx, cert, | 704 | x509_verify_consider_candidate(ctx, cert, |
| 668 | cert_md, 0, candidate, current_chain, | 705 | 0, candidate, current_chain, |
| 669 | full_chain); | 706 | full_chain); |
| 670 | } | 707 | } |
| 671 | } | 708 | } |
| @@ -748,47 +785,9 @@ x509_verify_set_check_time(struct x509_verify_ctx *ctx) { | |||
| 748 | return 1; | 785 | return 1; |
| 749 | } | 786 | } |
| 750 | 787 | ||
| 751 | int | ||
| 752 | x509_verify_asn1_time_to_tm(const ASN1_TIME *atime, struct tm *tm, int notafter) | ||
| 753 | { | ||
| 754 | int type; | ||
| 755 | |||
| 756 | type = ASN1_time_parse(atime->data, atime->length, tm, atime->type); | ||
| 757 | if (type == -1) | ||
| 758 | return 0; | ||
| 759 | |||
| 760 | /* RFC 5280 section 4.1.2.5 */ | ||
| 761 | if (tm->tm_year < 150 && type != V_ASN1_UTCTIME) | ||
| 762 | return 0; | ||
| 763 | if (tm->tm_year >= 150 && type != V_ASN1_GENERALIZEDTIME) | ||
| 764 | return 0; | ||
| 765 | |||
| 766 | if (notafter) { | ||
| 767 | /* | ||
| 768 | * If we are a completely broken operating system with a | ||
| 769 | * 32 bit time_t, and we have been told this is a notafter | ||
| 770 | * date, limit the date to a 32 bit representable value. | ||
| 771 | */ | ||
| 772 | if (!ASN1_time_tm_clamp_notafter(tm)) | ||
| 773 | return 0; | ||
| 774 | } | ||
| 775 | |||
| 776 | /* | ||
| 777 | * Defensively fail if the time string is not representable as | ||
| 778 | * a time_t. A time_t must be sane if you care about times after | ||
| 779 | * Jan 19 2038. | ||
| 780 | */ | ||
| 781 | if (timegm(tm) == -1) | ||
| 782 | return 0; | ||
| 783 | |||
| 784 | return 1; | ||
| 785 | } | ||
| 786 | |||
| 787 | static int | 788 | static int |
| 788 | x509_verify_cert_time(int is_notafter, const ASN1_TIME *cert_asn1, | 789 | x509_verify_cert_times(X509 *cert, time_t *cmp_time, int *error) |
| 789 | time_t *cmp_time, int *error) | ||
| 790 | { | 790 | { |
| 791 | struct tm cert_tm, when_tm; | ||
| 792 | time_t when; | 791 | time_t when; |
| 793 | 792 | ||
| 794 | if (cmp_time == NULL) | 793 | if (cmp_time == NULL) |
| @@ -796,29 +795,21 @@ x509_verify_cert_time(int is_notafter, const ASN1_TIME *cert_asn1, | |||
| 796 | else | 795 | else |
| 797 | when = *cmp_time; | 796 | when = *cmp_time; |
| 798 | 797 | ||
| 799 | if (!x509_verify_asn1_time_to_tm(cert_asn1, &cert_tm, | 798 | if (cert->not_before == -1) { |
| 800 | is_notafter)) { | 799 | *error = X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD; |
| 801 | *error = is_notafter ? | ||
| 802 | X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD : | ||
| 803 | X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD; | ||
| 804 | return 0; | 800 | return 0; |
| 805 | } | 801 | } |
| 806 | 802 | if (when < cert->not_before) { | |
| 807 | if (gmtime_r(&when, &when_tm) == NULL) { | 803 | *error = X509_V_ERR_CERT_NOT_YET_VALID; |
| 808 | *error = X509_V_ERR_UNSPECIFIED; | ||
| 809 | return 0; | 804 | return 0; |
| 810 | } | 805 | } |
| 811 | 806 | if (cert->not_after == -1) { | |
| 812 | if (is_notafter) { | 807 | *error = X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD; |
| 813 | if (ASN1_time_tm_cmp(&cert_tm, &when_tm) == -1) { | 808 | return 0; |
| 814 | *error = X509_V_ERR_CERT_HAS_EXPIRED; | 809 | } |
| 815 | return 0; | 810 | if (when > cert->not_after) { |
| 816 | } | 811 | *error = X509_V_ERR_CERT_HAS_EXPIRED; |
| 817 | } else { | 812 | return 0; |
| 818 | if (ASN1_time_tm_cmp(&cert_tm, &when_tm) == 1) { | ||
| 819 | *error = X509_V_ERR_CERT_NOT_YET_VALID; | ||
| 820 | return 0; | ||
| 821 | } | ||
| 822 | } | 813 | } |
| 823 | 814 | ||
| 824 | return 1; | 815 | return 1; |
| @@ -924,15 +915,8 @@ x509_verify_cert_valid(struct x509_verify_ctx *ctx, X509 *cert, | |||
| 924 | } | 915 | } |
| 925 | 916 | ||
| 926 | if (x509_verify_set_check_time(ctx)) { | 917 | if (x509_verify_set_check_time(ctx)) { |
| 927 | if (!x509_verify_cert_time(0, X509_get_notBefore(cert), | 918 | if (!x509_verify_cert_times(cert, ctx->check_time, |
| 928 | ctx->check_time, &ctx->error)) { | 919 | &ctx->error)) { |
| 929 | if (!x509_verify_cert_error(ctx, cert, depth, | ||
| 930 | ctx->error, 0)) | ||
| 931 | return 0; | ||
| 932 | } | ||
| 933 | |||
| 934 | if (!x509_verify_cert_time(1, X509_get_notAfter(cert), | ||
| 935 | ctx->check_time, &ctx->error)) { | ||
| 936 | if (!x509_verify_cert_error(ctx, cert, depth, | 920 | if (!x509_verify_cert_error(ctx, cert, depth, |
| 937 | ctx->error, 0)) | 921 | ctx->error, 0)) |
| 938 | return 0; | 922 | return 0; |
