coalescing_cert_verifier_unittest.cc 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518
  1. // Copyright 2019 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 "net/cert/coalescing_cert_verifier.h"
  5. #include <memory>
  6. #include "base/bind.h"
  7. #include "base/test/bind.h"
  8. #include "base/test/metrics/histogram_tester.h"
  9. #include "net/base/net_errors.h"
  10. #include "net/base/test_completion_callback.h"
  11. #include "net/cert/mock_cert_verifier.h"
  12. #include "net/cert/x509_certificate.h"
  13. #include "net/log/net_log_with_source.h"
  14. #include "net/test/cert_test_util.h"
  15. #include "net/test/gtest_util.h"
  16. #include "net/test/test_data_directory.h"
  17. #include "net/test/test_with_task_environment.h"
  18. #include "testing/gmock/include/gmock/gmock.h"
  19. #include "testing/gtest/include/gtest/gtest.h"
  20. using net::test::IsError;
  21. using net::test::IsOk;
  22. namespace net {
  23. using CoalescingCertVerifierTest = TestWithTaskEnvironment;
  24. // Tests that synchronous completion does not cause any issues.
  25. TEST_F(CoalescingCertVerifierTest, SyncCompletion) {
  26. scoped_refptr<X509Certificate> test_cert(
  27. ImportCertFromFile(GetTestCertsDirectory(), "ok_cert.pem"));
  28. ASSERT_TRUE(test_cert);
  29. CertVerifyResult fake_result;
  30. fake_result.verified_cert = test_cert;
  31. std::unique_ptr<MockCertVerifier> mock_verifier_owner =
  32. std::make_unique<MockCertVerifier>();
  33. MockCertVerifier* mock_verifier = mock_verifier_owner.get();
  34. mock_verifier->set_async(false); // Force sync completion.
  35. mock_verifier->AddResultForCert(test_cert, fake_result, OK);
  36. CoalescingCertVerifier verifier(std::move(mock_verifier_owner));
  37. CertVerifier::RequestParams request_params(test_cert, "www.example.com", 0,
  38. /*ocsp_response=*/std::string(),
  39. /*sct_list=*/std::string());
  40. CertVerifyResult result1, result2;
  41. TestCompletionCallback callback1, callback2;
  42. std::unique_ptr<CertVerifier::Request> request1, request2;
  43. // Start an (asynchronous) initial request.
  44. int error = verifier.Verify(request_params, &result1, callback1.callback(),
  45. &request1, NetLogWithSource());
  46. ASSERT_THAT(error, IsOk());
  47. ASSERT_FALSE(request1);
  48. ASSERT_TRUE(result1.verified_cert);
  49. }
  50. // Test that requests with identical parameters only result in a single
  51. // underlying verification; that is, the second Request is joined to the
  52. // in-progress first Request.
  53. TEST_F(CoalescingCertVerifierTest, InflightJoin) {
  54. scoped_refptr<X509Certificate> test_cert(
  55. ImportCertFromFile(GetTestCertsDirectory(), "ok_cert.pem"));
  56. ASSERT_TRUE(test_cert);
  57. base::HistogramTester histograms;
  58. CertVerifyResult fake_result;
  59. fake_result.verified_cert = test_cert;
  60. std::unique_ptr<MockCertVerifier> mock_verifier_owner =
  61. std::make_unique<MockCertVerifier>();
  62. MockCertVerifier* mock_verifier = mock_verifier_owner.get();
  63. mock_verifier->set_async(true); // Always complete via PostTask
  64. mock_verifier->AddResultForCert(test_cert, fake_result, OK);
  65. CoalescingCertVerifier verifier(std::move(mock_verifier_owner));
  66. CertVerifier::RequestParams request_params(test_cert, "www.example.com", 0,
  67. /*ocsp_response=*/std::string(),
  68. /*sct_list=*/std::string());
  69. CertVerifyResult result1, result2;
  70. TestCompletionCallback callback1, callback2;
  71. std::unique_ptr<CertVerifier::Request> request1, request2;
  72. // Start an (asynchronous) initial request.
  73. int error = verifier.Verify(request_params, &result1, callback1.callback(),
  74. &request1, NetLogWithSource());
  75. ASSERT_THAT(error, IsError(ERR_IO_PENDING));
  76. EXPECT_TRUE(request1);
  77. // Simulate the underlying verifier returning different results if another
  78. // verification is done.
  79. mock_verifier->ClearRules();
  80. mock_verifier->AddResultForCert(test_cert, fake_result, ERR_CERT_REVOKED);
  81. // Start a second request; this should join the first request.
  82. error = verifier.Verify(request_params, &result2, callback2.callback(),
  83. &request2, NetLogWithSource());
  84. ASSERT_THAT(error, IsError(ERR_IO_PENDING));
  85. EXPECT_TRUE(request2);
  86. // Ensure only one request was ever started.
  87. EXPECT_EQ(2u, verifier.requests_for_testing());
  88. EXPECT_EQ(1u, verifier.inflight_joins_for_testing());
  89. // Make sure both results completed.
  90. EXPECT_THAT(callback1.WaitForResult(), IsOk());
  91. EXPECT_THAT(callback2.WaitForResult(), IsOk());
  92. // There should only have been one Job started.
  93. histograms.ExpectTotalCount("Net.CertVerifier_Job_Latency", 1);
  94. histograms.ExpectTotalCount("Net.CertVerifier_First_Job_Latency", 1);
  95. }
  96. // Test that changing configurations between Requests prevents the second
  97. // Request from being attached to the first Request. There should be two
  98. // Requests to the underlying CertVerifier, and the correct results should be
  99. // received by each.
  100. TEST_F(CoalescingCertVerifierTest, DoesNotJoinAfterConfigChange) {
  101. scoped_refptr<X509Certificate> test_cert(
  102. ImportCertFromFile(GetTestCertsDirectory(), "ok_cert.pem"));
  103. ASSERT_TRUE(test_cert);
  104. base::HistogramTester histograms;
  105. CertVerifyResult fake_result;
  106. fake_result.verified_cert = test_cert;
  107. std::unique_ptr<MockCertVerifier> mock_verifier_owner =
  108. std::make_unique<MockCertVerifier>();
  109. MockCertVerifier* mock_verifier = mock_verifier_owner.get();
  110. mock_verifier->set_async(true); // Always complete via PostTask
  111. mock_verifier->AddResultForCert(test_cert, fake_result, OK);
  112. CoalescingCertVerifier verifier(std::move(mock_verifier_owner));
  113. CertVerifier::Config config1;
  114. verifier.SetConfig(config1);
  115. CertVerifier::RequestParams request_params(test_cert, "www.example.com", 0,
  116. /*ocsp_response=*/std::string(),
  117. /*sct_list=*/std::string());
  118. CertVerifyResult result1, result2;
  119. TestCompletionCallback callback1, callback2;
  120. std::unique_ptr<CertVerifier::Request> request1, request2;
  121. // Start an (asynchronous) initial request.
  122. int error = verifier.Verify(request_params, &result1, callback1.callback(),
  123. &request1, NetLogWithSource());
  124. ASSERT_THAT(error, IsError(ERR_IO_PENDING));
  125. EXPECT_TRUE(request1);
  126. // Change the configuration, and change the result to to simulate the
  127. // configuration change affecting behavior.
  128. CertVerifier::Config config2;
  129. config2.enable_rev_checking = !config1.enable_rev_checking;
  130. verifier.SetConfig(config2);
  131. mock_verifier->ClearRules();
  132. mock_verifier->AddResultForCert(test_cert, fake_result, ERR_CERT_REVOKED);
  133. // Start a second request; this should not join the first request, as the
  134. // config is different.
  135. error = verifier.Verify(request_params, &result2, callback2.callback(),
  136. &request2, NetLogWithSource());
  137. ASSERT_THAT(error, IsError(ERR_IO_PENDING));
  138. EXPECT_TRUE(request2);
  139. // Ensure a total of two requests were started, and neither were joined.
  140. EXPECT_EQ(2u, verifier.requests_for_testing());
  141. EXPECT_EQ(0u, verifier.inflight_joins_for_testing());
  142. // Make sure both results completed.
  143. EXPECT_THAT(callback1.WaitForResult(), IsOk());
  144. EXPECT_THAT(callback2.WaitForResult(), IsError(ERR_CERT_REVOKED));
  145. // There should have been two separate Jobs.
  146. histograms.ExpectTotalCount("Net.CertVerifier_Job_Latency", 2);
  147. histograms.ExpectTotalCount("Net.CertVerifier_First_Job_Latency", 1);
  148. }
  149. // Test that when two Requests are attached to the same Job, it's safe to
  150. // delete the second Request while processing the response to the first. The
  151. // second Request should not cause the second callback to be called.
  152. TEST_F(CoalescingCertVerifierTest, DeleteSecondRequestDuringFirstCompletion) {
  153. scoped_refptr<X509Certificate> test_cert(
  154. ImportCertFromFile(GetTestCertsDirectory(), "ok_cert.pem"));
  155. ASSERT_TRUE(test_cert);
  156. CertVerifyResult fake_result;
  157. fake_result.verified_cert = test_cert;
  158. std::unique_ptr<MockCertVerifier> mock_verifier_owner =
  159. std::make_unique<MockCertVerifier>();
  160. MockCertVerifier* mock_verifier = mock_verifier_owner.get();
  161. mock_verifier->set_async(true); // Always complete via PostTask
  162. mock_verifier->AddResultForCert(test_cert, fake_result, OK);
  163. CoalescingCertVerifier verifier(std::move(mock_verifier_owner));
  164. CertVerifier::RequestParams request_params(test_cert, "www.example.com", 0,
  165. /*ocsp_response=*/std::string(),
  166. /*sct_list=*/std::string());
  167. CertVerifyResult result1, result2;
  168. TestCompletionCallback callback1, callback2;
  169. std::unique_ptr<CertVerifier::Request> request1, request2;
  170. // Start an (asynchronous) initial request. When this request is completed,
  171. // it will delete (reset) |request2|, which should prevent it from being
  172. // called.
  173. int error = verifier.Verify(
  174. request_params, &result1,
  175. base::BindLambdaForTesting([&callback1, &request2](int result) {
  176. request2.reset();
  177. callback1.callback().Run(result);
  178. }),
  179. &request1, NetLogWithSource());
  180. ASSERT_THAT(error, IsError(ERR_IO_PENDING));
  181. EXPECT_TRUE(request1);
  182. // Start a second request; this should join the first request.
  183. error = verifier.Verify(request_params, &result2, callback2.callback(),
  184. &request2, NetLogWithSource());
  185. ASSERT_THAT(error, IsError(ERR_IO_PENDING));
  186. EXPECT_TRUE(request2);
  187. // Ensure only one underlying verification was started.
  188. ASSERT_EQ(2u, verifier.requests_for_testing());
  189. ASSERT_EQ(1u, verifier.inflight_joins_for_testing());
  190. // Make sure that only the first callback is invoked; because the second
  191. // CertVerifier::Request was deleted during processing the first's callback,
  192. // the second callback should not be invoked.
  193. EXPECT_THAT(callback1.WaitForResult(), IsOk());
  194. ASSERT_FALSE(callback2.have_result());
  195. ASSERT_FALSE(request2);
  196. // While CoalescingCertVerifier doesn't use PostTask, make sure to flush the
  197. // tasks as well, in case the implementation changes in the future.
  198. RunUntilIdle();
  199. ASSERT_FALSE(callback2.have_result());
  200. ASSERT_FALSE(request2);
  201. }
  202. // Test that it's safe to delete the CoalescingCertVerifier during completion,
  203. // even when there are outstanding Requests to be processed. The additional
  204. // Requests should not invoke the user callback once the
  205. // CoalescingCertVerifier is deleted.
  206. TEST_F(CoalescingCertVerifierTest, DeleteVerifierDuringCompletion) {
  207. scoped_refptr<X509Certificate> test_cert(
  208. ImportCertFromFile(GetTestCertsDirectory(), "ok_cert.pem"));
  209. ASSERT_TRUE(test_cert);
  210. CertVerifyResult fake_result;
  211. fake_result.verified_cert = test_cert;
  212. std::unique_ptr<MockCertVerifier> mock_verifier_owner =
  213. std::make_unique<MockCertVerifier>();
  214. MockCertVerifier* mock_verifier = mock_verifier_owner.get();
  215. mock_verifier->set_async(true); // Always complete via PostTask
  216. mock_verifier->AddResultForCert(test_cert, fake_result, OK);
  217. auto verifier =
  218. std::make_unique<CoalescingCertVerifier>(std::move(mock_verifier_owner));
  219. CertVerifier::RequestParams request_params(test_cert, "www.example.com", 0,
  220. /*ocsp_response=*/std::string(),
  221. /*sct_list=*/std::string());
  222. CertVerifyResult result1, result2;
  223. TestCompletionCallback callback1, callback2;
  224. std::unique_ptr<CertVerifier::Request> request1, request2;
  225. // Start an (asynchronous) initial request. When this request is completed,
  226. // it will delete (reset) |request2|, which should prevent it from being
  227. // called.
  228. int error = verifier->Verify(
  229. request_params, &result1,
  230. base::BindLambdaForTesting([&callback1, &verifier](int result) {
  231. verifier.reset();
  232. callback1.callback().Run(result);
  233. }),
  234. &request1, NetLogWithSource());
  235. ASSERT_THAT(error, IsError(ERR_IO_PENDING));
  236. EXPECT_TRUE(request1);
  237. // Start a second request; this should join the first request.
  238. error = verifier->Verify(request_params, &result2, callback2.callback(),
  239. &request2, NetLogWithSource());
  240. ASSERT_THAT(error, IsError(ERR_IO_PENDING));
  241. EXPECT_TRUE(request2);
  242. // Ensure only one underlying verification was started.
  243. ASSERT_EQ(2u, verifier->requests_for_testing());
  244. ASSERT_EQ(1u, verifier->inflight_joins_for_testing());
  245. // Make sure that only the first callback is invoked. This will delete the
  246. // underlying CoalescingCertVerifier, which should prevent the second
  247. // request's callback from being invoked.
  248. EXPECT_THAT(callback1.WaitForResult(), IsOk());
  249. ASSERT_FALSE(callback2.have_result());
  250. ASSERT_TRUE(request2);
  251. // While CoalescingCertVerifier doesn't use PostTask, make sure to flush the
  252. // tasks as well, in case the implementation changes in the future.
  253. RunUntilIdle();
  254. ASSERT_FALSE(callback2.have_result());
  255. ASSERT_TRUE(request2);
  256. }
  257. // Test that it's safe to delete a Request before the underlying verifier has
  258. // completed. This is a guard against memory safety (e.g. when this Request
  259. // is the last/only Request remaining).
  260. TEST_F(CoalescingCertVerifierTest, DeleteRequestBeforeCompletion) {
  261. scoped_refptr<X509Certificate> test_cert(
  262. ImportCertFromFile(GetTestCertsDirectory(), "ok_cert.pem"));
  263. ASSERT_TRUE(test_cert);
  264. CertVerifyResult fake_result;
  265. fake_result.verified_cert = test_cert;
  266. std::unique_ptr<MockCertVerifier> mock_verifier_owner =
  267. std::make_unique<MockCertVerifier>();
  268. MockCertVerifier* mock_verifier = mock_verifier_owner.get();
  269. mock_verifier->set_async(true); // Always complete via PostTask
  270. mock_verifier->AddResultForCert(test_cert, fake_result, OK);
  271. CoalescingCertVerifier verifier(std::move(mock_verifier_owner));
  272. CertVerifier::RequestParams request_params(test_cert, "www.example.com", 0,
  273. /*ocsp_response=*/std::string(),
  274. /*sct_list=*/std::string());
  275. CertVerifyResult result1;
  276. TestCompletionCallback callback1;
  277. std::unique_ptr<CertVerifier::Request> request1;
  278. // Start an (asynchronous) initial request.
  279. int error = verifier.Verify(request_params, &result1, callback1.callback(),
  280. &request1, NetLogWithSource());
  281. ASSERT_THAT(error, IsError(ERR_IO_PENDING));
  282. EXPECT_TRUE(request1);
  283. // Abandon the request before it's completed.
  284. request1.reset();
  285. EXPECT_FALSE(callback1.have_result());
  286. // Make sure the request never completes / the callback is never invoked.
  287. RunUntilIdle();
  288. EXPECT_FALSE(callback1.have_result());
  289. }
  290. // Test that it's safe to delete a Request before the underlying verifier has
  291. // completed. This is a correctness test, to ensure that other Requests are
  292. // still notified.
  293. TEST_F(CoalescingCertVerifierTest,
  294. DeleteFirstRequestBeforeCompletionStillCompletesSecondRequest) {
  295. scoped_refptr<X509Certificate> test_cert(
  296. ImportCertFromFile(GetTestCertsDirectory(), "ok_cert.pem"));
  297. ASSERT_TRUE(test_cert);
  298. CertVerifyResult fake_result;
  299. fake_result.verified_cert = test_cert;
  300. std::unique_ptr<MockCertVerifier> mock_verifier_owner =
  301. std::make_unique<MockCertVerifier>();
  302. MockCertVerifier* mock_verifier = mock_verifier_owner.get();
  303. mock_verifier->set_async(true); // Always complete via PostTask
  304. mock_verifier->AddResultForCert(test_cert, fake_result, OK);
  305. CoalescingCertVerifier verifier(std::move(mock_verifier_owner));
  306. CertVerifier::RequestParams request_params(test_cert, "www.example.com", 0,
  307. /*ocsp_response=*/std::string(),
  308. /*sct_list=*/std::string());
  309. CertVerifyResult result1, result2;
  310. TestCompletionCallback callback1, callback2;
  311. std::unique_ptr<CertVerifier::Request> request1, request2;
  312. // Start an (asynchronous) initial request.
  313. int error = verifier.Verify(request_params, &result1, callback1.callback(),
  314. &request1, NetLogWithSource());
  315. ASSERT_THAT(error, IsError(ERR_IO_PENDING));
  316. EXPECT_TRUE(request1);
  317. // Start a second request; this should join the first request.
  318. error = verifier.Verify(request_params, &result2, callback2.callback(),
  319. &request2, NetLogWithSource());
  320. ASSERT_THAT(error, IsError(ERR_IO_PENDING));
  321. EXPECT_TRUE(request2);
  322. // Ensure only one underlying verification was started.
  323. ASSERT_EQ(2u, verifier.requests_for_testing());
  324. ASSERT_EQ(1u, verifier.inflight_joins_for_testing());
  325. // Abandon the first request before it's completed.
  326. request1.reset();
  327. // Make sure the first request never completes / the callback is never
  328. // invoked, while the second request completes normally.
  329. EXPECT_THAT(callback2.WaitForResult(), IsOk());
  330. EXPECT_FALSE(callback1.have_result());
  331. // Simulate the second request going away during processing.
  332. request2.reset();
  333. // Flush any events, although there should not be any.
  334. RunUntilIdle();
  335. EXPECT_FALSE(callback1.have_result());
  336. }
  337. TEST_F(CoalescingCertVerifierTest, DeleteRequestDuringCompletion) {
  338. scoped_refptr<X509Certificate> test_cert(
  339. ImportCertFromFile(GetTestCertsDirectory(), "ok_cert.pem"));
  340. ASSERT_TRUE(test_cert);
  341. CertVerifyResult fake_result;
  342. fake_result.verified_cert = test_cert;
  343. std::unique_ptr<MockCertVerifier> mock_verifier_owner =
  344. std::make_unique<MockCertVerifier>();
  345. MockCertVerifier* mock_verifier = mock_verifier_owner.get();
  346. mock_verifier->set_async(true); // Always complete via PostTask
  347. mock_verifier->AddResultForCert(test_cert, fake_result, OK);
  348. CoalescingCertVerifier verifier(std::move(mock_verifier_owner));
  349. CertVerifier::RequestParams request_params(test_cert, "www.example.com", 0,
  350. /*ocsp_response=*/std::string(),
  351. /*sct_list=*/std::string());
  352. CertVerifyResult result1;
  353. TestCompletionCallback callback1;
  354. std::unique_ptr<CertVerifier::Request> request1;
  355. // Start an (asynchronous) initial request.
  356. int error = verifier.Verify(
  357. request_params, &result1,
  358. base::BindLambdaForTesting([&callback1, &request1](int result) {
  359. // Delete the Request during the completion callback. This should be
  360. // perfectly safe, and not cause any memory trouble, because the
  361. // Request was already detached from the Job prior to being invoked.
  362. request1.reset();
  363. callback1.callback().Run(result);
  364. }),
  365. &request1, NetLogWithSource());
  366. ASSERT_THAT(error, IsError(ERR_IO_PENDING));
  367. EXPECT_TRUE(request1);
  368. // The result should be available, even though the request is deleted
  369. // during the result processing. This should not cause any memory errors.
  370. EXPECT_THAT(callback1.WaitForResult(), IsOk());
  371. }
  372. TEST_F(CoalescingCertVerifierTest, DeleteVerifierBeforeRequest) {
  373. scoped_refptr<X509Certificate> test_cert(
  374. ImportCertFromFile(GetTestCertsDirectory(), "ok_cert.pem"));
  375. ASSERT_TRUE(test_cert);
  376. base::HistogramTester histograms;
  377. CertVerifyResult fake_result;
  378. fake_result.verified_cert = test_cert;
  379. std::unique_ptr<MockCertVerifier> mock_verifier_owner =
  380. std::make_unique<MockCertVerifier>();
  381. MockCertVerifier* mock_verifier = mock_verifier_owner.get();
  382. mock_verifier->set_async(true); // Always complete via PostTask
  383. mock_verifier->AddResultForCert(test_cert, fake_result, OK);
  384. auto verifier =
  385. std::make_unique<CoalescingCertVerifier>(std::move(mock_verifier_owner));
  386. CertVerifier::RequestParams request_params(test_cert, "www.example.com", 0,
  387. /*ocsp_response=*/std::string(),
  388. /*sct_list=*/std::string());
  389. CertVerifyResult result1;
  390. TestCompletionCallback callback1;
  391. std::unique_ptr<CertVerifier::Request> request1;
  392. // Start an (asynchronous) initial request.
  393. int error = verifier->Verify(request_params, &result1, callback1.callback(),
  394. &request1, NetLogWithSource());
  395. ASSERT_THAT(error, IsError(ERR_IO_PENDING));
  396. EXPECT_TRUE(request1);
  397. // Delete the CoalescingCertVerifier first. This should orphan all
  398. // outstanding Requests and delete all associated Jobs.
  399. verifier.reset();
  400. // Flush any pending tasks; there should not be any, at this point, but use
  401. // it in case the implementation changes.
  402. RunUntilIdle();
  403. // Make sure the callback was never called.
  404. EXPECT_FALSE(callback1.have_result());
  405. // Delete the Request. This should be a no-op as the Request was orphaned
  406. // when the CoalescingCertVerifier was deleted.
  407. request1.reset();
  408. // There should not have been any histograms logged.
  409. histograms.ExpectTotalCount("Net.CertVerifier_Job_Latency", 0);
  410. histograms.ExpectTotalCount("Net.CertVerifier_First_Job_Latency", 0);
  411. }
  412. } // namespace net