• 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 #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