1 // Copyright 2021 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "net/cert/internal/trust_store_win.h"
6
7 #include <memory>
8 #include <string_view>
9
10 #include "base/containers/to_vector.h"
11 #include "base/logging.h"
12 #include "base/memory/ptr_util.h"
13 #include "base/ranges/algorithm.h"
14 #include "base/strings/string_number_conversions.h"
15 #include "base/test/scoped_feature_list.h"
16 #include "base/win/wincrypt_shim.h"
17 #include "crypto/scoped_capi_types.h"
18 #include "net/base/features.h"
19 #include "net/cert/cert_net_fetcher.h"
20 #include "net/cert/internal/test_helpers.h"
21 #include "net/cert/x509_certificate.h"
22 #include "net/cert/x509_util.h"
23 #include "net/cert/x509_util_win.h"
24 #include "net/test/cert_test_util.h"
25 #include "net/test/test_data_directory.h"
26 #include "testing/gmock/include/gmock/gmock.h"
27 #include "testing/gtest/include/gtest/gtest.h"
28 #include "third_party/boringssl/src/include/openssl/pool.h"
29 #include "third_party/boringssl/src/pki/cert_errors.h"
30 #include "third_party/boringssl/src/pki/parsed_certificate.h"
31 #include "third_party/boringssl/src/pki/trust_store.h"
32
33 namespace net {
34
35 namespace {
36
ParseCertFromFile(std::string_view file_name,std::shared_ptr<const bssl::ParsedCertificate> * out_cert)37 ::testing::AssertionResult ParseCertFromFile(
38 std::string_view file_name,
39 std::shared_ptr<const bssl::ParsedCertificate>* out_cert) {
40 const scoped_refptr<X509Certificate> cert =
41 ImportCertFromFile(net::GetTestCertsDirectory(), file_name);
42 if (!cert) {
43 return ::testing::AssertionFailure() << "ImportCertFromFile failed";
44 }
45 bssl::CertErrors errors;
46 std::shared_ptr<const bssl::ParsedCertificate> parsed =
47 bssl::ParsedCertificate::Create(
48 bssl::UpRef(cert->cert_buffer()),
49 x509_util::DefaultParseCertificateOptions(), &errors);
50 if (!parsed) {
51 return ::testing::AssertionFailure()
52 << "bssl::ParseCertificate::Create failed:\n"
53 << errors.ToDebugString();
54 }
55 *out_cert = parsed;
56 return ::testing::AssertionSuccess();
57 }
58
59 class TrustStoreWinTest : public testing::Test {
60 public:
SetUp()61 void SetUp() override {
62 ASSERT_TRUE(ParseCertFromFile("multi-root-A-by-B.pem", &a_by_b_));
63 ASSERT_TRUE(ParseCertFromFile("multi-root-B-by-C.pem", &b_by_c_));
64 ASSERT_TRUE(ParseCertFromFile("multi-root-B-by-F.pem", &b_by_f_));
65 ASSERT_TRUE(ParseCertFromFile("multi-root-C-by-D.pem", &c_by_d_));
66 ASSERT_TRUE(ParseCertFromFile("multi-root-C-by-E.pem", &c_by_e_));
67 ASSERT_TRUE(ParseCertFromFile("multi-root-D-by-D.pem", &d_by_d_));
68 ASSERT_TRUE(ParseCertFromFile("multi-root-E-by-E.pem", &e_by_e_));
69 ASSERT_TRUE(ParseCertFromFile("multi-root-F-by-E.pem", &f_by_e_));
70 }
71
ExpectedTrustForAnchor() const72 bssl::CertificateTrust ExpectedTrustForAnchor() const {
73 return bssl::CertificateTrust::ForTrustAnchorOrLeaf()
74 .WithEnforceAnchorExpiry()
75 .WithEnforceAnchorConstraints()
76 .WithRequireLeafSelfSigned();
77 }
78
ExpectedTrustForPeer() const79 bssl::CertificateTrust ExpectedTrustForPeer() const {
80 return bssl::CertificateTrust::ForTrustedLeaf().WithRequireLeafSelfSigned();
81 }
82
83 // Returns true if |cert| successfully added to store, false otherwise.
AddToStore(HCERTSTORE store,std::shared_ptr<const bssl::ParsedCertificate> cert)84 bool AddToStore(HCERTSTORE store,
85 std::shared_ptr<const bssl::ParsedCertificate> cert) {
86 crypto::ScopedPCCERT_CONTEXT os_cert(CertCreateCertificateContext(
87 X509_ASN_ENCODING, CRYPTO_BUFFER_data(cert->cert_buffer()),
88 CRYPTO_BUFFER_len(cert->cert_buffer())));
89 return CertAddCertificateContextToStore(store, os_cert.get(),
90 CERT_STORE_ADD_ALWAYS, nullptr);
91 }
92
93 // Returns true if cert at file_name successfully added to store with
94 // restricted usage, false otherwise.
AddToStoreWithEKURestriction(HCERTSTORE store,std::shared_ptr<const bssl::ParsedCertificate> cert,LPCSTR usage_identifier)95 bool AddToStoreWithEKURestriction(
96 HCERTSTORE store,
97 std::shared_ptr<const bssl::ParsedCertificate> cert,
98 LPCSTR usage_identifier) {
99 crypto::ScopedPCCERT_CONTEXT os_cert(CertCreateCertificateContext(
100 X509_ASN_ENCODING, CRYPTO_BUFFER_data(cert->cert_buffer()),
101 CRYPTO_BUFFER_len(cert->cert_buffer())));
102
103 CERT_ENHKEY_USAGE usage;
104 memset(&usage, 0, sizeof(usage));
105 if (!CertSetEnhancedKeyUsage(os_cert.get(), &usage)) {
106 return false;
107 }
108 if (usage_identifier) {
109 if (!CertAddEnhancedKeyUsageIdentifier(os_cert.get(), usage_identifier)) {
110 return false;
111 }
112 }
113 return !!CertAddCertificateContextToStore(store, os_cert.get(),
114 CERT_STORE_ADD_ALWAYS, nullptr);
115 }
116
CreateTrustStoreWin()117 std::unique_ptr<TrustStoreWin> CreateTrustStoreWin() {
118 return TrustStoreWin::CreateForTesting(std::move(stores_));
119 }
120
121 // The cert stores that will be used to create the trust store. These handles
122 // will be null after CreateTrustStoreWin() is called.
123 TrustStoreWin::CertStores stores_ =
124 TrustStoreWin::CertStores::CreateInMemoryStoresForTesting();
125
126 std::shared_ptr<const bssl::ParsedCertificate> a_by_b_, b_by_c_, b_by_f_,
127 c_by_d_, c_by_e_, d_by_d_, e_by_e_, f_by_e_;
128 };
129
TEST_F(TrustStoreWinTest,GetTrustInitializationError)130 TEST_F(TrustStoreWinTest, GetTrustInitializationError) {
131 // Simulate an initialization error by using null stores.
132 std::unique_ptr<TrustStoreWin> trust_store_win =
133 TrustStoreWin::CreateForTesting(
134 TrustStoreWin::CertStores::CreateNullStoresForTesting());
135 ASSERT_TRUE(trust_store_win);
136 bssl::CertificateTrust trust = trust_store_win->GetTrust(d_by_d_.get());
137 EXPECT_EQ(bssl::CertificateTrust::ForUnspecified().ToDebugString(),
138 trust.ToDebugString());
139 }
140
TEST_F(TrustStoreWinTest,GetTrust)141 TEST_F(TrustStoreWinTest, GetTrust) {
142 ASSERT_TRUE(AddToStore(stores_.roots.get(), d_by_d_));
143 ASSERT_TRUE(AddToStore(stores_.intermediates.get(), c_by_d_));
144 ASSERT_TRUE(AddToStore(stores_.trusted_people.get(), a_by_b_));
145
146 std::unique_ptr<TrustStoreWin> trust_store_win = CreateTrustStoreWin();
147 ASSERT_TRUE(trust_store_win);
148
149 // Explicitly trusted root should be trusted.
150 EXPECT_EQ(ExpectedTrustForAnchor().ToDebugString(),
151 trust_store_win->GetTrust(d_by_d_.get()).ToDebugString());
152
153 // Explicitly trusted peer should be trusted.
154 // (Although it wouldn't actually verify since it's not self-signed but has
155 // require_leaf_selfsigned set. That doesn't matter for the purposes of these
156 // tests.)
157 EXPECT_EQ(ExpectedTrustForPeer().ToDebugString(),
158 trust_store_win->GetTrust(a_by_b_.get()).ToDebugString());
159
160 // Intermediate for path building should not be trusted.
161 EXPECT_EQ(bssl::CertificateTrust::ForUnspecified().ToDebugString(),
162 trust_store_win->GetTrust(c_by_d_.get()).ToDebugString());
163
164 // Unknown roots should not be trusted (e.g. just because they're
165 // self-signed doesn't make them a root)
166 EXPECT_EQ(bssl::CertificateTrust::ForUnspecified().ToDebugString(),
167 trust_store_win->GetTrust(e_by_e_.get()).ToDebugString());
168 }
169
170 // This test has a special TrustStoreWin setup with restricted EKU usages.
171 // Specifically, the only certs set up in the root store are set up
172 // as follows:
173 //
174 // - kMultiRootDByD: only has szOID_PKIX_KP_SERVER_AUTH EKU set
175 // - kMultiRootEByE: only has szOID_PKIX_KP_CLIENT_AUTH set
176 // - kMultiRootCByE: only has szOID_ANY_ENHANCED_KEY_USAGE set
177 // - kMultiRootCByD: no EKU usages set
TEST_F(TrustStoreWinTest,GetTrustRestrictedEKU)178 TEST_F(TrustStoreWinTest, GetTrustRestrictedEKU) {
179 ASSERT_TRUE(AddToStoreWithEKURestriction(stores_.roots.get(), d_by_d_,
180 szOID_PKIX_KP_SERVER_AUTH));
181 ASSERT_TRUE(AddToStoreWithEKURestriction(stores_.roots.get(), e_by_e_,
182 szOID_PKIX_KP_CLIENT_AUTH));
183 ASSERT_TRUE(AddToStoreWithEKURestriction(stores_.roots.get(), c_by_e_,
184 szOID_ANY_ENHANCED_KEY_USAGE));
185 ASSERT_TRUE(
186 AddToStoreWithEKURestriction(stores_.roots.get(), c_by_d_, nullptr));
187
188 std::unique_ptr<TrustStoreWin> trust_store_win = CreateTrustStoreWin();
189 ASSERT_TRUE(trust_store_win);
190
191 // Root cert with EKU szOID_PKIX_KP_SERVER_AUTH usage set should be
192 // trusted.
193 EXPECT_EQ(ExpectedTrustForAnchor().ToDebugString(),
194 trust_store_win->GetTrust(d_by_d_.get()).ToDebugString());
195
196 // Root cert with EKU szOID_ANY_ENHANCED_KEY_USAGE usage set should be
197 // trusted.
198 EXPECT_EQ(ExpectedTrustForAnchor().ToDebugString(),
199 trust_store_win->GetTrust(c_by_e_.get()).ToDebugString());
200
201 // Root cert with EKU szOID_PKIX_KP_CLIENT_AUTH does not allow usage of
202 // cert for server auth, return UNSPECIFIED.
203 EXPECT_EQ(bssl::CertificateTrust::ForUnspecified().ToDebugString(),
204 trust_store_win->GetTrust(e_by_e_.get()).ToDebugString());
205
206 // Root cert with no EKU usages, return UNSPECIFIED.
207 EXPECT_EQ(bssl::CertificateTrust::ForUnspecified().ToDebugString(),
208 trust_store_win->GetTrust(c_by_d_.get()).ToDebugString());
209
210 // Unknown cert has unspecified trust.
211 EXPECT_EQ(bssl::CertificateTrust::ForUnspecified().ToDebugString(),
212 trust_store_win->GetTrust(f_by_e_.get()).ToDebugString());
213 }
214
215 // Same as GetTrustRestrictedEKU but for the Trusted People store.
TEST_F(TrustStoreWinTest,GetTrustTrustedPeopleRestrictedEKU)216 TEST_F(TrustStoreWinTest, GetTrustTrustedPeopleRestrictedEKU) {
217 ASSERT_TRUE(AddToStoreWithEKURestriction(stores_.trusted_people.get(),
218 d_by_d_, szOID_PKIX_KP_SERVER_AUTH));
219 ASSERT_TRUE(AddToStoreWithEKURestriction(stores_.trusted_people.get(),
220 e_by_e_, szOID_PKIX_KP_CLIENT_AUTH));
221 ASSERT_TRUE(AddToStoreWithEKURestriction(
222 stores_.trusted_people.get(), c_by_e_, szOID_ANY_ENHANCED_KEY_USAGE));
223 ASSERT_TRUE(AddToStoreWithEKURestriction(stores_.trusted_people.get(),
224 c_by_d_, nullptr));
225
226 std::unique_ptr<TrustStoreWin> trust_store_win = CreateTrustStoreWin();
227 ASSERT_TRUE(trust_store_win);
228
229 // TrustedPeople cert with EKU szOID_PKIX_KP_SERVER_AUTH usage set should be
230 // trusted.
231 EXPECT_EQ(ExpectedTrustForPeer().ToDebugString(),
232 trust_store_win->GetTrust(d_by_d_.get()).ToDebugString());
233
234 // TrustedPeople cert with EKU szOID_ANY_ENHANCED_KEY_USAGE usage set should
235 // be trusted.
236 EXPECT_EQ(ExpectedTrustForPeer().ToDebugString(),
237 trust_store_win->GetTrust(c_by_e_.get()).ToDebugString());
238
239 // TrustedPeople cert with EKU szOID_PKIX_KP_CLIENT_AUTH does not allow usage
240 // of cert for server auth, return UNSPECIFIED.
241 EXPECT_EQ(bssl::CertificateTrust::ForUnspecified().ToDebugString(),
242 trust_store_win->GetTrust(e_by_e_.get()).ToDebugString());
243
244 // TrustedPeople cert with no EKU usages, return UNSPECIFIED.
245 EXPECT_EQ(bssl::CertificateTrust::ForUnspecified().ToDebugString(),
246 trust_store_win->GetTrust(c_by_d_.get()).ToDebugString());
247
248 // Unknown cert has unspecified trust.
249 EXPECT_EQ(bssl::CertificateTrust::ForUnspecified().ToDebugString(),
250 trust_store_win->GetTrust(f_by_e_.get()).ToDebugString());
251 }
252
253 // If duplicate certs are added to the root store with different EKU usages,
254 // the cert should be trusted if any one of the usages is valid.
255 // Root store set up as follows:
256 //
257 // - kMultiRootDByD: only has szOID_PKIX_KP_CLIENT_AUTH EKU set
258 // - kMultiRootDByD (dupe): only has szOID_PKIX_KP_SERVER_AUTH set
259 // - kMultiRootDByD (dupe 2): no EKU usages set
TEST_F(TrustStoreWinTest,GetTrustRestrictedEKUDuplicateCerts)260 TEST_F(TrustStoreWinTest, GetTrustRestrictedEKUDuplicateCerts) {
261 ASSERT_TRUE(AddToStoreWithEKURestriction(stores_.roots.get(), d_by_d_,
262 szOID_PKIX_KP_CLIENT_AUTH));
263 ASSERT_TRUE(AddToStoreWithEKURestriction(stores_.roots.get(), d_by_d_,
264 szOID_PKIX_KP_SERVER_AUTH));
265 ASSERT_TRUE(
266 AddToStoreWithEKURestriction(stores_.roots.get(), d_by_d_, nullptr));
267
268 std::unique_ptr<TrustStoreWin> trust_store_win = CreateTrustStoreWin();
269 ASSERT_TRUE(trust_store_win);
270
271 // One copy of the Root cert is trusted for TLS Server Auth.
272 EXPECT_EQ(ExpectedTrustForAnchor().ToDebugString(),
273 trust_store_win->GetTrust(d_by_d_.get()).ToDebugString());
274 }
275
276 // Test that disallowed certs will be distrusted regardless of EKU settings.
TEST_F(TrustStoreWinTest,GetTrustDisallowedCerts)277 TEST_F(TrustStoreWinTest, GetTrustDisallowedCerts) {
278 ASSERT_TRUE(AddToStore(stores_.roots.get(), d_by_d_));
279 ASSERT_TRUE(AddToStore(stores_.roots.get(), e_by_e_));
280 ASSERT_TRUE(AddToStore(stores_.trusted_people.get(), f_by_e_));
281
282 ASSERT_TRUE(AddToStoreWithEKURestriction(stores_.disallowed.get(), d_by_d_,
283 szOID_PKIX_KP_CLIENT_AUTH));
284 ASSERT_TRUE(AddToStore(stores_.disallowed.get(), e_by_e_));
285 ASSERT_TRUE(AddToStore(stores_.disallowed.get(), f_by_e_));
286
287 std::unique_ptr<TrustStoreWin> trust_store_win = CreateTrustStoreWin();
288 ASSERT_TRUE(trust_store_win);
289
290 // E-by-E is in both root and distrusted store. Distrust takes precedence.
291 EXPECT_EQ(bssl::CertificateTrust::ForDistrusted().ToDebugString(),
292 trust_store_win->GetTrust(e_by_e_.get()).ToDebugString());
293
294 // F-by-E is in both trusted people and distrusted store. Distrust takes
295 // precedence.
296 EXPECT_EQ(bssl::CertificateTrust::ForDistrusted().ToDebugString(),
297 trust_store_win->GetTrust(f_by_e_.get()).ToDebugString());
298
299 // D-by-D is in root and in distrusted but without szOID_PKIX_KP_SERVER_AUTH
300 // set. It should still be distrusted since the EKU settings aren't checked
301 // on distrust.
302 EXPECT_EQ(bssl::CertificateTrust::ForDistrusted().ToDebugString(),
303 trust_store_win->GetTrust(d_by_d_.get()).ToDebugString());
304 }
305
306 MATCHER_P(ParsedCertEq, expected_cert, "") {
307 return arg && expected_cert &&
308 base::ranges::equal(arg->der_cert(), expected_cert->der_cert());
309 }
310
TEST_F(TrustStoreWinTest,GetIssuersInitializationError)311 TEST_F(TrustStoreWinTest, GetIssuersInitializationError) {
312 // Simulate an initialization error by using null stores.
313 std::unique_ptr<TrustStoreWin> trust_store_win =
314 TrustStoreWin::CreateForTesting(
315 TrustStoreWin::CertStores::CreateNullStoresForTesting());
316 ASSERT_TRUE(trust_store_win);
317 bssl::ParsedCertificateList issuers;
318 trust_store_win->SyncGetIssuersOf(b_by_f_.get(), &issuers);
319 ASSERT_EQ(0U, issuers.size());
320 }
321
TEST_F(TrustStoreWinTest,GetIssuers)322 TEST_F(TrustStoreWinTest, GetIssuers) {
323 ASSERT_TRUE(AddToStore(stores_.roots.get(), d_by_d_));
324
325 ASSERT_TRUE(AddToStore(stores_.intermediates.get(), c_by_d_));
326 ASSERT_TRUE(AddToStore(stores_.intermediates.get(), c_by_e_));
327 ASSERT_TRUE(AddToStore(stores_.intermediates.get(), f_by_e_));
328
329 ASSERT_TRUE(AddToStore(stores_.trusted_people.get(), b_by_c_));
330
331 ASSERT_TRUE(AddToStore(stores_.disallowed.get(), b_by_f_));
332
333 std::unique_ptr<TrustStoreWin> trust_store_win = CreateTrustStoreWin();
334
335 // No matching issuer (Trusted People and Disallowed are not consulted).
336 {
337 bssl::ParsedCertificateList issuers;
338 trust_store_win->SyncGetIssuersOf(a_by_b_.get(), &issuers);
339 ASSERT_EQ(0U, issuers.size());
340 }
341
342 // Single matching issuer found in intermediates.
343 {
344 bssl::ParsedCertificateList issuers;
345 trust_store_win->SyncGetIssuersOf(b_by_f_.get(), &issuers);
346 ASSERT_EQ(1U, issuers.size());
347 EXPECT_THAT(issuers, testing::UnorderedElementsAre(ParsedCertEq(f_by_e_)));
348 }
349
350 // Single matching issuer found in roots.
351 {
352 bssl::ParsedCertificateList issuers;
353 trust_store_win->SyncGetIssuersOf(d_by_d_.get(), &issuers);
354 ASSERT_EQ(1U, issuers.size());
355 EXPECT_THAT(issuers, testing::UnorderedElementsAre(ParsedCertEq(d_by_d_)));
356 }
357
358 // Multiple issuers found.
359 {
360 bssl::ParsedCertificateList issuers;
361 trust_store_win->SyncGetIssuersOf(b_by_c_.get(), &issuers);
362 ASSERT_EQ(2U, issuers.size());
363 EXPECT_THAT(issuers, testing::UnorderedElementsAre(ParsedCertEq(c_by_d_),
364 ParsedCertEq(c_by_e_)));
365 }
366 }
367
368 MATCHER_P(CertWithTrustEq, expected_cert_with_trust, "") {
369 return arg.cert_bytes == expected_cert_with_trust.cert_bytes &&
370 arg.trust.ToDebugString() ==
371 expected_cert_with_trust.trust.ToDebugString();
372 }
373
TEST_F(TrustStoreWinTest,GetAllUserAddedCerts)374 TEST_F(TrustStoreWinTest, GetAllUserAddedCerts) {
375 ASSERT_TRUE(AddToStore(stores_.roots.get(), d_by_d_));
376 ASSERT_TRUE(
377 AddToStoreWithEKURestriction(stores_.roots.get(), c_by_d_, nullptr));
378
379 ASSERT_TRUE(AddToStore(stores_.intermediates.get(), c_by_e_));
380 ASSERT_TRUE(AddToStore(stores_.intermediates.get(), f_by_e_));
381
382 ASSERT_TRUE(AddToStore(stores_.trusted_people.get(), b_by_c_));
383
384 ASSERT_TRUE(AddToStore(stores_.disallowed.get(), b_by_f_));
385
386 std::unique_ptr<TrustStoreWin> trust_store_win = CreateTrustStoreWin();
387
388 std::vector<net::PlatformTrustStore::CertWithTrust> certs =
389 trust_store_win->GetAllUserAddedCerts();
390 ASSERT_EQ(5U, certs.size());
391 EXPECT_THAT(certs, testing::UnorderedElementsAre(
392 CertWithTrustEq(net::PlatformTrustStore::CertWithTrust(
393 base::ToVector(d_by_d_->der_cert()),
394 bssl::CertificateTrust::ForTrustAnchorOrLeaf()
395 .WithEnforceAnchorExpiry()
396 .WithEnforceAnchorConstraints()
397 .WithRequireLeafSelfSigned())),
398 CertWithTrustEq(net::PlatformTrustStore::CertWithTrust(
399 base::ToVector(c_by_e_->der_cert()),
400 bssl::CertificateTrust::ForUnspecified())),
401 CertWithTrustEq(net::PlatformTrustStore::CertWithTrust(
402 base::ToVector(f_by_e_->der_cert()),
403 bssl::CertificateTrust::ForUnspecified())),
404 CertWithTrustEq(net::PlatformTrustStore::CertWithTrust(
405 base::ToVector(b_by_c_->der_cert()),
406 bssl::CertificateTrust::ForTrustedLeaf()
407 .WithRequireLeafSelfSigned())),
408 CertWithTrustEq(net::PlatformTrustStore::CertWithTrust(
409 base::ToVector(b_by_f_->der_cert()),
410 bssl::CertificateTrust::ForDistrusted()))));
411 }
412
413 } // namespace
414 } // namespace net
415