diff options
author | beck <> | 2020-09-13 15:06:17 +0000 |
---|---|---|
committer | beck <> | 2020-09-13 15:06:17 +0000 |
commit | a328631fddec2556ad8af08ce4de240790c537c9 (patch) | |
tree | 4e2deda0db62092481ad6901c374736e60f249a2 /src/regress/lib/libcrypto/x509/verify.c | |
parent | 4f04d3f588f91c98b4b1cdfcffe028a036c96283 (diff) | |
download | openbsd-a328631fddec2556ad8af08ce4de240790c537c9.tar.gz openbsd-a328631fddec2556ad8af08ce4de240790c537c9.tar.bz2 openbsd-a328631fddec2556ad8af08ce4de240790c537c9.zip |
Add new x509 certificate chain validator in x509_verify.c
The new validator finds multiple validated chains to handle the modern
PKI cases which may frequently have multiple paths via different
intermediates to different roots. It is loosely based on golang's x509
validator
This includes integration so that the new validator can be used via
X509_verify_cert() as well as a new api x509_verify() which will
return multiple chains (similar to go).
The new validator is not enabled by default with this commit, this
will be changed in a follow on commit.
The new public API is not yet exposed, and will be finalized and
exposed with a man page and a library minor bump later.
ok tb@ inoguchi@ jsing@
Diffstat (limited to 'src/regress/lib/libcrypto/x509/verify.c')
-rw-r--r-- | src/regress/lib/libcrypto/x509/verify.c | 99 |
1 files changed, 90 insertions, 9 deletions
diff --git a/src/regress/lib/libcrypto/x509/verify.c b/src/regress/lib/libcrypto/x509/verify.c index 08ca0b24ff..1a11c2ffe5 100644 --- a/src/regress/lib/libcrypto/x509/verify.c +++ b/src/regress/lib/libcrypto/x509/verify.c | |||
@@ -1,6 +1,7 @@ | |||
1 | /* $OpenBSD: verify.c,v 1.1 2020/07/14 18:33:00 jsing Exp $ */ | 1 | /* $OpenBSD: verify.c,v 1.2 2020/09/13 15:06:17 beck Exp $ */ |
2 | /* | 2 | /* |
3 | * Copyright (c) 2020 Joel Sing <jsing@openbsd.org> | 3 | * Copyright (c) 2020 Joel Sing <jsing@openbsd.org> |
4 | * Copyright (c) 2020 Bob Beck <beck@openbsd.org> | ||
4 | * | 5 | * |
5 | * Permission to use, copy, modify, and distribute this software for any | 6 | * Permission to use, copy, modify, and distribute this software for any |
6 | * purpose with or without fee is hereby granted, provided that the above | 7 | * purpose with or without fee is hereby granted, provided that the above |
@@ -23,6 +24,11 @@ | |||
23 | #include <openssl/pem.h> | 24 | #include <openssl/pem.h> |
24 | #include <openssl/x509.h> | 25 | #include <openssl/x509.h> |
25 | #include <openssl/x509v3.h> | 26 | #include <openssl/x509v3.h> |
27 | #include <openssl/x509_verify.h> | ||
28 | |||
29 | #define MODE_MODERN_VFY 0 | ||
30 | #define MODE_LEGACY_VFY 1 | ||
31 | #define MODE_VERIFY 2 | ||
26 | 32 | ||
27 | static int verbose = 1; | 33 | static int verbose = 1; |
28 | 34 | ||
@@ -94,10 +100,12 @@ verify_cert_cb(int ok, X509_STORE_CTX *xsc) | |||
94 | } | 100 | } |
95 | 101 | ||
96 | static void | 102 | static void |
97 | verify_cert(const char *roots_file, const char *bundle_file, int *chains) | 103 | verify_cert(const char *roots_file, const char *bundle_file, int *chains, |
104 | int mode) | ||
98 | { | 105 | { |
99 | STACK_OF(X509) *roots = NULL, *bundle = NULL; | 106 | STACK_OF(X509) *roots = NULL, *bundle = NULL; |
100 | X509_STORE_CTX *xsc = NULL; | 107 | X509_STORE_CTX *xsc = NULL; |
108 | unsigned long flags; | ||
101 | X509 *leaf = NULL; | 109 | X509 *leaf = NULL; |
102 | int verify_err; | 110 | int verify_err; |
103 | 111 | ||
@@ -117,6 +125,16 @@ verify_cert(const char *roots_file, const char *bundle_file, int *chains) | |||
117 | ERR_print_errors_fp(stderr); | 125 | ERR_print_errors_fp(stderr); |
118 | errx(1, "failed to init store context"); | 126 | errx(1, "failed to init store context"); |
119 | } | 127 | } |
128 | if (mode == MODE_LEGACY_VFY) { | ||
129 | flags = X509_VERIFY_PARAM_get_flags(xsc->param); | ||
130 | flags |= X509_V_FLAG_LEGACY_VERIFY; | ||
131 | X509_VERIFY_PARAM_set_flags(xsc->param, flags); | ||
132 | } else { | ||
133 | flags = X509_VERIFY_PARAM_get_flags(xsc->param); | ||
134 | flags &= ~X509_V_FLAG_LEGACY_VERIFY; | ||
135 | X509_VERIFY_PARAM_set_flags(xsc->param, flags); | ||
136 | } | ||
137 | |||
120 | if (verbose) | 138 | if (verbose) |
121 | X509_STORE_CTX_set_verify_cb(xsc, verify_cert_cb); | 139 | X509_STORE_CTX_set_verify_cb(xsc, verify_cert_cb); |
122 | X509_STORE_CTX_set0_trusted_stack(xsc, roots); | 140 | X509_STORE_CTX_set0_trusted_stack(xsc, roots); |
@@ -143,6 +161,60 @@ struct verify_cert_test { | |||
143 | int failing; | 161 | int failing; |
144 | }; | 162 | }; |
145 | 163 | ||
164 | static void | ||
165 | verify_cert_new(const char *roots_file, const char *bundle_file, int *chains) | ||
166 | { | ||
167 | STACK_OF(X509) *roots = NULL, *bundle = NULL; | ||
168 | X509_STORE_CTX *xsc = NULL; | ||
169 | X509 *leaf = NULL; | ||
170 | struct x509_verify_ctx *ctx; | ||
171 | |||
172 | *chains = 0; | ||
173 | |||
174 | if (!certs_from_file(roots_file, &roots)) | ||
175 | errx(1, "failed to load roots from '%s'", roots_file); | ||
176 | if (!certs_from_file(bundle_file, &bundle)) | ||
177 | errx(1, "failed to load bundle from '%s'", bundle_file); | ||
178 | if (sk_X509_num(bundle) < 1) | ||
179 | errx(1, "not enough certs in bundle"); | ||
180 | leaf = sk_X509_shift(bundle); | ||
181 | |||
182 | if ((xsc = X509_STORE_CTX_new()) == NULL) | ||
183 | errx(1, "X509_STORE_CTX"); | ||
184 | if (!X509_STORE_CTX_init(xsc, NULL, leaf, bundle)) { | ||
185 | ERR_print_errors_fp(stderr); | ||
186 | errx(1, "failed to init store context"); | ||
187 | } | ||
188 | if (verbose) | ||
189 | X509_STORE_CTX_set_verify_cb(xsc, verify_cert_cb); | ||
190 | |||
191 | if ((ctx = x509_verify_ctx_new(roots)) == NULL) | ||
192 | errx(1, "failed to create ctx"); | ||
193 | if (!x509_verify_ctx_set_intermediates(ctx, bundle)) | ||
194 | errx(1, "failed to set intermediates"); | ||
195 | |||
196 | if ((*chains = x509_verify(ctx, leaf, NULL)) == 0) { | ||
197 | fprintf(stderr, "failed to verify at %lu: %s\n", | ||
198 | x509_verify_ctx_error_depth(ctx), | ||
199 | x509_verify_ctx_error_string(ctx)); | ||
200 | } else { | ||
201 | for (int c = 0; verbose && c < *chains; c++) { | ||
202 | fprintf(stderr, "Chain %d\n--------\n", c); | ||
203 | STACK_OF(X509) * chain = x509_verify_ctx_chain(ctx, c); | ||
204 | for (int i = 0; i < sk_X509_num(chain); i++) { | ||
205 | X509 *cert = sk_X509_value(chain, i); | ||
206 | X509_NAME_print_ex_fp(stderr, | ||
207 | X509_get_subject_name(cert), 0, | ||
208 | XN_FLAG_ONELINE); | ||
209 | fprintf(stderr, "\n"); | ||
210 | } | ||
211 | } | ||
212 | } | ||
213 | sk_X509_pop_free(roots, X509_free); | ||
214 | sk_X509_pop_free(bundle, X509_free); | ||
215 | X509_free(leaf); | ||
216 | } | ||
217 | |||
146 | struct verify_cert_test verify_cert_tests[] = { | 218 | struct verify_cert_test verify_cert_tests[] = { |
147 | { | 219 | { |
148 | .id = "1a", | 220 | .id = "1a", |
@@ -306,7 +378,7 @@ struct verify_cert_test verify_cert_tests[] = { | |||
306 | (sizeof(verify_cert_tests) / sizeof(*verify_cert_tests)) | 378 | (sizeof(verify_cert_tests) / sizeof(*verify_cert_tests)) |
307 | 379 | ||
308 | static int | 380 | static int |
309 | verify_cert_test(const char *certs_path) | 381 | verify_cert_test(const char *certs_path, int mode) |
310 | { | 382 | { |
311 | char *roots_file, *bundle_file; | 383 | char *roots_file, *bundle_file; |
312 | struct verify_cert_test *vct; | 384 | struct verify_cert_test *vct; |
@@ -325,16 +397,20 @@ verify_cert_test(const char *certs_path) | |||
325 | errx(1, "asprintf"); | 397 | errx(1, "asprintf"); |
326 | 398 | ||
327 | fprintf(stderr, "== Test %zu (%s)\n", i, vct->id); | 399 | fprintf(stderr, "== Test %zu (%s)\n", i, vct->id); |
328 | verify_cert(roots_file, bundle_file, &chains); | 400 | if (mode == MODE_VERIFY) |
329 | if ((chains == 0 && vct->want_chains == 0) || | 401 | verify_cert_new(roots_file, bundle_file, &chains); |
402 | else | ||
403 | verify_cert(roots_file, bundle_file, &chains, mode); | ||
404 | if ((mode == 2 && chains == vct->want_chains) || | ||
405 | (chains == 0 && vct->want_chains == 0) || | ||
330 | (chains == 1 && vct->want_chains > 0)) { | 406 | (chains == 1 && vct->want_chains > 0)) { |
331 | fprintf(stderr, "INFO: Succeeded with %d chains%s\n", | 407 | fprintf(stderr, "INFO: Succeeded with %d chains%s\n", |
332 | chains, vct->failing ? " (known failure)" : ""); | 408 | chains, vct->failing ? " (legacy failure)" : ""); |
333 | if (vct->failing) | 409 | if (mode == MODE_LEGACY_VFY && vct->failing) |
334 | failed |= 1; | 410 | failed |= 1; |
335 | } else { | 411 | } else { |
336 | fprintf(stderr, "FAIL: Failed with %d chains%s\n", | 412 | fprintf(stderr, "FAIL: Failed with %d chains%s\n", |
337 | chains, vct->failing ? " (known failure)" : ""); | 413 | chains, vct->failing ? " (legacy failure)" : ""); |
338 | if (!vct->failing) | 414 | if (!vct->failing) |
339 | failed |= 1; | 415 | failed |= 1; |
340 | } | 416 | } |
@@ -357,7 +433,12 @@ main(int argc, char **argv) | |||
357 | exit(1); | 433 | exit(1); |
358 | } | 434 | } |
359 | 435 | ||
360 | failed |= verify_cert_test(argv[1]); | 436 | fprintf(stderr, "\n\nTesting legacy x509_vfy\n"); |
437 | failed |= verify_cert_test(argv[1], MODE_LEGACY_VFY); | ||
438 | fprintf(stderr, "\n\nTesting modern x509_vfy\n"); | ||
439 | failed |= verify_cert_test(argv[1], MODE_MODERN_VFY); | ||
440 | fprintf(stderr, "\n\nTesting x509_verify\n"); | ||
441 | failed |= verify_cert_test(argv[1], MODE_VERIFY); | ||
361 | 442 | ||
362 | return (failed); | 443 | return (failed); |
363 | } | 444 | } |