diff options
author | beck <> | 2020-09-13 15:06:17 +0000 |
---|---|---|
committer | beck <> | 2020-09-13 15:06:17 +0000 |
commit | a328631fddec2556ad8af08ce4de240790c537c9 (patch) | |
tree | 4e2deda0db62092481ad6901c374736e60f249a2 /src/lib/libcrypto/x509/x509_vfy.c | |
parent | 4f04d3f588f91c98b4b1cdfcffe028a036c96283 (diff) | |
download | openbsd-a328631fddec2556ad8af08ce4de240790c537c9.tar.gz openbsd-a328631fddec2556ad8af08ce4de240790c537c9.tar.bz2 openbsd-a328631fddec2556ad8af08ce4de240790c537c9.zip |
Add new x509 certificate chain validator in x509_verify.c
The new validator finds multiple validated chains to handle the modern
PKI cases which may frequently have multiple paths via different
intermediates to different roots. It is loosely based on golang's x509
validator
This includes integration so that the new validator can be used via
X509_verify_cert() as well as a new api x509_verify() which will
return multiple chains (similar to go).
The new validator is not enabled by default with this commit, this
will be changed in a follow on commit.
The new public API is not yet exposed, and will be finalized and
exposed with a man page and a library minor bump later.
ok tb@ inoguchi@ jsing@
Diffstat (limited to 'src/lib/libcrypto/x509/x509_vfy.c')
-rw-r--r-- | src/lib/libcrypto/x509/x509_vfy.c | 228 |
1 files changed, 180 insertions, 48 deletions
diff --git a/src/lib/libcrypto/x509/x509_vfy.c b/src/lib/libcrypto/x509/x509_vfy.c index 28dbf60c38..b1cc9b5a00 100644 --- a/src/lib/libcrypto/x509/x509_vfy.c +++ b/src/lib/libcrypto/x509/x509_vfy.c | |||
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: x509_vfy.c,v 1.74 2020/09/12 14:14:02 beck Exp $ */ | 1 | /* $OpenBSD: x509_vfy.c,v 1.75 2020/09/13 15:06:17 beck Exp $ */ |
2 | /* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) | 2 | /* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) |
3 | * All rights reserved. | 3 | * All rights reserved. |
4 | * | 4 | * |
@@ -77,6 +77,7 @@ | |||
77 | #include "vpm_int.h" | 77 | #include "vpm_int.h" |
78 | #include "x509_internal.h" | 78 | #include "x509_internal.h" |
79 | #include "x509_lcl.h" | 79 | #include "x509_lcl.h" |
80 | #include "x509_internal.h" | ||
80 | 81 | ||
81 | /* CRL score values */ | 82 | /* CRL score values */ |
82 | 83 | ||
@@ -124,7 +125,7 @@ static int check_chain_extensions(X509_STORE_CTX *ctx); | |||
124 | static int check_name_constraints(X509_STORE_CTX *ctx); | 125 | static int check_name_constraints(X509_STORE_CTX *ctx); |
125 | static int check_trust(X509_STORE_CTX *ctx); | 126 | static int check_trust(X509_STORE_CTX *ctx); |
126 | static int check_revocation(X509_STORE_CTX *ctx); | 127 | static int check_revocation(X509_STORE_CTX *ctx); |
127 | static int check_cert(X509_STORE_CTX *ctx); | 128 | static int check_cert(X509_STORE_CTX *ctx, STACK_OF(X509) *chain, int depth); |
128 | static int check_policy(X509_STORE_CTX *ctx); | 129 | static int check_policy(X509_STORE_CTX *ctx); |
129 | 130 | ||
130 | static int get_crl_score(X509_STORE_CTX *ctx, X509 **pissuer, | 131 | static int get_crl_score(X509_STORE_CTX *ctx, X509 **pissuer, |
@@ -144,6 +145,7 @@ static int X509_cmp_time_internal(const ASN1_TIME *ctm, time_t *cmp_time, | |||
144 | int clamp_notafter); | 145 | int clamp_notafter); |
145 | 146 | ||
146 | static int internal_verify(X509_STORE_CTX *ctx); | 147 | static int internal_verify(X509_STORE_CTX *ctx); |
148 | static int get_issuer_sk(X509 **issuer, X509_STORE_CTX *ctx, X509 *x); | ||
147 | 149 | ||
148 | int ASN1_time_tm_clamp_notafter(struct tm *tm); | 150 | int ASN1_time_tm_clamp_notafter(struct tm *tm); |
149 | 151 | ||
@@ -224,7 +226,21 @@ check_id(X509_STORE_CTX *ctx) | |||
224 | } | 226 | } |
225 | 227 | ||
226 | int | 228 | int |
227 | X509_verify_cert(X509_STORE_CTX *ctx) | 229 | x509_vfy_check_id(X509_STORE_CTX *ctx) { |
230 | return check_id(ctx); | ||
231 | } | ||
232 | |||
233 | /* | ||
234 | * This is the effectively broken legacy OpenSSL chain builder. It | ||
235 | * might find an unvalidated chain and leave it sitting in | ||
236 | * ctx->chain. It does not correctly handle many cases where multiple | ||
237 | * chains could exist. | ||
238 | * | ||
239 | * Oh no.. I know a dirty word... | ||
240 | * Oooooooh.. | ||
241 | */ | ||
242 | static int | ||
243 | X509_verify_cert_legacy_build_chain(X509_STORE_CTX *ctx, int *bad) | ||
228 | { | 244 | { |
229 | X509 *x, *xtmp, *xtmp2, *chain_ss = NULL; | 245 | X509 *x, *xtmp, *xtmp2, *chain_ss = NULL; |
230 | int bad_chain = 0; | 246 | int bad_chain = 0; |
@@ -234,39 +250,6 @@ X509_verify_cert(X509_STORE_CTX *ctx) | |||
234 | int (*cb) (int xok, X509_STORE_CTX *xctx); | 250 | int (*cb) (int xok, X509_STORE_CTX *xctx); |
235 | STACK_OF(X509) *sktmp = NULL; | 251 | STACK_OF(X509) *sktmp = NULL; |
236 | 252 | ||
237 | if (ctx->cert == NULL) { | ||
238 | X509error(X509_R_NO_CERT_SET_FOR_US_TO_VERIFY); | ||
239 | ctx->error = X509_V_ERR_INVALID_CALL; | ||
240 | return -1; | ||
241 | } | ||
242 | if (ctx->chain != NULL) { | ||
243 | /* | ||
244 | * This X509_STORE_CTX has already been used to verify | ||
245 | * a cert. We cannot do another one. | ||
246 | */ | ||
247 | X509error(ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED); | ||
248 | ctx->error = X509_V_ERR_INVALID_CALL; | ||
249 | return -1; | ||
250 | } | ||
251 | if (ctx->param->id->poisoned) { | ||
252 | /* | ||
253 | * This X509_STORE_CTX had failures setting | ||
254 | * up verify parameters. We can not use it. | ||
255 | */ | ||
256 | X509error(ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED); | ||
257 | ctx->error = X509_V_ERR_INVALID_CALL; | ||
258 | return -1; | ||
259 | } | ||
260 | if (ctx->error != X509_V_ERR_INVALID_CALL) { | ||
261 | /* | ||
262 | * This X509_STORE_CTX has not been properly initialized. | ||
263 | */ | ||
264 | X509error(ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED); | ||
265 | ctx->error = X509_V_ERR_INVALID_CALL; | ||
266 | return -1; | ||
267 | } | ||
268 | ctx->error = X509_V_OK; /* Initialize to OK */ | ||
269 | |||
270 | cb = ctx->verify_cb; | 253 | cb = ctx->verify_cb; |
271 | 254 | ||
272 | /* | 255 | /* |
@@ -534,6 +517,23 @@ X509_verify_cert(X509_STORE_CTX *ctx) | |||
534 | if (!ok) | 517 | if (!ok) |
535 | goto end; | 518 | goto end; |
536 | } | 519 | } |
520 | end: | ||
521 | sk_X509_free(sktmp); | ||
522 | X509_free(chain_ss); | ||
523 | *bad = bad_chain; | ||
524 | return ok; | ||
525 | } | ||
526 | |||
527 | static int | ||
528 | X509_verify_cert_legacy(X509_STORE_CTX *ctx) | ||
529 | { | ||
530 | int ok = 0, bad_chain; | ||
531 | |||
532 | ctx->error = X509_V_OK; /* Initialize to OK */ | ||
533 | |||
534 | ok = X509_verify_cert_legacy_build_chain(ctx, &bad_chain); | ||
535 | if (!ok) | ||
536 | goto end; | ||
537 | 537 | ||
538 | /* We have the chain complete: now we need to check its purpose */ | 538 | /* We have the chain complete: now we need to check its purpose */ |
539 | ok = check_chain_extensions(ctx); | 539 | ok = check_chain_extensions(ctx); |
@@ -548,6 +548,7 @@ X509_verify_cert(X509_STORE_CTX *ctx) | |||
548 | ok = check_id(ctx); | 548 | ok = check_id(ctx); |
549 | if (!ok) | 549 | if (!ok) |
550 | goto end; | 550 | goto end; |
551 | |||
551 | /* | 552 | /* |
552 | * Check revocation status: we do this after copying parameters because | 553 | * Check revocation status: we do this after copying parameters because |
553 | * they may be needed for CRL signature verification. | 554 | * they may be needed for CRL signature verification. |
@@ -569,15 +570,125 @@ X509_verify_cert(X509_STORE_CTX *ctx) | |||
569 | ok = ctx->check_policy(ctx); | 570 | ok = ctx->check_policy(ctx); |
570 | 571 | ||
571 | end: | 572 | end: |
572 | sk_X509_free(sktmp); | ||
573 | X509_free(chain_ss); | ||
574 | |||
575 | /* Safety net, error returns must set ctx->error */ | 573 | /* Safety net, error returns must set ctx->error */ |
576 | if (ok <= 0 && ctx->error == X509_V_OK) | 574 | if (ok <= 0 && ctx->error == X509_V_OK) |
577 | ctx->error = X509_V_ERR_UNSPECIFIED; | 575 | ctx->error = X509_V_ERR_UNSPECIFIED; |
576 | |||
578 | return ok; | 577 | return ok; |
579 | } | 578 | } |
580 | 579 | ||
580 | int | ||
581 | X509_verify_cert(X509_STORE_CTX *ctx) | ||
582 | { | ||
583 | STACK_OF(X509) *roots = NULL; | ||
584 | struct x509_verify_ctx *vctx = NULL; | ||
585 | int chain_count = 0; | ||
586 | |||
587 | if (ctx->cert == NULL) { | ||
588 | X509error(X509_R_NO_CERT_SET_FOR_US_TO_VERIFY); | ||
589 | ctx->error = X509_V_ERR_INVALID_CALL; | ||
590 | return -1; | ||
591 | } | ||
592 | if (ctx->chain != NULL) { | ||
593 | /* | ||
594 | * This X509_STORE_CTX has already been used to verify | ||
595 | * a cert. We cannot do another one. | ||
596 | */ | ||
597 | X509error(ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED); | ||
598 | ctx->error = X509_V_ERR_INVALID_CALL; | ||
599 | return -1; | ||
600 | } | ||
601 | if (ctx->param->id->poisoned) { | ||
602 | /* | ||
603 | * This X509_STORE_CTX had failures setting | ||
604 | * up verify parameters. We can not use it. | ||
605 | */ | ||
606 | X509error(ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED); | ||
607 | ctx->error = X509_V_ERR_INVALID_CALL; | ||
608 | return -1; | ||
609 | } | ||
610 | if (ctx->error != X509_V_ERR_INVALID_CALL) { | ||
611 | /* | ||
612 | * This X509_STORE_CTX has not been properly initialized. | ||
613 | */ | ||
614 | X509error(ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED); | ||
615 | ctx->error = X509_V_ERR_INVALID_CALL; | ||
616 | return -1; | ||
617 | } | ||
618 | |||
619 | /* | ||
620 | * If flags request legacy, use the legacy verifier. If we | ||
621 | * requested "no alt chains" from the age of hammer pants, use | ||
622 | * the legacy verifier because the multi chain verifier really | ||
623 | * does find all the "alt chains". | ||
624 | * | ||
625 | * XXX deprecate the NO_ALT_CHAINS flag? | ||
626 | */ | ||
627 | if ((ctx->param->flags & X509_V_FLAG_LEGACY_VERIFY) || | ||
628 | (ctx->param->flags & X509_V_FLAG_NO_ALT_CHAINS)) | ||
629 | return X509_verify_cert_legacy(ctx); | ||
630 | |||
631 | /* Use the modern multi-chain verifier from x509_verify_cert */ | ||
632 | |||
633 | /* Find our trusted roots */ | ||
634 | ctx->error = X509_V_ERR_OUT_OF_MEM; | ||
635 | |||
636 | if (ctx->get_issuer == get_issuer_sk) { | ||
637 | /* | ||
638 | * We are using the trusted stack method. so | ||
639 | * the roots are in the aptly named "ctx->other_ctx" | ||
640 | * pointer. (It could have been called "al") | ||
641 | */ | ||
642 | if ((roots = X509_chain_up_ref(ctx->other_ctx)) == NULL) | ||
643 | return -1; | ||
644 | } else { | ||
645 | /* | ||
646 | * We have a X509_STORE and need to pull out the roots. | ||
647 | * Don't look Ethel... | ||
648 | */ | ||
649 | STACK_OF(X509_OBJECT) *objs; | ||
650 | size_t i, good = 1; | ||
651 | |||
652 | if ((roots = sk_X509_new_null()) == NULL) | ||
653 | return -1; | ||
654 | |||
655 | CRYPTO_w_lock(CRYPTO_LOCK_X509_STORE); | ||
656 | if ((objs = X509_STORE_get0_objects(ctx->ctx)) == NULL) | ||
657 | good = 0; | ||
658 | for (i = 0; good && i < sk_X509_OBJECT_num(objs); i++) { | ||
659 | X509_OBJECT *obj; | ||
660 | X509 *root; | ||
661 | obj = sk_X509_OBJECT_value(objs, i); | ||
662 | if (obj->type != X509_LU_X509) | ||
663 | continue; | ||
664 | root = obj->data.x509; | ||
665 | if (X509_up_ref(root) == 0) | ||
666 | good = 0; | ||
667 | if (sk_X509_push(roots, root) == 0) { | ||
668 | X509_free(root); | ||
669 | good = 0; | ||
670 | } | ||
671 | } | ||
672 | CRYPTO_w_unlock(CRYPTO_LOCK_X509_STORE); | ||
673 | |||
674 | if (!good) { | ||
675 | sk_X509_pop_free(roots, X509_free); | ||
676 | return -1; | ||
677 | } | ||
678 | } | ||
679 | |||
680 | if ((vctx = x509_verify_ctx_new_from_xsc(ctx, roots)) != NULL) { | ||
681 | ctx->error = X509_V_OK; /* Initialize to OK */ | ||
682 | chain_count = x509_verify(vctx, NULL, NULL); | ||
683 | } | ||
684 | |||
685 | sk_X509_pop_free(roots, X509_free); | ||
686 | x509_verify_ctx_free(vctx); | ||
687 | |||
688 | /* if we succeed we have a chain in ctx->chain */ | ||
689 | return (chain_count > 0 && ctx->chain != NULL); | ||
690 | } | ||
691 | |||
581 | /* Given a STACK_OF(X509) find the issuer of cert (if any) | 692 | /* Given a STACK_OF(X509) find the issuer of cert (if any) |
582 | */ | 693 | */ |
583 | 694 | ||
@@ -637,8 +748,8 @@ get_issuer_sk(X509 **issuer, X509_STORE_CTX *ctx, X509 *x) | |||
637 | * with the supplied purpose | 748 | * with the supplied purpose |
638 | */ | 749 | */ |
639 | 750 | ||
640 | static int | 751 | int |
641 | check_chain_extensions(X509_STORE_CTX *ctx) | 752 | x509_vfy_check_chain_extensions(X509_STORE_CTX *ctx) |
642 | { | 753 | { |
643 | #ifdef OPENSSL_NO_CHAIN_VERIFY | 754 | #ifdef OPENSSL_NO_CHAIN_VERIFY |
644 | return 1; | 755 | return 1; |
@@ -781,6 +892,11 @@ end: | |||
781 | } | 892 | } |
782 | 893 | ||
783 | static int | 894 | static int |
895 | check_chain_extensions(X509_STORE_CTX *ctx) { | ||
896 | return x509_vfy_check_chain_extensions(ctx); | ||
897 | } | ||
898 | |||
899 | static int | ||
784 | check_name_constraints(X509_STORE_CTX *ctx) | 900 | check_name_constraints(X509_STORE_CTX *ctx) |
785 | { | 901 | { |
786 | if (!x509_constraints_chain(ctx->chain, &ctx->error, | 902 | if (!x509_constraints_chain(ctx->chain, &ctx->error, |
@@ -875,6 +991,11 @@ static int check_trust(X509_STORE_CTX *ctx) | |||
875 | return X509_TRUST_UNTRUSTED; | 991 | return X509_TRUST_UNTRUSTED; |
876 | } | 992 | } |
877 | 993 | ||
994 | int x509_vfy_check_trust(X509_STORE_CTX *ctx) | ||
995 | { | ||
996 | return check_trust(ctx); | ||
997 | } | ||
998 | |||
878 | static int | 999 | static int |
879 | check_revocation(X509_STORE_CTX *ctx) | 1000 | check_revocation(X509_STORE_CTX *ctx) |
880 | { | 1001 | { |
@@ -891,24 +1012,29 @@ check_revocation(X509_STORE_CTX *ctx) | |||
891 | last = 0; | 1012 | last = 0; |
892 | } | 1013 | } |
893 | for (i = 0; i <= last; i++) { | 1014 | for (i = 0; i <= last; i++) { |
894 | ctx->error_depth = i; | 1015 | ok = check_cert(ctx, ctx->chain, i); |
895 | ok = check_cert(ctx); | ||
896 | if (!ok) | 1016 | if (!ok) |
897 | return ok; | 1017 | return ok; |
898 | } | 1018 | } |
899 | return 1; | 1019 | return 1; |
900 | } | 1020 | } |
901 | 1021 | ||
1022 | int | ||
1023 | x509_vfy_check_revocation(X509_STORE_CTX *ctx) | ||
1024 | { | ||
1025 | return check_revocation(ctx); | ||
1026 | } | ||
1027 | |||
902 | static int | 1028 | static int |
903 | check_cert(X509_STORE_CTX *ctx) | 1029 | check_cert(X509_STORE_CTX *ctx, STACK_OF(X509) *chain, int depth) |
904 | { | 1030 | { |
905 | X509_CRL *crl = NULL, *dcrl = NULL; | 1031 | X509_CRL *crl = NULL, *dcrl = NULL; |
906 | X509 *x; | 1032 | X509 *x; |
907 | int ok = 0, cnum; | 1033 | int ok = 0, cnum; |
908 | unsigned int last_reasons; | 1034 | unsigned int last_reasons; |
909 | 1035 | ||
910 | cnum = ctx->error_depth; | 1036 | cnum = ctx->error_depth = depth; |
911 | x = sk_X509_value(ctx->chain, cnum); | 1037 | x = sk_X509_value(chain, cnum); |
912 | ctx->current_cert = x; | 1038 | ctx->current_cert = x; |
913 | ctx->current_issuer = NULL; | 1039 | ctx->current_issuer = NULL; |
914 | ctx->current_crl_score = 0; | 1040 | ctx->current_crl_score = 0; |
@@ -1660,8 +1786,8 @@ cert_crl(X509_STORE_CTX *ctx, X509_CRL *crl, X509 *x) | |||
1660 | return 1; | 1786 | return 1; |
1661 | } | 1787 | } |
1662 | 1788 | ||
1663 | static int | 1789 | int |
1664 | check_policy(X509_STORE_CTX *ctx) | 1790 | x509_vfy_check_policy(X509_STORE_CTX *ctx) |
1665 | { | 1791 | { |
1666 | int ret; | 1792 | int ret; |
1667 | 1793 | ||
@@ -1707,6 +1833,12 @@ check_policy(X509_STORE_CTX *ctx) | |||
1707 | return 1; | 1833 | return 1; |
1708 | } | 1834 | } |
1709 | 1835 | ||
1836 | static int | ||
1837 | check_policy(X509_STORE_CTX *ctx) | ||
1838 | { | ||
1839 | return x509_vfy_check_policy(ctx); | ||
1840 | } | ||
1841 | |||
1710 | /* | 1842 | /* |
1711 | * Inform the verify callback of an error. | 1843 | * Inform the verify callback of an error. |
1712 | * | 1844 | * |