diff options
author | beck <> | 2022-06-25 20:01:43 +0000 |
---|---|---|
committer | beck <> | 2022-06-25 20:01:43 +0000 |
commit | 8f49e18d8b58138d52d4c7d55385ef2f47508529 (patch) | |
tree | a057ee19ce4f7b27f7b8864ab578d7746ac590e9 /src | |
parent | 45d168a6140632da2ca76c8437622ccf56118001 (diff) | |
download | openbsd-8f49e18d8b58138d52d4c7d55385ef2f47508529.tar.gz openbsd-8f49e18d8b58138d52d4c7d55385ef2f47508529.tar.bz2 openbsd-8f49e18d8b58138d52d4c7d55385ef2f47508529.zip |
Move leaf certificate checks to the last thing after chain validation.
While seemingly illogical and not what is done in Go's validator, this
mimics OpenSSL's behavior so that callback overrides for the expiry of
a certificate will not "sticky" override a failure to build a chain.
ok jsing@
Diffstat (limited to 'src')
-rw-r--r-- | src/lib/libcrypto/x509/x509_verify.c | 51 | ||||
-rw-r--r-- | src/regress/lib/libcrypto/x509/Makefile | 7 | ||||
-rw-r--r-- | src/regress/lib/libcrypto/x509/expirecallback.c | 279 |
3 files changed, 317 insertions, 20 deletions
diff --git a/src/lib/libcrypto/x509/x509_verify.c b/src/lib/libcrypto/x509/x509_verify.c index 630c9f9b5a..f6959d1f3a 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.55 2022/04/12 10:42:35 tb Exp $ */ | 1 | /* $OpenBSD: x509_verify.c,v 1.56 2022/06/25 20:01:43 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 | * |
@@ -32,8 +32,10 @@ | |||
32 | 32 | ||
33 | static int x509_verify_cert_valid(struct x509_verify_ctx *ctx, X509 *cert, | 33 | static int x509_verify_cert_valid(struct x509_verify_ctx *ctx, X509 *cert, |
34 | struct x509_verify_chain *current_chain); | 34 | struct x509_verify_chain *current_chain); |
35 | static int x509_verify_cert_hostname(struct x509_verify_ctx *ctx, X509 *cert, | ||
36 | char *name); | ||
35 | static void x509_verify_build_chains(struct x509_verify_ctx *ctx, X509 *cert, | 37 | static void x509_verify_build_chains(struct x509_verify_ctx *ctx, X509 *cert, |
36 | struct x509_verify_chain *current_chain, int full_chain); | 38 | struct x509_verify_chain *current_chain, int full_chain, char *name); |
37 | static int x509_verify_cert_error(struct x509_verify_ctx *ctx, X509 *cert, | 39 | static int x509_verify_cert_error(struct x509_verify_ctx *ctx, X509 *cert, |
38 | size_t depth, int error, int ok); | 40 | size_t depth, int error, int ok); |
39 | static void x509_verify_chain_free(struct x509_verify_chain *chain); | 41 | static void x509_verify_chain_free(struct x509_verify_chain *chain); |
@@ -233,7 +235,7 @@ x509_verify_ctx_clear(struct x509_verify_ctx *ctx) | |||
233 | x509_verify_ctx_reset(ctx); | 235 | x509_verify_ctx_reset(ctx); |
234 | sk_X509_pop_free(ctx->intermediates, X509_free); | 236 | sk_X509_pop_free(ctx->intermediates, X509_free); |
235 | free(ctx->chains); | 237 | free(ctx->chains); |
236 | memset(ctx, 0, sizeof(*ctx)); | 238 | |
237 | } | 239 | } |
238 | 240 | ||
239 | static int | 241 | static int |
@@ -453,10 +455,11 @@ x509_verify_ctx_validate_legacy_chain(struct x509_verify_ctx *ctx, | |||
453 | /* Add a validated chain to our list of valid chains */ | 455 | /* Add a validated chain to our list of valid chains */ |
454 | static int | 456 | static int |
455 | x509_verify_ctx_add_chain(struct x509_verify_ctx *ctx, | 457 | x509_verify_ctx_add_chain(struct x509_verify_ctx *ctx, |
456 | struct x509_verify_chain *chain) | 458 | struct x509_verify_chain *chain, char *name) |
457 | { | 459 | { |
458 | size_t depth; | 460 | size_t depth; |
459 | X509 *last = x509_verify_chain_last(chain); | 461 | X509 *last = x509_verify_chain_last(chain); |
462 | X509 *leaf = x509_verify_chain_leaf(chain); | ||
460 | 463 | ||
461 | depth = sk_X509_num(chain->certs); | 464 | depth = sk_X509_num(chain->certs); |
462 | if (depth > 0) | 465 | if (depth > 0) |
@@ -488,6 +491,13 @@ x509_verify_ctx_add_chain(struct x509_verify_ctx *ctx, | |||
488 | return x509_verify_cert_error(ctx, last, depth, | 491 | return x509_verify_cert_error(ctx, last, depth, |
489 | X509_V_ERR_OUT_OF_MEM, 0); | 492 | X509_V_ERR_OUT_OF_MEM, 0); |
490 | } | 493 | } |
494 | |||
495 | if (!x509_verify_cert_valid(ctx, leaf, NULL)) | ||
496 | return 0; | ||
497 | |||
498 | if (!x509_verify_cert_hostname(ctx, leaf, name)) | ||
499 | return 0; | ||
500 | |||
491 | ctx->chains_count++; | 501 | ctx->chains_count++; |
492 | ctx->error = X509_V_OK; | 502 | ctx->error = X509_V_OK; |
493 | ctx->error_depth = depth; | 503 | ctx->error_depth = depth; |
@@ -539,7 +549,7 @@ x509_verify_parent_signature(X509 *parent, X509 *child, int *error) | |||
539 | static int | 549 | static int |
540 | x509_verify_consider_candidate(struct x509_verify_ctx *ctx, X509 *cert, | 550 | x509_verify_consider_candidate(struct x509_verify_ctx *ctx, X509 *cert, |
541 | int is_root_cert, X509 *candidate, struct x509_verify_chain *current_chain, | 551 | int is_root_cert, X509 *candidate, struct x509_verify_chain *current_chain, |
542 | int full_chain) | 552 | int full_chain, char *name) |
543 | { | 553 | { |
544 | int depth = sk_X509_num(current_chain->certs); | 554 | int depth = sk_X509_num(current_chain->certs); |
545 | struct x509_verify_chain *new_chain; | 555 | struct x509_verify_chain *new_chain; |
@@ -590,14 +600,14 @@ x509_verify_consider_candidate(struct x509_verify_ctx *ctx, X509 *cert, | |||
590 | x509_verify_chain_free(new_chain); | 600 | x509_verify_chain_free(new_chain); |
591 | return 0; | 601 | return 0; |
592 | } | 602 | } |
593 | if (!x509_verify_ctx_add_chain(ctx, new_chain)) { | 603 | if (!x509_verify_ctx_add_chain(ctx, new_chain, name)) { |
594 | x509_verify_chain_free(new_chain); | 604 | x509_verify_chain_free(new_chain); |
595 | return 0; | 605 | return 0; |
596 | } | 606 | } |
597 | goto done; | 607 | goto done; |
598 | } | 608 | } |
599 | 609 | ||
600 | x509_verify_build_chains(ctx, candidate, new_chain, full_chain); | 610 | x509_verify_build_chains(ctx, candidate, new_chain, full_chain, name); |
601 | 611 | ||
602 | done: | 612 | done: |
603 | x509_verify_chain_free(new_chain); | 613 | x509_verify_chain_free(new_chain); |
@@ -621,7 +631,7 @@ x509_verify_cert_error(struct x509_verify_ctx *ctx, X509 *cert, size_t depth, | |||
621 | 631 | ||
622 | static void | 632 | static void |
623 | x509_verify_build_chains(struct x509_verify_ctx *ctx, X509 *cert, | 633 | x509_verify_build_chains(struct x509_verify_ctx *ctx, X509 *cert, |
624 | struct x509_verify_chain *current_chain, int full_chain) | 634 | struct x509_verify_chain *current_chain, int full_chain, char *name) |
625 | { | 635 | { |
626 | X509 *candidate; | 636 | X509 *candidate; |
627 | int i, depth, count, ret, is_root; | 637 | int i, depth, count, ret, is_root; |
@@ -679,7 +689,7 @@ x509_verify_build_chains(struct x509_verify_ctx *ctx, X509 *cert, | |||
679 | x509_verify_cert_self_signed(candidate); | 689 | x509_verify_cert_self_signed(candidate); |
680 | x509_verify_consider_candidate(ctx, cert, | 690 | x509_verify_consider_candidate(ctx, cert, |
681 | is_root, candidate, current_chain, | 691 | is_root, candidate, current_chain, |
682 | full_chain); | 692 | full_chain, name); |
683 | } | 693 | } |
684 | X509_free(candidate); | 694 | X509_free(candidate); |
685 | } | 695 | } |
@@ -692,7 +702,7 @@ x509_verify_build_chains(struct x509_verify_ctx *ctx, X509 *cert, | |||
692 | x509_verify_cert_self_signed(candidate); | 702 | x509_verify_cert_self_signed(candidate); |
693 | x509_verify_consider_candidate(ctx, cert, | 703 | x509_verify_consider_candidate(ctx, cert, |
694 | is_root, candidate, current_chain, | 704 | is_root, candidate, current_chain, |
695 | full_chain); | 705 | full_chain, name); |
696 | } | 706 | } |
697 | } | 707 | } |
698 | } | 708 | } |
@@ -704,7 +714,7 @@ x509_verify_build_chains(struct x509_verify_ctx *ctx, X509 *cert, | |||
704 | if (x509_verify_potential_parent(ctx, candidate, cert)) { | 714 | if (x509_verify_potential_parent(ctx, candidate, cert)) { |
705 | x509_verify_consider_candidate(ctx, cert, | 715 | x509_verify_consider_candidate(ctx, cert, |
706 | 0, candidate, current_chain, | 716 | 0, candidate, current_chain, |
707 | full_chain); | 717 | full_chain, name); |
708 | } | 718 | } |
709 | } | 719 | } |
710 | } | 720 | } |
@@ -1116,16 +1126,18 @@ x509_verify(struct x509_verify_ctx *ctx, X509 *leaf, char *name) | |||
1116 | ctx->xsc->current_cert = leaf; | 1126 | ctx->xsc->current_cert = leaf; |
1117 | } | 1127 | } |
1118 | 1128 | ||
1119 | if (!x509_verify_cert_valid(ctx, leaf, NULL)) | ||
1120 | goto err; | ||
1121 | |||
1122 | if (!x509_verify_cert_hostname(ctx, leaf, name)) | ||
1123 | goto err; | ||
1124 | |||
1125 | if ((current_chain = x509_verify_chain_new()) == NULL) { | 1129 | if ((current_chain = x509_verify_chain_new()) == NULL) { |
1126 | ctx->error = X509_V_ERR_OUT_OF_MEM; | 1130 | ctx->error = X509_V_ERR_OUT_OF_MEM; |
1127 | goto err; | 1131 | goto err; |
1128 | } | 1132 | } |
1133 | |||
1134 | /* | ||
1135 | * Add the leaf to the chain and try to build chains from it. | ||
1136 | * Note that unlike Go's verifier, we have not yet checked | ||
1137 | * anything about the leaf, This is intentional, so that we | ||
1138 | * report failures in chain building before we report problems | ||
1139 | * with the leaf. | ||
1140 | */ | ||
1129 | if (!x509_verify_chain_append(current_chain, leaf, &ctx->error)) { | 1141 | if (!x509_verify_chain_append(current_chain, leaf, &ctx->error)) { |
1130 | x509_verify_chain_free(current_chain); | 1142 | x509_verify_chain_free(current_chain); |
1131 | goto err; | 1143 | goto err; |
@@ -1133,13 +1145,14 @@ x509_verify(struct x509_verify_ctx *ctx, X509 *leaf, char *name) | |||
1133 | do { | 1145 | do { |
1134 | retry_chain_build = 0; | 1146 | retry_chain_build = 0; |
1135 | if (x509_verify_ctx_cert_is_root(ctx, leaf, full_chain)) { | 1147 | if (x509_verify_ctx_cert_is_root(ctx, leaf, full_chain)) { |
1136 | if (!x509_verify_ctx_add_chain(ctx, current_chain)) { | 1148 | if (!x509_verify_ctx_add_chain(ctx, current_chain, |
1149 | name)) { | ||
1137 | x509_verify_chain_free(current_chain); | 1150 | x509_verify_chain_free(current_chain); |
1138 | goto err; | 1151 | goto err; |
1139 | } | 1152 | } |
1140 | } else { | 1153 | } else { |
1141 | x509_verify_build_chains(ctx, leaf, current_chain, | 1154 | x509_verify_build_chains(ctx, leaf, current_chain, |
1142 | full_chain); | 1155 | full_chain, name); |
1143 | if (full_chain && ctx->chains_count == 0) { | 1156 | if (full_chain && ctx->chains_count == 0) { |
1144 | /* | 1157 | /* |
1145 | * Save the error state from the xsc | 1158 | * Save the error state from the xsc |
diff --git a/src/regress/lib/libcrypto/x509/Makefile b/src/regress/lib/libcrypto/x509/Makefile index 919bef31d1..ca66df19cd 100644 --- a/src/regress/lib/libcrypto/x509/Makefile +++ b/src/regress/lib/libcrypto/x509/Makefile | |||
@@ -1,6 +1,7 @@ | |||
1 | # $OpenBSD: Makefile,v 1.12 2022/06/02 12:08:41 tb Exp $ | 1 | # $OpenBSD: Makefile,v 1.13 2022/06/25 20:01:43 beck Exp $ |
2 | 2 | ||
3 | PROGS = constraints verify x509attribute x509name x509req_ext callback | 3 | PROGS = constraints verify x509attribute x509name x509req_ext callback |
4 | PROGS += expirecallback | ||
4 | LDADD = -lcrypto | 5 | LDADD = -lcrypto |
5 | DPADD = ${LIBCRYPTO} | 6 | DPADD = ${LIBCRYPTO} |
6 | 7 | ||
@@ -18,6 +19,7 @@ REGRESS_TARGETS += regress-x509attribute | |||
18 | REGRESS_TARGETS += regress-x509name | 19 | REGRESS_TARGETS += regress-x509name |
19 | REGRESS_TARGETS += regress-x509req_ext | 20 | REGRESS_TARGETS += regress-x509req_ext |
20 | REGRESS_TARGETS += regress-callback | 21 | REGRESS_TARGETS += regress-callback |
22 | REGRESS_TARGETS += regress-expirecallback | ||
21 | 23 | ||
22 | CLEANFILES += x509name.result callbackout | 24 | CLEANFILES += x509name.result callbackout |
23 | 25 | ||
@@ -49,4 +51,7 @@ regress-callback: callback | |||
49 | ./callback ${.CURDIR}/../certs | 51 | ./callback ${.CURDIR}/../certs |
50 | perl ${.CURDIR}/callback.pl callback.out | 52 | perl ${.CURDIR}/callback.pl callback.out |
51 | 53 | ||
54 | regress-expirecallback: expirecallback | ||
55 | ./expirecallback ${.CURDIR}/../certs | ||
56 | |||
52 | .include <bsd.regress.mk> | 57 | .include <bsd.regress.mk> |
diff --git a/src/regress/lib/libcrypto/x509/expirecallback.c b/src/regress/lib/libcrypto/x509/expirecallback.c new file mode 100644 index 0000000000..3da49708ff --- /dev/null +++ b/src/regress/lib/libcrypto/x509/expirecallback.c | |||
@@ -0,0 +1,279 @@ | |||
1 | /* $OpenBSD: expirecallback.c,v 1.1 2022/06/25 20:01:43 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 | |||
34 | static int verbose = 1; | ||
35 | |||
36 | static int | ||
37 | passwd_cb(char *buf, int size, int rwflag, void *u) | ||
38 | { | ||
39 | memset(buf, 0, size); | ||
40 | return (0); | ||
41 | } | ||
42 | |||
43 | static int | ||
44 | certs_from_file(const char *filename, STACK_OF(X509) **certs) | ||
45 | { | ||
46 | STACK_OF(X509_INFO) *xis = NULL; | ||
47 | STACK_OF(X509) *xs = NULL; | ||
48 | BIO *bio = NULL; | ||
49 | X509 *x; | ||
50 | int i; | ||
51 | |||
52 | if ((xs = sk_X509_new_null()) == NULL) | ||
53 | errx(1, "failed to create X509 stack"); | ||
54 | if ((bio = BIO_new_file(filename, "r")) == NULL) { | ||
55 | ERR_print_errors_fp(stderr); | ||
56 | errx(1, "failed to create bio"); | ||
57 | } | ||
58 | if ((xis = PEM_X509_INFO_read_bio(bio, NULL, passwd_cb, NULL)) == NULL) | ||
59 | errx(1, "failed to read PEM"); | ||
60 | |||
61 | for (i = 0; i < sk_X509_INFO_num(xis); i++) { | ||
62 | if ((x = sk_X509_INFO_value(xis, i)->x509) == NULL) | ||
63 | continue; | ||
64 | if (!sk_X509_push(xs, x)) | ||
65 | errx(1, "failed to push X509"); | ||
66 | X509_up_ref(x); | ||
67 | } | ||
68 | |||
69 | *certs = xs; | ||
70 | xs = NULL; | ||
71 | |||
72 | sk_X509_INFO_pop_free(xis, X509_INFO_free); | ||
73 | sk_X509_pop_free(xs, X509_free); | ||
74 | BIO_free(bio); | ||
75 | |||
76 | return 1; | ||
77 | } | ||
78 | |||
79 | static int | ||
80 | verify_cert_cb(int ok, X509_STORE_CTX *xsc) | ||
81 | { | ||
82 | X509 *current_cert; | ||
83 | int verify_err; | ||
84 | |||
85 | current_cert = X509_STORE_CTX_get_current_cert(xsc); | ||
86 | if (current_cert != NULL) { | ||
87 | X509_NAME_print_ex_fp(stderr, | ||
88 | X509_get_subject_name(current_cert), 0, | ||
89 | XN_FLAG_ONELINE); | ||
90 | fprintf(stderr, "\n"); | ||
91 | } | ||
92 | |||
93 | verify_err = X509_STORE_CTX_get_error(xsc); | ||
94 | if (verify_err != X509_V_OK) { | ||
95 | if (verify_err == X509_V_ERR_CERT_HAS_EXPIRED) | ||
96 | fprintf(stderr, "IGNORING "); | ||
97 | fprintf(stderr, "verify error at depth %d: %s\n", | ||
98 | X509_STORE_CTX_get_error_depth(xsc), | ||
99 | X509_verify_cert_error_string(verify_err)); | ||
100 | } | ||
101 | |||
102 | /* | ||
103 | * Ignore expired certs, in the way people are told to do it | ||
104 | * by OpenSSL | ||
105 | */ | ||
106 | |||
107 | if (verify_err == X509_V_ERR_CERT_HAS_EXPIRED) | ||
108 | return 1; | ||
109 | |||
110 | return ok; | ||
111 | } | ||
112 | |||
113 | static void | ||
114 | verify_cert(const char *roots_dir, const char *roots_file, | ||
115 | const char *bundle_file, int *chains, int mode) | ||
116 | { | ||
117 | STACK_OF(X509) *roots = NULL, *bundle = NULL; | ||
118 | time_t future = 2000000000; /* May 17 2033 */ | ||
119 | X509_STORE_CTX *xsc = NULL; | ||
120 | X509_STORE *store = NULL; | ||
121 | int verify_err, use_dir; | ||
122 | X509 *leaf = NULL; | ||
123 | |||
124 | *chains = 0; | ||
125 | use_dir = (mode == MODE_MODERN_VFY_DIR); | ||
126 | |||
127 | if (!use_dir && !certs_from_file(roots_file, &roots)) | ||
128 | errx(1, "failed to load roots from '%s'", roots_file); | ||
129 | if (!certs_from_file(bundle_file, &bundle)) | ||
130 | errx(1, "failed to load bundle from '%s'", bundle_file); | ||
131 | if (sk_X509_num(bundle) < 1) | ||
132 | errx(1, "not enough certs in bundle"); | ||
133 | leaf = sk_X509_shift(bundle); | ||
134 | |||
135 | if ((xsc = X509_STORE_CTX_new()) == NULL) | ||
136 | errx(1, "X509_STORE_CTX"); | ||
137 | if (use_dir && (store = X509_STORE_new()) == NULL) | ||
138 | errx(1, "X509_STORE"); | ||
139 | if (!X509_STORE_CTX_init(xsc, store, leaf, bundle)) { | ||
140 | ERR_print_errors_fp(stderr); | ||
141 | errx(1, "failed to init store context"); | ||
142 | } | ||
143 | |||
144 | /* | ||
145 | * Set the time int the future to exercise the expired cert | ||
146 | * callback | ||
147 | */ | ||
148 | X509_STORE_CTX_set_time(xsc, 0, future); | ||
149 | |||
150 | if (use_dir) { | ||
151 | if (!X509_STORE_load_locations(store, NULL, roots_dir)) | ||
152 | errx(1, "failed to set by_dir directory of %s", roots_dir); | ||
153 | } | ||
154 | if (mode == MODE_LEGACY_VFY) | ||
155 | X509_STORE_CTX_set_flags(xsc, X509_V_FLAG_LEGACY_VERIFY); | ||
156 | else | ||
157 | X509_VERIFY_PARAM_clear_flags(X509_STORE_CTX_get0_param(xsc), | ||
158 | X509_V_FLAG_LEGACY_VERIFY); | ||
159 | |||
160 | if (verbose) | ||
161 | X509_STORE_CTX_set_verify_cb(xsc, verify_cert_cb); | ||
162 | if (!use_dir) | ||
163 | X509_STORE_CTX_set0_trusted_stack(xsc, roots); | ||
164 | if (X509_verify_cert(xsc) == 1) { | ||
165 | *chains = 1; /* XXX */ | ||
166 | goto done; | ||
167 | } | ||
168 | |||
169 | verify_err = X509_STORE_CTX_get_error(xsc); | ||
170 | if (verify_err == 0) | ||
171 | errx(1, "Error unset on failure!\n"); | ||
172 | |||
173 | fprintf(stderr, "failed to verify at %d: %s\n", | ||
174 | X509_STORE_CTX_get_error_depth(xsc), | ||
175 | X509_verify_cert_error_string(verify_err)); | ||
176 | |||
177 | done: | ||
178 | sk_X509_pop_free(roots, X509_free); | ||
179 | sk_X509_pop_free(bundle, X509_free); | ||
180 | X509_STORE_free(store); | ||
181 | X509_STORE_CTX_free(xsc); | ||
182 | X509_free(leaf); | ||
183 | } | ||
184 | |||
185 | struct verify_cert_test { | ||
186 | const char *id; | ||
187 | int want_chains; | ||
188 | int failing; | ||
189 | }; | ||
190 | |||
191 | struct verify_cert_test verify_cert_tests[] = { | ||
192 | { | ||
193 | .id = "1a", | ||
194 | .want_chains = 1, | ||
195 | }, | ||
196 | { | ||
197 | .id = "2a", | ||
198 | .want_chains = 1, | ||
199 | .failing = 1, | ||
200 | }, | ||
201 | { | ||
202 | .id = "2b", | ||
203 | .want_chains = 0, | ||
204 | }, | ||
205 | { | ||
206 | .id = "2c", | ||
207 | .want_chains = 1, | ||
208 | .failing = 1, | ||
209 | }, | ||
210 | }; | ||
211 | |||
212 | #define N_VERIFY_CERT_TESTS \ | ||
213 | (sizeof(verify_cert_tests) / sizeof(*verify_cert_tests)) | ||
214 | |||
215 | static int | ||
216 | verify_cert_test(const char *certs_path, int mode) | ||
217 | { | ||
218 | char *roots_file, *bundle_file, *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, "%s/%s/roots.pem", certs_path, | ||
228 | vct->id) == -1) | ||
229 | errx(1, "asprintf"); | ||
230 | if (asprintf(&bundle_file, "%s/%s/bundle.pem", certs_path, | ||
231 | vct->id) == -1) | ||
232 | errx(1, "asprintf"); | ||
233 | if (asprintf(&roots_dir, "./%s/roots", vct->id) == -1) | ||
234 | errx(1, "asprintf"); | ||
235 | |||
236 | fprintf(stderr, "== Test %zu (%s)\n", i, vct->id); | ||
237 | verify_cert(roots_dir, roots_file, bundle_file, &chains, mode); | ||
238 | if ((mode == MODE_VERIFY && chains == vct->want_chains) || | ||
239 | (chains == 0 && vct->want_chains == 0) || | ||
240 | (chains == 1 && vct->want_chains > 0)) { | ||
241 | fprintf(stderr, "INFO: Succeeded with %d chains%s\n", | ||
242 | chains, vct->failing ? " (legacy failure)" : ""); | ||
243 | if (mode == MODE_LEGACY_VFY && vct->failing) | ||
244 | failed |= 1; | ||
245 | } else { | ||
246 | fprintf(stderr, "FAIL: Failed with %d chains%s\n", | ||
247 | chains, vct->failing ? " (legacy failure)" : ""); | ||
248 | if (!vct->failing) | ||
249 | failed |= 1; | ||
250 | } | ||
251 | fprintf(stderr, "\n"); | ||
252 | |||
253 | free(roots_file); | ||
254 | free(bundle_file); | ||
255 | free(roots_dir); | ||
256 | } | ||
257 | |||
258 | return failed; | ||
259 | } | ||
260 | |||
261 | int | ||
262 | main(int argc, char **argv) | ||
263 | { | ||
264 | int failed = 0; | ||
265 | |||
266 | if (argc != 2) { | ||
267 | fprintf(stderr, "usage: %s <certs_path>\n", argv[0]); | ||
268 | exit(1); | ||
269 | } | ||
270 | |||
271 | fprintf(stderr, "\n\nTesting legacy x509_vfy\n"); | ||
272 | failed |= verify_cert_test(argv[1], MODE_LEGACY_VFY); | ||
273 | fprintf(stderr, "\n\nTesting modern x509_vfy\n"); | ||
274 | failed |= verify_cert_test(argv[1], MODE_MODERN_VFY); | ||
275 | fprintf(stderr, "\n\nTesting modern x509_vfy by_dir\n"); | ||
276 | failed |= verify_cert_test(argv[1], MODE_MODERN_VFY_DIR); | ||
277 | |||
278 | return (failed); | ||
279 | } | ||