summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorbeck <>2020-09-13 15:06:17 +0000
committerbeck <>2020-09-13 15:06:17 +0000
commita328631fddec2556ad8af08ce4de240790c537c9 (patch)
tree4e2deda0db62092481ad6901c374736e60f249a2
parent4f04d3f588f91c98b4b1cdfcffe028a036c96283 (diff)
downloadopenbsd-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/Makefile5
-rw-r--r--src/lib/libcrypto/x509/x509_internal.h37
-rw-r--r--src/lib/libcrypto/x509/x509_purp.c6
-rw-r--r--src/lib/libcrypto/x509/x509_utl.c5
-rw-r--r--src/lib/libcrypto/x509/x509_verify.c914
-rw-r--r--src/lib/libcrypto/x509/x509_verify.h42
-rw-r--r--src/lib/libcrypto/x509/x509_vfy.c228
-rw-r--r--src/lib/libcrypto/x509/x509_vfy.h5
-rw-r--r--src/lib/libcrypto/x509/x509_vpm.c4
-rw-r--r--src/lib/libcrypto/x509/x509v3.h4
-rw-r--r--src/regress/lib/libcrypto/x509/verify.c99
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
3LIB= crypto 3LIB= crypto
4LIBREBUILD=y 4LIBREBUILD=y
@@ -277,7 +277,7 @@ SRCS+= x509_bcons.c x509_bitst.c x509_conf.c x509_extku.c x509_ia5.c x509_lib.c
277SRCS+= x509_prn.c x509_utl.c x509_genn.c x509_alt.c x509_skey.c x509_akey.c x509_pku.c 277SRCS+= x509_prn.c x509_utl.c x509_genn.c x509_alt.c x509_skey.c x509_akey.c x509_pku.c
278SRCS+= x509_int.c x509_enum.c x509_sxnet.c x509_cpols.c x509_crld.c x509_purp.c x509_info.c 278SRCS+= x509_int.c x509_enum.c x509_sxnet.c x509_cpols.c x509_crld.c x509_purp.c x509_info.c
279SRCS+= x509_ocsp.c x509_akeya.c x509_pmaps.c x509_pcons.c x509_ncons.c x509_pcia.c x509_pci.c 279SRCS+= x509_ocsp.c x509_akeya.c x509_pmaps.c x509_pcons.c x509_ncons.c x509_pcia.c x509_pci.c
280SRCS+= x509_issuer_cache.c x509_constraints.c 280SRCS+= x509_issuer_cache.c x509_constraints.c x509_verify.c
281SRCS+= pcy_cache.c pcy_node.c pcy_data.c pcy_map.c pcy_tree.c pcy_lib.c 281SRCS+= 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
406HDRS_GEN=\ 407HDRS_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
63struct 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
79int ASN1_time_tm_clamp_notafter(struct tm *tm);
80
56__BEGIN_HIDDEN_DECLS 81__BEGIN_HIDDEN_DECLS
57 82
83int x509_vfy_check_id(X509_STORE_CTX *ctx);
84int x509_vfy_check_revocation(X509_STORE_CTX *ctx);
85int x509_vfy_check_policy(X509_STORE_CTX *ctx);
86int x509_vfy_check_trust(X509_STORE_CTX *ctx);
87int x509_vfy_check_chain_extensions(X509_STORE_CTX *ctx);
88void x509v3_cache_extensions(X509 *x);
89
90struct x509_verify_ctx *x509_verify_ctx_new_from_xsc(X509_STORE_CTX *xsc,
91 STACK_OF(X509) *roots);
92
58void x509_constraints_name_clear(struct x509_constraints_name *name); 93void x509_constraints_name_clear(struct x509_constraints_name *name);
59int x509_constraints_names_add(struct x509_constraints_names *names, 94int 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
76static void x509v3_cache_extensions(X509 *x); 76void x509v3_cache_extensions(X509 *x);
77 77
78static int check_ssl_ca(const X509 *x); 78static int check_ssl_ca(const X509 *x);
79static int check_purpose_ssl_client(const X509_PURPOSE *xp, const X509 *x, 79static 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
429static void 429void
430x509v3_cache_extensions(X509 *x) 430x509v3_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
33static int x509_verify_cert_valid(struct x509_verify_ctx *ctx, X509 *cert,
34 struct x509_verify_chain *current_chain);
35static void x509_verify_build_chains(struct x509_verify_ctx *ctx, X509 *cert,
36 struct x509_verify_chain *current_chain);
37static int x509_verify_cert_error(struct x509_verify_ctx *ctx, X509 *cert,
38 size_t depth, int error, int ok);
39static void x509_verify_chain_free(struct x509_verify_chain *chain);
40
41#define X509_VERIFY_CERT_HASH (EVP_sha512())
42
43struct x509_verify_chain *
44x509_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
61static void
62x509_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
70static void
71x509_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
79static struct x509_verify_chain *
80x509_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
97static int
98x509_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
117static X509 *
118x509_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
129X509 *
130x509_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
137static void
138x509_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
151static void
152x509_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
161static int
162x509_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 */
174static int
175x509_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
247static int
248x509_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
258static int
259x509_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
295static int
296x509_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
357static int
358x509_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
372static void
373x509_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
428static int
429x509_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
473static int
474x509_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
488static int
489x509_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
527static int
528x509_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
567static int
568x509_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
605static int
606x509_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 */
642static int
643x509_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
689struct x509_verify_ctx *
690x509_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
728struct x509_verify_ctx *
729x509_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
756void
757x509_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
766int
767x509_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
775int
776x509_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
784int
785x509_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
795int
796x509_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
804int
805x509_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
813const char *
814x509_verify_ctx_error_string(struct x509_verify_ctx *ctx)
815{
816 return X509_verify_cert_error_string(ctx->error);
817}
818
819size_t
820x509_verify_ctx_error_depth(struct x509_verify_ctx *ctx)
821{
822 return ctx->error_depth;
823}
824
825STACK_OF(X509) *
826x509_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
833size_t
834x509_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
21struct x509_verify_ctx;
22typedef struct x509_verify_ctx X509_VERIFY_CTX;
23
24X509_VERIFY_CTX *x509_verify_ctx_new(STACK_OF(X509) *roots);
25void x509_verify_ctx_free(struct x509_verify_ctx *ctx);
26
27int x509_verify_ctx_set_max_depth(X509_VERIFY_CTX *ctx, size_t max);
28int x509_verify_ctx_set_max_chains(X509_VERIFY_CTX *ctx, size_t max);
29int x509_verify_ctx_set_max_signatures(X509_VERIFY_CTX *ctx, size_t max);
30int x509_verify_ctx_set_purpose(X509_VERIFY_CTX *ctx, int purpose_id);
31int x509_verify_ctx_set_intermediates(X509_VERIFY_CTX *ctx,
32 STACK_OF(X509) *intermediates);
33
34const char *x509_verify_ctx_error_string(X509_VERIFY_CTX *ctx);
35size_t x509_verify_ctx_error_depth(X509_VERIFY_CTX *ctx);
36
37STACK_OF(X509) *x509_verify_ctx_chain(X509_VERIFY_CTX *ctx, size_t chain);
38
39size_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);
124static int check_name_constraints(X509_STORE_CTX *ctx); 125static int check_name_constraints(X509_STORE_CTX *ctx);
125static int check_trust(X509_STORE_CTX *ctx); 126static int check_trust(X509_STORE_CTX *ctx);
126static int check_revocation(X509_STORE_CTX *ctx); 127static int check_revocation(X509_STORE_CTX *ctx);
127static int check_cert(X509_STORE_CTX *ctx); 128static int check_cert(X509_STORE_CTX *ctx, STACK_OF(X509) *chain, int depth);
128static int check_policy(X509_STORE_CTX *ctx); 129static int check_policy(X509_STORE_CTX *ctx);
129 130
130static int get_crl_score(X509_STORE_CTX *ctx, X509 **pissuer, 131static 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
146static int internal_verify(X509_STORE_CTX *ctx); 147static int internal_verify(X509_STORE_CTX *ctx);
148static int get_issuer_sk(X509 **issuer, X509_STORE_CTX *ctx, X509 *x);
147 149
148int ASN1_time_tm_clamp_notafter(struct tm *tm); 150int ASN1_time_tm_clamp_notafter(struct tm *tm);
149 151
@@ -224,7 +226,21 @@ check_id(X509_STORE_CTX *ctx)
224} 226}
225 227
226int 228int
227X509_verify_cert(X509_STORE_CTX *ctx) 229x509_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 */
242static int
243X509_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
527static int
528X509_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
580int
581X509_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
640static int 751int
641check_chain_extensions(X509_STORE_CTX *ctx) 752x509_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
783static int 894static int
895check_chain_extensions(X509_STORE_CTX *ctx) {
896 return x509_vfy_check_chain_extensions(ctx);
897}
898
899static int
784check_name_constraints(X509_STORE_CTX *ctx) 900check_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
994int x509_vfy_check_trust(X509_STORE_CTX *ctx)
995{
996 return check_trust(ctx);
997}
998
878static int 999static int
879check_revocation(X509_STORE_CTX *ctx) 1000check_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
1022int
1023x509_vfy_check_revocation(X509_STORE_CTX *ctx)
1024{
1025 return check_revocation(ctx);
1026}
1027
902static int 1028static int
903check_cert(X509_STORE_CTX *ctx) 1029check_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
1663static int 1789int
1664check_policy(X509_STORE_CTX *ctx) 1790x509_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
1836static int
1837check_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
27static int verbose = 1; 33static int verbose = 1;
28 34
@@ -94,10 +100,12 @@ verify_cert_cb(int ok, X509_STORE_CTX *xsc)
94} 100}
95 101
96static void 102static void
97verify_cert(const char *roots_file, const char *bundle_file, int *chains) 103verify_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
164static void
165verify_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
146struct verify_cert_test verify_cert_tests[] = { 218struct 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
308static int 380static int
309verify_cert_test(const char *certs_path) 381verify_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}