cert_verifier_service_unittest.cc 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369
  1. // Copyright 2020 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #include "services/cert_verifier/cert_verifier_service.h"
  5. #include <stdint.h>
  6. #include <iterator>
  7. #include <memory>
  8. #include <string>
  9. #include <tuple>
  10. #include "base/callback_helpers.h"
  11. #include "base/containers/adapters.h"
  12. #include "base/memory/ptr_util.h"
  13. #include "base/memory/raw_ptr.h"
  14. #include "base/memory/scoped_refptr.h"
  15. #include "base/strings/string_number_conversions.h"
  16. #include "base/test/bind.h"
  17. #include "base/test/task_environment.h"
  18. #include "base/time/time.h"
  19. #include "mojo/public/cpp/bindings/pending_remote.h"
  20. #include "mojo/public/cpp/bindings/receiver.h"
  21. #include "mojo/public/cpp/bindings/remote.h"
  22. #include "net/base/net_errors.h"
  23. #include "net/cert/cert_status_flags.h"
  24. #include "net/cert/cert_verifier.h"
  25. #include "net/cert/cert_verify_proc.h"
  26. #include "net/cert/cert_verify_result.h"
  27. #include "net/cert/x509_certificate.h"
  28. #include "net/log/net_log.h"
  29. #include "net/test/cert_test_util.h"
  30. #include "net/test/test_data_directory.h"
  31. #include "services/cert_verifier/cert_verifier_service_factory.h"
  32. #include "services/network/public/mojom/cert_verifier_service.mojom.h"
  33. #include "testing/gtest/include/gtest/gtest.h"
  34. #include "testing/platform_test.h"
  35. namespace net {
  36. class CertNetFetcher;
  37. class ChromeRootStoreData;
  38. } // namespace net
  39. namespace cert_verifier {
  40. namespace {
  41. const int kExpectedNetError = net::ERR_CERT_INVALID;
  42. const unsigned int kExpectedCertStatus = net::CERT_STATUS_INVALID;
  43. scoped_refptr<net::X509Certificate> GetTestCert() {
  44. return net::ImportCertFromFile(net::GetTestCertsDirectory(), "ok_cert.pem");
  45. }
  46. class DummyCertVerifier : public net::CertVerifierWithUpdatableProc {
  47. public:
  48. struct DummyRequest : public net::CertVerifier::Request {
  49. ~DummyRequest() override {
  50. if (cancel_cb)
  51. std::move(cancel_cb).Run();
  52. }
  53. raw_ptr<net::CertVerifyResult> verify_result;
  54. net::CompletionOnceCallback callback;
  55. base::OnceClosure cancel_cb;
  56. base::WeakPtrFactory<DummyRequest> weak_ptr_factory_{this};
  57. };
  58. ~DummyCertVerifier() override {
  59. for (base::WeakPtr<DummyRequest>& dummy_req : dummy_request_ptrs) {
  60. if (dummy_req)
  61. dummy_req->callback.Reset();
  62. }
  63. }
  64. // CertVerifier implementation
  65. int Verify(const net::CertVerifier::RequestParams& params,
  66. net::CertVerifyResult* verify_result,
  67. net::CompletionOnceCallback callback,
  68. std::unique_ptr<Request>* out_req,
  69. const net::NetLogWithSource& net_log) override {
  70. request_netlogs_[params] = net_log;
  71. if (sync_response_params_.find(params) != sync_response_params_.end()) {
  72. verify_result->cert_status = kExpectedCertStatus;
  73. return kExpectedNetError;
  74. }
  75. // Don't currently handle requests with same params for simplicity.
  76. EXPECT_TRUE(dummy_requests_.find(params) == dummy_requests_.end());
  77. auto dummy_req = std::make_unique<DummyRequest>();
  78. dummy_request_ptrs.push_back(dummy_req->weak_ptr_factory_.GetWeakPtr());
  79. dummy_req->verify_result = verify_result;
  80. dummy_req->callback = std::move(callback);
  81. dummy_req->cancel_cb = base::BindLambdaForTesting([this, params]() {
  82. ASSERT_TRUE(cancelled_requests_.find(params) ==
  83. cancelled_requests_.end());
  84. cancelled_requests_.insert(std::move(params));
  85. });
  86. dummy_requests_[params] = dummy_req.get();
  87. *out_req = std::move(dummy_req);
  88. return net::ERR_IO_PENDING;
  89. }
  90. void SetConfig(const Config& config) override { config_ = config; }
  91. void UpdateChromeRootStoreData(
  92. scoped_refptr<net::CertNetFetcher> cert_net_fetcher,
  93. const net::ChromeRootStoreData* root_store_data) override {}
  94. void RespondToRequest(const net::CertVerifier::RequestParams& params) {
  95. auto it = dummy_requests_.find(params);
  96. ASSERT_FALSE(it == dummy_requests_.end());
  97. DummyRequest* req = it->second;
  98. dummy_requests_.erase(it);
  99. req->cancel_cb.Reset();
  100. req->verify_result->cert_status = kExpectedCertStatus;
  101. std::move(req->callback).Run(kExpectedNetError);
  102. }
  103. void ShouldRespondSynchronouslyToParams(
  104. const net::CertVerifier::RequestParams& params) {
  105. sync_response_params_.insert(params);
  106. }
  107. bool WasRequestCancelled(const net::CertVerifier::RequestParams& params) {
  108. return cancelled_requests_.find(params) != cancelled_requests_.end();
  109. }
  110. void ExpectReceivedNetlogSource(
  111. const net::CertVerifier::RequestParams& params,
  112. uint32_t type,
  113. uint32_t id,
  114. base::TimeTicks start_time) {
  115. ASSERT_TRUE(request_netlogs_.count(params));
  116. EXPECT_EQ(type,
  117. static_cast<uint32_t>(request_netlogs_[params].source().type));
  118. EXPECT_EQ(id, request_netlogs_[params].source().id);
  119. EXPECT_EQ(start_time, request_netlogs_[params].source().start_time);
  120. }
  121. const net::CertVerifier::Config* config() const { return &config_; }
  122. private:
  123. std::map<net::CertVerifier::RequestParams, DummyRequest*> dummy_requests_;
  124. std::set<net::CertVerifier::RequestParams> sync_response_params_;
  125. std::set<net::CertVerifier::RequestParams> cancelled_requests_;
  126. // Keep WeakPtr's to all the DummyRequests in case we need to reset the
  127. // callbacks if |this| is destructed;
  128. std::vector<base::WeakPtr<DummyRequest>> dummy_request_ptrs;
  129. std::map<net::CertVerifier::RequestParams, net::NetLogWithSource>
  130. request_netlogs_;
  131. net::CertVerifier::Config config_;
  132. };
  133. struct DummyCVServiceRequest : public mojom::CertVerifierRequest {
  134. void Complete(const net::CertVerifyResult& result_param,
  135. int32_t net_error_param) override {
  136. is_completed = true;
  137. result = result_param;
  138. net_error = net_error_param;
  139. }
  140. bool is_completed = false;
  141. net::CertVerifyResult result;
  142. int net_error;
  143. };
  144. class CertVerifierServiceTest : public PlatformTest {
  145. public:
  146. struct RequestInfo {
  147. RequestInfo(net::CertVerifier::RequestParams request_params_p,
  148. uint32_t netlog_source_type_p,
  149. uint32_t netlog_source_id_p,
  150. base::TimeTicks netlog_source_start_time_p,
  151. std::unique_ptr<DummyCVServiceRequest> dummy_cv_request_p,
  152. std::unique_ptr<mojo::Receiver<mojom::CertVerifierRequest>>
  153. cv_request_receiver_p)
  154. : request_params(std::move(request_params_p)),
  155. netlog_source_type(netlog_source_type_p),
  156. netlog_source_id(netlog_source_id_p),
  157. netlog_source_start_time(netlog_source_start_time_p),
  158. dummy_cv_request(std::move(dummy_cv_request_p)),
  159. cv_request_receiver(std::move(cv_request_receiver_p)) {}
  160. net::CertVerifier::RequestParams request_params;
  161. uint32_t netlog_source_type;
  162. uint32_t netlog_source_id;
  163. base::TimeTicks netlog_source_start_time;
  164. std::unique_ptr<DummyCVServiceRequest> dummy_cv_request;
  165. std::unique_ptr<mojo::Receiver<mojom::CertVerifierRequest>>
  166. cv_request_receiver;
  167. };
  168. // Wraps a DummyCertVerifier with a CertVerifierServiceImpl.
  169. // NOTE: CertVerifierServiceImpl is self-deleting.
  170. CertVerifierServiceTest()
  171. : dummy_cv_(new DummyCertVerifier),
  172. cv_service_(new internal::CertVerifierServiceImpl(
  173. base::WrapUnique(dummy_cv_.get()),
  174. cv_service_remote_.BindNewPipeAndPassReceiver(),
  175. /*cert_net_fetcher=*/nullptr)) {}
  176. void SetUp() override { ASSERT_TRUE(GetTestCert()); }
  177. void TestCompletions(int num_simultaneous, bool sync) {
  178. std::vector<RequestInfo> request_infos;
  179. base::TimeTicks time_zero = base::TimeTicks::Now();
  180. for (int i = 0; i < num_simultaneous; i++) {
  181. std::string hostname = "www" + base::NumberToString(i) + ".example.com";
  182. net::CertVerifier::RequestParams dummy_params(
  183. GetTestCert(), hostname, 0,
  184. /*ocsp_response=*/std::string(),
  185. /*sct_list=*/std::string());
  186. if (sync) {
  187. dummy_cv_->ShouldRespondSynchronouslyToParams(dummy_params);
  188. }
  189. // Perform a verification request using the Remote<CertVerifierService>,
  190. // which forwards to the CertVerifierServiceImpl.
  191. auto cv_service_req = std::make_unique<DummyCVServiceRequest>();
  192. auto cv_request_receiver =
  193. std::make_unique<mojo::Receiver<mojom::CertVerifierRequest>>(
  194. cv_service_req.get());
  195. request_infos.emplace_back(
  196. std::move(dummy_params),
  197. static_cast<uint32_t>(net::NetLogSourceType::CERT_VERIFIER_JOB),
  198. 1234 + i, time_zero + base::Seconds(i), std::move(cv_service_req),
  199. std::move(cv_request_receiver));
  200. }
  201. for (RequestInfo& info : request_infos) {
  202. cv_service_remote_->Verify(
  203. info.request_params, info.netlog_source_type, info.netlog_source_id,
  204. info.netlog_source_start_time,
  205. info.cv_request_receiver->BindNewPipeAndPassRemote());
  206. }
  207. // Handle async Mojo request.
  208. task_environment_.RunUntilIdle();
  209. if (!sync) { // For fun, complete the requests in reverse order.
  210. for (auto& info : base::Reversed(request_infos)) {
  211. ASSERT_FALSE(info.dummy_cv_request->is_completed);
  212. dummy_cv()->RespondToRequest(info.request_params);
  213. }
  214. // FlushForTesting() so the CertVerifierServiceImpl Mojo response is
  215. // handled.
  216. cv_service_remote().FlushForTesting();
  217. }
  218. for (RequestInfo& info : request_infos) {
  219. // Check the CertVerifierService finished the request.
  220. ASSERT_TRUE(info.dummy_cv_request->is_completed);
  221. ASSERT_EQ(info.dummy_cv_request->net_error, kExpectedNetError);
  222. ASSERT_EQ(info.dummy_cv_request->result.cert_status, kExpectedCertStatus);
  223. dummy_cv()->ExpectReceivedNetlogSource(
  224. info.request_params, info.netlog_source_type, info.netlog_source_id,
  225. info.netlog_source_start_time);
  226. }
  227. }
  228. base::test::TaskEnvironment* task_environment() { return &task_environment_; }
  229. mojo::Remote<mojom::CertVerifierService>& cv_service_remote() {
  230. return cv_service_remote_;
  231. }
  232. DummyCertVerifier* dummy_cv() { return dummy_cv_; }
  233. private:
  234. base::test::TaskEnvironment task_environment_;
  235. mojo::Remote<mojom::CertVerifierService> cv_service_remote_;
  236. raw_ptr<DummyCertVerifier> dummy_cv_;
  237. raw_ptr<internal::CertVerifierServiceImpl> cv_service_;
  238. };
  239. } // namespace
  240. TEST_F(CertVerifierServiceTest, TestSingleCompletion) {
  241. TestCompletions(1, false);
  242. }
  243. TEST_F(CertVerifierServiceTest, TestMultipleSimultaneousCompletions) {
  244. TestCompletions(5, false);
  245. }
  246. TEST_F(CertVerifierServiceTest, TestSingleSyncCompletion) {
  247. TestCompletions(1, true);
  248. }
  249. TEST_F(CertVerifierServiceTest, TestMultipleSimultaneousSyncCompletions) {
  250. TestCompletions(5, true);
  251. }
  252. TEST_F(CertVerifierServiceTest, TestRequestDisconnectionCancelsCVRequest) {
  253. net::CertVerifier::RequestParams dummy_params(GetTestCert(), "example.com", 0,
  254. /*ocsp_response=*/std::string(),
  255. /*sct_list=*/std::string());
  256. // Perform a verification request using the Remote<CertVerifierService>,
  257. // which forwards to the CertVerifierServiceImpl.
  258. DummyCVServiceRequest cv_service_req;
  259. mojo::Receiver<mojom::CertVerifierRequest> cv_request_receiver(
  260. &cv_service_req);
  261. cv_service_remote()->Verify(
  262. dummy_params,
  263. static_cast<uint32_t>(net::NetLogSourceType::CERT_VERIFIER_JOB), 1234,
  264. base::TimeTicks::Now(), cv_request_receiver.BindNewPipeAndPassRemote());
  265. // Handle async Mojo request.
  266. cv_service_remote().FlushForTesting();
  267. ASSERT_FALSE(dummy_cv()->WasRequestCancelled(dummy_params));
  268. // Disconnect our receiver.
  269. cv_request_receiver.reset();
  270. // Run mojo disconnection request.
  271. task_environment()->RunUntilIdle();
  272. ASSERT_TRUE(dummy_cv()->WasRequestCancelled(dummy_params));
  273. }
  274. TEST_F(CertVerifierServiceTest, TestCVServiceDisconnection) {
  275. net::CertVerifier::RequestParams dummy_params(GetTestCert(), "example.com", 0,
  276. /*ocsp_response=*/std::string(),
  277. /*sct_list=*/std::string());
  278. bool disconnected = false;
  279. // Perform a verification request using the Remote<CertVerifierService>,
  280. // which forwards to the CertVerifierServiceImpl.
  281. DummyCVServiceRequest cv_service_req;
  282. mojo::Receiver<mojom::CertVerifierRequest> cv_request_receiver(
  283. &cv_service_req);
  284. cv_service_remote()->Verify(
  285. dummy_params,
  286. static_cast<uint32_t>(net::NetLogSourceType::CERT_VERIFIER_JOB), 1234,
  287. base::TimeTicks::Now(), cv_request_receiver.BindNewPipeAndPassRemote());
  288. // Make sure we observe disconnection.
  289. cv_request_receiver.set_disconnect_handler(
  290. base::BindLambdaForTesting([&]() { disconnected = true; }));
  291. // Disconnect our receiver.
  292. cv_service_remote().reset();
  293. task_environment()->RunUntilIdle();
  294. ASSERT_FALSE(cv_service_req.is_completed);
  295. ASSERT_TRUE(disconnected);
  296. }
  297. // Check that calling SetConfig() on the Mojo interface results in a SetConfig
  298. // call to the underlying net::CertVerifier.
  299. TEST_F(CertVerifierServiceTest, StoresConfig) {
  300. ASSERT_FALSE(dummy_cv()->config()->disable_symantec_enforcement);
  301. net::CertVerifier::Config config;
  302. config.disable_symantec_enforcement = true;
  303. cv_service_remote()->SetConfig(config);
  304. cv_service_remote().FlushForTesting();
  305. ASSERT_TRUE(dummy_cv()->config()->disable_symantec_enforcement);
  306. }
  307. } // namespace cert_verifier