]>
Commit | Line | Data |
---|---|---|
593e9c63 | 1 | /* |
4333b89f | 2 | * Copyright 2015-2021 The OpenSSL Project Authors. All Rights Reserved. |
593e9c63 | 3 | * |
909f1a2e | 4 | * Licensed under the Apache License 2.0 (the "License"). You may not use |
440e5d80 RS |
5 | * this file except in compliance with the License. You can obtain a copy |
6 | * in the file LICENSE in the source distribution or at | |
7 | * https://www.openssl.org/source/license.html | |
593e9c63 MC |
8 | */ |
9 | ||
10 | #include <stdio.h> | |
ccf45361 | 11 | #include <string.h> |
593e9c63 MC |
12 | #include <openssl/crypto.h> |
13 | #include <openssl/bio.h> | |
14 | #include <openssl/x509.h> | |
15 | #include <openssl/pem.h> | |
16 | #include <openssl/err.h> | |
4afc6060 | 17 | #include "testutil.h" |
593e9c63 | 18 | |
0d8dbb52 | 19 | static const char *root_f; |
ad887416 P |
20 | static const char *roots_f; |
21 | static const char *untrusted_f; | |
22 | static const char *bad_f; | |
bc42bd62 | 23 | static const char *req_f; |
ad887416 | 24 | |
0b7368dd | 25 | #define load_cert_from_file(file) load_cert_pem(file, NULL) |
593e9c63 | 26 | |
4dd00918 | 27 | /*- |
593e9c63 MC |
28 | * Test for CVE-2015-1793 (Alternate Chains Certificate Forgery) |
29 | * | |
30 | * Chain is as follows: | |
31 | * | |
32 | * rootCA (self-signed) | |
33 | * | | |
34 | * interCA | |
35 | * | | |
36 | * subinterCA subinterCA (self-signed) | |
37 | * | | | |
38 | * leaf ------------------ | |
39 | * | | |
40 | * bad | |
41 | * | |
42 | * rootCA, interCA, subinterCA, subinterCA (ss) all have CA=TRUE | |
43 | * leaf and bad have CA=FALSE | |
44 | * | |
45 | * subinterCA and subinterCA (ss) have the same subject name and keys | |
46 | * | |
47 | * interCA (but not rootCA) and subinterCA (ss) are in the trusted store | |
48 | * (roots.pem) | |
49 | * leaf and subinterCA are in the untrusted list (untrusted.pem) | |
50 | * bad is the certificate being verified (bad.pem) | |
51 | * | |
52 | * Versions vulnerable to CVE-2015-1793 will fail to detect that leaf has | |
53 | * CA=FALSE, and will therefore incorrectly verify bad | |
54 | * | |
55 | */ | |
ad887416 | 56 | static int test_alt_chains_cert_forgery(void) |
593e9c63 MC |
57 | { |
58 | int ret = 0; | |
59 | int i; | |
60 | X509 *x = NULL; | |
61 | STACK_OF(X509) *untrusted = NULL; | |
593e9c63 MC |
62 | X509_STORE_CTX *sctx = NULL; |
63 | X509_STORE *store = NULL; | |
64 | X509_LOOKUP *lookup = NULL; | |
65 | ||
66 | store = X509_STORE_new(); | |
67 | if (store == NULL) | |
68 | goto err; | |
69 | ||
70 | lookup = X509_STORE_add_lookup(store, X509_LOOKUP_file()); | |
71 | if (lookup == NULL) | |
72 | goto err; | |
28b86f31 | 73 | if (!X509_LOOKUP_load_file(lookup, roots_f, X509_FILETYPE_PEM)) |
593e9c63 MC |
74 | goto err; |
75 | ||
0b7368dd | 76 | untrusted = load_certs_pem(untrusted_f); |
593e9c63 | 77 | |
0d8dbb52 | 78 | if ((x = load_cert_from_file(bad_f)) == NULL) |
593e9c63 MC |
79 | goto err; |
80 | ||
81 | sctx = X509_STORE_CTX_new(); | |
82 | if (sctx == NULL) | |
83 | goto err; | |
84 | ||
85 | if (!X509_STORE_CTX_init(sctx, store, x, untrusted)) | |
86 | goto err; | |
87 | ||
88 | i = X509_verify_cert(sctx); | |
89 | ||
e8aa8b6c | 90 | if (i == 0 && X509_STORE_CTX_get_error(sctx) == X509_V_ERR_INVALID_CA) { |
593e9c63 MC |
91 | /* This is the result we were expecting: Test passed */ |
92 | ret = 1; | |
93 | } | |
94 | err: | |
95 | X509_STORE_CTX_free(sctx); | |
96 | X509_free(x); | |
79b2a2f2 | 97 | OSSL_STACK_OF_X509_free(untrusted); |
593e9c63 | 98 | X509_STORE_free(store); |
593e9c63 MC |
99 | return ret; |
100 | } | |
101 | ||
a43ce58f SL |
102 | OPT_TEST_DECLARE_USAGE("roots.pem untrusted.pem bad.pem\n") |
103 | ||
fda127be | 104 | static int test_distinguishing_id(void) |
ccf45361 | 105 | { |
ccf45361 | 106 | X509 *x = NULL; |
ccf45361 PY |
107 | int ret = 0; |
108 | ASN1_OCTET_STRING *v = NULL, *v2 = NULL; | |
fda127be | 109 | char *distid = "this is an ID"; |
ccf45361 | 110 | |
0d8dbb52 | 111 | x = load_cert_from_file(bad_f); |
ccf45361 PY |
112 | if (x == NULL) |
113 | goto err; | |
114 | ||
115 | v = ASN1_OCTET_STRING_new(); | |
116 | if (v == NULL) | |
117 | goto err; | |
118 | ||
fda127be RL |
119 | if (!ASN1_OCTET_STRING_set(v, (unsigned char *)distid, |
120 | (int)strlen(distid))) { | |
ccf45361 PY |
121 | ASN1_OCTET_STRING_free(v); |
122 | goto err; | |
123 | } | |
124 | ||
fda127be | 125 | X509_set0_distinguishing_id(x, v); |
ccf45361 | 126 | |
fda127be | 127 | v2 = X509_get0_distinguishing_id(x); |
ccf45361 PY |
128 | if (!TEST_ptr(v2) |
129 | || !TEST_int_eq(ASN1_OCTET_STRING_cmp(v, v2), 0)) | |
130 | goto err; | |
131 | ||
132 | ret = 1; | |
133 | err: | |
134 | X509_free(x); | |
ccf45361 PY |
135 | return ret; |
136 | } | |
bc42bd62 | 137 | |
fda127be | 138 | static int test_req_distinguishing_id(void) |
bc42bd62 | 139 | { |
bc42bd62 PY |
140 | X509_REQ *x = NULL; |
141 | BIO *bio = NULL; | |
142 | int ret = 0; | |
143 | ASN1_OCTET_STRING *v = NULL, *v2 = NULL; | |
fda127be | 144 | char *distid = "this is an ID"; |
bc42bd62 PY |
145 | |
146 | bio = BIO_new_file(req_f, "r"); | |
147 | if (bio == NULL) | |
148 | goto err; | |
149 | ||
150 | x = PEM_read_bio_X509_REQ(bio, NULL, 0, NULL); | |
151 | if (x == NULL) | |
152 | goto err; | |
153 | ||
154 | v = ASN1_OCTET_STRING_new(); | |
155 | if (v == NULL) | |
156 | goto err; | |
157 | ||
fda127be RL |
158 | if (!ASN1_OCTET_STRING_set(v, (unsigned char *)distid, |
159 | (int)strlen(distid))) { | |
bc42bd62 PY |
160 | ASN1_OCTET_STRING_free(v); |
161 | goto err; | |
162 | } | |
163 | ||
fda127be | 164 | X509_REQ_set0_distinguishing_id(x, v); |
bc42bd62 | 165 | |
fda127be | 166 | v2 = X509_REQ_get0_distinguishing_id(x); |
bc42bd62 PY |
167 | if (!TEST_ptr(v2) |
168 | || !TEST_int_eq(ASN1_OCTET_STRING_cmp(v, v2), 0)) | |
169 | goto err; | |
170 | ||
171 | ret = 1; | |
172 | err: | |
173 | X509_REQ_free(x); | |
174 | BIO_free(bio); | |
175 | return ret; | |
176 | } | |
ccf45361 | 177 | |
4dd00918 | 178 | static int test_self_signed(const char *filename, int use_trusted, int expected) |
0d8dbb52 | 179 | { |
1c0eede9 | 180 | X509 *cert = load_cert_from_file(filename); /* may result in NULL */ |
4dd00918 DDO |
181 | STACK_OF(X509) *trusted = sk_X509_new_null(); |
182 | X509_STORE_CTX *ctx = X509_STORE_CTX_new(); | |
0d8dbb52 DDO |
183 | int ret; |
184 | ||
0d8dbb52 | 185 | ret = TEST_int_eq(X509_self_signed(cert, 1), expected); |
4dd00918 DDO |
186 | |
187 | if (cert != NULL) { | |
188 | if (use_trusted) | |
189 | ret = ret && TEST_true(sk_X509_push(trusted, cert)); | |
190 | ret = ret && TEST_true(X509_STORE_CTX_init(ctx, NULL, cert, NULL)); | |
191 | X509_STORE_CTX_set0_trusted_stack(ctx, trusted); | |
192 | ret = ret && TEST_int_eq(X509_verify_cert(ctx), expected); | |
193 | } | |
194 | ||
195 | X509_STORE_CTX_free(ctx); | |
196 | sk_X509_free(trusted); | |
0d8dbb52 DDO |
197 | X509_free(cert); |
198 | return ret; | |
199 | } | |
200 | ||
201 | static int test_self_signed_good(void) | |
202 | { | |
4dd00918 | 203 | return test_self_signed(root_f, 1, 1); |
0d8dbb52 DDO |
204 | } |
205 | ||
206 | static int test_self_signed_bad(void) | |
207 | { | |
4dd00918 | 208 | return test_self_signed(bad_f, 1, 0); |
0d8dbb52 DDO |
209 | } |
210 | ||
211 | static int test_self_signed_error(void) | |
212 | { | |
4dd00918 DDO |
213 | return test_self_signed("nonexistent file name", 1, -1); |
214 | } | |
215 | ||
216 | static int test_store_ctx(void) | |
217 | { | |
218 | /* Verifying a cert where we have no trusted certs should fail */ | |
219 | return test_self_signed(bad_f, 0, 0); | |
0d8dbb52 DDO |
220 | } |
221 | ||
ad887416 | 222 | int setup_tests(void) |
593e9c63 | 223 | { |
8d242823 MC |
224 | if (!test_skip_common_options()) { |
225 | TEST_error("Error parsing test options\n"); | |
226 | return 0; | |
227 | } | |
228 | ||
0d8dbb52 DDO |
229 | if (!TEST_ptr(root_f = test_get_argument(0)) |
230 | || !TEST_ptr(roots_f = test_get_argument(1)) | |
231 | || !TEST_ptr(untrusted_f = test_get_argument(2)) | |
232 | || !TEST_ptr(bad_f = test_get_argument(3)) | |
233 | || !TEST_ptr(req_f = test_get_argument(4))) | |
ad887416 | 234 | return 0; |
593e9c63 | 235 | |
ad887416 | 236 | ADD_TEST(test_alt_chains_cert_forgery); |
7f6dfa19 | 237 | ADD_TEST(test_store_ctx); |
fda127be RL |
238 | ADD_TEST(test_distinguishing_id); |
239 | ADD_TEST(test_req_distinguishing_id); | |
0d8dbb52 DDO |
240 | ADD_TEST(test_self_signed_good); |
241 | ADD_TEST(test_self_signed_bad); | |
242 | ADD_TEST(test_self_signed_error); | |
ad887416 | 243 | return 1; |
593e9c63 | 244 | } |