Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2016 The Chromium Authors. All rights reserved. | 1 // Copyright 2016 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "components/certificate_transparency/single_tree_tracker.h" | 5 #include "components/certificate_transparency/single_tree_tracker.h" |
| 6 | 6 |
| 7 #include <string> | 7 #include <string> |
| 8 #include <utility> | 8 #include <utility> |
| 9 | 9 |
| 10 #include "base/memory/ptr_util.h" | |
| 11 #include "base/message_loop/message_loop.h" | |
| 12 #include "base/run_loop.h" | |
| 10 #include "base/strings/string_piece.h" | 13 #include "base/strings/string_piece.h" |
| 11 #include "base/test/histogram_tester.h" | 14 #include "base/test/histogram_tester.h" |
| 15 #include "components/base32/base32.h" | |
| 16 #include "components/certificate_transparency/log_dns_client.h" | |
| 17 #include "components/certificate_transparency/mock_log_dns_traffic.h" | |
| 18 #include "crypto/sha2.h" | |
| 19 #include "net/base/network_change_notifier.h" | |
| 12 #include "net/cert/ct_log_verifier.h" | 20 #include "net/cert/ct_log_verifier.h" |
| 13 #include "net/cert/ct_serialization.h" | 21 #include "net/cert/ct_serialization.h" |
| 22 #include "net/cert/merkle_tree_leaf.h" | |
| 14 #include "net/cert/signed_certificate_timestamp.h" | 23 #include "net/cert/signed_certificate_timestamp.h" |
| 15 #include "net/cert/signed_tree_head.h" | 24 #include "net/cert/signed_tree_head.h" |
| 16 #include "net/cert/x509_certificate.h" | 25 #include "net/cert/x509_certificate.h" |
| 26 #include "net/dns/dns_client.h" | |
| 27 #include "net/log/net_log.h" | |
| 17 #include "net/test/ct_test_util.h" | 28 #include "net/test/ct_test_util.h" |
| 18 #include "testing/gtest/include/gtest/gtest.h" | 29 #include "testing/gtest/include/gtest/gtest.h" |
| 19 | 30 |
| 31 using net::ct::SignedCertificateTimestamp; | |
| 32 using net::ct::SignedTreeHead; | |
| 33 | |
| 20 namespace certificate_transparency { | 34 namespace certificate_transparency { |
| 21 | 35 |
| 22 namespace { | 36 namespace { |
| 23 | 37 |
| 24 const char kCanCheckForInclusionHistogramName[] = | 38 const char kCanCheckForInclusionHistogramName[] = |
| 25 "Net.CertificateTransparency.CanInclusionCheckSCT"; | 39 "Net.CertificateTransparency.CanInclusionCheckSCT"; |
| 40 const char kInclusionCheckResultHistogramName[] = | |
| 41 "Net.CertificateTransparency.InclusionCheckResult"; | |
| 26 | 42 |
| 27 bool GetOldSignedTreeHead(net::ct::SignedTreeHead* sth) { | 43 base::TimeDelta kMoreThanMMD = base::TimeDelta::FromHours(25); |
| 28 sth->version = net::ct::SignedTreeHead::V1; | 44 |
| 45 bool GetOldSignedTreeHead(SignedTreeHead* sth) { | |
| 46 sth->version = SignedTreeHead::V1; | |
| 29 sth->timestamp = base::Time::UnixEpoch() + | 47 sth->timestamp = base::Time::UnixEpoch() + |
| 30 base::TimeDelta::FromMilliseconds(INT64_C(1348589665525)); | 48 base::TimeDelta::FromMilliseconds(INT64_C(1348589665525)); |
| 31 sth->tree_size = 12u; | 49 sth->tree_size = 12u; |
| 32 | 50 |
| 33 const uint8_t kOldSTHRootHash[] = { | 51 const uint8_t kOldSTHRootHash[] = { |
| 34 0x18, 0x04, 0x1b, 0xd4, 0x66, 0x50, 0x83, 0x00, 0x1f, 0xba, 0x8c, | 52 0x18, 0x04, 0x1b, 0xd4, 0x66, 0x50, 0x83, 0x00, 0x1f, 0xba, 0x8c, |
| 35 0x54, 0x11, 0xd2, 0xd7, 0x48, 0xe8, 0xab, 0xbf, 0xdc, 0xdf, 0xd9, | 53 0x54, 0x11, 0xd2, 0xd7, 0x48, 0xe8, 0xab, 0xbf, 0xdc, 0xdf, 0xd9, |
| 36 0x21, 0x8c, 0xb0, 0x2b, 0x68, 0xa7, 0x8e, 0x7d, 0x4c, 0x23}; | 54 0x21, 0x8c, 0xb0, 0x2b, 0x68, 0xa7, 0x8e, 0x7d, 0x4c, 0x23}; |
| 37 memcpy(sth->sha256_root_hash, kOldSTHRootHash, net::ct::kSthRootHashLength); | 55 memcpy(sth->sha256_root_hash, kOldSTHRootHash, net::ct::kSthRootHashLength); |
| 38 | 56 |
| 39 sth->log_id = net::ct::GetTestPublicKeyId(); | 57 sth->log_id = net::ct::GetTestPublicKeyId(); |
| 40 | 58 |
| 41 const uint8_t kOldSTHSignatureData[] = { | 59 const uint8_t kOldSTHSignatureData[] = { |
| 42 0x04, 0x03, 0x00, 0x47, 0x30, 0x45, 0x02, 0x20, 0x15, 0x7b, 0x23, | 60 0x04, 0x03, 0x00, 0x47, 0x30, 0x45, 0x02, 0x20, 0x15, 0x7b, 0x23, |
| 43 0x42, 0xa2, 0x5f, 0x88, 0xc9, 0x0b, 0x30, 0xa6, 0xb4, 0x49, 0x50, | 61 0x42, 0xa2, 0x5f, 0x88, 0xc9, 0x0b, 0x30, 0xa6, 0xb4, 0x49, 0x50, |
| 44 0xb3, 0xab, 0xf5, 0x25, 0xfe, 0x27, 0xf0, 0x3f, 0x9a, 0xbf, 0xc1, | 62 0xb3, 0xab, 0xf5, 0x25, 0xfe, 0x27, 0xf0, 0x3f, 0x9a, 0xbf, 0xc1, |
| 45 0x16, 0x5a, 0x7a, 0xc0, 0x62, 0x2b, 0xbb, 0x02, 0x21, 0x00, 0xe6, | 63 0x16, 0x5a, 0x7a, 0xc0, 0x62, 0x2b, 0xbb, 0x02, 0x21, 0x00, 0xe6, |
| 46 0x57, 0xa3, 0xfe, 0xfc, 0x5a, 0x82, 0x9b, 0x29, 0x46, 0x15, 0x1d, | 64 0x57, 0xa3, 0xfe, 0xfc, 0x5a, 0x82, 0x9b, 0x29, 0x46, 0x15, 0x1d, |
| 47 0xbc, 0xfd, 0x9e, 0x87, 0x7f, 0xd0, 0x00, 0x5d, 0x62, 0x4f, 0x9a, | 65 0xbc, 0xfd, 0x9e, 0x87, 0x7f, 0xd0, 0x00, 0x5d, 0x62, 0x4f, 0x9a, |
| 48 0x1a, 0x9f, 0x20, 0x79, 0xd0, 0xc1, 0x34, 0x2e, 0x08}; | 66 0x1a, 0x9f, 0x20, 0x79, 0xd0, 0xc1, 0x34, 0x2e, 0x08}; |
| 49 base::StringPiece sp(reinterpret_cast<const char*>(kOldSTHSignatureData), | 67 base::StringPiece sp(reinterpret_cast<const char*>(kOldSTHSignatureData), |
| 50 sizeof(kOldSTHSignatureData)); | 68 sizeof(kOldSTHSignatureData)); |
| 51 return DecodeDigitallySigned(&sp, &(sth->signature)) && sp.empty(); | 69 return DecodeDigitallySigned(&sp, &(sth->signature)) && sp.empty(); |
| 52 } | 70 } |
| 53 | 71 |
| 72 scoped_refptr<SignedCertificateTimestamp> GetSCT() { | |
| 73 scoped_refptr<SignedCertificateTimestamp> sct; | |
| 74 | |
| 75 // TODO(eranm): Move setting of the origin field to ct_test_util.cc | |
| 76 net::ct::GetX509CertSCT(&sct); | |
| 77 sct->origin = SignedCertificateTimestamp::SCT_FROM_OCSP_RESPONSE; | |
| 78 return sct; | |
| 79 } | |
| 80 | |
| 81 std::string Base32LeafHash(const net::X509Certificate* cert, | |
| 82 const SignedCertificateTimestamp* sct) { | |
| 83 net::ct::MerkleTreeLeaf leaf; | |
| 84 if (!GetMerkleTreeLeaf(cert, sct, &leaf)) | |
| 85 return std::string(); | |
| 86 | |
| 87 std::string leaf_hash; | |
| 88 if (!HashMerkleTreeLeaf(leaf, &leaf_hash)) | |
| 89 return std::string(); | |
| 90 | |
| 91 return base32::Base32Encode(leaf_hash, | |
| 92 base32::Base32EncodePolicy::OMIT_PADDING); | |
| 93 } | |
| 94 | |
| 95 template <typename... T> | |
| 96 void AssertSCTsMatchingState(SingleTreeTracker* tree_tracker, | |
| 97 net::X509Certificate* chain, | |
| 98 SingleTreeTracker::SCTInclusionStatus status, | |
| 99 T... scts) { | |
|
Ryan Sleevi
2016/12/14 01:34:15
This seems like a lot of... undesirable template o
Eran Messeri
2016/12/22 16:12:11
Added documentation.
I've created this function b
| |
| 100 const int sct_list_size = sizeof...(scts); | |
| 101 SignedCertificateTimestamp* sct_list[sct_list_size] = {scts...}; | |
| 102 for (const auto& sct : sct_list) { | |
| 103 EXPECT_EQ(status, tree_tracker->GetLogEntryInclusionStatus(chain, sct)) | |
| 104 << "SCT age: " << sct->timestamp; | |
| 105 } | |
| 106 }; | |
| 107 | |
| 108 bool GetSignedTreeHeadForTreeOfSize2(SignedTreeHead* sth) { | |
| 109 sth->version = SignedTreeHead::V1; | |
| 110 sth->timestamp = base::Time::UnixEpoch() + | |
| 111 base::TimeDelta::FromMilliseconds(INT64_C(1365354256089)); | |
|
Ryan Sleevi
2016/12/14 01:34:16
Document.
Eran Messeri
2016/12/22 16:12:11
Done.
| |
| 112 sth->tree_size = 2; | |
| 113 const uint8_t kRootHash[] = {0x16, 0x80, 0xbd, 0x5a, 0x1b, 0xc1, 0xb6, 0xcf, | |
| 114 0x1b, 0x7e, 0x77, 0x41, 0xeb, 0xed, 0x86, 0x8b, | |
| 115 0x73, 0x81, 0x87, 0xf5, 0xab, 0x93, 0x6d, 0xb2, | |
| 116 0x0a, 0x79, 0x0d, 0x9e, 0x40, 0x55, 0xc3, 0xe6}; | |
|
Ryan Sleevi
2016/12/14 01:34:16
Document.
Eran Messeri
2016/12/22 16:12:11
Done.
| |
| 117 std::string decoded_root_hash(reinterpret_cast<const char*>(kRootHash), | |
| 118 net::ct::kSthRootHashLength); | |
| 119 | |
| 120 memcpy(sth->sha256_root_hash, decoded_root_hash.data(), | |
| 121 decoded_root_hash.size()); | |
|
Ryan Sleevi
2016/12/14 01:34:15
Why is 117-121 necessary? Can't you just copy in d
Eran Messeri
2016/12/22 16:12:11
Not necessary, removed.
| |
| 122 sth->log_id = net::ct::GetTestPublicKeyId(); | |
| 123 | |
| 124 const uint8_t kTreeHeadSignatureData[] = { | |
| 125 0x04, 0x03, 0x00, 0x46, 0x30, 0x44, 0x02, 0x20, 0x25, 0xa1, 0x9d, | |
| 126 0x7b, 0xf6, 0xe6, 0xfc, 0x47, 0xa7, 0x2d, 0xef, 0x6b, 0xf4, 0x84, | |
| 127 0x71, 0xb7, 0x7b, 0x7e, 0xd4, 0x4c, 0x7a, 0x5c, 0x4f, 0x9a, 0xb7, | |
| 128 0x04, 0x71, 0x6e, 0xd0, 0xa8, 0x0f, 0x53, 0x02, 0x20, 0x27, 0xe5, | |
| 129 0xed, 0x7d, 0xc3, 0x5d, 0x4c, 0xf0, 0x67, 0x35, 0x5d, 0x8a, 0x10, | |
| 130 0xae, 0x25, 0x87, 0x1a, 0xef, 0xea, 0xd2, 0xf7, 0xe3, 0x73, 0x2f, | |
| 131 0x07, 0xb3, 0x4b, 0xea, 0x5b, 0xdd, 0x81, 0x2d}; | |
|
Ryan Sleevi
2016/12/14 01:34:16
Document.
Eran Messeri
2016/12/22 16:12:12
Done.
| |
| 132 | |
| 133 base::StringPiece sp(reinterpret_cast<const char*>(kTreeHeadSignatureData), | |
| 134 sizeof(kTreeHeadSignatureData)); | |
| 135 return DecodeDigitallySigned(&sp, &sth->signature); | |
| 136 } | |
| 137 | |
| 138 void FillVectorWithValidAuditProofForTreeOfSize2( | |
| 139 std::vector<std::string>* out_proof) { | |
| 140 std::string node(crypto::kSHA256Length, '\0'); | |
| 141 for (size_t i = 0; i < crypto::kSHA256Length; ++i) { | |
| 142 node[i] = static_cast<char>(0x0a); | |
| 143 } | |
| 144 out_proof->push_back(node); | |
| 145 } | |
| 146 | |
| 54 } // namespace | 147 } // namespace |
| 55 | 148 |
| 56 class SingleTreeTrackerTest : public ::testing::Test { | 149 class SingleTreeTrackerTest : public ::testing::Test { |
| 57 void SetUp() override { | 150 void SetUp() override { |
| 58 log_ = | 151 log_ = |
| 59 net::CTLogVerifier::Create(net::ct::GetTestPublicKey(), "testlog", | 152 net::CTLogVerifier::Create(net::ct::GetTestPublicKey(), "testlog", |
| 60 "https://ct.example.com", "dns.example.com"); | 153 "https://ct.example.com", "dns.example.com"); |
| 61 | 154 |
| 62 ASSERT_TRUE(log_); | 155 ASSERT_TRUE(log_); |
| 63 ASSERT_EQ(log_->key_id(), net::ct::GetTestPublicKeyId()); | 156 ASSERT_EQ(log_->key_id(), net::ct::GetTestPublicKeyId()); |
| 64 | 157 |
| 65 tree_tracker_.reset(new SingleTreeTracker(log_)); | |
| 66 const std::string der_test_cert(net::ct::GetDerEncodedX509Cert()); | 158 const std::string der_test_cert(net::ct::GetDerEncodedX509Cert()); |
| 67 chain_ = net::X509Certificate::CreateFromBytes(der_test_cert.data(), | 159 chain_ = net::X509Certificate::CreateFromBytes(der_test_cert.data(), |
| 68 der_test_cert.length()); | 160 der_test_cert.length()); |
| 69 ASSERT_TRUE(chain_.get()); | 161 ASSERT_TRUE(chain_.get()); |
| 70 net::ct::GetX509CertSCT(&cert_sct_); | 162 net::ct::GetX509CertSCT(&cert_sct_); |
| 163 cert_sct_->origin = SignedCertificateTimestamp::SCT_FROM_OCSP_RESPONSE; | |
| 164 | |
| 165 ClearDnsConfig(); | |
|
Ryan Sleevi
2016/12/14 01:34:16
Why is this necessary? Why can't it just be handle
Eran Messeri
2016/12/22 16:12:11
If I understand correctly, the question is why isn
Ryan Sleevi
2016/12/22 21:33:20
The latter - initialize the pointer in the ctor, a
| |
| 166 // Default to throttling requests as it means observed log entries will | |
| 167 // be frozen in a pending state, simplifying testing of the | |
| 168 // SingleTreeTracker. | |
| 169 ASSERT_TRUE(ExpectLeafHashRequestAndThrottle(chain_, cert_sct_)); | |
| 170 CreateTreeTracker(); | |
| 71 } | 171 } |
| 72 | 172 |
| 73 protected: | 173 protected: |
| 174 void ClearDnsConfig() { | |
| 175 // Must clear the global one first. | |
| 176 net_change_notifier_.reset(); | |
| 177 net_change_notifier_.reset(net::NetworkChangeNotifier::CreateMock()); | |
|
Ryan Sleevi
2016/12/14 01:34:15
Every test creates a new instance, so the first .r
Eran Messeri
2016/12/22 16:12:11
It's true that every test creates a new instance.
| |
| 178 | |
| 179 mock_dns_.reset(new MockLogDnsTraffic); | |
| 180 mock_dns_->InitializeDnsConfig(); | |
|
Ryan Sleevi
2016/12/14 01:34:16
Do these need to be unique? Can they just be membe
Eran Messeri
2016/12/22 16:12:12
Not sure about the question: Are you suggesting it
Ryan Sleevi
2016/12/22 21:33:20
Yes.
| |
| 181 } | |
| 182 | |
| 183 void CreateTreeTracker() { | |
|
Ryan Sleevi
2016/12/14 01:34:16
Doesn't seem necessary to have this helper functio
Eran Messeri
2016/12/22 16:12:11
Do you mean it seems like this function is not cal
Ryan Sleevi
2016/12/22 21:33:20
No. I meant more specifically: It does not seem ne
| |
| 184 log_dns_client_ = base::MakeUnique<LogDnsClient>( | |
| 185 mock_dns_->CreateDnsClient(), net_log_, 1); | |
| 186 | |
| 187 tree_tracker_.reset(new SingleTreeTracker(log_, log_dns_client_.get())); | |
| 188 } | |
| 189 | |
| 190 bool ExpectLeafHashRequestAndThrottle( | |
|
Ryan Sleevi
2016/12/14 01:34:16
Document
Eran Messeri
2016/12/22 16:12:12
Done, also renamed to ExpectLeafIndexRequestAndThr
| |
| 191 scoped_refptr<net::X509Certificate> chain, | |
| 192 scoped_refptr<SignedCertificateTimestamp> sct) { | |
|
Ryan Sleevi
2016/12/14 01:34:16
Doesn't seem like you need to be passing these byv
Eran Messeri
2016/12/22 16:12:12
Done (const-ref rather than naked pointers because
| |
| 193 return mock_dns_->ExpectRequestAndSocketError( | |
| 194 Base32LeafHash(chain.get(), sct.get()) + | |
| 195 ".hash.dns.example." | |
|
Ryan Sleevi
2016/12/14 01:34:16
Mostly since you're adding it in this test, I thin
Eran Messeri
2016/12/22 16:12:11
Fixed throughout by adding a constant for the pref
Ryan Sleevi
2016/12/22 21:33:20
No, I think you're fine.
| |
| 196 "com", | |
| 197 net::Error::ERR_TEMPORARILY_THROTTLED); | |
| 198 } | |
| 199 | |
| 200 base::MessageLoopForIO message_loop_; | |
| 201 std::unique_ptr<MockLogDnsTraffic> mock_dns_; | |
| 74 scoped_refptr<const net::CTLogVerifier> log_; | 202 scoped_refptr<const net::CTLogVerifier> log_; |
| 203 std::unique_ptr<net::NetworkChangeNotifier> net_change_notifier_; | |
| 204 std::unique_ptr<LogDnsClient> log_dns_client_; | |
| 75 std::unique_ptr<SingleTreeTracker> tree_tracker_; | 205 std::unique_ptr<SingleTreeTracker> tree_tracker_; |
| 76 scoped_refptr<net::X509Certificate> chain_; | 206 scoped_refptr<net::X509Certificate> chain_; |
| 77 scoped_refptr<net::ct::SignedCertificateTimestamp> cert_sct_; | 207 scoped_refptr<SignedCertificateTimestamp> cert_sct_; |
| 208 net::NetLogWithSource net_log_; | |
| 78 }; | 209 }; |
| 79 | 210 |
| 80 // Test that an SCT is classified as pending for a newer STH if the | 211 // Test that an SCT is classified as pending for a newer STH if the |
| 81 // SingleTreeTracker has not seen any STHs so far. | 212 // SingleTreeTracker has not seen any STHs so far. |
| 82 TEST_F(SingleTreeTrackerTest, CorrectlyClassifiesUnobservedSCTNoSTH) { | 213 TEST_F(SingleTreeTrackerTest, CorrectlyClassifiesUnobservedSCTNoSTH) { |
| 83 base::HistogramTester histograms; | 214 base::HistogramTester histograms; |
| 84 // First make sure the SCT has not been observed at all. | 215 // First make sure the SCT has not been observed at all. |
| 85 EXPECT_EQ( | 216 EXPECT_EQ( |
| 86 SingleTreeTracker::SCT_NOT_OBSERVED, | 217 SingleTreeTracker::SCT_NOT_OBSERVED, |
| 87 tree_tracker_->GetLogEntryInclusionStatus(chain_.get(), cert_sct_.get())); | 218 tree_tracker_->GetLogEntryInclusionStatus(chain_.get(), cert_sct_.get())); |
| 88 | 219 |
| 89 tree_tracker_->OnSCTVerified(chain_.get(), cert_sct_.get()); | 220 tree_tracker_->OnSCTVerified(chain_.get(), cert_sct_.get()); |
| 90 | 221 |
| 91 // Since no STH was provided to the tree_tracker_ the status should be that | 222 // Since no STH was provided to the tree_tracker_ the status should be that |
| 92 // the SCT is pending a newer STH. | 223 // the SCT is pending a newer STH. |
| 93 EXPECT_EQ( | 224 EXPECT_EQ( |
| 94 SingleTreeTracker::SCT_PENDING_NEWER_STH, | 225 SingleTreeTracker::SCT_PENDING_NEWER_STH, |
| 95 tree_tracker_->GetLogEntryInclusionStatus(chain_.get(), cert_sct_.get())); | 226 tree_tracker_->GetLogEntryInclusionStatus(chain_.get(), cert_sct_.get())); |
| 96 | 227 |
| 97 // Expect logging of a value indicating a valid STH is required. | 228 // Expect logging of a value indicating a valid STH is required. |
| 98 histograms.ExpectTotalCount(kCanCheckForInclusionHistogramName, 1); | 229 histograms.ExpectTotalCount(kCanCheckForInclusionHistogramName, 1); |
| 99 histograms.ExpectBucketCount(kCanCheckForInclusionHistogramName, 0, 1); | 230 histograms.ExpectBucketCount(kCanCheckForInclusionHistogramName, 0, 1); |
| 100 } | 231 } |
| 101 | 232 |
| 102 // Test that an SCT is classified as pending an inclusion check if the | 233 // Test that an SCT is classified as pending an inclusion check if the |
| 103 // SingleTreeTracker has a fresh-enough STH to check inclusion against. | 234 // SingleTreeTracker has a fresh-enough STH to check inclusion against. |
| 104 TEST_F(SingleTreeTrackerTest, CorrectlyClassifiesUnobservedSCTWithRecentSTH) { | 235 TEST_F(SingleTreeTrackerTest, CorrectlyClassifiesUnobservedSCTWithRecentSTH) { |
| 105 base::HistogramTester histograms; | 236 base::HistogramTester histograms; |
| 106 // Provide an STH to the tree_tracker_. | 237 // Provide an STH to the tree_tracker_. |
| 107 net::ct::SignedTreeHead sth; | 238 SignedTreeHead sth; |
| 108 net::ct::GetSampleSignedTreeHead(&sth); | 239 net::ct::GetSampleSignedTreeHead(&sth); |
| 109 tree_tracker_->NewSTHObserved(sth); | 240 tree_tracker_->NewSTHObserved(sth); |
| 110 | 241 |
| 111 // Make sure the SCT status is the same as if there's no STH for | 242 // Make sure the SCT status is the same as if there's no STH for |
| 112 // this log. | 243 // this log. |
| 113 EXPECT_EQ( | 244 EXPECT_EQ( |
| 114 SingleTreeTracker::SCT_NOT_OBSERVED, | 245 SingleTreeTracker::SCT_NOT_OBSERVED, |
| 115 tree_tracker_->GetLogEntryInclusionStatus(chain_.get(), cert_sct_.get())); | 246 tree_tracker_->GetLogEntryInclusionStatus(chain_.get(), cert_sct_.get())); |
| 116 | 247 |
| 117 tree_tracker_->OnSCTVerified(chain_.get(), cert_sct_.get()); | 248 tree_tracker_->OnSCTVerified(chain_.get(), cert_sct_.get()); |
| 118 | 249 |
| 119 // The status for this SCT should be 'pending inclusion check' since the STH | 250 // The status for this SCT should be 'pending inclusion check' since the STH |
| 120 // provided at the beginning of the test is newer than the SCT. | 251 // provided at the beginning of the test is newer than the SCT. |
| 121 EXPECT_EQ( | 252 EXPECT_EQ( |
| 122 SingleTreeTracker::SCT_PENDING_INCLUSION_CHECK, | 253 SingleTreeTracker::SCT_PENDING_INCLUSION_CHECK, |
| 123 tree_tracker_->GetLogEntryInclusionStatus(chain_.get(), cert_sct_.get())); | 254 tree_tracker_->GetLogEntryInclusionStatus(chain_.get(), cert_sct_.get())); |
| 124 | 255 |
| 125 // Exactly one value should be logged, indicating the SCT can be checked for | 256 // Exactly one value should be logged, indicating the SCT can be checked for |
| 126 // inclusion, as |tree_tracker_| did have a valid STH when it was notified | 257 // inclusion, as |tree_tracker_| did have a valid STH when it was notified |
| 127 // of a new SCT. | 258 // of a new SCT. |
| 128 histograms.ExpectTotalCount(kCanCheckForInclusionHistogramName, 1); | 259 histograms.ExpectTotalCount(kCanCheckForInclusionHistogramName, 1); |
| 129 histograms.ExpectBucketCount(kCanCheckForInclusionHistogramName, 2, 1); | 260 histograms.ExpectBucketCount(kCanCheckForInclusionHistogramName, 2, 1); |
| 261 // Nothing should be logged in the result histogram since inclusion check | |
| 262 // didn't finish. | |
| 263 histograms.ExpectTotalCount(kInclusionCheckResultHistogramName, 0); | |
| 130 } | 264 } |
| 131 | 265 |
| 132 // Test that the SingleTreeTracker correctly queues verified SCTs for inclusion | 266 // Test that the SingleTreeTracker correctly queues verified SCTs for inclusion |
| 133 // checking such that, upon receiving a fresh STH, it changes the SCT's status | 267 // checking such that, upon receiving a fresh STH, it changes the SCT's status |
| 134 // from pending newer STH to pending inclusion check. | 268 // from pending newer STH to pending inclusion check. |
| 135 TEST_F(SingleTreeTrackerTest, CorrectlyUpdatesSCTStatusOnNewSTH) { | 269 TEST_F(SingleTreeTrackerTest, CorrectlyUpdatesSCTStatusOnNewSTH) { |
| 136 base::HistogramTester histograms; | 270 base::HistogramTester histograms; |
| 137 // Report an observed SCT and make sure it's in the pending newer STH | 271 // Report an observed SCT and make sure it's in the pending newer STH |
| 138 // state. | 272 // state. |
| 139 tree_tracker_->OnSCTVerified(chain_.get(), cert_sct_.get()); | 273 tree_tracker_->OnSCTVerified(chain_.get(), cert_sct_.get()); |
| 140 EXPECT_EQ( | 274 EXPECT_EQ( |
| 141 SingleTreeTracker::SCT_PENDING_NEWER_STH, | 275 SingleTreeTracker::SCT_PENDING_NEWER_STH, |
| 142 tree_tracker_->GetLogEntryInclusionStatus(chain_.get(), cert_sct_.get())); | 276 tree_tracker_->GetLogEntryInclusionStatus(chain_.get(), cert_sct_.get())); |
| 143 histograms.ExpectTotalCount(kCanCheckForInclusionHistogramName, 1); | 277 histograms.ExpectTotalCount(kCanCheckForInclusionHistogramName, 1); |
| 144 | 278 |
| 145 // Provide with a fresh STH | 279 // Provide with a fresh STH |
| 146 net::ct::SignedTreeHead sth; | 280 SignedTreeHead sth; |
| 147 net::ct::GetSampleSignedTreeHead(&sth); | 281 net::ct::GetSampleSignedTreeHead(&sth); |
| 148 tree_tracker_->NewSTHObserved(sth); | 282 tree_tracker_->NewSTHObserved(sth); |
| 149 | 283 |
| 150 // Test that its status has changed. | 284 // Test that its status has changed. |
| 151 EXPECT_EQ( | 285 EXPECT_EQ( |
| 152 SingleTreeTracker::SCT_PENDING_INCLUSION_CHECK, | 286 SingleTreeTracker::SCT_PENDING_INCLUSION_CHECK, |
| 153 tree_tracker_->GetLogEntryInclusionStatus(chain_.get(), cert_sct_.get())); | 287 tree_tracker_->GetLogEntryInclusionStatus(chain_.get(), cert_sct_.get())); |
| 154 // Check that no additional UMA was logged for this case as the histogram is | 288 // Check that no additional UMA was logged for this case as the histogram is |
| 155 // only supposed to measure the state of newly-observed SCTs, not pending | 289 // only supposed to measure the state of newly-observed SCTs, not pending |
| 156 // ones. | 290 // ones. |
| 157 histograms.ExpectTotalCount(kCanCheckForInclusionHistogramName, 1); | 291 histograms.ExpectTotalCount(kCanCheckForInclusionHistogramName, 1); |
| 158 } | 292 } |
| 159 | 293 |
| 160 // Test that the SingleTreeTracker does not change an SCT's status if an STH | 294 // Test that the SingleTreeTracker does not change an SCT's status if an STH |
| 161 // from the log it was issued by is observed, but that STH is too old to check | 295 // from the log it was issued by is observed, but that STH is too old to check |
| 162 // inclusion against. | 296 // inclusion against. |
| 163 TEST_F(SingleTreeTrackerTest, DoesNotUpdatesSCTStatusOnOldSTH) { | 297 TEST_F(SingleTreeTrackerTest, DoesNotUpdatesSCTStatusOnOldSTH) { |
| 164 // Notify of an SCT and make sure it's in the 'pending newer STH' state. | 298 // Notify of an SCT and make sure it's in the 'pending newer STH' state. |
| 165 tree_tracker_->OnSCTVerified(chain_.get(), cert_sct_.get()); | 299 tree_tracker_->OnSCTVerified(chain_.get(), cert_sct_.get()); |
| 166 EXPECT_EQ( | 300 EXPECT_EQ( |
| 167 SingleTreeTracker::SCT_PENDING_NEWER_STH, | 301 SingleTreeTracker::SCT_PENDING_NEWER_STH, |
| 168 tree_tracker_->GetLogEntryInclusionStatus(chain_.get(), cert_sct_.get())); | 302 tree_tracker_->GetLogEntryInclusionStatus(chain_.get(), cert_sct_.get())); |
| 169 | 303 |
| 170 // Provide an old STH for the same log. | 304 // Provide an old STH for the same log. |
| 171 net::ct::SignedTreeHead sth; | 305 SignedTreeHead sth; |
| 172 GetOldSignedTreeHead(&sth); | 306 GetOldSignedTreeHead(&sth); |
| 173 tree_tracker_->NewSTHObserved(sth); | 307 tree_tracker_->NewSTHObserved(sth); |
| 174 | 308 |
| 175 // Make sure the SCT's state hasn't changed. | 309 // Make sure the SCT's state hasn't changed. |
| 176 EXPECT_EQ( | 310 EXPECT_EQ( |
| 177 SingleTreeTracker::SCT_PENDING_NEWER_STH, | 311 SingleTreeTracker::SCT_PENDING_NEWER_STH, |
| 178 tree_tracker_->GetLogEntryInclusionStatus(chain_.get(), cert_sct_.get())); | 312 tree_tracker_->GetLogEntryInclusionStatus(chain_.get(), cert_sct_.get())); |
| 179 } | 313 } |
| 180 | 314 |
| 181 // Test that the SingleTreeTracker correctly logs that an SCT is pending a new | 315 // Test that the SingleTreeTracker correctly logs that an SCT is pending a new |
| 182 // STH, when it has a valid STH, but the observed SCT is not covered by the | 316 // STH, when it has a valid STH, but the observed SCT is not covered by the |
| 183 // STH. | 317 // STH. |
| 184 TEST_F(SingleTreeTrackerTest, LogsUMAForNewSCTAndOldSTH) { | 318 TEST_F(SingleTreeTrackerTest, LogsUMAForNewSCTAndOldSTH) { |
| 185 base::HistogramTester histograms; | 319 base::HistogramTester histograms; |
| 186 // Provide an old STH for the same log. | 320 // Provide an old STH for the same log. |
| 187 net::ct::SignedTreeHead sth; | 321 SignedTreeHead sth; |
| 188 GetOldSignedTreeHead(&sth); | 322 GetOldSignedTreeHead(&sth); |
| 189 tree_tracker_->NewSTHObserved(sth); | 323 tree_tracker_->NewSTHObserved(sth); |
| 190 | 324 |
| 191 histograms.ExpectTotalCount(kCanCheckForInclusionHistogramName, 0); | 325 histograms.ExpectTotalCount(kCanCheckForInclusionHistogramName, 0); |
| 192 | 326 |
| 193 // Notify of an SCT and make sure it's in the 'pending newer STH' state. | 327 // Notify of an SCT and make sure it's in the 'pending newer STH' state. |
| 194 tree_tracker_->OnSCTVerified(chain_.get(), cert_sct_.get()); | 328 tree_tracker_->OnSCTVerified(chain_.get(), cert_sct_.get()); |
| 195 | 329 |
| 196 // Exactly one value should be logged, indicating the SCT cannot be checked | 330 // Exactly one value should be logged, indicating the SCT cannot be checked |
| 197 // for inclusion as the STH is too old. | 331 // for inclusion as the STH is too old. |
| 198 histograms.ExpectTotalCount(kCanCheckForInclusionHistogramName, 1); | 332 histograms.ExpectTotalCount(kCanCheckForInclusionHistogramName, 1); |
| 199 histograms.ExpectBucketCount(kCanCheckForInclusionHistogramName, 1, 1); | 333 histograms.ExpectBucketCount(kCanCheckForInclusionHistogramName, 1, 1); |
| 200 } | 334 } |
| 201 | 335 |
| 336 // Test that an entry transitions to the "not found" state if the LogDnsClient | |
| 337 // fails to get a leaf index. | |
| 338 TEST_F(SingleTreeTrackerTest, TestEntryNotPendingAfterLeafIndexFetchFailure) { | |
| 339 ClearDnsConfig(); | |
|
Ryan Sleevi
2016/12/14 01:34:16
Unnecessary?
Eran Messeri
2016/12/22 16:12:11
Done.
| |
| 340 ASSERT_TRUE(mock_dns_->ExpectRequestAndSocketError( | |
| 341 Base32LeafHash(chain_.get(), cert_sct_.get()) + ".hash.dns.example." | |
| 342 "com", | |
| 343 net::Error::ERR_FAILED)); | |
| 344 | |
| 345 CreateTreeTracker(); | |
| 346 | |
| 347 tree_tracker_->OnSCTVerified(chain_.get(), cert_sct_.get()); | |
| 348 EXPECT_EQ( | |
| 349 SingleTreeTracker::SCT_PENDING_NEWER_STH, | |
| 350 tree_tracker_->GetLogEntryInclusionStatus(chain_.get(), cert_sct_.get())); | |
| 351 | |
| 352 // Provide with a fresh STH | |
| 353 SignedTreeHead sth; | |
| 354 net::ct::GetSampleSignedTreeHead(&sth); | |
| 355 tree_tracker_->NewSTHObserved(sth); | |
| 356 base::RunLoop().RunUntilIdle(); | |
| 357 | |
| 358 EXPECT_EQ( | |
| 359 SingleTreeTracker::SCT_NOT_OBSERVED, | |
| 360 tree_tracker_->GetLogEntryInclusionStatus(chain_.get(), cert_sct_.get())); | |
| 361 } | |
| 362 | |
| 363 // Test that an entry transitions to the "not found" state if the LogDnsClient | |
| 364 // succeeds to get a leaf index but fails to get an inclusion proof. | |
| 365 TEST_F(SingleTreeTrackerTest, TestEntryNotPendingAfterInclusionCheckFailure) { | |
| 366 ClearDnsConfig(); | |
|
Ryan Sleevi
2016/12/14 01:34:16
Unnecessary?
Eran Messeri
2016/12/22 16:12:11
Acknowledged, see explanation below why we need to
| |
| 367 ASSERT_TRUE(mock_dns_->ExpectLeafIndexRequestAndResponse( | |
| 368 Base32LeafHash(chain_.get(), cert_sct_.get()) + ".hash.dns.example." | |
| 369 "com", | |
| 370 12)); | |
| 371 ASSERT_TRUE(mock_dns_->ExpectRequestAndSocketError( | |
| 372 "0.12.21.tree.dns.example.com", net::Error::ERR_FAILED)); | |
|
Ryan Sleevi
2016/12/14 01:34:16
Document why 0.12.21 is meaningful here.
Eran Messeri
2016/12/22 16:12:12
Done.
| |
| 373 | |
| 374 CreateTreeTracker(); | |
| 375 | |
| 376 tree_tracker_->OnSCTVerified(chain_.get(), cert_sct_.get()); | |
| 377 EXPECT_EQ( | |
| 378 SingleTreeTracker::SCT_PENDING_NEWER_STH, | |
| 379 tree_tracker_->GetLogEntryInclusionStatus(chain_.get(), cert_sct_.get())); | |
| 380 | |
| 381 // Provide with a fresh STH | |
| 382 SignedTreeHead sth; | |
| 383 net::ct::GetSampleSignedTreeHead(&sth); | |
| 384 tree_tracker_->NewSTHObserved(sth); | |
| 385 base::RunLoop().RunUntilIdle(); | |
| 386 | |
| 387 EXPECT_EQ( | |
| 388 SingleTreeTracker::SCT_NOT_OBSERVED, | |
| 389 tree_tracker_->GetLogEntryInclusionStatus(chain_.get(), cert_sct_.get())); | |
| 390 } | |
| 391 | |
| 392 // Test that an entry transitions to the "included" state if the LogDnsClient | |
| 393 // succeeds to get a leaf index and an inclusion proof. | |
| 394 TEST_F(SingleTreeTrackerTest, TestEntryIncludedAfterInclusionCheckSuccess) { | |
| 395 std::vector<std::string> audit_proof; | |
| 396 FillVectorWithValidAuditProofForTreeOfSize2(&audit_proof); | |
| 397 | |
| 398 ClearDnsConfig(); | |
|
Ryan Sleevi
2016/12/14 01:34:16
Unnecessary?
Eran Messeri
2016/12/22 16:12:12
Acknowledged, see explanation below.
| |
| 399 ASSERT_TRUE(mock_dns_->ExpectLeafIndexRequestAndResponse( | |
| 400 Base32LeafHash(chain_.get(), cert_sct_.get()) + ".hash.dns.example." | |
| 401 "com", | |
| 402 0)); | |
| 403 ASSERT_TRUE(mock_dns_->ExpectAuditProofRequestAndResponse( | |
| 404 "0.0.2.tree.dns.example.com", audit_proof.begin(), | |
|
Ryan Sleevi
2016/12/14 01:34:16
Document why 0.0.2 is meaningful here
Eran Messeri
2016/12/22 16:12:11
Done.
| |
| 405 audit_proof.begin() + 1)); | |
| 406 | |
| 407 CreateTreeTracker(); | |
| 408 | |
| 409 tree_tracker_->OnSCTVerified(chain_.get(), cert_sct_.get()); | |
| 410 EXPECT_EQ( | |
| 411 SingleTreeTracker::SCT_PENDING_NEWER_STH, | |
| 412 tree_tracker_->GetLogEntryInclusionStatus(chain_.get(), cert_sct_.get())); | |
| 413 | |
| 414 // Provide with a fresh STH | |
| 415 SignedTreeHead sth; | |
| 416 ASSERT_TRUE(GetSignedTreeHeadForTreeOfSize2(&sth)); | |
| 417 ASSERT_TRUE(log_->VerifySignedTreeHead(sth)); | |
| 418 | |
| 419 tree_tracker_->NewSTHObserved(sth); | |
| 420 base::RunLoop().RunUntilIdle(); | |
| 421 | |
| 422 EXPECT_EQ( | |
| 423 SingleTreeTracker::SCT_INCLUDED_IN_LOG, | |
| 424 tree_tracker_->GetLogEntryInclusionStatus(chain_.get(), cert_sct_.get())); | |
| 425 } | |
| 426 | |
| 427 // Test that pending entries transition states correctly according to the | |
| 428 // STHs provided: | |
| 429 // * Start without an STH. | |
| 430 // * Add a collection of entries with mixed timestamps (i.e. SCTs not added | |
| 431 // in the order of their timestamps). | |
|
Ryan Sleevi
2016/12/14 01:34:16
Follow markdown style indents
* Add a ...
in the
Eran Messeri
2016/12/22 16:12:11
Done.
| |
| 432 // * Provide an STH that covers some of the entries, test these are audited. | |
| 433 // * Provide another STH that covers more of the entries, test that the entries | |
| 434 // already audited are not audited again and that those that need to be | |
| 435 // audited are audited, while those that are not covered by that STH are | |
| 436 // not audited. | |
|
Ryan Sleevi
2016/12/14 01:34:15
Is it wholly necessary to test this, as large as y
Eran Messeri
2016/12/22 16:12:12
I acknowledge this is a large and complex test. An
| |
| 437 TEST_F(SingleTreeTrackerTest, TestMultipleEntriesTransitionStateCorrectly) { | |
| 438 SignedTreeHead old_sth; | |
| 439 GetOldSignedTreeHead(&old_sth); | |
| 440 | |
| 441 SignedTreeHead new_sth; | |
| 442 net::ct::GetSampleSignedTreeHead(&new_sth); | |
|
Ryan Sleevi
2016/12/14 01:34:15
You removed other net::ct:: qualifications, but ad
Eran Messeri
2016/12/22 16:12:12
Done.
| |
| 443 | |
| 444 base::TimeDelta kLessThanMMD = base::TimeDelta::FromHours(23); | |
| 445 | |
| 446 // Assert the gap between the two timestamps is big enough so that | |
| 447 // all assumptions below on which SCT can be audited with the | |
| 448 // new STH are true. | |
| 449 ASSERT_LT(old_sth.timestamp + (kMoreThanMMD * 2), new_sth.timestamp); | |
| 450 | |
| 451 // Oldest SCT - auditable by the old and new STHs. | |
| 452 scoped_refptr<SignedCertificateTimestamp> oldest_sct(GetSCT()); | |
| 453 oldest_sct->timestamp = old_sth.timestamp - kMoreThanMMD; | |
| 454 | |
| 455 // SCT that's older than the old STH's timestamp but by less than the MMD, | |
| 456 // so not auditable by old STH. | |
| 457 scoped_refptr<SignedCertificateTimestamp> not_auditable_by_old_sth_sct( | |
| 458 GetSCT()); | |
| 459 not_auditable_by_old_sth_sct->timestamp = old_sth.timestamp - kLessThanMMD; | |
| 460 | |
| 461 // SCT that's newer than the old STH's timestamp so is only auditable by | |
| 462 // the new STH. | |
| 463 scoped_refptr<SignedCertificateTimestamp> newer_than_old_sth_sct(GetSCT()); | |
| 464 newer_than_old_sth_sct->timestamp = old_sth.timestamp + kLessThanMMD; | |
| 465 | |
| 466 // SCT that's older than the new STH's timestamp but by less than the MMD, | |
| 467 // so isn't auditable by the new STH. | |
| 468 scoped_refptr<SignedCertificateTimestamp> not_auditable_by_new_sth_sct( | |
| 469 GetSCT()); | |
| 470 not_auditable_by_new_sth_sct->timestamp = new_sth.timestamp - kLessThanMMD; | |
| 471 | |
| 472 // SCT that's newer than the new STH's timestamp so isn't auditable by the | |
| 473 // the new STH. | |
| 474 scoped_refptr<SignedCertificateTimestamp> newer_than_new_sth_sct(GetSCT()); | |
| 475 newer_than_new_sth_sct->timestamp = new_sth.timestamp + kLessThanMMD; | |
| 476 | |
| 477 // Set up DNS expectations based on inclusion proof request order. | |
| 478 ClearDnsConfig(); | |
|
Ryan Sleevi
2016/12/14 01:34:15
This is the only one that seems 'necessary' (e.g.
Eran Messeri
2016/12/22 16:12:11
Trying to clarify the relationship between the moc
| |
| 479 ASSERT_TRUE(ExpectLeafHashRequestAndThrottle(chain_, oldest_sct)); | |
| 480 ASSERT_TRUE( | |
| 481 ExpectLeafHashRequestAndThrottle(chain_, not_auditable_by_old_sth_sct)); | |
| 482 ASSERT_TRUE(ExpectLeafHashRequestAndThrottle(chain_, newer_than_old_sth_sct)); | |
| 483 CreateTreeTracker(); | |
| 484 | |
| 485 // Add SCTs in mixed order. | |
| 486 tree_tracker_->OnSCTVerified(chain_.get(), newer_than_new_sth_sct.get()); | |
| 487 tree_tracker_->OnSCTVerified(chain_.get(), oldest_sct.get()); | |
| 488 tree_tracker_->OnSCTVerified(chain_.get(), | |
| 489 not_auditable_by_new_sth_sct.get()); | |
| 490 tree_tracker_->OnSCTVerified(chain_.get(), newer_than_old_sth_sct.get()); | |
| 491 tree_tracker_->OnSCTVerified(chain_.get(), | |
| 492 not_auditable_by_old_sth_sct.get()); | |
| 493 | |
| 494 // Ensure all are in the PENDING_NEWER_STH state. | |
| 495 AssertSCTsMatchingState<SignedCertificateTimestamp*>( | |
| 496 tree_tracker_.get(), chain_.get(), | |
| 497 SingleTreeTracker::SCT_PENDING_NEWER_STH, oldest_sct.get(), | |
| 498 not_auditable_by_old_sth_sct.get(), newer_than_old_sth_sct.get(), | |
| 499 not_auditable_by_new_sth_sct.get(), newer_than_new_sth_sct.get()); | |
| 500 | |
| 501 // Provide the old STH, ensure only the oldest one is auditable. | |
| 502 tree_tracker_->NewSTHObserved(old_sth); | |
| 503 // Ensure all but the oldest are in the PENDING_NEWER_STH state. | |
| 504 AssertSCTsMatchingState<SignedCertificateTimestamp*>( | |
| 505 tree_tracker_.get(), chain_.get(), | |
| 506 SingleTreeTracker::SCT_PENDING_INCLUSION_CHECK, oldest_sct.get()); | |
| 507 | |
| 508 AssertSCTsMatchingState<SignedCertificateTimestamp*>( | |
| 509 tree_tracker_.get(), chain_.get(), | |
| 510 SingleTreeTracker::SCT_PENDING_NEWER_STH, | |
| 511 not_auditable_by_old_sth_sct.get(), newer_than_old_sth_sct.get(), | |
| 512 not_auditable_by_new_sth_sct.get(), newer_than_new_sth_sct.get()); | |
| 513 | |
| 514 // Provide the newer one, ensure two more are auditable but the | |
| 515 // rest aren't. | |
| 516 tree_tracker_->NewSTHObserved(new_sth); | |
| 517 | |
| 518 AssertSCTsMatchingState<SignedCertificateTimestamp*>( | |
| 519 tree_tracker_.get(), chain_.get(), | |
| 520 SingleTreeTracker::SCT_PENDING_INCLUSION_CHECK, oldest_sct.get(), | |
| 521 not_auditable_by_old_sth_sct.get(), newer_than_old_sth_sct.get()); | |
| 522 | |
| 523 AssertSCTsMatchingState<SignedCertificateTimestamp*>( | |
| 524 tree_tracker_.get(), chain_.get(), | |
| 525 SingleTreeTracker::SCT_PENDING_NEWER_STH, | |
| 526 not_auditable_by_new_sth_sct.get(), newer_than_new_sth_sct.get()); | |
| 527 } | |
| 528 | |
| 529 // Test that if a request for an entry is throttled, it remains in a | |
| 530 // pending state. | |
| 531 | |
| 532 // Test that if several entries are throttled, when the LogDnsClient notifies | |
| 533 // of un-throttling all entries are handled. | |
| 534 TEST_F(SingleTreeTrackerTest, TestThrottledEntryGetsHandledAfterUnthrottling) { | |
| 535 std::vector<std::string> audit_proof; | |
| 536 FillVectorWithValidAuditProofForTreeOfSize2(&audit_proof); | |
| 537 | |
| 538 ClearDnsConfig(); | |
|
Ryan Sleevi
2016/12/14 01:34:15
Unnecessary?
Eran Messeri
2016/12/22 16:12:11
Acknowledged, see above.
| |
| 539 ASSERT_TRUE(mock_dns_->ExpectLeafIndexRequestAndResponse( | |
| 540 Base32LeafHash(chain_.get(), cert_sct_.get()) + ".hash.dns.example." | |
| 541 "com", | |
| 542 0)); | |
| 543 ASSERT_TRUE(mock_dns_->ExpectAuditProofRequestAndResponse( | |
| 544 "0.0.2.tree.dns.example.com", audit_proof.begin(), | |
| 545 audit_proof.begin() + 1)); | |
| 546 | |
| 547 scoped_refptr<SignedCertificateTimestamp> second_sct(GetSCT()); | |
| 548 second_sct->timestamp -= base::TimeDelta::FromHours(1); | |
| 549 | |
| 550 // Process request for |second_sct| | |
| 551 ASSERT_TRUE(mock_dns_->ExpectLeafIndexRequestAndResponse( | |
| 552 Base32LeafHash(chain_.get(), second_sct.get()) + ".hash.dns.example." | |
| 553 "com", | |
| 554 1)); | |
| 555 ASSERT_TRUE(mock_dns_->ExpectAuditProofRequestAndResponse( | |
| 556 "0.1.2.tree.dns.example.com", audit_proof.begin(), | |
| 557 audit_proof.begin() + 1)); | |
| 558 | |
| 559 CreateTreeTracker(); | |
| 560 | |
| 561 SignedTreeHead sth; | |
| 562 ASSERT_TRUE(GetSignedTreeHeadForTreeOfSize2(&sth)); | |
| 563 tree_tracker_->NewSTHObserved(sth); | |
| 564 | |
| 565 tree_tracker_->OnSCTVerified(chain_.get(), cert_sct_.get()); | |
| 566 tree_tracker_->OnSCTVerified(chain_.get(), second_sct.get()); | |
| 567 | |
| 568 // Both entries should be in the pending state, the first because the | |
| 569 // LogDnsClient did not invoke the callback yet, the second one because | |
| 570 // the LogDnsClient is "busy" with the first entry and so would throttle. | |
| 571 ASSERT_EQ( | |
| 572 SingleTreeTracker::SCT_PENDING_INCLUSION_CHECK, | |
| 573 tree_tracker_->GetLogEntryInclusionStatus(chain_.get(), cert_sct_.get())); | |
| 574 ASSERT_EQ(SingleTreeTracker::SCT_PENDING_INCLUSION_CHECK, | |
| 575 tree_tracker_->GetLogEntryInclusionStatus(chain_.get(), | |
| 576 second_sct.get())); | |
| 577 | |
| 578 // Pump the message loop. | |
|
Ryan Sleevi
2016/12/14 01:34:16
It's obvious from line 579 that the message loop w
Eran Messeri
2016/12/22 16:12:11
Done - replaced the comment.
| |
| 579 base::RunLoop().RunUntilIdle(); | |
| 580 | |
| 581 // Check that the first sct is included in the log. | |
| 582 ASSERT_EQ( | |
| 583 SingleTreeTracker::SCT_INCLUDED_IN_LOG, | |
| 584 tree_tracker_->GetLogEntryInclusionStatus(chain_.get(), cert_sct_.get())); | |
| 585 | |
| 586 // Check that the second SCT got an invalid proof and is not included, rather | |
| 587 // than being in the pending state. | |
| 588 ASSERT_EQ(SingleTreeTracker::SCT_NOT_OBSERVED, | |
| 589 tree_tracker_->GetLogEntryInclusionStatus(chain_.get(), | |
| 590 second_sct.get())); | |
| 591 } | |
| 592 | |
| 593 // Test that proof fetching failure due to DNS config errors is handled | |
| 594 // correctly: | |
| 595 // (1) Entry removed from pending queue. | |
| 596 // (2) UMA logged | |
| 597 TEST_F(SingleTreeTrackerTest, | |
| 598 TestProofLookupDueToBadDNSConfigHandledCorrectly) { | |
| 599 base::HistogramTester histograms; | |
| 600 // Provide an STH to the tree_tracker_. | |
| 601 SignedTreeHead sth; | |
| 602 net::ct::GetSampleSignedTreeHead(&sth); | |
| 603 | |
| 604 // Clear existing DNS configuration, so that the DnsClient created | |
| 605 // by the MockLogDnsTraffic has no valid DnsConfig. | |
| 606 net_change_notifier_.reset(); | |
| 607 net_change_notifier_.reset(net::NetworkChangeNotifier::CreateMock()); | |
| 608 CreateTreeTracker(); | |
| 609 | |
| 610 tree_tracker_->NewSTHObserved(sth); | |
| 611 tree_tracker_->OnSCTVerified(chain_.get(), cert_sct_.get()); | |
| 612 | |
| 613 // Make sure the SCT status indicates the entry has been removed from | |
| 614 // the SingleTreeTracker's internal queue as the DNS lookup failed | |
| 615 // synchronously. | |
| 616 EXPECT_EQ( | |
| 617 SingleTreeTracker::SCT_NOT_OBSERVED, | |
| 618 tree_tracker_->GetLogEntryInclusionStatus(chain_.get(), cert_sct_.get())); | |
| 619 | |
| 620 // Exactly one value should be logged, indicating the SCT can be checked for | |
| 621 // inclusion, as |tree_tracker_| did have a valid STH when it was notified | |
| 622 // of a new SCT. | |
| 623 histograms.ExpectTotalCount(kCanCheckForInclusionHistogramName, 1); | |
| 624 histograms.ExpectBucketCount(kCanCheckForInclusionHistogramName, 2, 1); | |
| 625 // Failure due to DNS configuration should be logged in the result histogram. | |
| 626 histograms.ExpectTotalCount(kInclusionCheckResultHistogramName, 1); | |
| 627 histograms.ExpectBucketCount(kInclusionCheckResultHistogramName, 3, 1); | |
| 628 } | |
| 629 | |
| 202 } // namespace certificate_transparency | 630 } // namespace certificate_transparency |
| OLD | NEW |