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/strings/string_piece.h" | 10 #include "base/strings/string_piece.h" |
| 11 #include "base/test/histogram_tester.h" | |
| 11 #include "net/cert/ct_log_verifier.h" | 12 #include "net/cert/ct_log_verifier.h" |
| 12 #include "net/cert/ct_serialization.h" | 13 #include "net/cert/ct_serialization.h" |
| 13 #include "net/cert/signed_certificate_timestamp.h" | 14 #include "net/cert/signed_certificate_timestamp.h" |
| 14 #include "net/cert/signed_tree_head.h" | 15 #include "net/cert/signed_tree_head.h" |
| 15 #include "net/cert/x509_certificate.h" | 16 #include "net/cert/x509_certificate.h" |
| 16 #include "net/test/ct_test_util.h" | 17 #include "net/test/ct_test_util.h" |
| 17 #include "testing/gtest/include/gtest/gtest.h" | 18 #include "testing/gtest/include/gtest/gtest.h" |
| 18 | 19 |
| 19 namespace certificate_transparency { | 20 namespace certificate_transparency { |
| 20 | 21 |
| 21 namespace { | 22 namespace { |
| 23 const char kPendingSTHHistogramName[] = | |
| 24 "Net.CertificateTransparency.SCTNeedsFreshSTH"; | |
| 22 | 25 |
| 23 bool GetOldSignedTreeHead(net::ct::SignedTreeHead* sth) { | 26 bool GetOldSignedTreeHead(net::ct::SignedTreeHead* sth) { |
| 24 sth->version = net::ct::SignedTreeHead::V1; | 27 sth->version = net::ct::SignedTreeHead::V1; |
| 25 sth->timestamp = base::Time::UnixEpoch() + | 28 sth->timestamp = base::Time::UnixEpoch() + |
| 26 base::TimeDelta::FromMilliseconds(INT64_C(1348589665525)); | 29 base::TimeDelta::FromMilliseconds(INT64_C(1348589665525)); |
| 27 sth->tree_size = 12u; | 30 sth->tree_size = 12u; |
| 28 | 31 |
| 29 const uint8_t kOldSTHRootHash[] = { | 32 const uint8_t kOldSTHRootHash[] = { |
| 30 0x18, 0x04, 0x1b, 0xd4, 0x66, 0x50, 0x83, 0x00, 0x1f, 0xba, 0x8c, | 33 0x18, 0x04, 0x1b, 0xd4, 0x66, 0x50, 0x83, 0x00, 0x1f, 0xba, 0x8c, |
| 31 0x54, 0x11, 0xd2, 0xd7, 0x48, 0xe8, 0xab, 0xbf, 0xdc, 0xdf, 0xd9, | 34 0x54, 0x11, 0xd2, 0xd7, 0x48, 0xe8, 0xab, 0xbf, 0xdc, 0xdf, 0xd9, |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 68 protected: | 71 protected: |
| 69 scoped_refptr<const net::CTLogVerifier> log_; | 72 scoped_refptr<const net::CTLogVerifier> log_; |
| 70 std::unique_ptr<SingleTreeTracker> tree_tracker_; | 73 std::unique_ptr<SingleTreeTracker> tree_tracker_; |
| 71 scoped_refptr<net::X509Certificate> chain_; | 74 scoped_refptr<net::X509Certificate> chain_; |
| 72 scoped_refptr<net::ct::SignedCertificateTimestamp> cert_sct_; | 75 scoped_refptr<net::ct::SignedCertificateTimestamp> cert_sct_; |
| 73 }; | 76 }; |
| 74 | 77 |
| 75 // Test that an SCT is classified as pending for a newer STH if the | 78 // Test that an SCT is classified as pending for a newer STH if the |
| 76 // SingleTreeTracker has not seen any STHs so far. | 79 // SingleTreeTracker has not seen any STHs so far. |
| 77 TEST_F(SingleTreeTrackerTest, CorrectlyClassifiesUnobservedSCTNoSTH) { | 80 TEST_F(SingleTreeTrackerTest, CorrectlyClassifiesUnobservedSCTNoSTH) { |
| 81 base::HistogramTester histograms; | |
| 78 // First make sure the SCT has not been observed at all. | 82 // First make sure the SCT has not been observed at all. |
| 79 EXPECT_EQ( | 83 EXPECT_EQ( |
| 80 SingleTreeTracker::SCT_NOT_OBSERVED, | 84 SingleTreeTracker::SCT_NOT_OBSERVED, |
| 81 tree_tracker_->GetLogEntryInclusionStatus(chain_.get(), cert_sct_.get())); | 85 tree_tracker_->GetLogEntryInclusionStatus(chain_.get(), cert_sct_.get())); |
| 82 | 86 |
| 83 tree_tracker_->OnSCTVerified(chain_.get(), cert_sct_.get()); | 87 tree_tracker_->OnSCTVerified(chain_.get(), cert_sct_.get()); |
| 84 | 88 |
| 85 // Since no STH was provided to the tree_tracker_ the status should be that | 89 // Since no STH was provided to the tree_tracker_ the status should be that |
| 86 // the SCT is pending a newer STH. | 90 // the SCT is pending a newer STH. |
| 87 EXPECT_EQ( | 91 EXPECT_EQ( |
| 88 SingleTreeTracker::SCT_PENDING_NEWER_STH, | 92 SingleTreeTracker::SCT_PENDING_NEWER_STH, |
| 89 tree_tracker_->GetLogEntryInclusionStatus(chain_.get(), cert_sct_.get())); | 93 tree_tracker_->GetLogEntryInclusionStatus(chain_.get(), cert_sct_.get())); |
| 94 | |
| 95 histograms.ExpectTotalCount(kPendingSTHHistogramName, 0); | |
| 90 } | 96 } |
| 91 | 97 |
| 92 // Test that an SCT is classified as pending an inclusion check if the | 98 // Test that an SCT is classified as pending an inclusion check if the |
| 93 // SingleTreeTracker has a fresh-enough STH to check inclusion against. | 99 // SingleTreeTracker has a fresh-enough STH to check inclusion against. |
| 94 TEST_F(SingleTreeTrackerTest, CorrectlyClassifiesUnobservedSCTWithRecentSTH) { | 100 TEST_F(SingleTreeTrackerTest, CorrectlyClassifiesUnobservedSCTWithRecentSTH) { |
| 101 base::HistogramTester histograms; | |
| 95 // Provide an STH to the tree_tracker_. | 102 // Provide an STH to the tree_tracker_. |
| 96 net::ct::SignedTreeHead sth; | 103 net::ct::SignedTreeHead sth; |
| 97 net::ct::GetSampleSignedTreeHead(&sth); | 104 net::ct::GetSampleSignedTreeHead(&sth); |
| 98 tree_tracker_->NewSTHObserved(sth); | 105 tree_tracker_->NewSTHObserved(sth); |
| 99 | 106 |
| 100 // Make sure the SCT status is the same as if there's no STH for | 107 // Make sure the SCT status is the same as if there's no STH for |
| 101 // this log. | 108 // this log. |
| 102 EXPECT_EQ( | 109 EXPECT_EQ( |
| 103 SingleTreeTracker::SCT_NOT_OBSERVED, | 110 SingleTreeTracker::SCT_NOT_OBSERVED, |
| 104 tree_tracker_->GetLogEntryInclusionStatus(chain_.get(), cert_sct_.get())); | 111 tree_tracker_->GetLogEntryInclusionStatus(chain_.get(), cert_sct_.get())); |
| 105 | 112 |
| 106 tree_tracker_->OnSCTVerified(chain_.get(), cert_sct_.get()); | 113 tree_tracker_->OnSCTVerified(chain_.get(), cert_sct_.get()); |
| 107 | 114 |
| 108 // The status for this SCT should be 'pending inclusion check' since the STH | 115 // The status for this SCT should be 'pending inclusion check' since the STH |
| 109 // provided at the beginning of the test is newer than the SCT. | 116 // provided at the beginning of the test is newer than the SCT. |
| 110 EXPECT_EQ( | 117 EXPECT_EQ( |
| 111 SingleTreeTracker::SCT_PENDING_INCLUSION_CHECK, | 118 SingleTreeTracker::SCT_PENDING_INCLUSION_CHECK, |
| 112 tree_tracker_->GetLogEntryInclusionStatus(chain_.get(), cert_sct_.get())); | 119 tree_tracker_->GetLogEntryInclusionStatus(chain_.get(), cert_sct_.get())); |
| 120 histograms.ExpectTotalCount(kPendingSTHHistogramName, 1); | |
| 121 histograms.ExpectBucketCount(kPendingSTHHistogramName, false, 1); | |
| 113 } | 122 } |
| 114 | 123 |
| 115 // Test that the SingleTreeTracker correctly queues verified SCTs for inclusion | 124 // Test that the SingleTreeTracker correctly queues verified SCTs for inclusion |
| 116 // checking such that, upon receiving a fresh STH, it changes the SCT's status | 125 // checking such that, upon receiving a fresh STH, it changes the SCT's status |
| 117 // from pending newer STH to pending inclusion check. | 126 // from pending newer STH to pending inclusion check. |
| 118 TEST_F(SingleTreeTrackerTest, CorrectlyUpdatesSCTStatusOnNewSTH) { | 127 TEST_F(SingleTreeTrackerTest, CorrectlyUpdatesSCTStatusOnNewSTH) { |
| 128 base::HistogramTester histograms; | |
| 119 // Report an observed SCT and make sure it's in the pending newer STH | 129 // Report an observed SCT and make sure it's in the pending newer STH |
| 120 // state. | 130 // state. |
| 121 tree_tracker_->OnSCTVerified(chain_.get(), cert_sct_.get()); | 131 tree_tracker_->OnSCTVerified(chain_.get(), cert_sct_.get()); |
| 122 EXPECT_EQ( | 132 EXPECT_EQ( |
| 123 SingleTreeTracker::SCT_PENDING_NEWER_STH, | 133 SingleTreeTracker::SCT_PENDING_NEWER_STH, |
| 124 tree_tracker_->GetLogEntryInclusionStatus(chain_.get(), cert_sct_.get())); | 134 tree_tracker_->GetLogEntryInclusionStatus(chain_.get(), cert_sct_.get())); |
| 135 histograms.ExpectTotalCount(kPendingSTHHistogramName, 0); | |
|
Rob Percival
2016/07/15 14:38:16
I think it's worth adding a comment for this line,
Eran Messeri
2016/07/18 08:53:41
Done.
| |
| 125 | 136 |
| 126 // Provide with a fresh STH | 137 // Provide with a fresh STH |
| 127 net::ct::SignedTreeHead sth; | 138 net::ct::SignedTreeHead sth; |
| 128 net::ct::GetSampleSignedTreeHead(&sth); | 139 net::ct::GetSampleSignedTreeHead(&sth); |
| 129 tree_tracker_->NewSTHObserved(sth); | 140 tree_tracker_->NewSTHObserved(sth); |
| 130 | 141 |
| 131 // Test that its status has changed. | 142 // Test that its status has changed. |
| 132 EXPECT_EQ( | 143 EXPECT_EQ( |
| 133 SingleTreeTracker::SCT_PENDING_INCLUSION_CHECK, | 144 SingleTreeTracker::SCT_PENDING_INCLUSION_CHECK, |
| 134 tree_tracker_->GetLogEntryInclusionStatus(chain_.get(), cert_sct_.get())); | 145 tree_tracker_->GetLogEntryInclusionStatus(chain_.get(), cert_sct_.get())); |
| 146 histograms.ExpectTotalCount(kPendingSTHHistogramName, 0); | |
| 135 } | 147 } |
| 136 | 148 |
| 137 // Test that the SingleTreeTracker does not change an SCT's status if an STH | 149 // Test that the SingleTreeTracker does not change an SCT's status if an STH |
| 138 // from the log it was issued by is observed, but that STH is too old to check | 150 // from the log it was issued by is observed, but that STH is too old to check |
| 139 // inclusion against. | 151 // inclusion against. |
| 140 TEST_F(SingleTreeTrackerTest, DoesNotUpdatesSCTStatusOnOldSTH) { | 152 TEST_F(SingleTreeTrackerTest, DoesNotUpdatesSCTStatusOnOldSTH) { |
| 141 // Notify of an SCT and make sure it's in the 'pending newer STH' state. | 153 // Notify of an SCT and make sure it's in the 'pending newer STH' state. |
| 142 tree_tracker_->OnSCTVerified(chain_.get(), cert_sct_.get()); | 154 tree_tracker_->OnSCTVerified(chain_.get(), cert_sct_.get()); |
| 143 EXPECT_EQ( | 155 EXPECT_EQ( |
| 144 SingleTreeTracker::SCT_PENDING_NEWER_STH, | 156 SingleTreeTracker::SCT_PENDING_NEWER_STH, |
| 145 tree_tracker_->GetLogEntryInclusionStatus(chain_.get(), cert_sct_.get())); | 157 tree_tracker_->GetLogEntryInclusionStatus(chain_.get(), cert_sct_.get())); |
| 146 | 158 |
| 147 // Provide an old STH for the same log. | 159 // Provide an old STH for the same log. |
| 148 net::ct::SignedTreeHead sth; | 160 net::ct::SignedTreeHead sth; |
| 149 GetOldSignedTreeHead(&sth); | 161 GetOldSignedTreeHead(&sth); |
| 150 tree_tracker_->NewSTHObserved(sth); | 162 tree_tracker_->NewSTHObserved(sth); |
| 151 | 163 |
| 152 // Make sure the SCT's state hasn't changed. | 164 // Make sure the SCT's state hasn't changed. |
| 153 EXPECT_EQ( | 165 EXPECT_EQ( |
| 154 SingleTreeTracker::SCT_PENDING_NEWER_STH, | 166 SingleTreeTracker::SCT_PENDING_NEWER_STH, |
| 155 tree_tracker_->GetLogEntryInclusionStatus(chain_.get(), cert_sct_.get())); | 167 tree_tracker_->GetLogEntryInclusionStatus(chain_.get(), cert_sct_.get())); |
| 156 } | 168 } |
| 157 | 169 |
| 170 // Test that the SingleTreeTracker correctly logs that an SCT is pending a new | |
| 171 // STH when it has STH but the observed SCT is newer than that. | |
| 172 TEST_F(SingleTreeTrackerTest, LogsUMAForNewSCTAndOldSTH) { | |
| 173 base::HistogramTester histograms; | |
| 174 // Provide an old STH for the same log. | |
| 175 net::ct::SignedTreeHead sth; | |
| 176 GetOldSignedTreeHead(&sth); | |
| 177 tree_tracker_->NewSTHObserved(sth); | |
| 178 | |
| 179 histograms.ExpectTotalCount(kPendingSTHHistogramName, 0); | |
| 180 // Notify of an SCT and make sure it's in the 'pending newer STH' state. | |
| 181 tree_tracker_->OnSCTVerified(chain_.get(), cert_sct_.get()); | |
| 182 histograms.ExpectTotalCount(kPendingSTHHistogramName, 1); | |
| 183 histograms.ExpectBucketCount(kPendingSTHHistogramName, true, 1); | |
| 184 } | |
| 185 | |
| 158 } // namespace certificate_transparency | 186 } // namespace certificate_transparency |
| OLD | NEW |