diff options
author | eranm <eranm@chromium.org> | 2015-07-02 13:05:15 -0700 |
---|---|---|
committer | Commit bot <commit-bot@chromium.org> | 2015-07-02 20:05:52 +0000 |
commit | b68c27e0dfd59fe943aba065d724fcb8b565a679 (patch) | |
tree | 0c0a5367f155f2439f6d70a1db0440d6351d3f56 | |
parent | ee74ae9a813bd6ab3556cbe0f9a3e9a33809a438 (diff) | |
download | chromium_src-b68c27e0dfd59fe943aba065d724fcb8b565a679.zip chromium_src-b68c27e0dfd59fe943aba065d724fcb8b565a679.tar.gz chromium_src-b68c27e0dfd59fe943aba065d724fcb8b565a679.tar.bz2 |
Certificate Transparency: Add observer for Signed Certificate Timestamps
This will allow hooking a monitor that will check inclusion of
certificates that were accompanied by SCTs in CT logs.
BUG=506227
Review URL: https://codereview.chromium.org/1216153010
Cr-Commit-Position: refs/heads/master@{#337250}
-rw-r--r-- | net/cert/ct_verifier.h | 21 | ||||
-rw-r--r-- | net/cert/multi_log_ct_verifier.cc | 40 | ||||
-rw-r--r-- | net/cert/multi_log_ct_verifier.h | 13 | ||||
-rw-r--r-- | net/cert/multi_log_ct_verifier_unittest.cc | 32 | ||||
-rw-r--r-- | net/socket/ssl_client_socket_unittest.cc | 1 |
5 files changed, 83 insertions, 24 deletions
diff --git a/net/cert/ct_verifier.h b/net/cert/ct_verifier.h index 290a047..4063104 100644 --- a/net/cert/ct_verifier.h +++ b/net/cert/ct_verifier.h @@ -5,20 +5,35 @@ #ifndef NET_CERT_CT_VERIFIER_H_ #define NET_CERT_CT_VERIFIER_H_ +#include <string> + #include "net/base/net_export.h" namespace net { namespace ct { struct CTVerifyResult; +struct SignedCertificateTimestamp; } // namespace ct class BoundNetLog; +class CTLogVerifier; class X509Certificate; // Interface for verifying Signed Certificate Timestamps over a certificate. class NET_EXPORT CTVerifier { public: + class NET_EXPORT Observer { + public: + // Called for each Signed Certificate Timestamp from a known log that vas + // verified successfully (i.e. the signature verifies). |sct| is the + // Signed Certificate Timestamp, |cert| is the certificate it applies to. + // The certificate is needed to calculate the hash of the log entry, + // necessary for checking inclusion in the log. + virtual void OnSCTVerified(X509Certificate* cert, + const ct::SignedCertificateTimestamp* sct) = 0; + }; + virtual ~CTVerifier() {} // Verifies SCTs embedded in the certificate itself, SCTs embedded in a @@ -36,6 +51,12 @@ class NET_EXPORT CTVerifier { const std::string& sct_list_from_tls_extension, ct::CTVerifyResult* result, const BoundNetLog& net_log) = 0; + + // Registers |observer| to receive notifications of validated SCTs. Does not + // take ownership of the observer as the observer may be performing + // URLRequests which have to be cancelled before this object is destroyed. + // Setting |observer| to nullptr has the effect of stopping all notifications. + virtual void SetObserver(Observer* observer) = 0; }; } // namespace net diff --git a/net/cert/multi_log_ct_verifier.cc b/net/cert/multi_log_ct_verifier.cc index 2de8fcf..7e421b2 100644 --- a/net/cert/multi_log_ct_verifier.cc +++ b/net/cert/multi_log_ct_verifier.cc @@ -56,7 +56,8 @@ void LogNumSCTsToUMA(const ct::CTVerifyResult& result) { } // namespace -MultiLogCTVerifier::MultiLogCTVerifier() { } +MultiLogCTVerifier::MultiLogCTVerifier() : observer_(nullptr) { +} MultiLogCTVerifier::~MultiLogCTVerifier() { } @@ -68,6 +69,10 @@ void MultiLogCTVerifier::AddLogs( } } +void MultiLogCTVerifier::SetObserver(Observer* observer) { + observer_ = observer; +} + int MultiLogCTVerifier::Verify( X509Certificate* cert, const std::string& stapled_ocsp_response, @@ -91,15 +96,11 @@ int MultiLogCTVerifier::Verify( ct::LogEntry precert_entry; has_verified_scts = - ct::GetPrecertLogEntry( - cert->os_cert_handle(), - cert->GetIntermediateCertificates().front(), - &precert_entry) && - VerifySCTs( - embedded_scts, - precert_entry, - ct::SignedCertificateTimestamp::SCT_EMBEDDED, - result); + ct::GetPrecertLogEntry(cert->os_cert_handle(), + cert->GetIntermediateCertificates().front(), + &precert_entry) && + VerifySCTs(embedded_scts, precert_entry, + ct::SignedCertificateTimestamp::SCT_EMBEDDED, cert, result); } std::string sct_list_from_ocsp; @@ -123,16 +124,12 @@ int MultiLogCTVerifier::Verify( ct::LogEntry x509_entry; if (ct::GetX509LogEntry(cert->os_cert_handle(), &x509_entry)) { has_verified_scts |= VerifySCTs( - sct_list_from_ocsp, - x509_entry, - ct::SignedCertificateTimestamp::SCT_FROM_OCSP_RESPONSE, - result); + sct_list_from_ocsp, x509_entry, + ct::SignedCertificateTimestamp::SCT_FROM_OCSP_RESPONSE, cert, result); has_verified_scts |= VerifySCTs( - sct_list_from_tls_extension, - x509_entry, - ct::SignedCertificateTimestamp::SCT_FROM_TLS_EXTENSION, - result); + sct_list_from_tls_extension, x509_entry, + ct::SignedCertificateTimestamp::SCT_FROM_TLS_EXTENSION, cert, result); } NetLog::ParametersCallback net_log_checked_callback = @@ -154,6 +151,7 @@ bool MultiLogCTVerifier::VerifySCTs( const std::string& encoded_sct_list, const ct::LogEntry& expected_entry, ct::SignedCertificateTimestamp::Origin origin, + X509Certificate* cert, ct::CTVerifyResult* result) { if (logs_.empty()) return false; @@ -178,7 +176,7 @@ bool MultiLogCTVerifier::VerifySCTs( } decoded_sct->origin = origin; - verified |= VerifySingleSCT(decoded_sct, expected_entry, result); + verified |= VerifySingleSCT(decoded_sct, expected_entry, cert, result); } return verified; @@ -187,8 +185,8 @@ bool MultiLogCTVerifier::VerifySCTs( bool MultiLogCTVerifier::VerifySingleSCT( scoped_refptr<ct::SignedCertificateTimestamp> sct, const ct::LogEntry& expected_entry, + X509Certificate* cert, ct::CTVerifyResult* result) { - // Assume this SCT is untrusted until proven otherwise. const auto& it = logs_.find(sct->log_id); if (it == logs_.end()) { @@ -217,6 +215,8 @@ bool MultiLogCTVerifier::VerifySingleSCT( LogSCTStatusToUMA(ct::SCT_STATUS_OK); result->verified_scts.push_back(sct); + if (observer_) + observer_->OnSCTVerified(cert, sct.get()); return true; } diff --git a/net/cert/multi_log_ct_verifier.h b/net/cert/multi_log_ct_verifier.h index b18b680..4546606 100644 --- a/net/cert/multi_log_ct_verifier.h +++ b/net/cert/multi_log_ct_verifier.h @@ -40,6 +40,8 @@ class NET_EXPORT MultiLogCTVerifier : public CTVerifier { ct::CTVerifyResult* result, const BoundNetLog& net_log) override; + void SetObserver(Observer* observer) override; + private: // Verify a list of SCTs from |encoded_sct_list| over |expected_entry|, // placing the verification results in |result|. The SCTs in the list @@ -47,19 +49,22 @@ class NET_EXPORT MultiLogCTVerifier : public CTVerifier { bool VerifySCTs(const std::string& encoded_sct_list, const ct::LogEntry& expected_entry, ct::SignedCertificateTimestamp::Origin origin, + X509Certificate* cert, ct::CTVerifyResult* result); // Verifies a single, parsed SCT against all logs. - bool VerifySingleSCT( - scoped_refptr<ct::SignedCertificateTimestamp> sct, - const ct::LogEntry& expected_entry, - ct::CTVerifyResult* result); + bool VerifySingleSCT(scoped_refptr<ct::SignedCertificateTimestamp> sct, + const ct::LogEntry& expected_entry, + X509Certificate* cert, + ct::CTVerifyResult* result); // Mapping from a log's ID to the verifier for this log. // A log's ID is the SHA-256 of the log's key, as defined in section 3.2. // of RFC6962. std::map<std::string, scoped_refptr<CTLogVerifier>> logs_; + Observer* observer_; + DISALLOW_COPY_AND_ASSIGN(MultiLogCTVerifier); }; diff --git a/net/cert/multi_log_ct_verifier_unittest.cc b/net/cert/multi_log_ct_verifier_unittest.cc index 104335a..a994eb2 100644 --- a/net/cert/multi_log_ct_verifier_unittest.cc +++ b/net/cert/multi_log_ct_verifier_unittest.cc @@ -26,8 +26,12 @@ #include "net/log/test_net_log_entry.h" #include "net/test/cert_test_util.h" #include "net/test/ct_test_util.h" +#include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" +using testing::_; +using testing::Mock; + namespace net { namespace { @@ -36,6 +40,13 @@ const char kLogDescription[] = "somelog"; const char kSCTCountHistogram[] = "Net.CertificateTransparency.SCTsPerConnection"; +class MockSCTObserver : public CTVerifier::Observer { + public: + MOCK_METHOD2(OnSCTVerified, + void(X509Certificate* cert, + const ct::SignedCertificateTimestamp* sct)); +}; + class MultiLogCTVerifierTest : public ::testing::Test { public: void SetUp() override { @@ -301,6 +312,27 @@ TEST_F(MultiLogCTVerifierTest, CountsZeroSCTsCorrectly) { GetValueFromHistogram(kSCTCountHistogram, 0)); } +TEST_F(MultiLogCTVerifierTest, NotifiesOfValidSCT) { + MockSCTObserver observer; + verifier_->SetObserver(&observer); + + EXPECT_CALL(observer, OnSCTVerified(embedded_sct_chain_.get(), _)); + ASSERT_TRUE(VerifySinglePrecertificateChain(embedded_sct_chain_)); +} + +TEST_F(MultiLogCTVerifierTest, StopsNotifyingCorrectly) { + MockSCTObserver observer; + verifier_->SetObserver(&observer); + + EXPECT_CALL(observer, OnSCTVerified(embedded_sct_chain_.get(), _)).Times(1); + ASSERT_TRUE(VerifySinglePrecertificateChain(embedded_sct_chain_)); + Mock::VerifyAndClearExpectations(&observer); + + EXPECT_CALL(observer, OnSCTVerified(embedded_sct_chain_.get(), _)).Times(0); + verifier_->SetObserver(nullptr); + ASSERT_TRUE(VerifySinglePrecertificateChain(embedded_sct_chain_)); +} + } // namespace } // namespace net diff --git a/net/socket/ssl_client_socket_unittest.cc b/net/socket/ssl_client_socket_unittest.cc index c93473f..8eec657 100644 --- a/net/socket/ssl_client_socket_unittest.cc +++ b/net/socket/ssl_client_socket_unittest.cc @@ -683,6 +683,7 @@ class MockCTVerifier : public CTVerifier { const std::string&, ct::CTVerifyResult*, const BoundNetLog&)); + MOCK_METHOD1(SetObserver, void(CTVerifier::Observer*)); }; class SSLClientSocketTest : public PlatformTest { |