1*6822f9c8Santon /* $OpenBSD: verify.c,v 1.12 2024/08/23 12:56:26 anton Exp $ */
2fbd64e3cSjsing /*
3fbd64e3cSjsing * Copyright (c) 2020 Joel Sing <jsing@openbsd.org>
4b68b63e3Sbeck * Copyright (c) 2020-2021 Bob Beck <beck@openbsd.org>
5fbd64e3cSjsing *
6fbd64e3cSjsing * Permission to use, copy, modify, and distribute this software for any
7fbd64e3cSjsing * purpose with or without fee is hereby granted, provided that the above
8fbd64e3cSjsing * copyright notice and this permission notice appear in all copies.
9fbd64e3cSjsing *
10fbd64e3cSjsing * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11fbd64e3cSjsing * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12fbd64e3cSjsing * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13fbd64e3cSjsing * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14fbd64e3cSjsing * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15fbd64e3cSjsing * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16fbd64e3cSjsing * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17fbd64e3cSjsing */
18fbd64e3cSjsing
19fbd64e3cSjsing #include <err.h>
20fbd64e3cSjsing #include <string.h>
21fbd64e3cSjsing
22fbd64e3cSjsing #include <openssl/bio.h>
237cbb8da0Sjsing #include <openssl/crypto.h>
24fbd64e3cSjsing #include <openssl/err.h>
25fbd64e3cSjsing #include <openssl/pem.h>
26fbd64e3cSjsing #include <openssl/x509.h>
27fbd64e3cSjsing #include <openssl/x509v3.h>
28f45080b3Stb
29f45080b3Stb #include "x509_verify.h"
3023258cfeSbeck
3123258cfeSbeck #define MODE_MODERN_VFY 0
32b68b63e3Sbeck #define MODE_MODERN_VFY_DIR 1
33b68b63e3Sbeck #define MODE_LEGACY_VFY 2
34b68b63e3Sbeck #define MODE_VERIFY 3
35fbd64e3cSjsing
36fbd64e3cSjsing static int verbose = 1;
37fbd64e3cSjsing
38fbd64e3cSjsing static int
passwd_cb(char * buf,int size,int rwflag,void * u)39fbd64e3cSjsing passwd_cb(char *buf, int size, int rwflag, void *u)
40fbd64e3cSjsing {
41fbd64e3cSjsing memset(buf, 0, size);
42fbd64e3cSjsing return (0);
43fbd64e3cSjsing }
44fbd64e3cSjsing
45fbd64e3cSjsing static int
certs_from_file(const char * filename,STACK_OF (X509)** certs)46fbd64e3cSjsing certs_from_file(const char *filename, STACK_OF(X509) **certs)
47fbd64e3cSjsing {
48fbd64e3cSjsing STACK_OF(X509_INFO) *xis = NULL;
49fbd64e3cSjsing STACK_OF(X509) *xs = NULL;
50fbd64e3cSjsing BIO *bio = NULL;
51fbd64e3cSjsing X509 *x;
52fbd64e3cSjsing int i;
53fbd64e3cSjsing
54fbd64e3cSjsing if ((xs = sk_X509_new_null()) == NULL)
55fbd64e3cSjsing errx(1, "failed to create X509 stack");
56fbd64e3cSjsing if ((bio = BIO_new_file(filename, "r")) == NULL) {
57fbd64e3cSjsing ERR_print_errors_fp(stderr);
58fbd64e3cSjsing errx(1, "failed to create bio");
59fbd64e3cSjsing }
60fbd64e3cSjsing if ((xis = PEM_X509_INFO_read_bio(bio, NULL, passwd_cb, NULL)) == NULL)
61fbd64e3cSjsing errx(1, "failed to read PEM");
62fbd64e3cSjsing
63fbd64e3cSjsing for (i = 0; i < sk_X509_INFO_num(xis); i++) {
64fbd64e3cSjsing if ((x = sk_X509_INFO_value(xis, i)->x509) == NULL)
65fbd64e3cSjsing continue;
66fbd64e3cSjsing if (!sk_X509_push(xs, x))
67fbd64e3cSjsing errx(1, "failed to push X509");
68fbd64e3cSjsing X509_up_ref(x);
69fbd64e3cSjsing }
70fbd64e3cSjsing
71fbd64e3cSjsing *certs = xs;
72fbd64e3cSjsing xs = NULL;
73fbd64e3cSjsing
74fbd64e3cSjsing sk_X509_INFO_pop_free(xis, X509_INFO_free);
75fbd64e3cSjsing sk_X509_pop_free(xs, X509_free);
76fbd64e3cSjsing BIO_free(bio);
77fbd64e3cSjsing
78fbd64e3cSjsing return 1;
79fbd64e3cSjsing }
80fbd64e3cSjsing
81fbd64e3cSjsing static int
verify_cert_cb(int ok,X509_STORE_CTX * xsc)82fbd64e3cSjsing verify_cert_cb(int ok, X509_STORE_CTX *xsc)
83fbd64e3cSjsing {
84fbd64e3cSjsing X509 *current_cert;
85fbd64e3cSjsing int verify_err;
86fbd64e3cSjsing
87fbd64e3cSjsing current_cert = X509_STORE_CTX_get_current_cert(xsc);
88fbd64e3cSjsing if (current_cert != NULL) {
89fbd64e3cSjsing X509_NAME_print_ex_fp(stderr,
90fbd64e3cSjsing X509_get_subject_name(current_cert), 0,
91fbd64e3cSjsing XN_FLAG_ONELINE);
92fbd64e3cSjsing fprintf(stderr, "\n");
93fbd64e3cSjsing }
94fbd64e3cSjsing
95fbd64e3cSjsing verify_err = X509_STORE_CTX_get_error(xsc);
96fbd64e3cSjsing if (verify_err != X509_V_OK) {
97fbd64e3cSjsing fprintf(stderr, "verify error at depth %d: %s\n",
98fbd64e3cSjsing X509_STORE_CTX_get_error_depth(xsc),
99fbd64e3cSjsing X509_verify_cert_error_string(verify_err));
100fbd64e3cSjsing }
101fbd64e3cSjsing
102fbd64e3cSjsing return ok;
103fbd64e3cSjsing }
104fbd64e3cSjsing
105fbd64e3cSjsing static void
verify_cert(const char * roots_dir,const char * roots_file,const char * bundle_file,int * chains,int * error,int * error_depth,int mode)106b68b63e3Sbeck verify_cert(const char *roots_dir, const char *roots_file,
1077cbb8da0Sjsing const char *bundle_file, int *chains, int *error, int *error_depth,
1087cbb8da0Sjsing int mode)
109fbd64e3cSjsing {
110fbd64e3cSjsing STACK_OF(X509) *roots = NULL, *bundle = NULL;
111fbd64e3cSjsing X509_STORE_CTX *xsc = NULL;
112b68b63e3Sbeck X509_STORE *store = NULL;
113fbd64e3cSjsing X509 *leaf = NULL;
1147cbb8da0Sjsing int use_dir;
1157cbb8da0Sjsing int ret;
116fbd64e3cSjsing
117fbd64e3cSjsing *chains = 0;
1187cbb8da0Sjsing *error = 0;
1197cbb8da0Sjsing *error_depth = 0;
1207cbb8da0Sjsing
121b68b63e3Sbeck use_dir = (mode == MODE_MODERN_VFY_DIR);
122fbd64e3cSjsing
123b68b63e3Sbeck if (!use_dir && !certs_from_file(roots_file, &roots))
124fbd64e3cSjsing errx(1, "failed to load roots from '%s'", roots_file);
125fbd64e3cSjsing if (!certs_from_file(bundle_file, &bundle))
126fbd64e3cSjsing errx(1, "failed to load bundle from '%s'", bundle_file);
127fbd64e3cSjsing if (sk_X509_num(bundle) < 1)
128fbd64e3cSjsing errx(1, "not enough certs in bundle");
129fbd64e3cSjsing leaf = sk_X509_shift(bundle);
130fbd64e3cSjsing
131fbd64e3cSjsing if ((xsc = X509_STORE_CTX_new()) == NULL)
132fbd64e3cSjsing errx(1, "X509_STORE_CTX");
133b68b63e3Sbeck if (use_dir && (store = X509_STORE_new()) == NULL)
134b68b63e3Sbeck errx(1, "X509_STORE");
135b68b63e3Sbeck if (!X509_STORE_CTX_init(xsc, store, leaf, bundle)) {
136fbd64e3cSjsing ERR_print_errors_fp(stderr);
137fbd64e3cSjsing errx(1, "failed to init store context");
138fbd64e3cSjsing }
139b68b63e3Sbeck if (use_dir) {
140b68b63e3Sbeck if (!X509_STORE_load_locations(store, NULL, roots_dir))
141b68b63e3Sbeck errx(1, "failed to set by_dir directory of %s", roots_dir);
142b68b63e3Sbeck }
143920585faStb if (mode == MODE_LEGACY_VFY)
144920585faStb X509_STORE_CTX_set_flags(xsc, X509_V_FLAG_LEGACY_VERIFY);
145920585faStb else
146920585faStb X509_VERIFY_PARAM_clear_flags(X509_STORE_CTX_get0_param(xsc),
147920585faStb X509_V_FLAG_LEGACY_VERIFY);
14823258cfeSbeck
149fbd64e3cSjsing if (verbose)
150fbd64e3cSjsing X509_STORE_CTX_set_verify_cb(xsc, verify_cert_cb);
151b68b63e3Sbeck if (!use_dir)
152fbd64e3cSjsing X509_STORE_CTX_set0_trusted_stack(xsc, roots);
1537cbb8da0Sjsing
1547cbb8da0Sjsing ret = X509_verify_cert(xsc);
1557cbb8da0Sjsing
1567cbb8da0Sjsing *error = X509_STORE_CTX_get_error(xsc);
1577cbb8da0Sjsing *error_depth = X509_STORE_CTX_get_error_depth(xsc);
1587cbb8da0Sjsing
1597cbb8da0Sjsing if (ret == 1) {
160fbd64e3cSjsing *chains = 1; /* XXX */
161fbd64e3cSjsing goto done;
162fbd64e3cSjsing }
163fbd64e3cSjsing
1647cbb8da0Sjsing if (*error == 0)
165*6822f9c8Santon errx(1, "Error unset on failure!");
16628dcb2c6Sbeck
167fbd64e3cSjsing fprintf(stderr, "failed to verify at %d: %s\n",
1687cbb8da0Sjsing *error_depth, X509_verify_cert_error_string(*error));
169fbd64e3cSjsing
170fbd64e3cSjsing done:
171fbd64e3cSjsing sk_X509_pop_free(roots, X509_free);
172fbd64e3cSjsing sk_X509_pop_free(bundle, X509_free);
173b68b63e3Sbeck X509_STORE_free(store);
174fbd64e3cSjsing X509_STORE_CTX_free(xsc);
175fbd64e3cSjsing X509_free(leaf);
176fbd64e3cSjsing }
177fbd64e3cSjsing
17823258cfeSbeck static void
verify_cert_new(const char * roots_file,const char * bundle_file,int * chains)17923258cfeSbeck verify_cert_new(const char *roots_file, const char *bundle_file, int *chains)
18023258cfeSbeck {
18123258cfeSbeck STACK_OF(X509) *roots = NULL, *bundle = NULL;
18223258cfeSbeck X509_STORE_CTX *xsc = NULL;
18323258cfeSbeck X509 *leaf = NULL;
18423258cfeSbeck struct x509_verify_ctx *ctx;
18523258cfeSbeck
18623258cfeSbeck *chains = 0;
18723258cfeSbeck
18823258cfeSbeck if (!certs_from_file(roots_file, &roots))
18923258cfeSbeck errx(1, "failed to load roots from '%s'", roots_file);
19023258cfeSbeck if (!certs_from_file(bundle_file, &bundle))
19123258cfeSbeck errx(1, "failed to load bundle from '%s'", bundle_file);
19223258cfeSbeck if (sk_X509_num(bundle) < 1)
19323258cfeSbeck errx(1, "not enough certs in bundle");
19423258cfeSbeck leaf = sk_X509_shift(bundle);
19523258cfeSbeck
19623258cfeSbeck if ((xsc = X509_STORE_CTX_new()) == NULL)
19723258cfeSbeck errx(1, "X509_STORE_CTX");
19823258cfeSbeck if (!X509_STORE_CTX_init(xsc, NULL, leaf, bundle)) {
19923258cfeSbeck ERR_print_errors_fp(stderr);
20023258cfeSbeck errx(1, "failed to init store context");
20123258cfeSbeck }
20223258cfeSbeck if (verbose)
20323258cfeSbeck X509_STORE_CTX_set_verify_cb(xsc, verify_cert_cb);
20423258cfeSbeck
20523258cfeSbeck if ((ctx = x509_verify_ctx_new(roots)) == NULL)
20623258cfeSbeck errx(1, "failed to create ctx");
20723258cfeSbeck if (!x509_verify_ctx_set_intermediates(ctx, bundle))
20823258cfeSbeck errx(1, "failed to set intermediates");
20923258cfeSbeck
21023258cfeSbeck if ((*chains = x509_verify(ctx, leaf, NULL)) == 0) {
21123258cfeSbeck fprintf(stderr, "failed to verify at %lu: %s\n",
21223258cfeSbeck x509_verify_ctx_error_depth(ctx),
21323258cfeSbeck x509_verify_ctx_error_string(ctx));
21423258cfeSbeck } else {
2154820661fStb int c;
2164820661fStb
2174820661fStb for (c = 0; verbose && c < *chains; c++) {
2184820661fStb STACK_OF(X509) *chain;
2194820661fStb int i;
2204820661fStb
22123258cfeSbeck fprintf(stderr, "Chain %d\n--------\n", c);
2224820661fStb chain = x509_verify_ctx_chain(ctx, c);
2234820661fStb for (i = 0; i < sk_X509_num(chain); i++) {
22423258cfeSbeck X509 *cert = sk_X509_value(chain, i);
22523258cfeSbeck X509_NAME_print_ex_fp(stderr,
22623258cfeSbeck X509_get_subject_name(cert), 0,
22723258cfeSbeck XN_FLAG_ONELINE);
22823258cfeSbeck fprintf(stderr, "\n");
22923258cfeSbeck }
23023258cfeSbeck }
23123258cfeSbeck }
23223258cfeSbeck sk_X509_pop_free(roots, X509_free);
23323258cfeSbeck sk_X509_pop_free(bundle, X509_free);
23423258cfeSbeck X509_free(leaf);
235047399e3Stb X509_STORE_CTX_free(xsc);
236047399e3Stb x509_verify_ctx_free(ctx);
23723258cfeSbeck }
23823258cfeSbeck
2397cbb8da0Sjsing struct verify_cert_test {
2407cbb8da0Sjsing const char *id;
2417cbb8da0Sjsing int want_chains;
2427cbb8da0Sjsing int want_error;
2437cbb8da0Sjsing int want_error_depth;
2447cbb8da0Sjsing int want_legacy_error;
2457cbb8da0Sjsing int want_legacy_error_depth;
2467cbb8da0Sjsing int failing;
2477cbb8da0Sjsing };
2487cbb8da0Sjsing
249fbd64e3cSjsing struct verify_cert_test verify_cert_tests[] = {
250fbd64e3cSjsing {
251fbd64e3cSjsing .id = "1a",
252fbd64e3cSjsing .want_chains = 1,
253fbd64e3cSjsing },
254fbd64e3cSjsing {
255fbd64e3cSjsing .id = "2a",
256fbd64e3cSjsing .want_chains = 1,
257fbd64e3cSjsing },
258fbd64e3cSjsing {
259fbd64e3cSjsing .id = "2b",
260fbd64e3cSjsing .want_chains = 0,
2617cbb8da0Sjsing .want_error = X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY,
2627cbb8da0Sjsing .want_error_depth = 0,
2637cbb8da0Sjsing .want_legacy_error = X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY,
2647cbb8da0Sjsing .want_legacy_error_depth = 0,
265fbd64e3cSjsing },
266fbd64e3cSjsing {
2676f4c0c98Sbeck .id = "2c",
2686f4c0c98Sbeck .want_chains = 1,
2696f4c0c98Sbeck },
2706f4c0c98Sbeck {
271fbd64e3cSjsing .id = "3a",
272fbd64e3cSjsing .want_chains = 1,
273fbd64e3cSjsing },
274fbd64e3cSjsing {
275fbd64e3cSjsing .id = "3b",
276fbd64e3cSjsing .want_chains = 0,
2777cbb8da0Sjsing .want_error = X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY,
2787cbb8da0Sjsing .want_error_depth = 2,
2797cbb8da0Sjsing .want_legacy_error = X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY,
2807cbb8da0Sjsing .want_legacy_error_depth = 2,
281fbd64e3cSjsing },
282fbd64e3cSjsing {
283fbd64e3cSjsing .id = "3c",
284fbd64e3cSjsing .want_chains = 0,
2857cbb8da0Sjsing .want_error = X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY,
2867cbb8da0Sjsing .want_error_depth = 1,
2877cbb8da0Sjsing .want_legacy_error = X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY,
2887cbb8da0Sjsing .want_legacy_error_depth = 1,
289fbd64e3cSjsing },
290fbd64e3cSjsing {
291fbd64e3cSjsing .id = "3d",
292fbd64e3cSjsing .want_chains = 0,
2937cbb8da0Sjsing .want_error = X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY,
2947cbb8da0Sjsing .want_error_depth = 0,
2957cbb8da0Sjsing .want_legacy_error = X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY,
2967cbb8da0Sjsing .want_legacy_error_depth = 0,
297fbd64e3cSjsing },
298fbd64e3cSjsing {
299fbd64e3cSjsing .id = "3e",
300fbd64e3cSjsing .want_chains = 1,
301fbd64e3cSjsing },
302fbd64e3cSjsing {
303fbd64e3cSjsing .id = "4a",
304fbd64e3cSjsing .want_chains = 2,
305fbd64e3cSjsing },
306fbd64e3cSjsing {
307fbd64e3cSjsing .id = "4b",
308fbd64e3cSjsing .want_chains = 1,
309fbd64e3cSjsing },
310fbd64e3cSjsing {
311fbd64e3cSjsing .id = "4c",
312fbd64e3cSjsing .want_chains = 1,
3137cbb8da0Sjsing .want_legacy_error = X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY,
3147cbb8da0Sjsing .want_legacy_error_depth = 1,
315fbd64e3cSjsing .failing = 1,
316fbd64e3cSjsing },
317fbd64e3cSjsing {
318fbd64e3cSjsing .id = "4d",
319fbd64e3cSjsing .want_chains = 1,
320fbd64e3cSjsing },
321fbd64e3cSjsing {
322fbd64e3cSjsing .id = "4e",
323fbd64e3cSjsing .want_chains = 1,
324fbd64e3cSjsing },
325fbd64e3cSjsing {
326fbd64e3cSjsing .id = "4f",
327fbd64e3cSjsing .want_chains = 2,
328fbd64e3cSjsing },
329fbd64e3cSjsing {
330fbd64e3cSjsing .id = "4g",
331fbd64e3cSjsing .want_chains = 1,
3327cbb8da0Sjsing .want_legacy_error = X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY,
3337cbb8da0Sjsing .want_legacy_error_depth = 1,
334fbd64e3cSjsing .failing = 1,
335fbd64e3cSjsing },
336fbd64e3cSjsing {
337fbd64e3cSjsing .id = "4h",
338fbd64e3cSjsing .want_chains = 1,
339fbd64e3cSjsing },
340fbd64e3cSjsing {
341fbd64e3cSjsing .id = "5a",
342fbd64e3cSjsing .want_chains = 2,
343fbd64e3cSjsing },
344fbd64e3cSjsing {
345fbd64e3cSjsing .id = "5b",
346fbd64e3cSjsing .want_chains = 1,
3477cbb8da0Sjsing .want_legacy_error = X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY,
3487cbb8da0Sjsing .want_legacy_error_depth = 2,
349fbd64e3cSjsing .failing = 1,
350fbd64e3cSjsing },
351fbd64e3cSjsing {
352fbd64e3cSjsing .id = "5c",
353fbd64e3cSjsing .want_chains = 1,
354fbd64e3cSjsing },
355fbd64e3cSjsing {
356fbd64e3cSjsing .id = "5d",
357fbd64e3cSjsing .want_chains = 1,
358fbd64e3cSjsing },
359fbd64e3cSjsing {
360fbd64e3cSjsing .id = "5e",
361fbd64e3cSjsing .want_chains = 1,
3627cbb8da0Sjsing .want_legacy_error = X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY,
3637cbb8da0Sjsing .want_legacy_error_depth = 1,
364fbd64e3cSjsing .failing = 1,
365fbd64e3cSjsing },
366fbd64e3cSjsing {
367fbd64e3cSjsing .id = "5f",
368fbd64e3cSjsing .want_chains = 1,
369fbd64e3cSjsing },
370fbd64e3cSjsing {
371fbd64e3cSjsing .id = "5g",
372fbd64e3cSjsing .want_chains = 2,
373fbd64e3cSjsing },
374fbd64e3cSjsing {
375fbd64e3cSjsing .id = "5h",
376fbd64e3cSjsing .want_chains = 1,
377fbd64e3cSjsing },
378fbd64e3cSjsing {
379fbd64e3cSjsing .id = "5i",
380fbd64e3cSjsing .want_chains = 1,
3817cbb8da0Sjsing .want_legacy_error = X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY,
3827cbb8da0Sjsing .want_legacy_error_depth = 1,
383fbd64e3cSjsing .failing = 1,
384fbd64e3cSjsing },
385fbd64e3cSjsing {
386fbd64e3cSjsing .id = "6a",
387fbd64e3cSjsing .want_chains = 1,
388fbd64e3cSjsing },
389fbd64e3cSjsing {
390fbd64e3cSjsing .id = "6b",
391fbd64e3cSjsing .want_chains = 1,
3927cbb8da0Sjsing .want_error = X509_V_ERR_CERT_HAS_EXPIRED,
3937cbb8da0Sjsing .want_error_depth = 0,
3947cbb8da0Sjsing .want_legacy_error = X509_V_ERR_CERT_HAS_EXPIRED,
3957cbb8da0Sjsing .want_legacy_error_depth = 2,
396fbd64e3cSjsing .failing = 1,
397fbd64e3cSjsing },
398fbd64e3cSjsing {
399fbd64e3cSjsing .id = "7a",
400fbd64e3cSjsing .want_chains = 1,
4017cbb8da0Sjsing .want_error = X509_V_ERR_CERT_HAS_EXPIRED,
4027cbb8da0Sjsing .want_error_depth = 0,
4037cbb8da0Sjsing .want_legacy_error = X509_V_ERR_CERT_HAS_EXPIRED,
4047cbb8da0Sjsing .want_legacy_error_depth = 3,
405fbd64e3cSjsing .failing = 1,
406fbd64e3cSjsing },
407fbd64e3cSjsing {
408fbd64e3cSjsing .id = "7b",
409fbd64e3cSjsing .want_chains = 1,
410fbd64e3cSjsing },
411fbd64e3cSjsing {
412fbd64e3cSjsing .id = "8a",
413fbd64e3cSjsing .want_chains = 0,
4147cbb8da0Sjsing .want_error = X509_V_ERR_CERT_HAS_EXPIRED,
4157cbb8da0Sjsing .want_error_depth = 0,
4167cbb8da0Sjsing .want_legacy_error = X509_V_ERR_CERT_HAS_EXPIRED,
4177cbb8da0Sjsing .want_legacy_error_depth = 0,
418fbd64e3cSjsing },
419fbd64e3cSjsing {
420fbd64e3cSjsing .id = "9a",
421fbd64e3cSjsing .want_chains = 0,
4227cbb8da0Sjsing .want_error = X509_V_ERR_CERT_HAS_EXPIRED,
4237cbb8da0Sjsing .want_error_depth = 1,
4247cbb8da0Sjsing .want_legacy_error = X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY,
4257cbb8da0Sjsing .want_legacy_error_depth = 0,
426fbd64e3cSjsing },
427fbd64e3cSjsing {
428fbd64e3cSjsing .id = "10a",
429fbd64e3cSjsing .want_chains = 1,
4307cbb8da0Sjsing .want_error = X509_V_ERR_CERT_HAS_EXPIRED,
4317cbb8da0Sjsing .want_error_depth = 0,
432fbd64e3cSjsing },
433fbd64e3cSjsing {
434fbd64e3cSjsing .id = "10b",
435fbd64e3cSjsing .want_chains = 1,
436fbd64e3cSjsing },
437fbd64e3cSjsing {
438fbd64e3cSjsing .id = "11a",
439fbd64e3cSjsing .want_chains = 1,
4407cbb8da0Sjsing .want_error = X509_V_ERR_CERT_HAS_EXPIRED,
4417cbb8da0Sjsing .want_error_depth = 0,
4427cbb8da0Sjsing .want_legacy_error = X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY,
4437cbb8da0Sjsing .want_legacy_error_depth = 1,
444fbd64e3cSjsing .failing = 1,
445fbd64e3cSjsing },
446fbd64e3cSjsing {
447fbd64e3cSjsing .id = "11b",
448fbd64e3cSjsing .want_chains = 1,
449fbd64e3cSjsing },
450fbd64e3cSjsing {
451fbd64e3cSjsing .id = "12a",
452fbd64e3cSjsing .want_chains = 1,
453fbd64e3cSjsing },
454fbd64e3cSjsing {
455fbd64e3cSjsing .id = "13a",
456fbd64e3cSjsing .want_chains = 1,
4577cbb8da0Sjsing .want_error = X509_V_ERR_CERT_HAS_EXPIRED,
4587cbb8da0Sjsing .want_error_depth = 0,
4597cbb8da0Sjsing .want_legacy_error = X509_V_ERR_CERT_HAS_EXPIRED,
4607cbb8da0Sjsing .want_legacy_error_depth = 2,
46107499e19Sjsing .failing = 1,
462fbd64e3cSjsing },
463fbd64e3cSjsing };
464fbd64e3cSjsing
465fbd64e3cSjsing #define N_VERIFY_CERT_TESTS \
466fbd64e3cSjsing (sizeof(verify_cert_tests) / sizeof(*verify_cert_tests))
467fbd64e3cSjsing
468fbd64e3cSjsing static int
verify_cert_test(const char * certs_path,int mode)46923258cfeSbeck verify_cert_test(const char *certs_path, int mode)
470fbd64e3cSjsing {
471b68b63e3Sbeck char *roots_file, *bundle_file, *roots_dir;
472fbd64e3cSjsing struct verify_cert_test *vct;
4737cbb8da0Sjsing int chains, error, error_depth;
474fbd64e3cSjsing int failed = 0;
475fbd64e3cSjsing size_t i;
476fbd64e3cSjsing
477fbd64e3cSjsing for (i = 0; i < N_VERIFY_CERT_TESTS; i++) {
478fbd64e3cSjsing vct = &verify_cert_tests[i];
479fbd64e3cSjsing
480fbd64e3cSjsing if (asprintf(&roots_file, "%s/%s/roots.pem", certs_path,
481fbd64e3cSjsing vct->id) == -1)
482fbd64e3cSjsing errx(1, "asprintf");
483fbd64e3cSjsing if (asprintf(&bundle_file, "%s/%s/bundle.pem", certs_path,
484fbd64e3cSjsing vct->id) == -1)
485fbd64e3cSjsing errx(1, "asprintf");
486b68b63e3Sbeck if (asprintf(&roots_dir, "./%s/roots", vct->id) == -1)
487b68b63e3Sbeck errx(1, "asprintf");
488fbd64e3cSjsing
4897cbb8da0Sjsing error = 0;
4907cbb8da0Sjsing error_depth = 0;
4917cbb8da0Sjsing
492fbd64e3cSjsing fprintf(stderr, "== Test %zu (%s)\n", i, vct->id);
49323258cfeSbeck if (mode == MODE_VERIFY)
49423258cfeSbeck verify_cert_new(roots_file, bundle_file, &chains);
49523258cfeSbeck else
4967cbb8da0Sjsing verify_cert(roots_dir, roots_file, bundle_file, &chains,
4977cbb8da0Sjsing &error, &error_depth, mode);
4987cbb8da0Sjsing
499b68b63e3Sbeck if ((mode == MODE_VERIFY && chains == vct->want_chains) ||
50023258cfeSbeck (chains == 0 && vct->want_chains == 0) ||
501fbd64e3cSjsing (chains == 1 && vct->want_chains > 0)) {
502fbd64e3cSjsing fprintf(stderr, "INFO: Succeeded with %d chains%s\n",
50323258cfeSbeck chains, vct->failing ? " (legacy failure)" : "");
50423258cfeSbeck if (mode == MODE_LEGACY_VFY && vct->failing)
505fbd64e3cSjsing failed |= 1;
506fbd64e3cSjsing } else {
507fbd64e3cSjsing fprintf(stderr, "FAIL: Failed with %d chains%s\n",
50823258cfeSbeck chains, vct->failing ? " (legacy failure)" : "");
509fbd64e3cSjsing if (!vct->failing)
510fbd64e3cSjsing failed |= 1;
511fbd64e3cSjsing }
5127cbb8da0Sjsing
5137cbb8da0Sjsing if (mode == MODE_LEGACY_VFY) {
5147cbb8da0Sjsing if (error != vct->want_legacy_error) {
5157cbb8da0Sjsing fprintf(stderr, "FAIL: Got legacy error %d, "
5167cbb8da0Sjsing "want %d\n", error, vct->want_legacy_error);
5177cbb8da0Sjsing failed |= 1;
5187cbb8da0Sjsing }
5197cbb8da0Sjsing if (error_depth != vct->want_legacy_error_depth) {
5207cbb8da0Sjsing fprintf(stderr, "FAIL: Got legacy error depth "
5217cbb8da0Sjsing "%d, want %d\n", error_depth,
5227cbb8da0Sjsing vct->want_legacy_error_depth);
5237cbb8da0Sjsing failed |= 1;
5247cbb8da0Sjsing }
5257cbb8da0Sjsing } else if (mode == MODE_MODERN_VFY || mode == MODE_MODERN_VFY_DIR) {
5267cbb8da0Sjsing if (error != vct->want_error) {
5277cbb8da0Sjsing fprintf(stderr, "FAIL: Got error %d, want %d\n",
5287cbb8da0Sjsing error, vct->want_error);
5297cbb8da0Sjsing failed |= 1;
5307cbb8da0Sjsing }
5317cbb8da0Sjsing if (error_depth != vct->want_error_depth) {
5327cbb8da0Sjsing fprintf(stderr, "FAIL: Got error depth %d, want"
5337cbb8da0Sjsing " %d\n", error_depth, vct->want_error_depth);
5347cbb8da0Sjsing failed |= 1;
5357cbb8da0Sjsing }
5367cbb8da0Sjsing }
5377cbb8da0Sjsing
538fbd64e3cSjsing fprintf(stderr, "\n");
539fbd64e3cSjsing
540fbd64e3cSjsing free(roots_file);
541fbd64e3cSjsing free(bundle_file);
542b68b63e3Sbeck free(roots_dir);
543fbd64e3cSjsing }
544fbd64e3cSjsing
545fbd64e3cSjsing return failed;
546fbd64e3cSjsing }
547fbd64e3cSjsing
548fbd64e3cSjsing int
main(int argc,char ** argv)549fbd64e3cSjsing main(int argc, char **argv)
550fbd64e3cSjsing {
551fbd64e3cSjsing int failed = 0;
552fbd64e3cSjsing
553fbd64e3cSjsing if (argc != 2) {
554fbd64e3cSjsing fprintf(stderr, "usage: %s <certs_path>\n", argv[0]);
555fbd64e3cSjsing exit(1);
556fbd64e3cSjsing }
557fbd64e3cSjsing
55823258cfeSbeck fprintf(stderr, "\n\nTesting legacy x509_vfy\n");
55923258cfeSbeck failed |= verify_cert_test(argv[1], MODE_LEGACY_VFY);
56023258cfeSbeck fprintf(stderr, "\n\nTesting modern x509_vfy\n");
56123258cfeSbeck failed |= verify_cert_test(argv[1], MODE_MODERN_VFY);
562b68b63e3Sbeck fprintf(stderr, "\n\nTesting modern x509_vfy by_dir\n");
563b68b63e3Sbeck failed |= verify_cert_test(argv[1], MODE_MODERN_VFY_DIR);
56423258cfeSbeck fprintf(stderr, "\n\nTesting x509_verify\n");
56523258cfeSbeck failed |= verify_cert_test(argv[1], MODE_VERIFY);
566fbd64e3cSjsing
567fbd64e3cSjsing return (failed);
568fbd64e3cSjsing }
569