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