summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/lib/libcrypto/x509/x509_verify.c61
-rw-r--r--src/regress/lib/libcrypto/x509/Makefile8
-rw-r--r--src/regress/lib/libcrypto/x509/callbackfailures.c297
3 files changed, 347 insertions, 19 deletions
diff --git a/src/lib/libcrypto/x509/x509_verify.c b/src/lib/libcrypto/x509/x509_verify.c
index 83030672ef..aa14bc1933 100644
--- a/src/lib/libcrypto/x509/x509_verify.c
+++ b/src/lib/libcrypto/x509/x509_verify.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: x509_verify.c,v 1.57 2022/06/27 14:10:22 tb Exp $ */ 1/* $OpenBSD: x509_verify.c,v 1.58 2022/06/28 07:56:34 beck Exp $ */
2/* 2/*
3 * Copyright (c) 2020-2021 Bob Beck <beck@openbsd.org> 3 * Copyright (c) 2020-2021 Bob Beck <beck@openbsd.org>
4 * 4 *
@@ -258,6 +258,25 @@ x509_verify_cert_self_signed(X509 *cert)
258 return (cert->ex_flags & EXFLAG_SS) ? 1 : 0; 258 return (cert->ex_flags & EXFLAG_SS) ? 1 : 0;
259} 259}
260 260
261/* XXX beck - clean up this mess of is_root */
262static int
263x509_verify_check_chain_end(X509 *cert, int full_chain)
264{
265 if (full_chain)
266 return x509_verify_cert_self_signed(cert);
267 return 1;
268}
269
270static int
271x509_verify_check_legacy_chain_end(struct x509_verify_ctx *ctx, X509 *cert,
272 int full_chain)
273{
274 if (X509_check_trust(cert, ctx->xsc->param->trust, 0) !=
275 X509_TRUST_TRUSTED)
276 return 0;
277 return x509_verify_check_chain_end(cert, full_chain);
278}
279
261static int 280static int
262x509_verify_ctx_cert_is_root(struct x509_verify_ctx *ctx, X509 *cert, 281x509_verify_ctx_cert_is_root(struct x509_verify_ctx *ctx, X509 *cert,
263 int full_chain) 282 int full_chain)
@@ -273,15 +292,16 @@ x509_verify_ctx_cert_is_root(struct x509_verify_ctx *ctx, X509 *cert,
273 if ((match = x509_vfy_lookup_cert_match(ctx->xsc, 292 if ((match = x509_vfy_lookup_cert_match(ctx->xsc,
274 cert)) != NULL) { 293 cert)) != NULL) {
275 X509_free(match); 294 X509_free(match);
276 return !full_chain || 295 return x509_verify_check_legacy_chain_end(ctx, cert,
277 x509_verify_cert_self_signed(cert); 296 full_chain);
297
278 } 298 }
279 } else { 299 } else {
280 /* Check the provided roots */ 300 /* Check the provided roots */
281 for (i = 0; i < sk_X509_num(ctx->roots); i++) { 301 for (i = 0; i < sk_X509_num(ctx->roots); i++) {
282 if (X509_cmp(sk_X509_value(ctx->roots, i), cert) == 0) 302 if (X509_cmp(sk_X509_value(ctx->roots, i), cert) == 0)
283 return !full_chain || 303 return x509_verify_check_chain_end(cert,
284 x509_verify_cert_self_signed(cert); 304 full_chain);
285 } 305 }
286 } 306 }
287 307
@@ -393,14 +413,23 @@ x509_verify_ctx_validate_legacy_chain(struct x509_verify_ctx *ctx,
393 ctx->xsc->error = X509_V_OK; 413 ctx->xsc->error = X509_V_OK;
394 ctx->xsc->error_depth = 0; 414 ctx->xsc->error_depth = 0;
395 415
396 trust = x509_vfy_check_trust(ctx->xsc);
397 if (trust == X509_TRUST_REJECTED)
398 goto err;
399
400 if (!x509_verify_ctx_set_xsc_chain(ctx, chain, 0, 1)) 416 if (!x509_verify_ctx_set_xsc_chain(ctx, chain, 0, 1))
401 goto err; 417 goto err;
402 418
403 /* 419 /*
420 * Call the legacy code to walk the chain and check trust
421 * in the legacy way to handle partial chains and get the
422 * callback fired correctly.
423 */
424 trust = x509_vfy_check_trust(ctx->xsc);
425 if (trust == X509_TRUST_REJECTED)
426 goto err; /* callback was called in x509_vfy_check_trust */
427 if (trust != X509_TRUST_TRUSTED) {
428 /* NOTREACHED */
429 goto err; /* should not happen if we get in here - abort? */
430 }
431
432 /*
404 * XXX currently this duplicates some work done in chain 433 * XXX currently this duplicates some work done in chain
405 * build, but we keep it here until we have feature parity 434 * build, but we keep it here until we have feature parity
406 */ 435 */
@@ -432,10 +461,6 @@ x509_verify_ctx_validate_legacy_chain(struct x509_verify_ctx *ctx,
432 if (!x509_vfy_check_policy(ctx->xsc)) 461 if (!x509_vfy_check_policy(ctx->xsc))
433 goto err; 462 goto err;
434 463
435 if ((!(ctx->xsc->param->flags & X509_V_FLAG_PARTIAL_CHAIN)) &&
436 trust != X509_TRUST_TRUSTED)
437 goto err;
438
439 ret = 1; 464 ret = 1;
440 465
441 err: 466 err:
@@ -688,8 +713,8 @@ x509_verify_build_chains(struct x509_verify_ctx *ctx, X509 *cert,
688 } 713 }
689 if (ret > 0) { 714 if (ret > 0) {
690 if (x509_verify_potential_parent(ctx, candidate, cert)) { 715 if (x509_verify_potential_parent(ctx, candidate, cert)) {
691 is_root = !full_chain || 716 is_root = x509_verify_check_legacy_chain_end(
692 x509_verify_cert_self_signed(candidate); 717 ctx, candidate, full_chain);
693 x509_verify_consider_candidate(ctx, cert, 718 x509_verify_consider_candidate(ctx, cert,
694 is_root, candidate, current_chain, 719 is_root, candidate, current_chain,
695 full_chain, name); 720 full_chain, name);
@@ -701,8 +726,8 @@ x509_verify_build_chains(struct x509_verify_ctx *ctx, X509 *cert,
701 for (i = 0; i < sk_X509_num(ctx->roots); i++) { 726 for (i = 0; i < sk_X509_num(ctx->roots); i++) {
702 candidate = sk_X509_value(ctx->roots, i); 727 candidate = sk_X509_value(ctx->roots, i);
703 if (x509_verify_potential_parent(ctx, candidate, cert)) { 728 if (x509_verify_potential_parent(ctx, candidate, cert)) {
704 is_root = !full_chain || 729 is_root = x509_verify_check_chain_end(candidate,
705 x509_verify_cert_self_signed(candidate); 730 full_chain);
706 x509_verify_consider_candidate(ctx, cert, 731 x509_verify_consider_candidate(ctx, cert,
707 is_root, candidate, current_chain, 732 is_root, candidate, current_chain,
708 full_chain, name); 733 full_chain, name);
@@ -1168,6 +1193,8 @@ x509_verify(struct x509_verify_ctx *ctx, X509 *leaf, char *name)
1168 * on failure and will be needed for 1193 * on failure and will be needed for
1169 * that. 1194 * that.
1170 */ 1195 */
1196 ctx->xsc->error = ctx->error;
1197 ctx->xsc->error_depth = ctx->error_depth;
1171 if (!x509_verify_ctx_save_xsc_error(ctx)) { 1198 if (!x509_verify_ctx_save_xsc_error(ctx)) {
1172 x509_verify_chain_free(current_chain); 1199 x509_verify_chain_free(current_chain);
1173 goto err; 1200 goto err;
diff --git a/src/regress/lib/libcrypto/x509/Makefile b/src/regress/lib/libcrypto/x509/Makefile
index ca66df19cd..4635d63ed0 100644
--- a/src/regress/lib/libcrypto/x509/Makefile
+++ b/src/regress/lib/libcrypto/x509/Makefile
@@ -1,7 +1,7 @@
1# $OpenBSD: Makefile,v 1.13 2022/06/25 20:01:43 beck Exp $ 1# $OpenBSD: Makefile,v 1.14 2022/06/28 07:56:34 beck Exp $
2 2
3PROGS = constraints verify x509attribute x509name x509req_ext callback 3PROGS = constraints verify x509attribute x509name x509req_ext callback
4PROGS += expirecallback 4PROGS += expirecallback callbackfailures
5LDADD = -lcrypto 5LDADD = -lcrypto
6DPADD = ${LIBCRYPTO} 6DPADD = ${LIBCRYPTO}
7 7
@@ -20,6 +20,7 @@ REGRESS_TARGETS += regress-x509name
20REGRESS_TARGETS += regress-x509req_ext 20REGRESS_TARGETS += regress-x509req_ext
21REGRESS_TARGETS += regress-callback 21REGRESS_TARGETS += regress-callback
22REGRESS_TARGETS += regress-expirecallback 22REGRESS_TARGETS += regress-expirecallback
23REGRESS_TARGETS += regress-callbackfailures
23 24
24CLEANFILES += x509name.result callbackout 25CLEANFILES += x509name.result callbackout
25 26
@@ -54,4 +55,7 @@ regress-callback: callback
54regress-expirecallback: expirecallback 55regress-expirecallback: expirecallback
55 ./expirecallback ${.CURDIR}/../certs 56 ./expirecallback ${.CURDIR}/../certs
56 57
58regress-callbackfailures: callbackfailures
59 ./callbackfailures ${.CURDIR}/../certs
60
57.include <bsd.regress.mk> 61.include <bsd.regress.mk>
diff --git a/src/regress/lib/libcrypto/x509/callbackfailures.c b/src/regress/lib/libcrypto/x509/callbackfailures.c
new file mode 100644
index 0000000000..f714adffff
--- /dev/null
+++ b/src/regress/lib/libcrypto/x509/callbackfailures.c
@@ -0,0 +1,297 @@
1/* $OpenBSD: callbackfailures.c,v 1.1 2022/06/28 07:56:34 beck Exp $ */
2/*
3 * Copyright (c) 2020 Joel Sing <jsing@openbsd.org>
4 * Copyright (c) 2020-2021 Bob Beck <beck@openbsd.org>
5 *
6 * Permission to use, copy, modify, and distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
9 *
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 */
18
19#include <err.h>
20#include <string.h>
21
22#include <openssl/bio.h>
23#include <openssl/err.h>
24#include <openssl/pem.h>
25#include <openssl/x509.h>
26#include <openssl/x509v3.h>
27#include <openssl/x509_verify.h>
28
29#define MODE_MODERN_VFY 0
30#define MODE_MODERN_VFY_DIR 1
31#define MODE_LEGACY_VFY 2
32#define MODE_VERIFY 3
33
34static int verbose = 1;
35
36static int expected_depth;
37static int expected_error;
38static int seen_depth;
39static int seen_error;
40
41static int
42passwd_cb(char *buf, int size, int rwflag, void *u)
43{
44 memset(buf, 0, size);
45 return (0);
46}
47
48static int
49certs_from_file(const char *filename, STACK_OF(X509) **certs, int clear)
50{
51 STACK_OF(X509_INFO) *xis = NULL;
52 STACK_OF(X509) *xs = NULL;
53 BIO *bio = NULL;
54 X509 *x;
55 int i;
56
57 if (clear) {
58 if ((xs = sk_X509_new_null()) == NULL)
59 errx(1, "failed to create X509 stack");
60 } else
61 xs = *certs;
62 if ((bio = BIO_new_file(filename, "r")) == NULL) {
63 ERR_print_errors_fp(stderr);
64 errx(1, "failed to create bio");
65 }
66 if ((xis = PEM_X509_INFO_read_bio(bio, NULL, passwd_cb, NULL)) == NULL)
67 errx(1, "failed to read PEM");
68
69 for (i = 0; i < sk_X509_INFO_num(xis); i++) {
70 if ((x = sk_X509_INFO_value(xis, i)->x509) == NULL)
71 continue;
72 if (!sk_X509_push(xs, x))
73 errx(1, "failed to push X509");
74 X509_up_ref(x);
75 }
76
77 *certs = xs;
78 xs = NULL;
79
80 sk_X509_INFO_pop_free(xis, X509_INFO_free);
81 sk_X509_pop_free(xs, X509_free);
82 BIO_free(bio);
83
84 return 1;
85}
86
87static int
88verify_cert_cb(int ok, X509_STORE_CTX *xsc)
89{
90 X509 *current_cert;
91 int verify_err;
92
93 current_cert = X509_STORE_CTX_get_current_cert(xsc);
94 if (current_cert != NULL) {
95 X509_NAME_print_ex_fp(stderr,
96 X509_get_subject_name(current_cert), 0,
97 XN_FLAG_ONELINE);
98 fprintf(stderr, "\n");
99 }
100
101 verify_err = X509_STORE_CTX_get_error(xsc);
102 if (verify_err != X509_V_OK) {
103 seen_depth = X509_STORE_CTX_get_error_depth(xsc);
104 seen_error = verify_err;
105 fprintf(stderr, "verify error at depth %d: %s\n",
106 X509_STORE_CTX_get_error_depth(xsc),
107 X509_verify_cert_error_string(verify_err));
108 }
109
110 fprintf(stderr, "chain of length %d\n", sk_X509_num (X509_STORE_CTX_get0_chain (xsc)));
111
112 return ok;
113}
114
115static void
116verify_cert(const char *roots_dir, const char *roots_file,
117 const char *bundle_file, const char*bundle_file2, int *chains, int mode)
118{
119 STACK_OF(X509) *roots = NULL, *bundle = NULL;
120 X509_STORE_CTX *xsc = NULL;
121 X509_STORE *store = NULL;
122 int verify_err, use_dir;
123 X509 *leaf = NULL;
124
125 *chains = 0;
126 use_dir = (mode == MODE_MODERN_VFY_DIR);
127
128 if (!use_dir && !certs_from_file(roots_file, &roots, 1))
129 errx(1, "failed to load roots from '%s'", roots_file);
130 if (!certs_from_file(bundle_file, &bundle, 1))
131 errx(1, "failed to load bundle from '%s'", bundle_file);
132 if (!certs_from_file(bundle_file, &bundle, 0))
133 errx(1, "failed to load bundle from '%s'", bundle_file2);
134 if (sk_X509_num(bundle) < 1)
135 errx(1, "not enough certs in bundle");
136 leaf = sk_X509_shift(bundle);
137
138 if ((xsc = X509_STORE_CTX_new()) == NULL)
139 errx(1, "X509_STORE_CTX");
140 if (use_dir && (store = X509_STORE_new()) == NULL)
141 errx(1, "X509_STORE");
142 if (!X509_STORE_CTX_init(xsc, store, leaf, bundle)) {
143 ERR_print_errors_fp(stderr);
144 errx(1, "failed to init store context");
145 }
146
147 if (use_dir) {
148 if (!X509_STORE_load_locations(store, NULL, roots_dir))
149 errx(1, "failed to set by_dir directory of %s", roots_dir);
150 }
151 if (mode == MODE_LEGACY_VFY)
152 X509_STORE_CTX_set_flags(xsc, X509_V_FLAG_LEGACY_VERIFY);
153 else
154 X509_VERIFY_PARAM_clear_flags(X509_STORE_CTX_get0_param(xsc),
155 X509_V_FLAG_LEGACY_VERIFY);
156
157 if (verbose)
158 X509_STORE_CTX_set_verify_cb(xsc, verify_cert_cb);
159 if (!use_dir)
160 X509_STORE_CTX_set0_trusted_stack(xsc, roots);
161
162 if (X509_verify_cert(xsc) == 1) {
163 *chains = 1; /* XXX */
164 goto done;
165 }
166
167 verify_err = X509_STORE_CTX_get_error(xsc);
168 if (verify_err == 0)
169 errx(1, "Error unset on failure!\n");
170
171 fprintf(stderr, "failed to verify at %d: %s\n",
172 X509_STORE_CTX_get_error_depth(xsc),
173 X509_verify_cert_error_string(verify_err));
174
175 done:
176 sk_X509_pop_free(roots, X509_free);
177 sk_X509_pop_free(bundle, X509_free);
178 X509_STORE_free(store);
179 X509_STORE_CTX_free(xsc);
180 X509_free(leaf);
181}
182
183struct verify_cert_test {
184 const char *id;
185 int want_chains;
186 int failing;
187 int depth;
188 int error;
189};
190
191struct verify_cert_test verify_cert_tests[] = {
192 {
193 .id = "1a",
194 .want_chains = 0,
195 .depth = 0,
196 .error = X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY,
197 },
198 {
199 .id = "2a",
200 .want_chains = 0,
201 .depth = 1,
202 .error = X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY,
203 },
204 {
205 .id = "2c",
206 .want_chains = 0,
207 .depth = 2,
208 .error = X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN,
209 },
210};
211
212#define N_VERIFY_CERT_TESTS \
213 (sizeof(verify_cert_tests) / sizeof(*verify_cert_tests))
214
215static int
216verify_cert_test(const char *certs_path, int mode)
217{
218 char *roots_file, *bundle_file, *bundle_file2, *roots_dir;
219 struct verify_cert_test *vct;
220 int failed = 0;
221 int chains;
222 size_t i;
223
224 for (i = 0; i < N_VERIFY_CERT_TESTS; i++) {
225 vct = &verify_cert_tests[i];
226
227 if (asprintf(&roots_file, "/etc/ssl/cert.pem") == -1)
228 errx(1, "asprintf");
229 if (asprintf(&bundle_file, "%s/%s/bundle.pem", certs_path,
230 vct->id) == -1)
231 errx(1, "asprintf");
232 if (asprintf(&bundle_file2, "%s/%s/roots.pem", certs_path,
233 vct->id) == -1)
234 errx(1, "asprintf");
235 if (asprintf(&roots_dir, "./%s/roots", vct->id) == -1)
236 errx(1, "asprintf");
237
238 fprintf(stderr, "== Test %zu (%s)\n", i, vct->id);
239 fprintf(stderr, "== depth %d\n", vct->depth);
240 fprintf(stderr, "== error %d\n", vct->error);
241 expected_depth = vct->depth;
242 expected_error = vct->error;
243 verify_cert(roots_dir, roots_file, bundle_file, bundle_file2, &chains, mode);
244 if (chains == 0 && vct->want_chains == 0) {
245 if (seen_error != expected_error) {
246 fprintf(stderr, "FAIL: expected error %d, got %d\n",
247 seen_error, expected_error);
248 failed |= 1;
249 }
250 if (seen_depth != expected_depth) {
251 fprintf(stderr, "FAIL: expected depth %d, got %d\n",
252 seen_depth, expected_depth);
253 failed |= 1;
254 }
255 }
256
257 if ((mode == MODE_VERIFY && chains == vct->want_chains) ||
258 (chains == 0 && vct->want_chains == 0) ||
259 (chains == 1 && vct->want_chains > 0)) {
260 fprintf(stderr, "INFO: Succeeded with %d chains%s\n",
261 chains, vct->failing ? " (legacy failure)" : "");
262 if (mode == MODE_LEGACY_VFY && vct->failing)
263 failed |= 1;
264 } else {
265 fprintf(stderr, "FAIL: Failed with %d chains%s\n",
266 chains, vct->failing ? " (legacy failure)" : "");
267 if (!vct->failing)
268 failed |= 1;
269 }
270 fprintf(stderr, "\n");
271
272 free(roots_file);
273 free(bundle_file);
274 free(bundle_file2);
275 free(roots_dir);
276 }
277
278 return failed;
279}
280
281int
282main(int argc, char **argv)
283{
284 int failed = 0;
285
286 if (argc != 2) {
287 fprintf(stderr, "usage: %s <certs_path>\n", argv[0]);
288 exit(1);
289 }
290
291 fprintf(stderr, "\n\nTesting legacy x509_vfy\n");
292 failed |= verify_cert_test(argv[1], MODE_LEGACY_VFY);
293 fprintf(stderr, "\n\nTesting modern x509_vfy\n");
294 failed |= verify_cert_test(argv[1], MODE_MODERN_VFY);
295
296 return (failed);
297}