xref: /aosp_15_r20/external/cronet/net/cert/internal/path_builder_trust_store_win_unittest.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1 // Copyright 2016 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 "third_party/boringssl/src/pki/path_builder.h"
6 
7 #include <algorithm>
8 
9 #include "base/base_paths.h"
10 #include "base/files/file_util.h"
11 #include "base/functional/callback_forward.h"
12 #include "base/path_service.h"
13 #include "base/test/bind.h"
14 #include "base/win/wincrypt_shim.h"
15 #include "build/build_config.h"
16 #include "crypto/scoped_capi_types.h"
17 #include "net/cert/internal/test_helpers.h"
18 #include "net/cert/internal/trust_store_win.h"
19 #include "net/net_buildflags.h"
20 #include "net/test/test_certificate_data.h"
21 #include "testing/gmock/include/gmock/gmock.h"
22 #include "testing/gtest/include/gtest/gtest.h"
23 #include "third_party/boringssl/src/include/openssl/pool.h"
24 #include "third_party/boringssl/src/pki/cert_error_params.h"
25 #include "third_party/boringssl/src/pki/cert_issuer_source_static.h"
26 #include "third_party/boringssl/src/pki/common_cert_errors.h"
27 #include "third_party/boringssl/src/pki/input.h"
28 #include "third_party/boringssl/src/pki/parsed_certificate.h"
29 #include "third_party/boringssl/src/pki/pem.h"
30 #include "third_party/boringssl/src/pki/simple_path_builder_delegate.h"
31 #include "third_party/boringssl/src/pki/trust_store_collection.h"
32 #include "third_party/boringssl/src/pki/trust_store_in_memory.h"
33 #include "third_party/boringssl/src/pki/verify_certificate_chain.h"
34 
35 namespace net {
36 
37 namespace {
38 
39 using ::testing::_;
40 using ::testing::ElementsAre;
41 using ::testing::Invoke;
42 using ::testing::NiceMock;
43 using ::testing::Return;
44 using ::testing::SaveArg;
45 using ::testing::SetArgPointee;
46 using ::testing::StrictMock;
47 
48 class DeadlineTestingPathBuilderDelegate
49     : public bssl::SimplePathBuilderDelegate {
50  public:
DeadlineTestingPathBuilderDelegate(size_t min_rsa_modulus_length_bits,DigestPolicy digest_policy)51   DeadlineTestingPathBuilderDelegate(size_t min_rsa_modulus_length_bits,
52                                      DigestPolicy digest_policy)
53       : bssl::SimplePathBuilderDelegate(min_rsa_modulus_length_bits,
54                                         digest_policy) {}
55 
IsDeadlineExpired()56   bool IsDeadlineExpired() override { return deadline_is_expired_; }
57 
SetDeadlineExpiredForTesting(bool deadline_is_expired)58   void SetDeadlineExpiredForTesting(bool deadline_is_expired) {
59     deadline_is_expired_ = deadline_is_expired;
60   }
61 
62  private:
63   bool deadline_is_expired_ = false;
64 };
65 
66 // AsyncCertIssuerSourceStatic always returns its certs asynchronously.
67 class AsyncCertIssuerSourceStatic : public bssl::CertIssuerSource {
68  public:
69   class StaticAsyncRequest : public Request {
70    public:
StaticAsyncRequest(bssl::ParsedCertificateList && issuers)71     explicit StaticAsyncRequest(bssl::ParsedCertificateList&& issuers) {
72       issuers_.swap(issuers);
73       issuers_iter_ = issuers_.begin();
74     }
75 
76     StaticAsyncRequest(const StaticAsyncRequest&) = delete;
77     StaticAsyncRequest& operator=(const StaticAsyncRequest&) = delete;
78 
79     ~StaticAsyncRequest() override = default;
80 
GetNext(bssl::ParsedCertificateList * out_certs)81     void GetNext(bssl::ParsedCertificateList* out_certs) override {
82       if (issuers_iter_ != issuers_.end())
83         out_certs->push_back(std::move(*issuers_iter_++));
84     }
85 
86     bssl::ParsedCertificateList issuers_;
87     bssl::ParsedCertificateList::iterator issuers_iter_;
88   };
89 
90   ~AsyncCertIssuerSourceStatic() override = default;
91 
SetAsyncGetCallback(base::RepeatingClosure closure)92   void SetAsyncGetCallback(base::RepeatingClosure closure) {
93     async_get_callback_ = std::move(closure);
94   }
95 
AddCert(std::shared_ptr<const bssl::ParsedCertificate> cert)96   void AddCert(std::shared_ptr<const bssl::ParsedCertificate> cert) {
97     static_cert_issuer_source_.AddCert(std::move(cert));
98   }
99 
SyncGetIssuersOf(const bssl::ParsedCertificate * cert,bssl::ParsedCertificateList * issuers)100   void SyncGetIssuersOf(const bssl::ParsedCertificate* cert,
101                         bssl::ParsedCertificateList* issuers) override {}
AsyncGetIssuersOf(const bssl::ParsedCertificate * cert,std::unique_ptr<Request> * out_req)102   void AsyncGetIssuersOf(const bssl::ParsedCertificate* cert,
103                          std::unique_ptr<Request>* out_req) override {
104     num_async_gets_++;
105     bssl::ParsedCertificateList issuers;
106     static_cert_issuer_source_.SyncGetIssuersOf(cert, &issuers);
107     auto req = std::make_unique<StaticAsyncRequest>(std::move(issuers));
108     *out_req = std::move(req);
109     if (!async_get_callback_.is_null())
110       async_get_callback_.Run();
111   }
num_async_gets() const112   int num_async_gets() const { return num_async_gets_; }
113 
114  private:
115   bssl::CertIssuerSourceStatic static_cert_issuer_source_;
116 
117   int num_async_gets_ = 0;
118   base::RepeatingClosure async_get_callback_;
119 };
120 
ReadTestPem(const std::string & file_name,const std::string & block_name,std::string * result)121 ::testing::AssertionResult ReadTestPem(const std::string& file_name,
122                                        const std::string& block_name,
123                                        std::string* result) {
124   const PemBlockMapping mappings[] = {
125       {block_name.c_str(), result},
126   };
127 
128   return ReadTestDataFromPemFile(file_name, mappings);
129 }
130 
ReadTestCert(const std::string & file_name,std::shared_ptr<const bssl::ParsedCertificate> * result)131 ::testing::AssertionResult ReadTestCert(
132     const std::string& file_name,
133     std::shared_ptr<const bssl::ParsedCertificate>* result) {
134   std::string der;
135   ::testing::AssertionResult r = ReadTestPem(
136       "net/data/ssl/certificates/" + file_name, "CERTIFICATE", &der);
137   if (!r)
138     return r;
139   bssl::CertErrors errors;
140   *result = bssl::ParsedCertificate::Create(
141       bssl::UniquePtr<CRYPTO_BUFFER>(CRYPTO_BUFFER_new(
142           reinterpret_cast<const uint8_t*>(der.data()), der.size(), nullptr)),
143       {}, &errors);
144   if (!*result) {
145     return ::testing::AssertionFailure()
146            << "bssl::ParseCertificate::Create() failed:\n"
147            << errors.ToDebugString();
148   }
149   return ::testing::AssertionSuccess();
150 }
151 
152 class PathBuilderMultiRootWindowsTest : public ::testing::Test {
153  public:
PathBuilderMultiRootWindowsTest()154   PathBuilderMultiRootWindowsTest()
155       : delegate_(
156             1024,
157             DeadlineTestingPathBuilderDelegate::DigestPolicy::kWeakAllowSha1) {}
158 
SetUp()159   void SetUp() override {
160     ASSERT_TRUE(ReadTestCert("multi-root-A-by-B.pem", &a_by_b_));
161     ASSERT_TRUE(ReadTestCert("multi-root-B-by-C.pem", &b_by_c_));
162     ASSERT_TRUE(ReadTestCert("multi-root-B-by-F.pem", &b_by_f_));
163     ASSERT_TRUE(ReadTestCert("multi-root-C-by-D.pem", &c_by_d_));
164     ASSERT_TRUE(ReadTestCert("multi-root-C-by-E.pem", &c_by_e_));
165     ASSERT_TRUE(ReadTestCert("multi-root-D-by-D.pem", &d_by_d_));
166     ASSERT_TRUE(ReadTestCert("multi-root-E-by-E.pem", &e_by_e_));
167     ASSERT_TRUE(ReadTestCert("multi-root-F-by-E.pem", &f_by_e_));
168   }
169 
170  protected:
171   std::shared_ptr<const bssl::ParsedCertificate> a_by_b_, b_by_c_, b_by_f_,
172       c_by_d_, c_by_e_, d_by_d_, e_by_e_, f_by_e_;
173 
174   DeadlineTestingPathBuilderDelegate delegate_;
175   bssl::der::GeneralizedTime time_ = {2017, 3, 1, 0, 0, 0};
176 
177   const bssl::InitialExplicitPolicy initial_explicit_policy_ =
178       bssl::InitialExplicitPolicy::kFalse;
179   const std::set<bssl::der::Input> user_initial_policy_set_ = {
180       bssl::der::Input(bssl::kAnyPolicyOid)};
181   const bssl::InitialPolicyMappingInhibit initial_policy_mapping_inhibit_ =
182       bssl::InitialPolicyMappingInhibit::kFalse;
183   const bssl::InitialAnyPolicyInhibit initial_any_policy_inhibit_ =
184       bssl::InitialAnyPolicyInhibit::kFalse;
185 };
186 
AddToStoreWithEKURestriction(HCERTSTORE store,const std::shared_ptr<const bssl::ParsedCertificate> & cert,LPCSTR usage_identifier)187 void AddToStoreWithEKURestriction(
188     HCERTSTORE store,
189     const std::shared_ptr<const bssl::ParsedCertificate>& cert,
190     LPCSTR usage_identifier) {
191   crypto::ScopedPCCERT_CONTEXT os_cert(CertCreateCertificateContext(
192       X509_ASN_ENCODING, cert->der_cert().data(), cert->der_cert().size()));
193 
194   CERT_ENHKEY_USAGE usage;
195   memset(&usage, 0, sizeof(usage));
196   CertSetEnhancedKeyUsage(os_cert.get(), &usage);
197   if (usage_identifier) {
198     CertAddEnhancedKeyUsageIdentifier(os_cert.get(), usage_identifier);
199   }
200   CertAddCertificateContextToStore(store, os_cert.get(), CERT_STORE_ADD_ALWAYS,
201                                    nullptr);
202 }
203 
AreCertsEq(const std::shared_ptr<const bssl::ParsedCertificate> cert_1,const std::shared_ptr<const bssl::ParsedCertificate> cert_2)204 bool AreCertsEq(const std::shared_ptr<const bssl::ParsedCertificate> cert_1,
205                 const std::shared_ptr<const bssl::ParsedCertificate> cert_2) {
206   return cert_1 && cert_2 && cert_1->der_cert() == cert_2->der_cert();
207 }
208 
209 // Test to ensure that path building stops when an intermediate cert is
210 // encountered that is not usable for TLS because it is explicitly distrusted.
TEST_F(PathBuilderMultiRootWindowsTest,TrustStoreWinOnlyFindTrustedTLSPath)211 TEST_F(PathBuilderMultiRootWindowsTest, TrustStoreWinOnlyFindTrustedTLSPath) {
212   TrustStoreWin::CertStores stores =
213       TrustStoreWin::CertStores::CreateInMemoryStoresForTesting();
214 
215   AddToStoreWithEKURestriction(stores.roots.get(), d_by_d_,
216                                szOID_PKIX_KP_SERVER_AUTH);
217   AddToStoreWithEKURestriction(stores.roots.get(), e_by_e_,
218                                szOID_PKIX_KP_SERVER_AUTH);
219   AddToStoreWithEKURestriction(stores.intermediates.get(), c_by_e_,
220                                szOID_PKIX_KP_SERVER_AUTH);
221   AddToStoreWithEKURestriction(stores.disallowed.get(), c_by_d_, nullptr);
222 
223   std::unique_ptr<TrustStoreWin> trust_store =
224       TrustStoreWin::CreateForTesting(std::move(stores));
225 
226   bssl::CertPathBuilder path_builder(
227       b_by_c_, trust_store.get(), &delegate_, time_, bssl::KeyPurpose::ANY_EKU,
228       initial_explicit_policy_, user_initial_policy_set_,
229       initial_policy_mapping_inhibit_, initial_any_policy_inhibit_);
230 
231   // Check all paths.
232   path_builder.SetExploreAllPaths(true);
233 
234   auto result = path_builder.Run();
235   ASSERT_TRUE(result.HasValidPath());
236   ASSERT_EQ(1U, result.paths.size());
237   const auto& path = *result.GetBestValidPath();
238   ASSERT_EQ(3U, path.certs.size());
239   EXPECT_TRUE(AreCertsEq(b_by_c_, path.certs[0]));
240   EXPECT_TRUE(AreCertsEq(c_by_e_, path.certs[1]));
241   EXPECT_TRUE(AreCertsEq(e_by_e_, path.certs[2]));
242 
243   // Should only be one valid path, the one above.
244   const int valid_paths = std::count_if(
245       result.paths.begin(), result.paths.end(),
246       [](const auto& candidate_path) { return candidate_path->IsValid(); });
247   ASSERT_EQ(1, valid_paths);
248 }
249 
250 // Test that if an intermediate is untrusted, and it is the only
251 // path, then path building should fail, even if the root is enabled for
252 // TLS.
TEST_F(PathBuilderMultiRootWindowsTest,TrustStoreWinNoPathEKURestrictions)253 TEST_F(PathBuilderMultiRootWindowsTest, TrustStoreWinNoPathEKURestrictions) {
254   TrustStoreWin::CertStores stores =
255       TrustStoreWin::CertStores::CreateInMemoryStoresForTesting();
256 
257   AddToStoreWithEKURestriction(stores.roots.get(), d_by_d_,
258                                szOID_PKIX_KP_SERVER_AUTH);
259   AddToStoreWithEKURestriction(stores.disallowed.get(), c_by_d_, nullptr);
260   std::unique_ptr<TrustStoreWin> trust_store =
261       TrustStoreWin::CreateForTesting(std::move(stores));
262 
263   bssl::CertPathBuilder path_builder(
264       b_by_c_, trust_store.get(), &delegate_, time_, bssl::KeyPurpose::ANY_EKU,
265       initial_explicit_policy_, user_initial_policy_set_,
266       initial_policy_mapping_inhibit_, initial_any_policy_inhibit_);
267 
268   auto result = path_builder.Run();
269   ASSERT_FALSE(result.HasValidPath());
270 }
271 
272 }  // namespace
273 
274 }  // namespace net
275