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