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