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