summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/lib/libcrypto/x509/x509_verify.c51
-rw-r--r--src/regress/lib/libcrypto/x509/Makefile7
-rw-r--r--src/regress/lib/libcrypto/x509/expirecallback.c279
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
33static int x509_verify_cert_valid(struct x509_verify_ctx *ctx, X509 *cert, 33static 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);
35static int x509_verify_cert_hostname(struct x509_verify_ctx *ctx, X509 *cert,
36 char *name);
35static void x509_verify_build_chains(struct x509_verify_ctx *ctx, X509 *cert, 37static 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);
37static int x509_verify_cert_error(struct x509_verify_ctx *ctx, X509 *cert, 39static 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);
39static void x509_verify_chain_free(struct x509_verify_chain *chain); 41static 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
239static int 241static 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 */
454static int 456static int
455x509_verify_ctx_add_chain(struct x509_verify_ctx *ctx, 457x509_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)
539static int 549static int
540x509_verify_consider_candidate(struct x509_verify_ctx *ctx, X509 *cert, 550x509_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
622static void 632static void
623x509_verify_build_chains(struct x509_verify_ctx *ctx, X509 *cert, 633x509_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
3PROGS = constraints verify x509attribute x509name x509req_ext callback 3PROGS = constraints verify x509attribute x509name x509req_ext callback
4PROGS += expirecallback
4LDADD = -lcrypto 5LDADD = -lcrypto
5DPADD = ${LIBCRYPTO} 6DPADD = ${LIBCRYPTO}
6 7
@@ -18,6 +19,7 @@ REGRESS_TARGETS += regress-x509attribute
18REGRESS_TARGETS += regress-x509name 19REGRESS_TARGETS += regress-x509name
19REGRESS_TARGETS += regress-x509req_ext 20REGRESS_TARGETS += regress-x509req_ext
20REGRESS_TARGETS += regress-callback 21REGRESS_TARGETS += regress-callback
22REGRESS_TARGETS += regress-expirecallback
21 23
22CLEANFILES += x509name.result callbackout 24CLEANFILES += 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
54regress-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
34static int verbose = 1;
35
36static int
37passwd_cb(char *buf, int size, int rwflag, void *u)
38{
39 memset(buf, 0, size);
40 return (0);
41}
42
43static int
44certs_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
79static int
80verify_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
113static void
114verify_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
185struct verify_cert_test {
186 const char *id;
187 int want_chains;
188 int failing;
189};
190
191struct 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
215static int
216verify_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
261int
262main(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}