• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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