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 | |
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@
-rw-r--r-- | src/lib/libcrypto/Makefile | 5 | ||||
-rw-r--r-- | src/lib/libcrypto/x509/x509_internal.h | 37 | ||||
-rw-r--r-- | src/lib/libcrypto/x509/x509_purp.c | 6 | ||||
-rw-r--r-- | src/lib/libcrypto/x509/x509_utl.c | 5 | ||||
-rw-r--r-- | src/lib/libcrypto/x509/x509_verify.c | 914 | ||||
-rw-r--r-- | src/lib/libcrypto/x509/x509_verify.h | 42 | ||||
-rw-r--r-- | src/lib/libcrypto/x509/x509_vfy.c | 228 | ||||
-rw-r--r-- | src/lib/libcrypto/x509/x509_vfy.h | 5 | ||||
-rw-r--r-- | src/lib/libcrypto/x509/x509_vpm.c | 4 | ||||
-rw-r--r-- | src/lib/libcrypto/x509/x509v3.h | 4 | ||||
-rw-r--r-- | src/regress/lib/libcrypto/x509/verify.c | 99 |
11 files changed, 1281 insertions, 68 deletions
diff --git a/src/lib/libcrypto/Makefile b/src/lib/libcrypto/Makefile index 8f11313d58..1a3a388835 100644 --- a/src/lib/libcrypto/Makefile +++ b/src/lib/libcrypto/Makefile | |||
@@ -1,4 +1,4 @@ | |||
1 | # $OpenBSD: Makefile,v 1.44 2020/09/11 18:34:29 beck Exp $ | 1 | # $OpenBSD: Makefile,v 1.45 2020/09/13 15:06:16 beck Exp $ |
2 | 2 | ||
3 | LIB= crypto | 3 | LIB= crypto |
4 | LIBREBUILD=y | 4 | LIBREBUILD=y |
@@ -277,7 +277,7 @@ SRCS+= x509_bcons.c x509_bitst.c x509_conf.c x509_extku.c x509_ia5.c x509_lib.c | |||
277 | SRCS+= x509_prn.c x509_utl.c x509_genn.c x509_alt.c x509_skey.c x509_akey.c x509_pku.c | 277 | SRCS+= x509_prn.c x509_utl.c x509_genn.c x509_alt.c x509_skey.c x509_akey.c x509_pku.c |
278 | SRCS+= x509_int.c x509_enum.c x509_sxnet.c x509_cpols.c x509_crld.c x509_purp.c x509_info.c | 278 | SRCS+= x509_int.c x509_enum.c x509_sxnet.c x509_cpols.c x509_crld.c x509_purp.c x509_info.c |
279 | SRCS+= x509_ocsp.c x509_akeya.c x509_pmaps.c x509_pcons.c x509_ncons.c x509_pcia.c x509_pci.c | 279 | SRCS+= x509_ocsp.c x509_akeya.c x509_pmaps.c x509_pcons.c x509_ncons.c x509_pcia.c x509_pci.c |
280 | SRCS+= x509_issuer_cache.c x509_constraints.c | 280 | SRCS+= x509_issuer_cache.c x509_constraints.c x509_verify.c |
281 | SRCS+= pcy_cache.c pcy_node.c pcy_data.c pcy_map.c pcy_tree.c pcy_lib.c | 281 | SRCS+= pcy_cache.c pcy_node.c pcy_data.c pcy_map.c pcy_tree.c pcy_lib.c |
282 | 282 | ||
283 | .PATH: ${.CURDIR}/arch/${MACHINE_CPU} \ | 283 | .PATH: ${.CURDIR}/arch/${MACHINE_CPU} \ |
@@ -401,6 +401,7 @@ HDRS=\ | |||
401 | ${LCRYPTO_SRC}/whrlpool/whrlpool.h \ | 401 | ${LCRYPTO_SRC}/whrlpool/whrlpool.h \ |
402 | ${LCRYPTO_SRC}/x509/x509.h \ | 402 | ${LCRYPTO_SRC}/x509/x509.h \ |
403 | ${LCRYPTO_SRC}/x509/x509_vfy.h \ | 403 | ${LCRYPTO_SRC}/x509/x509_vfy.h \ |
404 | ${LCRYPTO_SRC}/x509/x509_verify.h \ | ||
404 | ${LCRYPTO_SRC}/x509/x509v3.h | 405 | ${LCRYPTO_SRC}/x509/x509v3.h |
405 | 406 | ||
406 | HDRS_GEN=\ | 407 | HDRS_GEN=\ |
diff --git a/src/lib/libcrypto/x509/x509_internal.h b/src/lib/libcrypto/x509/x509_internal.h index fad6c93231..ced6b306e5 100644 --- a/src/lib/libcrypto/x509/x509_internal.h +++ b/src/lib/libcrypto/x509/x509_internal.h | |||
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: x509_internal.h,v 1.1 2020/09/11 18:34:29 beck Exp $ */ | 1 | /* $OpenBSD: x509_internal.h,v 1.2 2020/09/13 15:06:17 beck Exp $ */ |
2 | /* | 2 | /* |
3 | * Copyright (c) 2020 Bob Beck <beck@openbsd.org> | 3 | * Copyright (c) 2020 Bob Beck <beck@openbsd.org> |
4 | * | 4 | * |
@@ -20,6 +20,13 @@ | |||
20 | /* Internal use only, not public API */ | 20 | /* Internal use only, not public API */ |
21 | #include <netinet/in.h> | 21 | #include <netinet/in.h> |
22 | 22 | ||
23 | #include <openssl/x509_verify.h> | ||
24 | |||
25 | /* Hard limits on structure size and number of signature checks. */ | ||
26 | #define X509_VERIFY_MAX_CHAINS 8 /* Max validated chains */ | ||
27 | #define X509_VERIFY_MAX_CHAIN_CERTS 32 /* Max depth of a chain */ | ||
28 | #define X509_VERIFY_MAX_SIGCHECKS 256 /* Max signature checks */ | ||
29 | |||
23 | /* | 30 | /* |
24 | * Limit the number of names and constraints we will check in a chain | 31 | * Limit the number of names and constraints we will check in a chain |
25 | * to avoid a hostile input DOS | 32 | * to avoid a hostile input DOS |
@@ -53,8 +60,36 @@ struct x509_verify_chain { | |||
53 | struct x509_constraints_names *names; /* All names from all certs */ | 60 | struct x509_constraints_names *names; /* All names from all certs */ |
54 | }; | 61 | }; |
55 | 62 | ||
63 | struct x509_verify_ctx { | ||
64 | X509_STORE_CTX *xsc; | ||
65 | struct x509_verify_chain **chains; /* Validated chains */ | ||
66 | size_t chains_count; | ||
67 | STACK_OF(X509) *roots; /* Trusted roots for this validation */ | ||
68 | STACK_OF(X509) *intermediates; /* Intermediates provided by peer */ | ||
69 | time_t *check_time; /* Time for validity checks */ | ||
70 | int purpose; /* Cert purpose we are validating */ | ||
71 | size_t max_chains; /* Max chains to return */ | ||
72 | size_t max_depth; /* Max chain depth for validation */ | ||
73 | size_t max_sigs; /* Max number of signature checks */ | ||
74 | size_t sig_checks; /* Number of signature checks done */ | ||
75 | size_t error_depth; /* Depth of last error seen */ | ||
76 | int error; /* Last error seen */ | ||
77 | }; | ||
78 | |||
79 | int ASN1_time_tm_clamp_notafter(struct tm *tm); | ||
80 | |||
56 | __BEGIN_HIDDEN_DECLS | 81 | __BEGIN_HIDDEN_DECLS |
57 | 82 | ||
83 | int x509_vfy_check_id(X509_STORE_CTX *ctx); | ||
84 | int x509_vfy_check_revocation(X509_STORE_CTX *ctx); | ||
85 | int x509_vfy_check_policy(X509_STORE_CTX *ctx); | ||
86 | int x509_vfy_check_trust(X509_STORE_CTX *ctx); | ||
87 | int x509_vfy_check_chain_extensions(X509_STORE_CTX *ctx); | ||
88 | void x509v3_cache_extensions(X509 *x); | ||
89 | |||
90 | struct x509_verify_ctx *x509_verify_ctx_new_from_xsc(X509_STORE_CTX *xsc, | ||
91 | STACK_OF(X509) *roots); | ||
92 | |||
58 | void x509_constraints_name_clear(struct x509_constraints_name *name); | 93 | void x509_constraints_name_clear(struct x509_constraints_name *name); |
59 | int x509_constraints_names_add(struct x509_constraints_names *names, | 94 | int x509_constraints_names_add(struct x509_constraints_names *names, |
60 | struct x509_constraints_name *name); | 95 | struct x509_constraints_name *name); |
diff --git a/src/lib/libcrypto/x509/x509_purp.c b/src/lib/libcrypto/x509/x509_purp.c index 62b3bcfe3a..f2d46658f6 100644 --- a/src/lib/libcrypto/x509/x509_purp.c +++ b/src/lib/libcrypto/x509/x509_purp.c | |||
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: x509_purp.c,v 1.1 2020/06/04 15:19:32 jsing Exp $ */ | 1 | /* $OpenBSD: x509_purp.c,v 1.2 2020/09/13 15:06:17 beck Exp $ */ |
2 | /* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL | 2 | /* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL |
3 | * project 2001. | 3 | * project 2001. |
4 | */ | 4 | */ |
@@ -73,7 +73,7 @@ | |||
73 | #define ns_reject(x, usage) \ | 73 | #define ns_reject(x, usage) \ |
74 | (((x)->ex_flags & EXFLAG_NSCERT) && !((x)->ex_nscert & (usage))) | 74 | (((x)->ex_flags & EXFLAG_NSCERT) && !((x)->ex_nscert & (usage))) |
75 | 75 | ||
76 | static void x509v3_cache_extensions(X509 *x); | 76 | void x509v3_cache_extensions(X509 *x); |
77 | 77 | ||
78 | static int check_ssl_ca(const X509 *x); | 78 | static int check_ssl_ca(const X509 *x); |
79 | static int check_purpose_ssl_client(const X509_PURPOSE *xp, const X509 *x, | 79 | static int check_purpose_ssl_client(const X509_PURPOSE *xp, const X509 *x, |
@@ -426,7 +426,7 @@ setup_crldp(X509 *x) | |||
426 | setup_dp(x, sk_DIST_POINT_value(x->crldp, i)); | 426 | setup_dp(x, sk_DIST_POINT_value(x->crldp, i)); |
427 | } | 427 | } |
428 | 428 | ||
429 | static void | 429 | void |
430 | x509v3_cache_extensions(X509 *x) | 430 | x509v3_cache_extensions(X509 *x) |
431 | { | 431 | { |
432 | BASIC_CONSTRAINTS *bs; | 432 | BASIC_CONSTRAINTS *bs; |
diff --git a/src/lib/libcrypto/x509/x509_utl.c b/src/lib/libcrypto/x509/x509_utl.c index 4641152f74..0fa6ea6d54 100644 --- a/src/lib/libcrypto/x509/x509_utl.c +++ b/src/lib/libcrypto/x509/x509_utl.c | |||
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: x509_utl.c,v 1.1 2020/06/04 15:19:32 jsing Exp $ */ | 1 | /* $OpenBSD: x509_utl.c,v 1.2 2020/09/13 15:06:17 beck Exp $ */ |
2 | /* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL | 2 | /* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL |
3 | * project. | 3 | * project. |
4 | */ | 4 | */ |
@@ -988,7 +988,8 @@ do_x509_check(X509 *x, const char *chk, size_t chklen, unsigned int flags, | |||
988 | alt_type = V_ASN1_IA5STRING; | 988 | alt_type = V_ASN1_IA5STRING; |
989 | equal = equal_email; | 989 | equal = equal_email; |
990 | } else if (check_type == GEN_DNS) { | 990 | } else if (check_type == GEN_DNS) { |
991 | cnid = NID_commonName; | 991 | if (!(flags & X509_CHECK_FLAG_NEVER_CHECK_SUBJECT)) |
992 | cnid = NID_commonName; | ||
992 | /* Implicit client-side DNS sub-domain pattern */ | 993 | /* Implicit client-side DNS sub-domain pattern */ |
993 | if (chklen > 1 && chk[0] == '.') | 994 | if (chklen > 1 && chk[0] == '.') |
994 | flags |= _X509_CHECK_FLAG_DOT_SUBDOMAINS; | 995 | flags |= _X509_CHECK_FLAG_DOT_SUBDOMAINS; |
diff --git a/src/lib/libcrypto/x509/x509_verify.c b/src/lib/libcrypto/x509/x509_verify.c new file mode 100644 index 0000000000..5f5070c122 --- /dev/null +++ b/src/lib/libcrypto/x509/x509_verify.c | |||
@@ -0,0 +1,914 @@ | |||
1 | /* $OpenBSD: x509_verify.c,v 1.1 2020/09/13 15:06:17 beck Exp $ */ | ||
2 | /* | ||
3 | * Copyright (c) 2020 Bob Beck <beck@openbsd.org> | ||
4 | * | ||
5 | * Permission to use, copy, modify, and distribute this software for any | ||
6 | * purpose with or without fee is hereby granted, provided that the above | ||
7 | * copyright notice and this permission notice appear in all copies. | ||
8 | * | ||
9 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | ||
10 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | ||
11 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | ||
12 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | ||
13 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | ||
14 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | ||
15 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | ||
16 | */ | ||
17 | |||
18 | /* x509_verify - inspired by golang's crypto/x509/Verify */ | ||
19 | |||
20 | #include <errno.h> | ||
21 | #include <stdio.h> | ||
22 | #include <string.h> | ||
23 | #include <time.h> | ||
24 | #include <unistd.h> | ||
25 | |||
26 | #include <openssl/safestack.h> | ||
27 | #include <openssl/x509.h> | ||
28 | #include <openssl/x509v3.h> | ||
29 | |||
30 | #include "x509_internal.h" | ||
31 | #include "x509_issuer_cache.h" | ||
32 | |||
33 | static int x509_verify_cert_valid(struct x509_verify_ctx *ctx, X509 *cert, | ||
34 | struct x509_verify_chain *current_chain); | ||
35 | static void x509_verify_build_chains(struct x509_verify_ctx *ctx, X509 *cert, | ||
36 | struct x509_verify_chain *current_chain); | ||
37 | static int x509_verify_cert_error(struct x509_verify_ctx *ctx, X509 *cert, | ||
38 | size_t depth, int error, int ok); | ||
39 | static void x509_verify_chain_free(struct x509_verify_chain *chain); | ||
40 | |||
41 | #define X509_VERIFY_CERT_HASH (EVP_sha512()) | ||
42 | |||
43 | struct x509_verify_chain * | ||
44 | x509_verify_chain_new(void) | ||
45 | { | ||
46 | struct x509_verify_chain *chain; | ||
47 | |||
48 | if ((chain = calloc(1, sizeof(*chain))) == NULL) | ||
49 | goto err; | ||
50 | if ((chain->certs = sk_X509_new_null()) == NULL) | ||
51 | goto err; | ||
52 | if ((chain->names = x509_constraints_names_new()) == NULL) | ||
53 | goto err; | ||
54 | |||
55 | return chain; | ||
56 | err: | ||
57 | x509_verify_chain_free(chain); | ||
58 | return NULL; | ||
59 | } | ||
60 | |||
61 | static void | ||
62 | x509_verify_chain_clear(struct x509_verify_chain *chain) | ||
63 | { | ||
64 | sk_X509_pop_free(chain->certs, X509_free); | ||
65 | chain->certs = NULL; | ||
66 | x509_constraints_names_free(chain->names); | ||
67 | chain->names = NULL; | ||
68 | } | ||
69 | |||
70 | static void | ||
71 | x509_verify_chain_free(struct x509_verify_chain *chain) | ||
72 | { | ||
73 | if (chain == NULL) | ||
74 | return; | ||
75 | x509_verify_chain_clear(chain); | ||
76 | free(chain); | ||
77 | } | ||
78 | |||
79 | static struct x509_verify_chain * | ||
80 | x509_verify_chain_dup(struct x509_verify_chain *chain) | ||
81 | { | ||
82 | struct x509_verify_chain *new_chain; | ||
83 | |||
84 | if ((new_chain = x509_verify_chain_new()) == NULL) | ||
85 | goto err; | ||
86 | if ((new_chain->certs = X509_chain_up_ref(chain->certs)) == NULL) | ||
87 | goto err; | ||
88 | if ((new_chain->names = | ||
89 | x509_constraints_names_dup(chain->names)) == NULL) | ||
90 | goto err; | ||
91 | return(new_chain); | ||
92 | err: | ||
93 | x509_verify_chain_free(new_chain); | ||
94 | return NULL; | ||
95 | } | ||
96 | |||
97 | static int | ||
98 | x509_verify_chain_append(struct x509_verify_chain *chain, X509 *cert, | ||
99 | int *error) | ||
100 | { | ||
101 | int verify_err = X509_V_ERR_UNSPECIFIED; | ||
102 | |||
103 | if (!x509_constraints_extract_names(chain->names, cert, | ||
104 | sk_X509_num(chain->certs) == 0, &verify_err)) { | ||
105 | *error = verify_err; | ||
106 | return 0; | ||
107 | } | ||
108 | X509_up_ref(cert); | ||
109 | if (!sk_X509_push(chain->certs, cert)) { | ||
110 | X509_free(cert); | ||
111 | *error = X509_V_ERR_UNSPECIFIED; | ||
112 | return 0; | ||
113 | } | ||
114 | return 1; | ||
115 | } | ||
116 | |||
117 | static X509 * | ||
118 | x509_verify_chain_last(struct x509_verify_chain *chain) | ||
119 | { | ||
120 | int last; | ||
121 | |||
122 | if (chain->certs == NULL) | ||
123 | return NULL; | ||
124 | if ((last = sk_X509_num(chain->certs) - 1) < 0) | ||
125 | return NULL; | ||
126 | return sk_X509_value(chain->certs, last); | ||
127 | } | ||
128 | |||
129 | X509 * | ||
130 | x509_verify_chain_leaf(struct x509_verify_chain *chain) | ||
131 | { | ||
132 | if (chain->certs == NULL) | ||
133 | return NULL; | ||
134 | return sk_X509_value(chain->certs, 0); | ||
135 | } | ||
136 | |||
137 | static void | ||
138 | x509_verify_ctx_reset(struct x509_verify_ctx *ctx) | ||
139 | { | ||
140 | size_t i; | ||
141 | |||
142 | for (i = 0; i < ctx->chains_count; i++) | ||
143 | x509_verify_chain_free(ctx->chains[i]); | ||
144 | ctx->error = 0; | ||
145 | ctx->error_depth = 0; | ||
146 | ctx->chains_count = 0; | ||
147 | ctx->sig_checks = 0; | ||
148 | ctx->check_time = NULL; | ||
149 | } | ||
150 | |||
151 | static void | ||
152 | x509_verify_ctx_clear(struct x509_verify_ctx *ctx) | ||
153 | { | ||
154 | x509_verify_ctx_reset(ctx); | ||
155 | sk_X509_pop_free(ctx->intermediates, X509_free); | ||
156 | sk_X509_pop_free(ctx->roots, X509_free); | ||
157 | free(ctx->chains); | ||
158 | memset(ctx, 0, sizeof(*ctx)); | ||
159 | } | ||
160 | |||
161 | static int | ||
162 | x509_verify_ctx_cert_is_root(struct x509_verify_ctx *ctx, X509 *cert) | ||
163 | { | ||
164 | int i; | ||
165 | |||
166 | for (i = 0; i < sk_X509_num(ctx->roots); i++) { | ||
167 | if (X509_cmp(sk_X509_value(ctx->roots, i), cert) == 0) | ||
168 | return 1; | ||
169 | } | ||
170 | return 0; | ||
171 | } | ||
172 | |||
173 | /* Add a validated chain to our list of valid chains */ | ||
174 | static int | ||
175 | x509_verify_ctx_add_chain(struct x509_verify_ctx *ctx, | ||
176 | struct x509_verify_chain *chain) | ||
177 | { | ||
178 | size_t depth; | ||
179 | X509 *last = x509_verify_chain_last(chain); | ||
180 | |||
181 | depth = sk_X509_num(chain->certs); | ||
182 | if (depth > 0) | ||
183 | depth--; | ||
184 | |||
185 | if (ctx->chains_count >= ctx->max_chains) | ||
186 | return x509_verify_cert_error(ctx, last, depth, | ||
187 | X509_V_ERR_CERT_CHAIN_TOO_LONG, 0); | ||
188 | |||
189 | /* | ||
190 | * If we have a legacy xsc, choose a validated chain, | ||
191 | * and apply the extensions, revocation, and policy checks | ||
192 | * just like the legacy code did. We do this here instead | ||
193 | * of as building the chains to more easily support the | ||
194 | * callback and the bewildering array of VERIFY_PARAM | ||
195 | * knobs that are there for the fiddling. | ||
196 | */ | ||
197 | if (ctx->xsc != NULL) { | ||
198 | ctx->xsc->last_untrusted = depth ? depth - 1 : 0; | ||
199 | sk_X509_pop_free(ctx->xsc->chain, X509_free); | ||
200 | ctx->xsc->chain = X509_chain_up_ref(chain->certs); | ||
201 | if (ctx->xsc->chain == NULL) | ||
202 | return x509_verify_cert_error(ctx, last, depth, | ||
203 | X509_V_ERR_OUT_OF_MEM, 0); | ||
204 | |||
205 | /* | ||
206 | * XXX currently this duplicates some work done | ||
207 | * in chain build, but we keep it here until | ||
208 | * we have feature parity | ||
209 | */ | ||
210 | if (!x509_vfy_check_chain_extensions(ctx->xsc)) | ||
211 | return 0; | ||
212 | |||
213 | if (!x509_constraints_chain(ctx->xsc->chain, | ||
214 | &ctx->xsc->error, &ctx->xsc->error_depth)) { | ||
215 | X509 *cert = sk_X509_value(ctx->xsc->chain, depth); | ||
216 | if (!x509_verify_cert_error(ctx, cert, | ||
217 | ctx->xsc->error_depth, ctx->xsc->error, 0)) | ||
218 | return 0; | ||
219 | } | ||
220 | |||
221 | if (!x509_vfy_check_revocation(ctx->xsc)) | ||
222 | return 0; | ||
223 | |||
224 | if (!x509_vfy_check_policy(ctx->xsc)) | ||
225 | return 0; | ||
226 | } | ||
227 | /* | ||
228 | * no xsc means we are being called from the non-legacy API, | ||
229 | * extensions and purpose are dealt with as the chain is built. | ||
230 | * | ||
231 | * The non-legacy api returns multiple chains but does not do | ||
232 | * any revocation checking (it must be done by the caller on | ||
233 | * any chain they wish to use) | ||
234 | */ | ||
235 | |||
236 | if ((ctx->chains[ctx->chains_count] = x509_verify_chain_dup(chain)) == | ||
237 | NULL) { | ||
238 | return x509_verify_cert_error(ctx, last, depth, | ||
239 | X509_V_ERR_OUT_OF_MEM, 0); | ||
240 | } | ||
241 | ctx->chains_count++; | ||
242 | ctx->error = X509_V_OK; | ||
243 | ctx->error_depth = depth; | ||
244 | return 1; | ||
245 | } | ||
246 | |||
247 | static int | ||
248 | x509_verify_potential_parent(struct x509_verify_ctx *ctx, X509 *parent, | ||
249 | X509 *child) | ||
250 | { | ||
251 | if (ctx->xsc != NULL) | ||
252 | return (ctx->xsc->check_issued(ctx->xsc, child, parent)); | ||
253 | |||
254 | /* XXX key usage */ | ||
255 | return X509_check_issued(child, parent) != X509_V_OK; | ||
256 | } | ||
257 | |||
258 | static int | ||
259 | x509_verify_parent_signature(X509 *parent, X509 *child, | ||
260 | unsigned char *child_md, int *error) | ||
261 | { | ||
262 | unsigned char parent_md[EVP_MAX_MD_SIZE] = { 0 }; | ||
263 | EVP_PKEY *pkey; | ||
264 | int cached; | ||
265 | int ret = 0; | ||
266 | |||
267 | /* Use cached value if we have it */ | ||
268 | if (child_md != NULL) { | ||
269 | if (!X509_digest(parent, X509_VERIFY_CERT_HASH, parent_md, | ||
270 | NULL)) | ||
271 | return 0; | ||
272 | if ((cached = x509_issuer_cache_find(parent_md, child_md)) >= 0) | ||
273 | return cached; | ||
274 | } | ||
275 | |||
276 | /* Check signature. Did parent sign child? */ | ||
277 | if ((pkey = X509_get_pubkey(parent)) == NULL) { | ||
278 | *error = X509_V_ERR_UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY; | ||
279 | return 0; | ||
280 | } | ||
281 | if (X509_verify(child, pkey) <= 0) | ||
282 | *error = X509_V_ERR_CERT_SIGNATURE_FAILURE; | ||
283 | else | ||
284 | ret = 1; | ||
285 | |||
286 | /* Add result to cache */ | ||
287 | if (child_md != NULL) | ||
288 | x509_issuer_cache_add(parent_md, child_md, ret); | ||
289 | |||
290 | EVP_PKEY_free(pkey); | ||
291 | |||
292 | return ret; | ||
293 | } | ||
294 | |||
295 | static int | ||
296 | x509_verify_consider_candidate(struct x509_verify_ctx *ctx, X509 *cert, | ||
297 | unsigned char *cert_md, int is_root_cert, X509 *candidate, | ||
298 | struct x509_verify_chain *current_chain) | ||
299 | { | ||
300 | int depth = sk_X509_num(current_chain->certs); | ||
301 | struct x509_verify_chain *new_chain; | ||
302 | int i; | ||
303 | |||
304 | /* Fail if the certificate is already in the chain */ | ||
305 | for (i = 0; i < sk_X509_num(current_chain->certs); i++) { | ||
306 | if (X509_cmp(sk_X509_value(current_chain->certs, i), | ||
307 | candidate) == 0) | ||
308 | return 0; | ||
309 | } | ||
310 | |||
311 | if (ctx->sig_checks++ > X509_VERIFY_MAX_SIGCHECKS) { | ||
312 | /* don't allow callback to override safety check */ | ||
313 | (void) x509_verify_cert_error(ctx, candidate, depth, | ||
314 | X509_V_ERR_CERT_CHAIN_TOO_LONG, 0); | ||
315 | return 0; | ||
316 | } | ||
317 | |||
318 | |||
319 | if (!x509_verify_parent_signature(candidate, cert, cert_md, | ||
320 | &ctx->error)) { | ||
321 | if (!x509_verify_cert_error(ctx, candidate, depth, | ||
322 | ctx->error, 0)) | ||
323 | return 0; | ||
324 | } | ||
325 | |||
326 | if (!x509_verify_cert_valid(ctx, candidate, current_chain)) | ||
327 | return 0; | ||
328 | |||
329 | /* candidate is good, add it to a copy of the current chain */ | ||
330 | if ((new_chain = x509_verify_chain_dup(current_chain)) == NULL) { | ||
331 | x509_verify_cert_error(ctx, candidate, depth, | ||
332 | X509_V_ERR_OUT_OF_MEM, 0); | ||
333 | return 0; | ||
334 | } | ||
335 | if (!x509_verify_chain_append(new_chain, candidate, &ctx->error)) { | ||
336 | x509_verify_cert_error(ctx, candidate, depth, | ||
337 | ctx->error, 0); | ||
338 | x509_verify_chain_free(new_chain); | ||
339 | return 0; | ||
340 | } | ||
341 | |||
342 | /* | ||
343 | * If candidate is a trusted root, we have a validated chain, | ||
344 | * so we save it. Otherwise, recurse until we find a root or | ||
345 | * give up. | ||
346 | */ | ||
347 | if (is_root_cert && | ||
348 | x509_verify_cert_error(ctx, candidate, depth, X509_V_OK, 1)) | ||
349 | (void) x509_verify_ctx_add_chain(ctx, new_chain); | ||
350 | else | ||
351 | x509_verify_build_chains(ctx, candidate, new_chain); | ||
352 | |||
353 | x509_verify_chain_free(new_chain); | ||
354 | return 1; | ||
355 | } | ||
356 | |||
357 | static int | ||
358 | x509_verify_cert_error(struct x509_verify_ctx *ctx, X509 *cert, size_t depth, | ||
359 | int error, int ok) | ||
360 | { | ||
361 | ctx->error = error; | ||
362 | ctx->error_depth = depth; | ||
363 | if (ctx->xsc != NULL) { | ||
364 | ctx->xsc->error = error; | ||
365 | ctx->xsc->error_depth = depth; | ||
366 | ctx->xsc->current_cert = cert; | ||
367 | return ctx->xsc->verify_cb(ok, ctx->xsc); | ||
368 | } | ||
369 | return ok; | ||
370 | } | ||
371 | |||
372 | static void | ||
373 | x509_verify_build_chains(struct x509_verify_ctx *ctx, X509 *cert, | ||
374 | struct x509_verify_chain *current_chain) | ||
375 | { | ||
376 | unsigned char cert_md[EVP_MAX_MD_SIZE] = { 0 }; | ||
377 | X509 *candidate; | ||
378 | int i, depth, count; | ||
379 | |||
380 | depth = sk_X509_num(current_chain->certs); | ||
381 | if (depth > 0) | ||
382 | depth--; | ||
383 | |||
384 | if (depth >= ctx->max_depth && | ||
385 | !x509_verify_cert_error(ctx, cert, depth, | ||
386 | X509_V_ERR_CERT_CHAIN_TOO_LONG, 0)) | ||
387 | return; | ||
388 | |||
389 | if (!X509_digest(cert, X509_VERIFY_CERT_HASH, cert_md, NULL) && | ||
390 | !x509_verify_cert_error(ctx, cert, depth, | ||
391 | X509_V_ERR_UNSPECIFIED, 0)) | ||
392 | return; | ||
393 | |||
394 | count = ctx->chains_count; | ||
395 | ctx->error = X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY; | ||
396 | ctx->error_depth = depth; | ||
397 | |||
398 | for (i = 0; i < sk_X509_num(ctx->roots); i++) { | ||
399 | candidate = sk_X509_value(ctx->roots, i); | ||
400 | if (x509_verify_potential_parent(ctx, candidate, cert)) { | ||
401 | x509_verify_consider_candidate(ctx, cert, | ||
402 | cert_md, 1, candidate, current_chain); | ||
403 | } | ||
404 | } | ||
405 | |||
406 | if (ctx->intermediates != NULL) { | ||
407 | for (i = 0; i < sk_X509_num(ctx->intermediates); i++) { | ||
408 | candidate = sk_X509_value(ctx->intermediates, i); | ||
409 | if (x509_verify_potential_parent(ctx, candidate, cert)) { | ||
410 | x509_verify_consider_candidate(ctx, cert, | ||
411 | cert_md, 0, candidate, current_chain); | ||
412 | } | ||
413 | } | ||
414 | } | ||
415 | if (ctx->chains_count > count) { | ||
416 | if (ctx->xsc != NULL) { | ||
417 | ctx->xsc->error = X509_V_OK; | ||
418 | ctx->xsc->error_depth = depth; | ||
419 | ctx->xsc->current_cert = cert; | ||
420 | (void) ctx->xsc->verify_cb(1, ctx->xsc); | ||
421 | } | ||
422 | } else if (ctx->error_depth == depth) { | ||
423 | (void) x509_verify_cert_error(ctx, cert, depth, | ||
424 | ctx->error, 0); | ||
425 | } | ||
426 | } | ||
427 | |||
428 | static int | ||
429 | x509_verify_cert_hostname(struct x509_verify_ctx *ctx, X509 *cert, char *name) | ||
430 | { | ||
431 | char *candidate; | ||
432 | size_t len; | ||
433 | |||
434 | if (name == NULL) { | ||
435 | if (ctx->xsc != NULL) | ||
436 | return x509_vfy_check_id(ctx->xsc); | ||
437 | return 1; | ||
438 | } | ||
439 | if ((candidate = strdup(name)) == NULL) { | ||
440 | ctx->error = X509_V_ERR_OUT_OF_MEM; | ||
441 | goto err; | ||
442 | } | ||
443 | if ((len = strlen(candidate)) < 1) { | ||
444 | ctx->error = X509_V_ERR_UNSPECIFIED; /* XXX */ | ||
445 | goto err; | ||
446 | } | ||
447 | |||
448 | /* IP addresses may be written in [ ]. */ | ||
449 | if (candidate[0] == '[' && candidate[len - 1] == ']') { | ||
450 | candidate[len - 1] = '\0'; | ||
451 | if (X509_check_ip_asc(cert, candidate + 1, 0) <= 0) { | ||
452 | ctx->error = X509_V_ERR_IP_ADDRESS_MISMATCH; | ||
453 | goto err; | ||
454 | } | ||
455 | } else { | ||
456 | int flags = 0; | ||
457 | |||
458 | if (ctx->xsc == NULL) | ||
459 | flags = X509_CHECK_FLAG_NEVER_CHECK_SUBJECT; | ||
460 | |||
461 | if (X509_check_host(cert, candidate, len, flags, NULL) <= 0) { | ||
462 | ctx->error = X509_V_ERR_HOSTNAME_MISMATCH; | ||
463 | goto err; | ||
464 | } | ||
465 | } | ||
466 | free(candidate); | ||
467 | return 1; | ||
468 | err: | ||
469 | free(candidate); | ||
470 | return x509_verify_cert_error(ctx, cert, 0, ctx->error, 0); | ||
471 | } | ||
472 | |||
473 | static int | ||
474 | x509_verify_set_check_time(struct x509_verify_ctx *ctx) { | ||
475 | if (ctx->xsc != NULL) { | ||
476 | if (ctx->xsc->param->flags & X509_V_FLAG_USE_CHECK_TIME) { | ||
477 | ctx->check_time = &ctx->xsc->param->check_time; | ||
478 | return 1; | ||
479 | } | ||
480 | if (ctx->xsc->param->flags & X509_V_FLAG_NO_CHECK_TIME) | ||
481 | return 0; | ||
482 | } | ||
483 | |||
484 | ctx->check_time = NULL; | ||
485 | return 1; | ||
486 | } | ||
487 | |||
488 | static int | ||
489 | x509_verify_asn1_time_to_tm(const ASN1_TIME *atime, struct tm *tm, int notafter) | ||
490 | { | ||
491 | time_t time; | ||
492 | int type; | ||
493 | |||
494 | memset(tm, 0, sizeof(*tm)); | ||
495 | |||
496 | type = ASN1_time_parse(atime->data, atime->length, tm, atime->type); | ||
497 | if (type == -1) | ||
498 | return 0; | ||
499 | |||
500 | /* RFC 5280 section 4.1.2.5 */ | ||
501 | if (tm->tm_year < 150 && type != V_ASN1_UTCTIME) | ||
502 | return 0; | ||
503 | if (tm->tm_year >= 150 && type != V_ASN1_GENERALIZEDTIME) | ||
504 | return 0; | ||
505 | |||
506 | if (notafter) { | ||
507 | /* | ||
508 | * If we are a completely broken operating system with a | ||
509 | * 32 bit time_t, and we have been told this is a notafter | ||
510 | * date, limit the date to a 32 bit representable value. | ||
511 | */ | ||
512 | if (!ASN1_time_tm_clamp_notafter(tm)) | ||
513 | return 0; | ||
514 | } | ||
515 | |||
516 | /* | ||
517 | * Defensively fail if the time string is not representable as | ||
518 | * a time_t. A time_t must be sane if you care about times after | ||
519 | * Jan 19 2038. | ||
520 | */ | ||
521 | if ((time = timegm(tm)) == -1) | ||
522 | return 0; | ||
523 | |||
524 | return 1; | ||
525 | } | ||
526 | |||
527 | static int | ||
528 | x509_verify_cert_time(int is_notafter, const ASN1_TIME *cert_asn1, | ||
529 | time_t *cmp_time, int *error) | ||
530 | { | ||
531 | struct tm cert_tm, when_tm; | ||
532 | time_t when; | ||
533 | |||
534 | if (cmp_time == NULL) | ||
535 | when = time(NULL); | ||
536 | else | ||
537 | when = *cmp_time; | ||
538 | |||
539 | if (!x509_verify_asn1_time_to_tm(cert_asn1, &cert_tm, | ||
540 | is_notafter)) { | ||
541 | *error = is_notafter ? | ||
542 | X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD : | ||
543 | X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD; | ||
544 | return 0; | ||
545 | } | ||
546 | |||
547 | if (gmtime_r(&when, &when_tm) == NULL) { | ||
548 | *error = X509_V_ERR_UNSPECIFIED; | ||
549 | return 0; | ||
550 | } | ||
551 | |||
552 | if (is_notafter) { | ||
553 | if (ASN1_time_tm_cmp(&cert_tm, &when_tm) == -1) { | ||
554 | *error = X509_V_ERR_CERT_HAS_EXPIRED; | ||
555 | return 0; | ||
556 | } | ||
557 | } else { | ||
558 | if (ASN1_time_tm_cmp(&cert_tm, &when_tm) == 1) { | ||
559 | *error = X509_V_ERR_CERT_NOT_YET_VALID; | ||
560 | return 0; | ||
561 | } | ||
562 | } | ||
563 | |||
564 | return 1; | ||
565 | } | ||
566 | |||
567 | static int | ||
568 | x509_verify_validate_constraints(X509 *cert, | ||
569 | struct x509_verify_chain *current_chain, int *error) | ||
570 | { | ||
571 | struct x509_constraints_names *excluded = NULL; | ||
572 | struct x509_constraints_names *permitted = NULL; | ||
573 | int err = X509_V_ERR_UNSPECIFIED; | ||
574 | |||
575 | if (current_chain == NULL) | ||
576 | return 1; | ||
577 | |||
578 | if (cert->nc != NULL) { | ||
579 | if ((permitted = x509_constraints_names_new()) == NULL) { | ||
580 | err = X509_V_ERR_OUT_OF_MEM; | ||
581 | goto err; | ||
582 | } | ||
583 | if ((excluded = x509_constraints_names_new()) == NULL) { | ||
584 | err = X509_V_ERR_OUT_OF_MEM; | ||
585 | goto err; | ||
586 | } | ||
587 | if (!x509_constraints_extract_constraints(cert, | ||
588 | permitted, excluded, &err)) | ||
589 | goto err; | ||
590 | if (!x509_constraints_check(current_chain->names, | ||
591 | permitted, excluded, &err)) | ||
592 | goto err; | ||
593 | x509_constraints_names_free(excluded); | ||
594 | x509_constraints_names_free(permitted); | ||
595 | } | ||
596 | |||
597 | return 1; | ||
598 | err: | ||
599 | *error = err; | ||
600 | x509_constraints_names_free(excluded); | ||
601 | x509_constraints_names_free(permitted); | ||
602 | return 0; | ||
603 | } | ||
604 | |||
605 | static int | ||
606 | x509_verify_cert_extensions(struct x509_verify_ctx *ctx, X509 *cert, int need_ca) | ||
607 | { | ||
608 | if (!(cert->ex_flags & EXFLAG_SET)) { | ||
609 | CRYPTO_w_lock(CRYPTO_LOCK_X509); | ||
610 | x509v3_cache_extensions(cert); | ||
611 | CRYPTO_w_unlock(CRYPTO_LOCK_X509); | ||
612 | } | ||
613 | |||
614 | if (ctx->xsc != NULL) | ||
615 | return 1; /* legacy is checked after chain is built */ | ||
616 | |||
617 | if (cert->ex_flags & EXFLAG_CRITICAL) { | ||
618 | ctx->error = X509_V_ERR_UNHANDLED_CRITICAL_EXTENSION; | ||
619 | return 0; | ||
620 | } | ||
621 | /* No we don't care about v1, netscape, and other ancient silliness */ | ||
622 | if (need_ca && (!(cert->ex_flags & EXFLAG_BCONS) && | ||
623 | (cert->ex_flags & EXFLAG_CA))) { | ||
624 | ctx->error = X509_V_ERR_INVALID_CA; | ||
625 | return 0; | ||
626 | } | ||
627 | if (ctx->purpose > 0 && X509_check_purpose(cert, ctx->purpose, need_ca)) { | ||
628 | ctx->error = X509_V_ERR_INVALID_PURPOSE; | ||
629 | return 0; | ||
630 | } | ||
631 | |||
632 | /* XXX support proxy certs later in new api */ | ||
633 | if (ctx->xsc == NULL && cert->ex_flags & EXFLAG_PROXY) { | ||
634 | ctx->error = X509_V_ERR_PROXY_CERTIFICATES_NOT_ALLOWED; | ||
635 | return 0; | ||
636 | } | ||
637 | |||
638 | return 1; | ||
639 | } | ||
640 | |||
641 | /* Validate that cert is a possible candidate to append to current_chain */ | ||
642 | static int | ||
643 | x509_verify_cert_valid(struct x509_verify_ctx *ctx, X509 *cert, | ||
644 | struct x509_verify_chain *current_chain) | ||
645 | { | ||
646 | X509 *issuer_candidate; | ||
647 | int should_be_ca = current_chain != NULL; | ||
648 | size_t depth = 0; | ||
649 | |||
650 | if (!should_be_ca) | ||
651 | depth = sk_X509_num(current_chain->certs); | ||
652 | |||
653 | if (!x509_verify_cert_extensions(ctx, cert, should_be_ca)) | ||
654 | return 0; | ||
655 | |||
656 | if (should_be_ca) { | ||
657 | issuer_candidate = x509_verify_chain_last(current_chain); | ||
658 | if (issuer_candidate != NULL && | ||
659 | !X509_check_issued(issuer_candidate, cert)) | ||
660 | if (!x509_verify_cert_error(ctx, cert, depth, | ||
661 | X509_V_ERR_SUBJECT_ISSUER_MISMATCH, 0)) | ||
662 | return 0; | ||
663 | } | ||
664 | |||
665 | if (x509_verify_set_check_time(ctx)) { | ||
666 | if (!x509_verify_cert_time(0, X509_get_notBefore(cert), | ||
667 | ctx->check_time, &ctx->error)) { | ||
668 | if (!x509_verify_cert_error(ctx, cert, depth, | ||
669 | ctx->error, 0)) | ||
670 | return 0; | ||
671 | } | ||
672 | |||
673 | if (!x509_verify_cert_time(1, X509_get_notAfter(cert), | ||
674 | ctx->check_time, &ctx->error)) { | ||
675 | if (!x509_verify_cert_error(ctx, cert, depth, | ||
676 | ctx->error, 0)) | ||
677 | return 0; | ||
678 | } | ||
679 | } | ||
680 | |||
681 | if (!x509_verify_validate_constraints(cert, current_chain, | ||
682 | &ctx->error) && !x509_verify_cert_error(ctx, cert, depth, | ||
683 | ctx->error, 0)) | ||
684 | return 0; | ||
685 | |||
686 | return 1; | ||
687 | } | ||
688 | |||
689 | struct x509_verify_ctx * | ||
690 | x509_verify_ctx_new_from_xsc(X509_STORE_CTX *xsc, STACK_OF(X509) *roots) | ||
691 | { | ||
692 | struct x509_verify_ctx *ctx; | ||
693 | |||
694 | if (xsc == NULL) | ||
695 | return NULL; | ||
696 | |||
697 | if ((ctx = calloc(1, sizeof(struct x509_verify_ctx))) == NULL) | ||
698 | return NULL; | ||
699 | |||
700 | ctx->xsc = xsc; | ||
701 | |||
702 | if ((ctx->roots = X509_chain_up_ref(roots)) == NULL) | ||
703 | goto err; | ||
704 | |||
705 | if (xsc->untrusted && | ||
706 | (ctx->intermediates = X509_chain_up_ref(xsc->untrusted)) == NULL) | ||
707 | goto err; | ||
708 | |||
709 | ctx->max_depth = xsc->param->depth; | ||
710 | if (ctx->max_depth == 0 || ctx->max_depth > X509_VERIFY_MAX_CHAIN_CERTS) | ||
711 | ctx->max_depth = X509_VERIFY_MAX_CHAIN_CERTS; | ||
712 | |||
713 | ctx->max_chains = X509_VERIFY_MAX_CHAINS; | ||
714 | ctx->max_sigs = X509_VERIFY_MAX_SIGCHECKS; | ||
715 | |||
716 | if ((ctx->chains = calloc(X509_VERIFY_MAX_CHAINS, sizeof(*ctx->chains))) == | ||
717 | NULL) | ||
718 | goto err; | ||
719 | |||
720 | return ctx; | ||
721 | err: | ||
722 | x509_verify_ctx_free(ctx); | ||
723 | return NULL; | ||
724 | } | ||
725 | |||
726 | /* Public API */ | ||
727 | |||
728 | struct x509_verify_ctx * | ||
729 | x509_verify_ctx_new(STACK_OF(X509) *roots) | ||
730 | { | ||
731 | struct x509_verify_ctx *ctx; | ||
732 | |||
733 | if (roots == NULL) | ||
734 | return NULL; | ||
735 | |||
736 | if ((ctx = calloc(1, sizeof(struct x509_verify_ctx))) == NULL) | ||
737 | return NULL; | ||
738 | |||
739 | if ((ctx->roots = X509_chain_up_ref(roots)) == NULL) | ||
740 | goto err; | ||
741 | |||
742 | ctx->max_depth = X509_VERIFY_MAX_CHAIN_CERTS; | ||
743 | ctx->max_chains = X509_VERIFY_MAX_CHAINS; | ||
744 | ctx->max_sigs = X509_VERIFY_MAX_SIGCHECKS; | ||
745 | |||
746 | if ((ctx->chains = calloc(X509_VERIFY_MAX_CHAINS, | ||
747 | sizeof(*ctx->chains))) == NULL) | ||
748 | goto err; | ||
749 | |||
750 | return ctx; | ||
751 | err: | ||
752 | x509_verify_ctx_free(ctx); | ||
753 | return NULL; | ||
754 | } | ||
755 | |||
756 | void | ||
757 | x509_verify_ctx_free(struct x509_verify_ctx *ctx) | ||
758 | { | ||
759 | if (ctx == NULL) | ||
760 | return; | ||
761 | sk_X509_pop_free(ctx->roots, X509_free); | ||
762 | x509_verify_ctx_clear(ctx); | ||
763 | free(ctx); | ||
764 | } | ||
765 | |||
766 | int | ||
767 | x509_verify_ctx_set_max_depth(struct x509_verify_ctx *ctx, size_t max) | ||
768 | { | ||
769 | if (max < 1 || max > X509_VERIFY_MAX_CHAIN_CERTS) | ||
770 | return 0; | ||
771 | ctx->max_depth = max; | ||
772 | return 1; | ||
773 | } | ||
774 | |||
775 | int | ||
776 | x509_verify_ctx_set_max_chains(struct x509_verify_ctx *ctx, size_t max) | ||
777 | { | ||
778 | if (max < 1 || max > X509_VERIFY_MAX_CHAINS) | ||
779 | return 0; | ||
780 | ctx->max_chains = max; | ||
781 | return 1; | ||
782 | } | ||
783 | |||
784 | int | ||
785 | x509_verify_ctx_set_max_signatures(struct x509_verify_ctx *ctx, size_t max) | ||
786 | { | ||
787 | if (max < 1) | ||
788 | return 0; | ||
789 | if (max > 100000) | ||
790 | return 0; | ||
791 | ctx->max_sigs = max; | ||
792 | return 1; | ||
793 | } | ||
794 | |||
795 | int | ||
796 | x509_verify_ctx_set_purpose(struct x509_verify_ctx *ctx, int purpose) | ||
797 | { | ||
798 | if (purpose < X509_PURPOSE_MIN || purpose > X509_PURPOSE_MAX) | ||
799 | return 0; | ||
800 | ctx->purpose = purpose; | ||
801 | return 1; | ||
802 | } | ||
803 | |||
804 | int | ||
805 | x509_verify_ctx_set_intermediates(struct x509_verify_ctx *ctx, | ||
806 | STACK_OF(X509) *intermediates) | ||
807 | { | ||
808 | if ((ctx->intermediates = X509_chain_up_ref(intermediates)) == NULL) | ||
809 | return 0; | ||
810 | return 1; | ||
811 | } | ||
812 | |||
813 | const char * | ||
814 | x509_verify_ctx_error_string(struct x509_verify_ctx *ctx) | ||
815 | { | ||
816 | return X509_verify_cert_error_string(ctx->error); | ||
817 | } | ||
818 | |||
819 | size_t | ||
820 | x509_verify_ctx_error_depth(struct x509_verify_ctx *ctx) | ||
821 | { | ||
822 | return ctx->error_depth; | ||
823 | } | ||
824 | |||
825 | STACK_OF(X509) * | ||
826 | x509_verify_ctx_chain(struct x509_verify_ctx *ctx, size_t i) | ||
827 | { | ||
828 | if (i >= ctx->chains_count) | ||
829 | return NULL; | ||
830 | return ctx->chains[i]->certs; | ||
831 | } | ||
832 | |||
833 | size_t | ||
834 | x509_verify(struct x509_verify_ctx *ctx, X509 *leaf, char *name) | ||
835 | { | ||
836 | struct x509_verify_chain *current_chain; | ||
837 | |||
838 | if (ctx == NULL) | ||
839 | return 0; | ||
840 | if (ctx->roots == NULL || ctx->max_depth == 0) { | ||
841 | ctx->error = X509_V_ERR_INVALID_CALL; | ||
842 | return 0; | ||
843 | } | ||
844 | |||
845 | if (ctx->xsc != NULL) { | ||
846 | if (leaf != NULL || name != NULL) { | ||
847 | ctx->error = X509_V_ERR_INVALID_CALL; | ||
848 | return 0; | ||
849 | } | ||
850 | leaf = ctx->xsc->cert; | ||
851 | } | ||
852 | |||
853 | if (!x509_verify_cert_valid(ctx, leaf, NULL)) | ||
854 | return 0; | ||
855 | |||
856 | if (!x509_verify_cert_hostname(ctx, leaf, name)) | ||
857 | return 0; | ||
858 | |||
859 | if (ctx->xsc != NULL) { | ||
860 | /* | ||
861 | * XXX | ||
862 | * The legacy code expects the top level cert to be | ||
863 | * there, even if we didn't find a chain. So put it | ||
864 | * there, we will clobber it later if we find a valid | ||
865 | * chain. | ||
866 | */ | ||
867 | if ((ctx->xsc->chain = sk_X509_new_null()) == NULL) { | ||
868 | ctx->error = X509_V_ERR_OUT_OF_MEM; | ||
869 | return 0; | ||
870 | } | ||
871 | if (!X509_up_ref(leaf)) { | ||
872 | ctx->error = X509_V_ERR_OUT_OF_MEM; | ||
873 | return 0; | ||
874 | } | ||
875 | if (!sk_X509_push(ctx->xsc->chain, leaf)) { | ||
876 | X509_free(leaf); | ||
877 | ctx->error = X509_V_ERR_OUT_OF_MEM; | ||
878 | return 0; | ||
879 | } | ||
880 | } | ||
881 | |||
882 | if ((current_chain = x509_verify_chain_new()) == NULL) { | ||
883 | ctx->error = X509_V_ERR_OUT_OF_MEM; | ||
884 | return 0; | ||
885 | } | ||
886 | if (!x509_verify_chain_append(current_chain, leaf, &ctx->error)) { | ||
887 | x509_verify_chain_free(current_chain); | ||
888 | return 0; | ||
889 | } | ||
890 | if (x509_verify_ctx_cert_is_root(ctx, leaf)) | ||
891 | x509_verify_ctx_add_chain(ctx, current_chain); | ||
892 | else | ||
893 | x509_verify_build_chains(ctx, leaf, current_chain); | ||
894 | |||
895 | x509_verify_chain_free(current_chain); | ||
896 | |||
897 | /* | ||
898 | * Safety net: | ||
899 | * We could not find a validated chain, and for some reason do not | ||
900 | * have an error set. | ||
901 | */ | ||
902 | if (ctx->chains_count == 0 && ctx->error == 0) | ||
903 | ctx->error = X509_V_ERR_UNSPECIFIED; | ||
904 | |||
905 | /* Clear whatever errors happened if we have any validated chain */ | ||
906 | if (ctx->chains_count > 0) | ||
907 | ctx->error = X509_V_OK; | ||
908 | |||
909 | if (ctx->xsc != NULL) { | ||
910 | ctx->xsc->error = ctx->error; | ||
911 | return ctx->xsc->verify_cb(ctx->chains_count, ctx->xsc); | ||
912 | } | ||
913 | return (ctx->chains_count); | ||
914 | } | ||
diff --git a/src/lib/libcrypto/x509/x509_verify.h b/src/lib/libcrypto/x509/x509_verify.h new file mode 100644 index 0000000000..a097404f2e --- /dev/null +++ b/src/lib/libcrypto/x509/x509_verify.h | |||
@@ -0,0 +1,42 @@ | |||
1 | /* $OpenBSD: x509_verify.h,v 1.1 2020/09/13 15:06:17 beck Exp $ */ | ||
2 | /* | ||
3 | * Copyright (c) 2020 Bob Beck <beck@openbsd.org> | ||
4 | * | ||
5 | * Permission to use, copy, modify, and distribute this software for any | ||
6 | * purpose with or without fee is hereby granted, provided that the above | ||
7 | * copyright notice and this permission notice appear in all copies. | ||
8 | * | ||
9 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | ||
10 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | ||
11 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | ||
12 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | ||
13 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | ||
14 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | ||
15 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | ||
16 | */ | ||
17 | #ifndef HEADER_X509_VERIFY_H | ||
18 | #define HEADER_X509_VERIFY_H | ||
19 | |||
20 | #ifdef LIBRESSL_INTERNAL | ||
21 | struct x509_verify_ctx; | ||
22 | typedef struct x509_verify_ctx X509_VERIFY_CTX; | ||
23 | |||
24 | X509_VERIFY_CTX *x509_verify_ctx_new(STACK_OF(X509) *roots); | ||
25 | void x509_verify_ctx_free(struct x509_verify_ctx *ctx); | ||
26 | |||
27 | int x509_verify_ctx_set_max_depth(X509_VERIFY_CTX *ctx, size_t max); | ||
28 | int x509_verify_ctx_set_max_chains(X509_VERIFY_CTX *ctx, size_t max); | ||
29 | int x509_verify_ctx_set_max_signatures(X509_VERIFY_CTX *ctx, size_t max); | ||
30 | int x509_verify_ctx_set_purpose(X509_VERIFY_CTX *ctx, int purpose_id); | ||
31 | int x509_verify_ctx_set_intermediates(X509_VERIFY_CTX *ctx, | ||
32 | STACK_OF(X509) *intermediates); | ||
33 | |||
34 | const char *x509_verify_ctx_error_string(X509_VERIFY_CTX *ctx); | ||
35 | size_t x509_verify_ctx_error_depth(X509_VERIFY_CTX *ctx); | ||
36 | |||
37 | STACK_OF(X509) *x509_verify_ctx_chain(X509_VERIFY_CTX *ctx, size_t chain); | ||
38 | |||
39 | size_t x509_verify(X509_VERIFY_CTX *ctx, X509 *leaf, char *name); | ||
40 | #endif | ||
41 | |||
42 | #endif | ||
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 | * |
diff --git a/src/lib/libcrypto/x509/x509_vfy.h b/src/lib/libcrypto/x509/x509_vfy.h index c5eae9d398..a68d5c0840 100644 --- a/src/lib/libcrypto/x509/x509_vfy.h +++ b/src/lib/libcrypto/x509/x509_vfy.h | |||
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: x509_vfy.h,v 1.30 2018/08/24 19:21:09 tb Exp $ */ | 1 | /* $OpenBSD: x509_vfy.h,v 1.31 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 | * |
@@ -407,6 +407,9 @@ void X509_STORE_CTX_set_depth(X509_STORE_CTX *ctx, int depth); | |||
407 | /* Do not check certificate or CRL validity against current time. */ | 407 | /* Do not check certificate or CRL validity against current time. */ |
408 | #define X509_V_FLAG_NO_CHECK_TIME 0x200000 | 408 | #define X509_V_FLAG_NO_CHECK_TIME 0x200000 |
409 | 409 | ||
410 | /* Force the use of the legacy certificate verifcation */ | ||
411 | #define X509_V_FLAG_LEGACY_VERIFY 0x400000 | ||
412 | |||
410 | #define X509_VP_FLAG_DEFAULT 0x1 | 413 | #define X509_VP_FLAG_DEFAULT 0x1 |
411 | #define X509_VP_FLAG_OVERWRITE 0x2 | 414 | #define X509_VP_FLAG_OVERWRITE 0x2 |
412 | #define X509_VP_FLAG_RESET_FLAGS 0x4 | 415 | #define X509_VP_FLAG_RESET_FLAGS 0x4 |
diff --git a/src/lib/libcrypto/x509/x509_vpm.c b/src/lib/libcrypto/x509/x509_vpm.c index baebcf7bca..ca533e26d1 100644 --- a/src/lib/libcrypto/x509/x509_vpm.c +++ b/src/lib/libcrypto/x509/x509_vpm.c | |||
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: x509_vpm.c,v 1.18 2018/04/06 07:08:20 beck Exp $ */ | 1 | /* $OpenBSD: x509_vpm.c,v 1.19 2020/09/13 15:06:17 beck Exp $ */ |
2 | /* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL | 2 | /* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL |
3 | * project 2004. | 3 | * project 2004. |
4 | */ | 4 | */ |
@@ -178,6 +178,8 @@ x509_verify_param_zero(X509_VERIFY_PARAM *param) | |||
178 | /*param->inh_flags = X509_VP_FLAG_DEFAULT;*/ | 178 | /*param->inh_flags = X509_VP_FLAG_DEFAULT;*/ |
179 | param->inh_flags = 0; | 179 | param->inh_flags = 0; |
180 | param->flags = 0; | 180 | param->flags = 0; |
181 | /* XXX remove to enable new verifier by default */ | ||
182 | param->flags |= X509_V_FLAG_LEGACY_VERIFY; | ||
181 | param->depth = -1; | 183 | param->depth = -1; |
182 | if (param->policies) { | 184 | if (param->policies) { |
183 | sk_ASN1_OBJECT_pop_free(param->policies, ASN1_OBJECT_free); | 185 | sk_ASN1_OBJECT_pop_free(param->policies, ASN1_OBJECT_free); |
diff --git a/src/lib/libcrypto/x509/x509v3.h b/src/lib/libcrypto/x509/x509v3.h index 8f7f5c5794..d2754fa624 100644 --- a/src/lib/libcrypto/x509/x509v3.h +++ b/src/lib/libcrypto/x509/x509v3.h | |||
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: x509v3.h,v 1.1 2020/06/04 15:19:32 jsing Exp $ */ | 1 | /* $OpenBSD: x509v3.h,v 1.2 2020/09/13 15:06:17 beck Exp $ */ |
2 | /* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL | 2 | /* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL |
3 | * project 1999. | 3 | * project 1999. |
4 | */ | 4 | */ |
@@ -815,6 +815,8 @@ STACK_OF(OPENSSL_STRING) *X509_get1_ocsp(X509 *x); | |||
815 | #define X509_CHECK_FLAG_MULTI_LABEL_WILDCARDS 0x8 | 815 | #define X509_CHECK_FLAG_MULTI_LABEL_WILDCARDS 0x8 |
816 | /* Constraint verifier subdomain patterns to match a single labels. */ | 816 | /* Constraint verifier subdomain patterns to match a single labels. */ |
817 | #define X509_CHECK_FLAG_SINGLE_LABEL_SUBDOMAINS 0x10 | 817 | #define X509_CHECK_FLAG_SINGLE_LABEL_SUBDOMAINS 0x10 |
818 | /* Disable checking the CN for a hostname, to support modern validation */ | ||
819 | #define X509_CHECK_FLAG_NEVER_CHECK_SUBJECT 0x20 | ||
818 | 820 | ||
819 | /* | 821 | /* |
820 | * Match reference identifiers starting with "." to any sub-domain. | 822 | * Match reference identifiers starting with "." to any sub-domain. |
diff --git a/src/regress/lib/libcrypto/x509/verify.c b/src/regress/lib/libcrypto/x509/verify.c index 08ca0b24ff..1a11c2ffe5 100644 --- a/src/regress/lib/libcrypto/x509/verify.c +++ b/src/regress/lib/libcrypto/x509/verify.c | |||
@@ -1,6 +1,7 @@ | |||
1 | /* $OpenBSD: verify.c,v 1.1 2020/07/14 18:33:00 jsing Exp $ */ | 1 | /* $OpenBSD: verify.c,v 1.2 2020/09/13 15:06:17 beck Exp $ */ |
2 | /* | 2 | /* |
3 | * Copyright (c) 2020 Joel Sing <jsing@openbsd.org> | 3 | * Copyright (c) 2020 Joel Sing <jsing@openbsd.org> |
4 | * Copyright (c) 2020 Bob Beck <beck@openbsd.org> | ||
4 | * | 5 | * |
5 | * Permission to use, copy, modify, and distribute this software for any | 6 | * Permission to use, copy, modify, and distribute this software for any |
6 | * purpose with or without fee is hereby granted, provided that the above | 7 | * purpose with or without fee is hereby granted, provided that the above |
@@ -23,6 +24,11 @@ | |||
23 | #include <openssl/pem.h> | 24 | #include <openssl/pem.h> |
24 | #include <openssl/x509.h> | 25 | #include <openssl/x509.h> |
25 | #include <openssl/x509v3.h> | 26 | #include <openssl/x509v3.h> |
27 | #include <openssl/x509_verify.h> | ||
28 | |||
29 | #define MODE_MODERN_VFY 0 | ||
30 | #define MODE_LEGACY_VFY 1 | ||
31 | #define MODE_VERIFY 2 | ||
26 | 32 | ||
27 | static int verbose = 1; | 33 | static int verbose = 1; |
28 | 34 | ||
@@ -94,10 +100,12 @@ verify_cert_cb(int ok, X509_STORE_CTX *xsc) | |||
94 | } | 100 | } |
95 | 101 | ||
96 | static void | 102 | static void |
97 | verify_cert(const char *roots_file, const char *bundle_file, int *chains) | 103 | verify_cert(const char *roots_file, const char *bundle_file, int *chains, |
104 | int mode) | ||
98 | { | 105 | { |
99 | STACK_OF(X509) *roots = NULL, *bundle = NULL; | 106 | STACK_OF(X509) *roots = NULL, *bundle = NULL; |
100 | X509_STORE_CTX *xsc = NULL; | 107 | X509_STORE_CTX *xsc = NULL; |
108 | unsigned long flags; | ||
101 | X509 *leaf = NULL; | 109 | X509 *leaf = NULL; |
102 | int verify_err; | 110 | int verify_err; |
103 | 111 | ||
@@ -117,6 +125,16 @@ verify_cert(const char *roots_file, const char *bundle_file, int *chains) | |||
117 | ERR_print_errors_fp(stderr); | 125 | ERR_print_errors_fp(stderr); |
118 | errx(1, "failed to init store context"); | 126 | errx(1, "failed to init store context"); |
119 | } | 127 | } |
128 | if (mode == MODE_LEGACY_VFY) { | ||
129 | flags = X509_VERIFY_PARAM_get_flags(xsc->param); | ||
130 | flags |= X509_V_FLAG_LEGACY_VERIFY; | ||
131 | X509_VERIFY_PARAM_set_flags(xsc->param, flags); | ||
132 | } else { | ||
133 | flags = X509_VERIFY_PARAM_get_flags(xsc->param); | ||
134 | flags &= ~X509_V_FLAG_LEGACY_VERIFY; | ||
135 | X509_VERIFY_PARAM_set_flags(xsc->param, flags); | ||
136 | } | ||
137 | |||
120 | if (verbose) | 138 | if (verbose) |
121 | X509_STORE_CTX_set_verify_cb(xsc, verify_cert_cb); | 139 | X509_STORE_CTX_set_verify_cb(xsc, verify_cert_cb); |
122 | X509_STORE_CTX_set0_trusted_stack(xsc, roots); | 140 | X509_STORE_CTX_set0_trusted_stack(xsc, roots); |
@@ -143,6 +161,60 @@ struct verify_cert_test { | |||
143 | int failing; | 161 | int failing; |
144 | }; | 162 | }; |
145 | 163 | ||
164 | static void | ||
165 | verify_cert_new(const char *roots_file, const char *bundle_file, int *chains) | ||
166 | { | ||
167 | STACK_OF(X509) *roots = NULL, *bundle = NULL; | ||
168 | X509_STORE_CTX *xsc = NULL; | ||
169 | X509 *leaf = NULL; | ||
170 | struct x509_verify_ctx *ctx; | ||
171 | |||
172 | *chains = 0; | ||
173 | |||
174 | if (!certs_from_file(roots_file, &roots)) | ||
175 | errx(1, "failed to load roots from '%s'", roots_file); | ||
176 | if (!certs_from_file(bundle_file, &bundle)) | ||
177 | errx(1, "failed to load bundle from '%s'", bundle_file); | ||
178 | if (sk_X509_num(bundle) < 1) | ||
179 | errx(1, "not enough certs in bundle"); | ||
180 | leaf = sk_X509_shift(bundle); | ||
181 | |||
182 | if ((xsc = X509_STORE_CTX_new()) == NULL) | ||
183 | errx(1, "X509_STORE_CTX"); | ||
184 | if (!X509_STORE_CTX_init(xsc, NULL, leaf, bundle)) { | ||
185 | ERR_print_errors_fp(stderr); | ||
186 | errx(1, "failed to init store context"); | ||
187 | } | ||
188 | if (verbose) | ||
189 | X509_STORE_CTX_set_verify_cb(xsc, verify_cert_cb); | ||
190 | |||
191 | if ((ctx = x509_verify_ctx_new(roots)) == NULL) | ||
192 | errx(1, "failed to create ctx"); | ||
193 | if (!x509_verify_ctx_set_intermediates(ctx, bundle)) | ||
194 | errx(1, "failed to set intermediates"); | ||
195 | |||
196 | if ((*chains = x509_verify(ctx, leaf, NULL)) == 0) { | ||
197 | fprintf(stderr, "failed to verify at %lu: %s\n", | ||
198 | x509_verify_ctx_error_depth(ctx), | ||
199 | x509_verify_ctx_error_string(ctx)); | ||
200 | } else { | ||
201 | for (int c = 0; verbose && c < *chains; c++) { | ||
202 | fprintf(stderr, "Chain %d\n--------\n", c); | ||
203 | STACK_OF(X509) * chain = x509_verify_ctx_chain(ctx, c); | ||
204 | for (int i = 0; i < sk_X509_num(chain); i++) { | ||
205 | X509 *cert = sk_X509_value(chain, i); | ||
206 | X509_NAME_print_ex_fp(stderr, | ||
207 | X509_get_subject_name(cert), 0, | ||
208 | XN_FLAG_ONELINE); | ||
209 | fprintf(stderr, "\n"); | ||
210 | } | ||
211 | } | ||
212 | } | ||
213 | sk_X509_pop_free(roots, X509_free); | ||
214 | sk_X509_pop_free(bundle, X509_free); | ||
215 | X509_free(leaf); | ||
216 | } | ||
217 | |||
146 | struct verify_cert_test verify_cert_tests[] = { | 218 | struct verify_cert_test verify_cert_tests[] = { |
147 | { | 219 | { |
148 | .id = "1a", | 220 | .id = "1a", |
@@ -306,7 +378,7 @@ struct verify_cert_test verify_cert_tests[] = { | |||
306 | (sizeof(verify_cert_tests) / sizeof(*verify_cert_tests)) | 378 | (sizeof(verify_cert_tests) / sizeof(*verify_cert_tests)) |
307 | 379 | ||
308 | static int | 380 | static int |
309 | verify_cert_test(const char *certs_path) | 381 | verify_cert_test(const char *certs_path, int mode) |
310 | { | 382 | { |
311 | char *roots_file, *bundle_file; | 383 | char *roots_file, *bundle_file; |
312 | struct verify_cert_test *vct; | 384 | struct verify_cert_test *vct; |
@@ -325,16 +397,20 @@ verify_cert_test(const char *certs_path) | |||
325 | errx(1, "asprintf"); | 397 | errx(1, "asprintf"); |
326 | 398 | ||
327 | fprintf(stderr, "== Test %zu (%s)\n", i, vct->id); | 399 | fprintf(stderr, "== Test %zu (%s)\n", i, vct->id); |
328 | verify_cert(roots_file, bundle_file, &chains); | 400 | if (mode == MODE_VERIFY) |
329 | if ((chains == 0 && vct->want_chains == 0) || | 401 | verify_cert_new(roots_file, bundle_file, &chains); |
402 | else | ||
403 | verify_cert(roots_file, bundle_file, &chains, mode); | ||
404 | if ((mode == 2 && chains == vct->want_chains) || | ||
405 | (chains == 0 && vct->want_chains == 0) || | ||
330 | (chains == 1 && vct->want_chains > 0)) { | 406 | (chains == 1 && vct->want_chains > 0)) { |
331 | fprintf(stderr, "INFO: Succeeded with %d chains%s\n", | 407 | fprintf(stderr, "INFO: Succeeded with %d chains%s\n", |
332 | chains, vct->failing ? " (known failure)" : ""); | 408 | chains, vct->failing ? " (legacy failure)" : ""); |
333 | if (vct->failing) | 409 | if (mode == MODE_LEGACY_VFY && vct->failing) |
334 | failed |= 1; | 410 | failed |= 1; |
335 | } else { | 411 | } else { |
336 | fprintf(stderr, "FAIL: Failed with %d chains%s\n", | 412 | fprintf(stderr, "FAIL: Failed with %d chains%s\n", |
337 | chains, vct->failing ? " (known failure)" : ""); | 413 | chains, vct->failing ? " (legacy failure)" : ""); |
338 | if (!vct->failing) | 414 | if (!vct->failing) |
339 | failed |= 1; | 415 | failed |= 1; |
340 | } | 416 | } |
@@ -357,7 +433,12 @@ main(int argc, char **argv) | |||
357 | exit(1); | 433 | exit(1); |
358 | } | 434 | } |
359 | 435 | ||
360 | failed |= verify_cert_test(argv[1]); | 436 | fprintf(stderr, "\n\nTesting legacy x509_vfy\n"); |
437 | failed |= verify_cert_test(argv[1], MODE_LEGACY_VFY); | ||
438 | fprintf(stderr, "\n\nTesting modern x509_vfy\n"); | ||
439 | failed |= verify_cert_test(argv[1], MODE_MODERN_VFY); | ||
440 | fprintf(stderr, "\n\nTesting x509_verify\n"); | ||
441 | failed |= verify_cert_test(argv[1], MODE_VERIFY); | ||
361 | 442 | ||
362 | return (failed); | 443 | return (failed); |
363 | } | 444 | } |