diff options
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; |
