summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-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}