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