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/logging.h"
11 #include "base/memory/ptr_util.h"
12 #include "base/ranges/algorithm.h"
13 #include "base/strings/string_number_conversions.h"
14 #include "base/test/scoped_feature_list.h"
15 #include "base/win/wincrypt_shim.h"
16 #include "crypto/scoped_capi_types.h"
17 #include "net/base/features.h"
18 #include "net/cert/cert_net_fetcher.h"
19 #include "net/cert/internal/test_helpers.h"
20 #include "net/cert/internal/trust_store_features.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
60 : public testing::TestWithParam<std::tuple<bool, bool>> {
61 public:
TrustStoreWinTest()62 TrustStoreWinTest()
63 : scoped_enforce_local_anchor_constraints_(
64 ExpectedEnforceLocalAnchorConstraintsEnabled()) {
65 if (ExpectedTrustedLeafSupportEnabled()) {
66 feature_list_.InitAndEnableFeature(
67 features::kTrustStoreTrustedLeafSupport);
68 } else {
69 feature_list_.InitAndDisableFeature(
70 features::kTrustStoreTrustedLeafSupport);
71 }
72 }
73
SetUp()74 void SetUp() override {
75 ASSERT_TRUE(ParseCertFromFile("multi-root-A-by-B.pem", &a_by_b_));
76 ASSERT_TRUE(ParseCertFromFile("multi-root-B-by-C.pem", &b_by_c_));
77 ASSERT_TRUE(ParseCertFromFile("multi-root-B-by-F.pem", &b_by_f_));
78 ASSERT_TRUE(ParseCertFromFile("multi-root-C-by-D.pem", &c_by_d_));
79 ASSERT_TRUE(ParseCertFromFile("multi-root-C-by-E.pem", &c_by_e_));
80 ASSERT_TRUE(ParseCertFromFile("multi-root-D-by-D.pem", &d_by_d_));
81 ASSERT_TRUE(ParseCertFromFile("multi-root-E-by-E.pem", &e_by_e_));
82 ASSERT_TRUE(ParseCertFromFile("multi-root-F-by-E.pem", &f_by_e_));
83 }
84
ExpectedTrustedLeafSupportEnabled() const85 bool ExpectedTrustedLeafSupportEnabled() const {
86 return std::get<0>(GetParam());
87 }
88
ExpectedEnforceLocalAnchorConstraintsEnabled() const89 bool ExpectedEnforceLocalAnchorConstraintsEnabled() const {
90 return std::get<1>(GetParam());
91 }
92
ExpectedTrustForAnchor() const93 bssl::CertificateTrust ExpectedTrustForAnchor() const {
94 if (ExpectedTrustedLeafSupportEnabled()) {
95 return bssl::CertificateTrust::ForTrustAnchorOrLeaf()
96 .WithEnforceAnchorExpiry()
97 .WithEnforceAnchorConstraints(
98 ExpectedEnforceLocalAnchorConstraintsEnabled())
99 .WithRequireLeafSelfSigned();
100 } else {
101 return bssl::CertificateTrust::ForTrustAnchor()
102 .WithEnforceAnchorExpiry()
103 .WithEnforceAnchorConstraints(
104 ExpectedEnforceLocalAnchorConstraintsEnabled());
105 }
106 }
107
ExpectedTrustForPeer() const108 bssl::CertificateTrust ExpectedTrustForPeer() const {
109 if (ExpectedTrustedLeafSupportEnabled()) {
110 return bssl::CertificateTrust::ForTrustedLeaf()
111 .WithRequireLeafSelfSigned();
112 } else {
113 return bssl::CertificateTrust::ForUnspecified();
114 }
115 }
116
117 // Returns true if |cert| successfully added to store, false otherwise.
AddToStore(HCERTSTORE store,std::shared_ptr<const bssl::ParsedCertificate> cert)118 bool AddToStore(HCERTSTORE store,
119 std::shared_ptr<const bssl::ParsedCertificate> cert) {
120 crypto::ScopedPCCERT_CONTEXT os_cert(CertCreateCertificateContext(
121 X509_ASN_ENCODING, CRYPTO_BUFFER_data(cert->cert_buffer()),
122 CRYPTO_BUFFER_len(cert->cert_buffer())));
123 return CertAddCertificateContextToStore(store, os_cert.get(),
124 CERT_STORE_ADD_ALWAYS, nullptr);
125 }
126
127 // Returns true if cert at file_name successfully added to store with
128 // restricted usage, false otherwise.
AddToStoreWithEKURestriction(HCERTSTORE store,std::shared_ptr<const bssl::ParsedCertificate> cert,LPCSTR usage_identifier)129 bool AddToStoreWithEKURestriction(
130 HCERTSTORE store,
131 std::shared_ptr<const bssl::ParsedCertificate> cert,
132 LPCSTR usage_identifier) {
133 crypto::ScopedPCCERT_CONTEXT os_cert(CertCreateCertificateContext(
134 X509_ASN_ENCODING, CRYPTO_BUFFER_data(cert->cert_buffer()),
135 CRYPTO_BUFFER_len(cert->cert_buffer())));
136
137 CERT_ENHKEY_USAGE usage;
138 memset(&usage, 0, sizeof(usage));
139 if (!CertSetEnhancedKeyUsage(os_cert.get(), &usage)) {
140 return false;
141 }
142 if (usage_identifier) {
143 if (!CertAddEnhancedKeyUsageIdentifier(os_cert.get(), usage_identifier)) {
144 return false;
145 }
146 }
147 return !!CertAddCertificateContextToStore(store, os_cert.get(),
148 CERT_STORE_ADD_ALWAYS, nullptr);
149 }
150
CreateTrustStoreWin()151 std::unique_ptr<TrustStoreWin> CreateTrustStoreWin() {
152 return TrustStoreWin::CreateForTesting(std::move(stores_));
153 }
154
155 // The cert stores that will be used to create the trust store. These handles
156 // will be null after CreateTrustStoreWin() is called.
157 TrustStoreWin::CertStores stores_ =
158 TrustStoreWin::CertStores::CreateInMemoryStoresForTesting();
159
160 std::shared_ptr<const bssl::ParsedCertificate> a_by_b_, b_by_c_, b_by_f_,
161 c_by_d_, c_by_e_, d_by_d_, e_by_e_, f_by_e_;
162
163 private:
164 base::test::ScopedFeatureList feature_list_;
165 ScopedLocalAnchorConstraintsEnforcementForTesting
166 scoped_enforce_local_anchor_constraints_;
167 };
168
TEST_P(TrustStoreWinTest,GetTrustInitializationError)169 TEST_P(TrustStoreWinTest, GetTrustInitializationError) {
170 // Simulate an initialization error by using null stores.
171 std::unique_ptr<TrustStoreWin> trust_store_win =
172 TrustStoreWin::CreateForTesting(
173 TrustStoreWin::CertStores::CreateNullStoresForTesting());
174 ASSERT_TRUE(trust_store_win);
175 bssl::CertificateTrust trust = trust_store_win->GetTrust(d_by_d_.get());
176 EXPECT_EQ(bssl::CertificateTrust::ForUnspecified().ToDebugString(),
177 trust.ToDebugString());
178 }
179
TEST_P(TrustStoreWinTest,GetTrust)180 TEST_P(TrustStoreWinTest, GetTrust) {
181 ASSERT_TRUE(AddToStore(stores_.roots.get(), d_by_d_));
182 ASSERT_TRUE(AddToStore(stores_.intermediates.get(), c_by_d_));
183 ASSERT_TRUE(AddToStore(stores_.trusted_people.get(), a_by_b_));
184
185 std::unique_ptr<TrustStoreWin> trust_store_win = CreateTrustStoreWin();
186 ASSERT_TRUE(trust_store_win);
187
188 // Explicitly trusted root should be trusted.
189 EXPECT_EQ(ExpectedTrustForAnchor().ToDebugString(),
190 trust_store_win->GetTrust(d_by_d_.get()).ToDebugString());
191
192 // Explicitly trusted peer should be trusted.
193 // (Although it wouldn't actually verify since it's not self-signed but has
194 // require_leaf_selfsigned set. That doesn't matter for the purposes of these
195 // tests.)
196 EXPECT_EQ(ExpectedTrustForPeer().ToDebugString(),
197 trust_store_win->GetTrust(a_by_b_.get()).ToDebugString());
198
199 // Intermediate for path building should not be trusted.
200 EXPECT_EQ(bssl::CertificateTrust::ForUnspecified().ToDebugString(),
201 trust_store_win->GetTrust(c_by_d_.get()).ToDebugString());
202
203 // Unknown roots should not be trusted (e.g. just because they're
204 // self-signed doesn't make them a root)
205 EXPECT_EQ(bssl::CertificateTrust::ForUnspecified().ToDebugString(),
206 trust_store_win->GetTrust(e_by_e_.get()).ToDebugString());
207 }
208
209 // This test has a special TrustStoreWin setup with restricted EKU usages.
210 // Specifically, the only certs set up in the root store are set up
211 // as follows:
212 //
213 // - kMultiRootDByD: only has szOID_PKIX_KP_SERVER_AUTH EKU set
214 // - kMultiRootEByE: only has szOID_PKIX_KP_CLIENT_AUTH set
215 // - kMultiRootCByE: only has szOID_ANY_ENHANCED_KEY_USAGE set
216 // - kMultiRootCByD: no EKU usages set
TEST_P(TrustStoreWinTest,GetTrustRestrictedEKU)217 TEST_P(TrustStoreWinTest, GetTrustRestrictedEKU) {
218 ASSERT_TRUE(AddToStoreWithEKURestriction(stores_.roots.get(), d_by_d_,
219 szOID_PKIX_KP_SERVER_AUTH));
220 ASSERT_TRUE(AddToStoreWithEKURestriction(stores_.roots.get(), e_by_e_,
221 szOID_PKIX_KP_CLIENT_AUTH));
222 ASSERT_TRUE(AddToStoreWithEKURestriction(stores_.roots.get(), c_by_e_,
223 szOID_ANY_ENHANCED_KEY_USAGE));
224 ASSERT_TRUE(
225 AddToStoreWithEKURestriction(stores_.roots.get(), c_by_d_, nullptr));
226
227 std::unique_ptr<TrustStoreWin> trust_store_win = CreateTrustStoreWin();
228 ASSERT_TRUE(trust_store_win);
229
230 // Root cert with EKU szOID_PKIX_KP_SERVER_AUTH usage set should be
231 // trusted.
232 EXPECT_EQ(ExpectedTrustForAnchor().ToDebugString(),
233 trust_store_win->GetTrust(d_by_d_.get()).ToDebugString());
234
235 // Root cert with EKU szOID_ANY_ENHANCED_KEY_USAGE usage set should be
236 // trusted.
237 EXPECT_EQ(ExpectedTrustForAnchor().ToDebugString(),
238 trust_store_win->GetTrust(c_by_e_.get()).ToDebugString());
239
240 // Root cert with EKU szOID_PKIX_KP_CLIENT_AUTH does not allow usage of
241 // cert for server auth, return UNSPECIFIED.
242 EXPECT_EQ(bssl::CertificateTrust::ForUnspecified().ToDebugString(),
243 trust_store_win->GetTrust(e_by_e_.get()).ToDebugString());
244
245 // Root cert with no EKU usages, return UNSPECIFIED.
246 EXPECT_EQ(bssl::CertificateTrust::ForUnspecified().ToDebugString(),
247 trust_store_win->GetTrust(c_by_d_.get()).ToDebugString());
248
249 // Unknown cert has unspecified trust.
250 EXPECT_EQ(bssl::CertificateTrust::ForUnspecified().ToDebugString(),
251 trust_store_win->GetTrust(f_by_e_.get()).ToDebugString());
252 }
253
254 // Same as GetTrustRestrictedEKU but for the Trusted People store.
TEST_P(TrustStoreWinTest,GetTrustTrustedPeopleRestrictedEKU)255 TEST_P(TrustStoreWinTest, GetTrustTrustedPeopleRestrictedEKU) {
256 ASSERT_TRUE(AddToStoreWithEKURestriction(stores_.trusted_people.get(),
257 d_by_d_, szOID_PKIX_KP_SERVER_AUTH));
258 ASSERT_TRUE(AddToStoreWithEKURestriction(stores_.trusted_people.get(),
259 e_by_e_, szOID_PKIX_KP_CLIENT_AUTH));
260 ASSERT_TRUE(AddToStoreWithEKURestriction(
261 stores_.trusted_people.get(), c_by_e_, szOID_ANY_ENHANCED_KEY_USAGE));
262 ASSERT_TRUE(AddToStoreWithEKURestriction(stores_.trusted_people.get(),
263 c_by_d_, nullptr));
264
265 std::unique_ptr<TrustStoreWin> trust_store_win = CreateTrustStoreWin();
266 ASSERT_TRUE(trust_store_win);
267
268 // TrustedPeople cert with EKU szOID_PKIX_KP_SERVER_AUTH usage set should be
269 // trusted.
270 EXPECT_EQ(ExpectedTrustForPeer().ToDebugString(),
271 trust_store_win->GetTrust(d_by_d_.get()).ToDebugString());
272
273 // TrustedPeople cert with EKU szOID_ANY_ENHANCED_KEY_USAGE usage set should
274 // be trusted.
275 EXPECT_EQ(ExpectedTrustForPeer().ToDebugString(),
276 trust_store_win->GetTrust(c_by_e_.get()).ToDebugString());
277
278 // TrustedPeople cert with EKU szOID_PKIX_KP_CLIENT_AUTH does not allow usage
279 // of cert for server auth, return UNSPECIFIED.
280 EXPECT_EQ(bssl::CertificateTrust::ForUnspecified().ToDebugString(),
281 trust_store_win->GetTrust(e_by_e_.get()).ToDebugString());
282
283 // TrustedPeople cert with no EKU usages, return UNSPECIFIED.
284 EXPECT_EQ(bssl::CertificateTrust::ForUnspecified().ToDebugString(),
285 trust_store_win->GetTrust(c_by_d_.get()).ToDebugString());
286
287 // Unknown cert has unspecified trust.
288 EXPECT_EQ(bssl::CertificateTrust::ForUnspecified().ToDebugString(),
289 trust_store_win->GetTrust(f_by_e_.get()).ToDebugString());
290 }
291
292 // If duplicate certs are added to the root store with different EKU usages,
293 // the cert should be trusted if any one of the usages is valid.
294 // Root store set up as follows:
295 //
296 // - kMultiRootDByD: only has szOID_PKIX_KP_CLIENT_AUTH EKU set
297 // - kMultiRootDByD (dupe): only has szOID_PKIX_KP_SERVER_AUTH set
298 // - kMultiRootDByD (dupe 2): no EKU usages set
TEST_P(TrustStoreWinTest,GetTrustRestrictedEKUDuplicateCerts)299 TEST_P(TrustStoreWinTest, GetTrustRestrictedEKUDuplicateCerts) {
300 ASSERT_TRUE(AddToStoreWithEKURestriction(stores_.roots.get(), d_by_d_,
301 szOID_PKIX_KP_CLIENT_AUTH));
302 ASSERT_TRUE(AddToStoreWithEKURestriction(stores_.roots.get(), d_by_d_,
303 szOID_PKIX_KP_SERVER_AUTH));
304 ASSERT_TRUE(
305 AddToStoreWithEKURestriction(stores_.roots.get(), d_by_d_, nullptr));
306
307 std::unique_ptr<TrustStoreWin> trust_store_win = CreateTrustStoreWin();
308 ASSERT_TRUE(trust_store_win);
309
310 // One copy of the Root cert is trusted for TLS Server Auth.
311 EXPECT_EQ(ExpectedTrustForAnchor().ToDebugString(),
312 trust_store_win->GetTrust(d_by_d_.get()).ToDebugString());
313 }
314
315 // Test that disallowed certs will be distrusted regardless of EKU settings.
TEST_P(TrustStoreWinTest,GetTrustDisallowedCerts)316 TEST_P(TrustStoreWinTest, GetTrustDisallowedCerts) {
317 ASSERT_TRUE(AddToStore(stores_.roots.get(), d_by_d_));
318 ASSERT_TRUE(AddToStore(stores_.roots.get(), e_by_e_));
319 ASSERT_TRUE(AddToStore(stores_.trusted_people.get(), f_by_e_));
320
321 ASSERT_TRUE(AddToStoreWithEKURestriction(stores_.disallowed.get(), d_by_d_,
322 szOID_PKIX_KP_CLIENT_AUTH));
323 ASSERT_TRUE(AddToStore(stores_.disallowed.get(), e_by_e_));
324 ASSERT_TRUE(AddToStore(stores_.disallowed.get(), f_by_e_));
325
326 std::unique_ptr<TrustStoreWin> trust_store_win = CreateTrustStoreWin();
327 ASSERT_TRUE(trust_store_win);
328
329 // E-by-E is in both root and distrusted store. Distrust takes precedence.
330 EXPECT_EQ(bssl::CertificateTrust::ForDistrusted().ToDebugString(),
331 trust_store_win->GetTrust(e_by_e_.get()).ToDebugString());
332
333 // F-by-E is in both trusted people and distrusted store. Distrust takes
334 // precedence.
335 EXPECT_EQ(bssl::CertificateTrust::ForDistrusted().ToDebugString(),
336 trust_store_win->GetTrust(f_by_e_.get()).ToDebugString());
337
338 // D-by-D is in root and in distrusted but without szOID_PKIX_KP_SERVER_AUTH
339 // set. It should still be distrusted since the EKU settings aren't checked
340 // on distrust.
341 EXPECT_EQ(bssl::CertificateTrust::ForDistrusted().ToDebugString(),
342 trust_store_win->GetTrust(d_by_d_.get()).ToDebugString());
343 }
344
345 MATCHER_P(ParsedCertEq, expected_cert, "") {
346 return arg && expected_cert &&
347 base::ranges::equal(arg->der_cert(), expected_cert->der_cert());
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()),
__anon9bf1124e0202(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