xref: /aosp_15_r20/external/cronet/net/cert/internal/trust_store_win_unittest.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
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