multi_log_ct_verifier_unittest.cc 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274
  1. // Copyright 2013 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/multi_log_ct_verifier.h"
  5. #include <memory>
  6. #include <string>
  7. #include "base/files/file_path.h"
  8. #include "base/files/file_util.h"
  9. #include "base/metrics/histogram.h"
  10. #include "base/metrics/histogram_samples.h"
  11. #include "base/metrics/statistics_recorder.h"
  12. #include "base/values.h"
  13. #include "net/base/net_errors.h"
  14. #include "net/cert/ct_log_verifier.h"
  15. #include "net/cert/ct_serialization.h"
  16. #include "net/cert/pem.h"
  17. #include "net/cert/sct_status_flags.h"
  18. #include "net/cert/signed_certificate_timestamp.h"
  19. #include "net/cert/signed_certificate_timestamp_and_status.h"
  20. #include "net/cert/x509_certificate.h"
  21. #include "net/log/net_log_source_type.h"
  22. #include "net/log/net_log_with_source.h"
  23. #include "net/log/test_net_log.h"
  24. #include "net/log/test_net_log_util.h"
  25. #include "net/test/cert_test_util.h"
  26. #include "net/test/ct_test_util.h"
  27. #include "net/test/test_data_directory.h"
  28. #include "testing/gmock/include/gmock/gmock.h"
  29. #include "testing/gtest/include/gtest/gtest.h"
  30. using testing::_;
  31. using testing::Mock;
  32. namespace net {
  33. namespace {
  34. const char kHostname[] = "example.com";
  35. const char kLogDescription[] = "somelog";
  36. class DoNothingLogProvider : public MultiLogCTVerifier::CTLogProvider {
  37. public:
  38. DoNothingLogProvider() = default;
  39. ~DoNothingLogProvider() = default;
  40. };
  41. class MultiLogCTVerifierTest : public ::testing::Test {
  42. public:
  43. void SetUp() override {
  44. scoped_refptr<const CTLogVerifier> log(
  45. CTLogVerifier::Create(ct::GetTestPublicKey(), kLogDescription));
  46. ASSERT_TRUE(log);
  47. log_verifiers_.push_back(log);
  48. DoNothingLogProvider notifier;
  49. verifier_ = std::make_unique<MultiLogCTVerifier>(&notifier);
  50. verifier_->SetLogs(log_verifiers_);
  51. std::string der_test_cert(ct::GetDerEncodedX509Cert());
  52. chain_ = X509Certificate::CreateFromBytes(
  53. base::as_bytes(base::make_span(der_test_cert)));
  54. ASSERT_TRUE(chain_.get());
  55. embedded_sct_chain_ =
  56. CreateCertificateChainFromFile(GetTestCertsDirectory(),
  57. "ct-test-embedded-cert.pem",
  58. X509Certificate::FORMAT_AUTO);
  59. ASSERT_TRUE(embedded_sct_chain_.get());
  60. }
  61. bool CheckForEmbeddedSCTInNetLog(
  62. const RecordingNetLogObserver& net_log_observer) {
  63. auto entries = net_log_observer.GetEntries();
  64. if (entries.size() != 2)
  65. return false;
  66. auto embedded_scts =
  67. GetOptionalStringValueFromParams(entries[0], "embedded_scts");
  68. if (!embedded_scts || embedded_scts->empty())
  69. return false;
  70. const NetLogEntry& parsed = entries[1];
  71. if (!parsed.params.is_dict())
  72. return false;
  73. const base::Value* scts = parsed.params.FindListPath("scts");
  74. if (!scts || scts->GetListDeprecated().size() != 1)
  75. return false;
  76. const base::Value& the_sct = scts->GetListDeprecated()[0];
  77. if (!the_sct.is_dict())
  78. return false;
  79. const std::string* origin = the_sct.FindStringPath("origin");
  80. if (!origin || *origin != "Embedded in certificate")
  81. return false;
  82. const std::string* verification_status =
  83. the_sct.FindStringPath("verification_status");
  84. if (!verification_status || *verification_status != "Verified")
  85. return false;
  86. return true;
  87. }
  88. // Returns true if |chain| is a certificate with embedded SCTs that can be
  89. // successfully extracted.
  90. bool VerifySinglePrecertificateChain(scoped_refptr<X509Certificate> chain) {
  91. SignedCertificateTimestampAndStatusList scts;
  92. verifier_->Verify(kHostname, chain.get(), base::StringPiece(),
  93. base::StringPiece(), &scts, NetLogWithSource());
  94. return !scts.empty();
  95. }
  96. // Returns true if |chain| is a certificate with a single embedded SCT that
  97. // can be successfully extracted and matched to the test log indicated by
  98. // |kLogDescription|.
  99. bool CheckPrecertificateVerification(scoped_refptr<X509Certificate> chain) {
  100. SignedCertificateTimestampAndStatusList scts;
  101. RecordingNetLogObserver net_log_observer(NetLogCaptureMode::kDefault);
  102. NetLogWithSource net_log = NetLogWithSource::Make(
  103. NetLog::Get(), NetLogSourceType::SSL_CONNECT_JOB);
  104. verifier_->Verify(kHostname, chain.get(), base::StringPiece(),
  105. base::StringPiece(), &scts, net_log);
  106. return ct::CheckForSingleVerifiedSCTInResult(scts, kLogDescription) &&
  107. ct::CheckForSCTOrigin(
  108. scts, ct::SignedCertificateTimestamp::SCT_EMBEDDED) &&
  109. CheckForEmbeddedSCTInNetLog(net_log_observer);
  110. }
  111. // Histogram-related helper methods
  112. int GetValueFromHistogram(const std::string& histogram_name,
  113. int sample_index) {
  114. base::Histogram* histogram = static_cast<base::Histogram*>(
  115. base::StatisticsRecorder::FindHistogram(histogram_name));
  116. if (histogram == nullptr)
  117. return 0;
  118. std::unique_ptr<base::HistogramSamples> samples =
  119. histogram->SnapshotSamples();
  120. return samples->GetCount(sample_index);
  121. }
  122. int NumEmbeddedSCTsInHistogram() {
  123. return GetValueFromHistogram("Net.CertificateTransparency.SCTOrigin",
  124. ct::SignedCertificateTimestamp::SCT_EMBEDDED);
  125. }
  126. int NumValidSCTsInStatusHistogram() {
  127. return GetValueFromHistogram("Net.CertificateTransparency.SCTStatus",
  128. ct::SCT_STATUS_OK);
  129. }
  130. protected:
  131. std::unique_ptr<MultiLogCTVerifier> verifier_;
  132. scoped_refptr<X509Certificate> chain_;
  133. scoped_refptr<X509Certificate> embedded_sct_chain_;
  134. std::vector<scoped_refptr<const CTLogVerifier>> log_verifiers_;
  135. };
  136. TEST_F(MultiLogCTVerifierTest, VerifiesEmbeddedSCT) {
  137. ASSERT_TRUE(CheckPrecertificateVerification(embedded_sct_chain_));
  138. }
  139. TEST_F(MultiLogCTVerifierTest, VerifiesEmbeddedSCTWithPreCA) {
  140. scoped_refptr<X509Certificate> chain(
  141. CreateCertificateChainFromFile(GetTestCertsDirectory(),
  142. "ct-test-embedded-with-preca-chain.pem",
  143. X509Certificate::FORMAT_AUTO));
  144. ASSERT_TRUE(chain.get());
  145. ASSERT_TRUE(CheckPrecertificateVerification(chain));
  146. }
  147. TEST_F(MultiLogCTVerifierTest, VerifiesEmbeddedSCTWithIntermediate) {
  148. scoped_refptr<X509Certificate> chain(CreateCertificateChainFromFile(
  149. GetTestCertsDirectory(),
  150. "ct-test-embedded-with-intermediate-chain.pem",
  151. X509Certificate::FORMAT_AUTO));
  152. ASSERT_TRUE(chain.get());
  153. ASSERT_TRUE(CheckPrecertificateVerification(chain));
  154. }
  155. TEST_F(MultiLogCTVerifierTest,
  156. VerifiesEmbeddedSCTWithIntermediateAndPreCA) {
  157. scoped_refptr<X509Certificate> chain(CreateCertificateChainFromFile(
  158. GetTestCertsDirectory(),
  159. "ct-test-embedded-with-intermediate-preca-chain.pem",
  160. X509Certificate::FORMAT_AUTO));
  161. ASSERT_TRUE(chain.get());
  162. ASSERT_TRUE(CheckPrecertificateVerification(chain));
  163. }
  164. TEST_F(MultiLogCTVerifierTest, VerifiesSCTOverX509Cert) {
  165. std::string sct_list = ct::GetSCTListForTesting();
  166. SignedCertificateTimestampAndStatusList scts;
  167. verifier_->Verify(kHostname, chain_.get(), base::StringPiece(), sct_list,
  168. &scts, NetLogWithSource());
  169. ASSERT_TRUE(ct::CheckForSingleVerifiedSCTInResult(scts, kLogDescription));
  170. ASSERT_TRUE(ct::CheckForSCTOrigin(
  171. scts, ct::SignedCertificateTimestamp::SCT_FROM_TLS_EXTENSION));
  172. }
  173. TEST_F(MultiLogCTVerifierTest, IdentifiesSCTFromUnknownLog) {
  174. std::string sct_list = ct::GetSCTListWithInvalidSCT();
  175. SignedCertificateTimestampAndStatusList scts;
  176. verifier_->Verify(kHostname, chain_.get(), base::StringPiece(), sct_list,
  177. &scts, NetLogWithSource());
  178. EXPECT_EQ(1U, scts.size());
  179. EXPECT_EQ("", scts[0].sct->log_description);
  180. EXPECT_EQ(ct::SCT_STATUS_LOG_UNKNOWN, scts[0].status);
  181. }
  182. TEST_F(MultiLogCTVerifierTest, CountsValidSCTsInStatusHistogram) {
  183. int num_valid_scts = NumValidSCTsInStatusHistogram();
  184. ASSERT_TRUE(VerifySinglePrecertificateChain(embedded_sct_chain_));
  185. EXPECT_EQ(num_valid_scts + 1, NumValidSCTsInStatusHistogram());
  186. }
  187. TEST_F(MultiLogCTVerifierTest, CountsInvalidSCTsInStatusHistogram) {
  188. std::string sct_list = ct::GetSCTListWithInvalidSCT();
  189. SignedCertificateTimestampAndStatusList scts;
  190. int num_valid_scts = NumValidSCTsInStatusHistogram();
  191. int num_invalid_scts = GetValueFromHistogram(
  192. "Net.CertificateTransparency.SCTStatus", ct::SCT_STATUS_LOG_UNKNOWN);
  193. verifier_->Verify(kHostname, chain_.get(), base::StringPiece(), sct_list,
  194. &scts, NetLogWithSource());
  195. ASSERT_EQ(num_valid_scts, NumValidSCTsInStatusHistogram());
  196. ASSERT_EQ(num_invalid_scts + 1,
  197. GetValueFromHistogram("Net.CertificateTransparency.SCTStatus",
  198. ct::SCT_STATUS_LOG_UNKNOWN));
  199. }
  200. TEST_F(MultiLogCTVerifierTest, CountsSingleEmbeddedSCTInOriginsHistogram) {
  201. int old_embedded_count = NumEmbeddedSCTsInHistogram();
  202. ASSERT_TRUE(CheckPrecertificateVerification(embedded_sct_chain_));
  203. EXPECT_EQ(old_embedded_count + 1, NumEmbeddedSCTsInHistogram());
  204. }
  205. TEST_F(MultiLogCTVerifierTest, SetLogsRemovesOldLogs) {
  206. log_verifiers_.clear();
  207. verifier_->SetLogs(log_verifiers_);
  208. // Log list is now empty so verification should fail.
  209. ASSERT_FALSE(CheckPrecertificateVerification(embedded_sct_chain_));
  210. }
  211. TEST_F(MultiLogCTVerifierTest, SetLogsAddsNewLogs) {
  212. // Clear the log list.
  213. log_verifiers_.clear();
  214. verifier_->SetLogs(log_verifiers_);
  215. // Add valid log again via SetLogs
  216. scoped_refptr<const CTLogVerifier> log(
  217. CTLogVerifier::Create(ct::GetTestPublicKey(), kLogDescription));
  218. ASSERT_TRUE(log);
  219. log_verifiers_.push_back(log);
  220. verifier_->SetLogs(log_verifiers_);
  221. // Verification should now succeed.
  222. ASSERT_TRUE(CheckPrecertificateVerification(embedded_sct_chain_));
  223. }
  224. } // namespace
  225. } // namespace net