1*4724848cSchristos /*
2*4724848cSchristos * Copyright 2015-2022 The OpenSSL Project Authors. All Rights Reserved.
3*4724848cSchristos *
4*4724848cSchristos * Licensed under the OpenSSL license (the "License"). You may not use
5*4724848cSchristos * this file except in compliance with the License. You can obtain a copy
6*4724848cSchristos * in the file LICENSE in the source distribution or at
7*4724848cSchristos * https://www.openssl.org/source/license.html
8*4724848cSchristos */
9*4724848cSchristos
10*4724848cSchristos #include <stdio.h>
11*4724848cSchristos #include <openssl/crypto.h>
12*4724848cSchristos #include <openssl/bio.h>
13*4724848cSchristos #include <openssl/x509.h>
14*4724848cSchristos #include <openssl/x509v3.h>
15*4724848cSchristos #include <openssl/pem.h>
16*4724848cSchristos #include <openssl/err.h>
17*4724848cSchristos #include "testutil.h"
18*4724848cSchristos
19*4724848cSchristos static const char *certs_dir;
20*4724848cSchristos static char *roots_f = NULL;
21*4724848cSchristos static char *untrusted_f = NULL;
22*4724848cSchristos static char *bad_f = NULL;
23*4724848cSchristos static char *good_f = NULL;
24*4724848cSchristos static char *sroot_cert = NULL;
25*4724848cSchristos static char *ca_cert = NULL;
26*4724848cSchristos static char *ee_cert = NULL;
27*4724848cSchristos
load_cert_pem(const char * file)28*4724848cSchristos static X509 *load_cert_pem(const char *file)
29*4724848cSchristos {
30*4724848cSchristos X509 *cert = NULL;
31*4724848cSchristos BIO *bio = NULL;
32*4724848cSchristos
33*4724848cSchristos if (!TEST_ptr(bio = BIO_new(BIO_s_file())))
34*4724848cSchristos return NULL;
35*4724848cSchristos if (TEST_int_gt(BIO_read_filename(bio, file), 0))
36*4724848cSchristos (void)TEST_ptr(cert = PEM_read_bio_X509(bio, NULL, NULL, NULL));
37*4724848cSchristos
38*4724848cSchristos BIO_free(bio);
39*4724848cSchristos return cert;
40*4724848cSchristos }
41*4724848cSchristos
STACK_OF(X509)42*4724848cSchristos static STACK_OF(X509) *load_certs_from_file(const char *filename)
43*4724848cSchristos {
44*4724848cSchristos STACK_OF(X509) *certs;
45*4724848cSchristos BIO *bio;
46*4724848cSchristos X509 *x;
47*4724848cSchristos
48*4724848cSchristos bio = BIO_new_file(filename, "r");
49*4724848cSchristos
50*4724848cSchristos if (bio == NULL) {
51*4724848cSchristos return NULL;
52*4724848cSchristos }
53*4724848cSchristos
54*4724848cSchristos certs = sk_X509_new_null();
55*4724848cSchristos if (certs == NULL) {
56*4724848cSchristos BIO_free(bio);
57*4724848cSchristos return NULL;
58*4724848cSchristos }
59*4724848cSchristos
60*4724848cSchristos ERR_set_mark();
61*4724848cSchristos do {
62*4724848cSchristos x = PEM_read_bio_X509(bio, NULL, 0, NULL);
63*4724848cSchristos if (x != NULL && !sk_X509_push(certs, x)) {
64*4724848cSchristos sk_X509_pop_free(certs, X509_free);
65*4724848cSchristos BIO_free(bio);
66*4724848cSchristos return NULL;
67*4724848cSchristos } else if (x == NULL) {
68*4724848cSchristos /*
69*4724848cSchristos * We probably just ran out of certs, so ignore any errors
70*4724848cSchristos * generated
71*4724848cSchristos */
72*4724848cSchristos ERR_pop_to_mark();
73*4724848cSchristos }
74*4724848cSchristos } while (x != NULL);
75*4724848cSchristos
76*4724848cSchristos BIO_free(bio);
77*4724848cSchristos
78*4724848cSchristos return certs;
79*4724848cSchristos }
80*4724848cSchristos
81*4724848cSchristos /*-
82*4724848cSchristos * Test for CVE-2015-1793 (Alternate Chains Certificate Forgery)
83*4724848cSchristos *
84*4724848cSchristos * Chain is as follows:
85*4724848cSchristos *
86*4724848cSchristos * rootCA (self-signed)
87*4724848cSchristos * |
88*4724848cSchristos * interCA
89*4724848cSchristos * |
90*4724848cSchristos * subinterCA subinterCA (self-signed)
91*4724848cSchristos * | |
92*4724848cSchristos * leaf ------------------
93*4724848cSchristos * |
94*4724848cSchristos * bad
95*4724848cSchristos *
96*4724848cSchristos * rootCA, interCA, subinterCA, subinterCA (ss) all have CA=TRUE
97*4724848cSchristos * leaf and bad have CA=FALSE
98*4724848cSchristos *
99*4724848cSchristos * subinterCA and subinterCA (ss) have the same subject name and keys
100*4724848cSchristos *
101*4724848cSchristos * interCA (but not rootCA) and subinterCA (ss) are in the trusted store
102*4724848cSchristos * (roots.pem)
103*4724848cSchristos * leaf and subinterCA are in the untrusted list (untrusted.pem)
104*4724848cSchristos * bad is the certificate being verified (bad.pem)
105*4724848cSchristos *
106*4724848cSchristos * Versions vulnerable to CVE-2015-1793 will fail to detect that leaf has
107*4724848cSchristos * CA=FALSE, and will therefore incorrectly verify bad
108*4724848cSchristos *
109*4724848cSchristos */
test_alt_chains_cert_forgery(void)110*4724848cSchristos static int test_alt_chains_cert_forgery(void)
111*4724848cSchristos {
112*4724848cSchristos int ret = 0;
113*4724848cSchristos int i;
114*4724848cSchristos X509 *x = NULL;
115*4724848cSchristos STACK_OF(X509) *untrusted = NULL;
116*4724848cSchristos BIO *bio = NULL;
117*4724848cSchristos X509_STORE_CTX *sctx = NULL;
118*4724848cSchristos X509_STORE *store = NULL;
119*4724848cSchristos X509_LOOKUP *lookup = NULL;
120*4724848cSchristos
121*4724848cSchristos store = X509_STORE_new();
122*4724848cSchristos if (store == NULL)
123*4724848cSchristos goto err;
124*4724848cSchristos
125*4724848cSchristos lookup = X509_STORE_add_lookup(store, X509_LOOKUP_file());
126*4724848cSchristos if (lookup == NULL)
127*4724848cSchristos goto err;
128*4724848cSchristos if (!X509_LOOKUP_load_file(lookup, roots_f, X509_FILETYPE_PEM))
129*4724848cSchristos goto err;
130*4724848cSchristos
131*4724848cSchristos untrusted = load_certs_from_file(untrusted_f);
132*4724848cSchristos
133*4724848cSchristos if ((bio = BIO_new_file(bad_f, "r")) == NULL)
134*4724848cSchristos goto err;
135*4724848cSchristos
136*4724848cSchristos if ((x = PEM_read_bio_X509(bio, NULL, 0, NULL)) == NULL)
137*4724848cSchristos goto err;
138*4724848cSchristos
139*4724848cSchristos sctx = X509_STORE_CTX_new();
140*4724848cSchristos if (sctx == NULL)
141*4724848cSchristos goto err;
142*4724848cSchristos
143*4724848cSchristos if (!X509_STORE_CTX_init(sctx, store, x, untrusted))
144*4724848cSchristos goto err;
145*4724848cSchristos
146*4724848cSchristos i = X509_verify_cert(sctx);
147*4724848cSchristos
148*4724848cSchristos if (i != 0 || X509_STORE_CTX_get_error(sctx) != X509_V_ERR_INVALID_CA)
149*4724848cSchristos goto err;
150*4724848cSchristos
151*4724848cSchristos /* repeat with X509_V_FLAG_X509_STRICT */
152*4724848cSchristos X509_STORE_CTX_cleanup(sctx);
153*4724848cSchristos X509_STORE_set_flags(store, X509_V_FLAG_X509_STRICT);
154*4724848cSchristos
155*4724848cSchristos if (!X509_STORE_CTX_init(sctx, store, x, untrusted))
156*4724848cSchristos goto err;
157*4724848cSchristos
158*4724848cSchristos i = X509_verify_cert(sctx);
159*4724848cSchristos
160*4724848cSchristos if (i == 0 && X509_STORE_CTX_get_error(sctx) == X509_V_ERR_INVALID_CA)
161*4724848cSchristos /* This is the result we were expecting: Test passed */
162*4724848cSchristos ret = 1;
163*4724848cSchristos
164*4724848cSchristos err:
165*4724848cSchristos X509_STORE_CTX_free(sctx);
166*4724848cSchristos X509_free(x);
167*4724848cSchristos BIO_free(bio);
168*4724848cSchristos sk_X509_pop_free(untrusted, X509_free);
169*4724848cSchristos X509_STORE_free(store);
170*4724848cSchristos return ret;
171*4724848cSchristos }
172*4724848cSchristos
test_store_ctx(void)173*4724848cSchristos static int test_store_ctx(void)
174*4724848cSchristos {
175*4724848cSchristos X509_STORE_CTX *sctx = NULL;
176*4724848cSchristos X509 *x = NULL;
177*4724848cSchristos BIO *bio = NULL;
178*4724848cSchristos int testresult = 0, ret;
179*4724848cSchristos
180*4724848cSchristos bio = BIO_new_file(bad_f, "r");
181*4724848cSchristos if (bio == NULL)
182*4724848cSchristos goto err;
183*4724848cSchristos
184*4724848cSchristos x = PEM_read_bio_X509(bio, NULL, 0, NULL);
185*4724848cSchristos if (x == NULL)
186*4724848cSchristos goto err;
187*4724848cSchristos
188*4724848cSchristos sctx = X509_STORE_CTX_new();
189*4724848cSchristos if (sctx == NULL)
190*4724848cSchristos goto err;
191*4724848cSchristos
192*4724848cSchristos if (!X509_STORE_CTX_init(sctx, NULL, x, NULL))
193*4724848cSchristos goto err;
194*4724848cSchristos
195*4724848cSchristos /* Verifying a cert where we have no trusted certs should fail */
196*4724848cSchristos ret = X509_verify_cert(sctx);
197*4724848cSchristos
198*4724848cSchristos if (ret == 0) {
199*4724848cSchristos /* This is the result we were expecting: Test passed */
200*4724848cSchristos testresult = 1;
201*4724848cSchristos }
202*4724848cSchristos
203*4724848cSchristos err:
204*4724848cSchristos X509_STORE_CTX_free(sctx);
205*4724848cSchristos X509_free(x);
206*4724848cSchristos BIO_free(bio);
207*4724848cSchristos return testresult;
208*4724848cSchristos }
209*4724848cSchristos
test_self_signed(const char * filename,int expected)210*4724848cSchristos static int test_self_signed(const char *filename, int expected)
211*4724848cSchristos {
212*4724848cSchristos X509 *cert = load_cert_pem(filename);
213*4724848cSchristos STACK_OF(X509) *trusted = sk_X509_new_null();
214*4724848cSchristos X509_STORE_CTX *ctx = X509_STORE_CTX_new();
215*4724848cSchristos int ret;
216*4724848cSchristos
217*4724848cSchristos ret = TEST_ptr(cert)
218*4724848cSchristos && TEST_true(sk_X509_push(trusted, cert))
219*4724848cSchristos && TEST_true(X509_STORE_CTX_init(ctx, NULL, cert, NULL));
220*4724848cSchristos X509_STORE_CTX_set0_trusted_stack(ctx, trusted);
221*4724848cSchristos ret = ret && TEST_int_eq(X509_verify_cert(ctx), expected);
222*4724848cSchristos
223*4724848cSchristos X509_STORE_CTX_free(ctx);
224*4724848cSchristos sk_X509_free(trusted);
225*4724848cSchristos X509_free(cert);
226*4724848cSchristos return ret;
227*4724848cSchristos }
228*4724848cSchristos
test_self_signed_good(void)229*4724848cSchristos static int test_self_signed_good(void)
230*4724848cSchristos {
231*4724848cSchristos return test_self_signed(good_f, 1);
232*4724848cSchristos }
233*4724848cSchristos
test_self_signed_bad(void)234*4724848cSchristos static int test_self_signed_bad(void)
235*4724848cSchristos {
236*4724848cSchristos return test_self_signed(bad_f, 0);
237*4724848cSchristos }
238*4724848cSchristos
do_test_purpose(int purpose,int expected)239*4724848cSchristos static int do_test_purpose(int purpose, int expected)
240*4724848cSchristos {
241*4724848cSchristos X509 *eecert = load_cert_pem(ee_cert); /* may result in NULL */
242*4724848cSchristos X509 *untrcert = load_cert_pem(ca_cert);
243*4724848cSchristos X509 *trcert = load_cert_pem(sroot_cert);
244*4724848cSchristos STACK_OF(X509) *trusted = sk_X509_new_null();
245*4724848cSchristos STACK_OF(X509) *untrusted = sk_X509_new_null();
246*4724848cSchristos X509_STORE_CTX *ctx = X509_STORE_CTX_new();
247*4724848cSchristos int testresult = 0;
248*4724848cSchristos
249*4724848cSchristos if (!TEST_ptr(eecert)
250*4724848cSchristos || !TEST_ptr(untrcert)
251*4724848cSchristos || !TEST_ptr(trcert)
252*4724848cSchristos || !TEST_ptr(trusted)
253*4724848cSchristos || !TEST_ptr(untrusted)
254*4724848cSchristos || !TEST_ptr(ctx))
255*4724848cSchristos goto err;
256*4724848cSchristos
257*4724848cSchristos
258*4724848cSchristos if (!TEST_true(sk_X509_push(trusted, trcert)))
259*4724848cSchristos goto err;
260*4724848cSchristos trcert = NULL;
261*4724848cSchristos if (!TEST_true(sk_X509_push(untrusted, untrcert)))
262*4724848cSchristos goto err;
263*4724848cSchristos untrcert = NULL;
264*4724848cSchristos
265*4724848cSchristos if (!TEST_true(X509_STORE_CTX_init(ctx, NULL, eecert, untrusted)))
266*4724848cSchristos goto err;
267*4724848cSchristos
268*4724848cSchristos if (!TEST_true(X509_STORE_CTX_set_purpose(ctx, purpose)))
269*4724848cSchristos goto err;
270*4724848cSchristos
271*4724848cSchristos /*
272*4724848cSchristos * X509_STORE_CTX_set0_trusted_stack() is bady named. Despite the set0 name
273*4724848cSchristos * we are still responsible for freeing trusted after we have finished with
274*4724848cSchristos * it.
275*4724848cSchristos */
276*4724848cSchristos X509_STORE_CTX_set0_trusted_stack(ctx, trusted);
277*4724848cSchristos
278*4724848cSchristos if (!TEST_int_eq(X509_verify_cert(ctx), expected))
279*4724848cSchristos goto err;
280*4724848cSchristos
281*4724848cSchristos testresult = 1;
282*4724848cSchristos err:
283*4724848cSchristos sk_X509_pop_free(trusted, X509_free);
284*4724848cSchristos sk_X509_pop_free(untrusted, X509_free);
285*4724848cSchristos X509_STORE_CTX_free(ctx);
286*4724848cSchristos X509_free(eecert);
287*4724848cSchristos X509_free(untrcert);
288*4724848cSchristos X509_free(trcert);
289*4724848cSchristos return testresult;
290*4724848cSchristos }
291*4724848cSchristos
test_purpose_ssl_client(void)292*4724848cSchristos static int test_purpose_ssl_client(void)
293*4724848cSchristos {
294*4724848cSchristos return do_test_purpose(X509_PURPOSE_SSL_CLIENT, 0);
295*4724848cSchristos }
296*4724848cSchristos
test_purpose_ssl_server(void)297*4724848cSchristos static int test_purpose_ssl_server(void)
298*4724848cSchristos {
299*4724848cSchristos return do_test_purpose(X509_PURPOSE_SSL_SERVER, 1);
300*4724848cSchristos }
301*4724848cSchristos
test_purpose_any(void)302*4724848cSchristos static int test_purpose_any(void)
303*4724848cSchristos {
304*4724848cSchristos return do_test_purpose(X509_PURPOSE_ANY, 1);
305*4724848cSchristos }
306*4724848cSchristos
setup_tests(void)307*4724848cSchristos int setup_tests(void)
308*4724848cSchristos {
309*4724848cSchristos if (!TEST_ptr(certs_dir = test_get_argument(0))) {
310*4724848cSchristos TEST_error("usage: verify_extra_test certs-dir\n");
311*4724848cSchristos return 0;
312*4724848cSchristos }
313*4724848cSchristos
314*4724848cSchristos if (!TEST_ptr(roots_f = test_mk_file_path(certs_dir, "roots.pem"))
315*4724848cSchristos || !TEST_ptr(untrusted_f = test_mk_file_path(certs_dir, "untrusted.pem"))
316*4724848cSchristos || !TEST_ptr(bad_f = test_mk_file_path(certs_dir, "bad.pem"))
317*4724848cSchristos || !TEST_ptr(good_f = test_mk_file_path(certs_dir, "rootCA.pem"))
318*4724848cSchristos || !TEST_ptr(sroot_cert = test_mk_file_path(certs_dir, "sroot-cert.pem"))
319*4724848cSchristos || !TEST_ptr(ca_cert = test_mk_file_path(certs_dir, "ca-cert.pem"))
320*4724848cSchristos || !TEST_ptr(ee_cert = test_mk_file_path(certs_dir, "ee-cert.pem")))
321*4724848cSchristos goto err;
322*4724848cSchristos
323*4724848cSchristos ADD_TEST(test_alt_chains_cert_forgery);
324*4724848cSchristos ADD_TEST(test_store_ctx);
325*4724848cSchristos ADD_TEST(test_self_signed_good);
326*4724848cSchristos ADD_TEST(test_self_signed_bad);
327*4724848cSchristos ADD_TEST(test_purpose_ssl_client);
328*4724848cSchristos ADD_TEST(test_purpose_ssl_server);
329*4724848cSchristos ADD_TEST(test_purpose_any);
330*4724848cSchristos return 1;
331*4724848cSchristos err:
332*4724848cSchristos cleanup_tests();
333*4724848cSchristos return 0;
334*4724848cSchristos }
335*4724848cSchristos
cleanup_tests(void)336*4724848cSchristos void cleanup_tests(void)
337*4724848cSchristos {
338*4724848cSchristos OPENSSL_free(roots_f);
339*4724848cSchristos OPENSSL_free(untrusted_f);
340*4724848cSchristos OPENSSL_free(bad_f);
341*4724848cSchristos OPENSSL_free(good_f);
342*4724848cSchristos OPENSSL_free(sroot_cert);
343*4724848cSchristos OPENSSL_free(ca_cert);
344*4724848cSchristos OPENSSL_free(ee_cert);
345*4724848cSchristos }
346