summaryrefslogtreecommitdiff
path: root/src/lib/libcrypto/x509/x509_verify.c
diff options
context:
space:
mode:
authorbeck <>2021-11-04 23:52:34 +0000
committerbeck <>2021-11-04 23:52:34 +0000
commit87decea9a33c04cfad36679efd6678bbc21363cd (patch)
tree3ca9bd91a3930e5f3e28873aa362dffdb8cf6227 /src/lib/libcrypto/x509/x509_verify.c
parent427635c8217e5b9c6e458a39dac977cc6818582f (diff)
downloadopenbsd-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.c172
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);
39static void x509_verify_chain_free(struct x509_verify_chain *chain); 39static 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 */
45time_t
46x509_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 */
83void
84x509_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
43struct x509_verify_chain * 94struct x509_verify_chain *
44x509_verify_chain_new(void) 95x509_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
457static int 509static int
458x509_verify_parent_signature(X509 *parent, X509 *child, 510x509_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
494static int 538static int
495x509_verify_consider_candidate(struct x509_verify_ctx *ctx, X509 *cert, 539x509_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
579x509_verify_build_chains(struct x509_verify_ctx *ctx, X509 *cert, 622x509_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
751int
752x509_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
787static int 788static int
788x509_verify_cert_time(int is_notafter, const ASN1_TIME *cert_asn1, 789x509_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;