diff options
author | wtc@chromium.org <wtc@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2014-08-07 19:14:32 +0000 |
---|---|---|
committer | wtc@chromium.org <wtc@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2014-08-07 19:14:32 +0000 |
commit | 8e3e1a681ee4ea8cc87aff4e7db87890da6e27a4 (patch) | |
tree | 12a7b4f8610ee130001fd77961a494b7c30340ab | |
parent | 56367df5ff3364060689afc21352c33966bfc2c3 (diff) | |
download | chromium_src-8e3e1a681ee4ea8cc87aff4e7db87890da6e27a4.zip chromium_src-8e3e1a681ee4ea8cc87aff4e7db87890da6e27a4.tar.gz chromium_src-8e3e1a681ee4ea8cc87aff4e7db87890da6e27a4.tar.bz2 |
Merge 287275 "Extend ProofVerifierChromium and ProofVerifyDetail..."
> Extend ProofVerifierChromium and ProofVerifyDetailsChromium.
>
> Original code review: https://codereview.chromium.org/436753002/
>
> TBR=agl@chromium.org,rch@chromium.org
> BUG=399457
>
> Review URL: https://codereview.chromium.org/439133002
TBR=wtc@chromium.org
Review URL: https://codereview.chromium.org/447073003
git-svn-id: svn://svn.chromium.org/chrome/branches/2062/src@288105 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r-- | net/http/http_network_session.cc | 1 | ||||
-rw-r--r-- | net/quic/crypto/proof_verifier_chromium.cc | 80 | ||||
-rw-r--r-- | net/quic/crypto/proof_verifier_chromium.h | 11 | ||||
-rw-r--r-- | net/quic/quic_client_session.cc | 9 | ||||
-rw-r--r-- | net/quic/quic_client_session.h | 1 | ||||
-rw-r--r-- | net/quic/quic_stream_factory.cc | 4 | ||||
-rw-r--r-- | net/quic/quic_stream_factory.h | 2 | ||||
-rw-r--r-- | net/quic/quic_stream_factory_test.cc | 3 | ||||
-rw-r--r-- | net/quic/test_tools/crypto_test_utils_chromium.cc | 14 |
9 files changed, 109 insertions, 16 deletions
diff --git a/net/http/http_network_session.cc b/net/http/http_network_session.cc index b4e373e..75c8ee4 100644 --- a/net/http/http_network_session.cc +++ b/net/http/http_network_session.cc @@ -117,6 +117,7 @@ HttpNetworkSession::HttpNetworkSession(const Params& params) net::ClientSocketFactory::GetDefaultFactory(), params.http_server_properties, params.cert_verifier, + params.transport_security_state, params.quic_crypto_client_stream_factory, params.quic_random ? params.quic_random : QuicRandom::GetInstance(), diff --git a/net/quic/crypto/proof_verifier_chromium.cc b/net/quic/crypto/proof_verifier_chromium.cc index 4b118da..a1365c5c 100644 --- a/net/quic/crypto/proof_verifier_chromium.cc +++ b/net/quic/crypto/proof_verifier_chromium.cc @@ -9,6 +9,7 @@ #include "base/callback_helpers.h" #include "base/compiler_specific.h" #include "base/logging.h" +#include "base/metrics/histogram.h" #include "base/stl_util.h" #include "base/strings/stringprintf.h" #include "crypto/signature_verifier.h" @@ -21,6 +22,7 @@ #include "net/cert/single_request_cert_verifier.h" #include "net/cert/x509_certificate.h" #include "net/cert/x509_util.h" +#include "net/http/transport_security_state.h" #include "net/quic/crypto/crypto_protocol.h" #include "net/ssl/ssl_config_service.h" @@ -38,6 +40,7 @@ class ProofVerifierChromium::Job { public: Job(ProofVerifierChromium* proof_verifier, CertVerifier* cert_verifier, + TransportSecurityState* transport_security_state, const BoundNetLog& net_log); // Starts the proof verification. If |QUIC_PENDING| is returned, then @@ -72,6 +75,8 @@ class ProofVerifierChromium::Job { // The underlying verifier used for verifying certificates. scoped_ptr<SingleRequestCertVerifier> verifier_; + TransportSecurityState* transport_security_state_; + // |hostname| specifies the hostname for which |certs| is a valid chain. std::string hostname_; @@ -89,11 +94,14 @@ class ProofVerifierChromium::Job { DISALLOW_COPY_AND_ASSIGN(Job); }; -ProofVerifierChromium::Job::Job(ProofVerifierChromium* proof_verifier, - CertVerifier* cert_verifier, - const BoundNetLog& net_log) +ProofVerifierChromium::Job::Job( + ProofVerifierChromium* proof_verifier, + CertVerifier* cert_verifier, + TransportSecurityState* transport_security_state, + const BoundNetLog& net_log) : proof_verifier_(proof_verifier), verifier_(new SingleRequestCertVerifier(cert_verifier)), + transport_security_state_(transport_security_state), next_state_(STATE_NONE), net_log_(net_log) { } @@ -222,6 +230,59 @@ int ProofVerifierChromium::Job::DoVerifyCert(int result) { int ProofVerifierChromium::Job::DoVerifyCertComplete(int result) { verifier_.reset(); +#if defined(OFFICIAL_BUILD) && !defined(OS_ANDROID) && !defined(OS_IOS) + // TODO(wtc): The following code was copied from ssl_client_socket_nss.cc. + // Convert it to a new function that can be called by both files. These + // variables simulate the arguments to the new function. + const CertVerifyResult& cert_verify_result = + verify_details_->cert_verify_result; + bool sni_available = true; + const std::string& host = hostname_; + TransportSecurityState* transport_security_state = transport_security_state_; + std::string* pinning_failure_log = &verify_details_->pinning_failure_log; + + // Take care of any mandates for public key pinning. + // + // Pinning is only enabled for official builds to make sure that others don't + // end up with pins that cannot be easily updated. + // + // TODO(agl): We might have an issue here where a request for foo.example.com + // merges into a SPDY connection to www.example.com, and gets a different + // certificate. + + // Perform pin validation if, and only if, all these conditions obtain: + // + // * a TransportSecurityState object is available; + // * the server's certificate chain is valid (or suffers from only a minor + // error); + // * the server's certificate chain chains up to a known root (i.e. not a + // user-installed trust anchor); and + // * the build is recent (very old builds should fail open so that users + // have some chance to recover). + // + const CertStatus cert_status = cert_verify_result.cert_status; + if (transport_security_state && + (result == OK || + (IsCertificateError(result) && IsCertStatusMinorError(cert_status))) && + cert_verify_result.is_issued_by_known_root && + TransportSecurityState::IsBuildTimely()) { + if (transport_security_state->HasPublicKeyPins(host, sni_available)) { + if (!transport_security_state->CheckPublicKeyPins( + host, + sni_available, + cert_verify_result.public_key_hashes, + pinning_failure_log)) { + LOG(ERROR) << *pinning_failure_log; + result = ERR_SSL_PINNED_KEY_NOT_IN_CERT_CHAIN; + UMA_HISTOGRAM_BOOLEAN("Net.PublicKeyPinSuccess", false); + TransportSecurityState::ReportUMAOnPinFailure(host); + } else { + UMA_HISTOGRAM_BOOLEAN("Net.PublicKeyPinSuccess", true); + } + } + } +#endif + if (result <= ERR_FAILED) { error_details_ = StringPrintf("Failed to verify certificate chain: %s", ErrorToString(result)); @@ -310,8 +371,12 @@ bool ProofVerifierChromium::Job::VerifySignature(const string& signed_data, return true; } -ProofVerifierChromium::ProofVerifierChromium(CertVerifier* cert_verifier) - : cert_verifier_(cert_verifier) {} +ProofVerifierChromium::ProofVerifierChromium( + CertVerifier* cert_verifier, + TransportSecurityState* transport_security_state) + : cert_verifier_(cert_verifier), + transport_security_state_(transport_security_state) { +} ProofVerifierChromium::~ProofVerifierChromium() { STLDeleteElements(&active_jobs_); @@ -332,7 +397,10 @@ QuicAsyncStatus ProofVerifierChromium::VerifyProof( } const ProofVerifyContextChromium* chromium_context = reinterpret_cast<const ProofVerifyContextChromium*>(verify_context); - scoped_ptr<Job> job(new Job(this, cert_verifier_, chromium_context->net_log)); + scoped_ptr<Job> job(new Job(this, + cert_verifier_, + transport_security_state_, + chromium_context->net_log)); QuicAsyncStatus status = job->VerifyProof(hostname, server_config, certs, signature, error_details, verify_details, callback); diff --git a/net/quic/crypto/proof_verifier_chromium.h b/net/quic/crypto/proof_verifier_chromium.h index 6f8a231..46632fb 100644 --- a/net/quic/crypto/proof_verifier_chromium.h +++ b/net/quic/crypto/proof_verifier_chromium.h @@ -22,12 +22,18 @@ namespace net { class CertVerifier; class SingleRequestCertVerifier; +class TransportSecurityState; // ProofVerifyDetailsChromium is the implementation-specific information that a // ProofVerifierChromium returns about a certificate verification. struct ProofVerifyDetailsChromium : public ProofVerifyDetails { public: CertVerifyResult cert_verify_result; + + // pinning_failure_log contains a message produced by + // TransportSecurityState::DomainState::CheckPublicKeyPins in the event of a + // pinning failure. It is a (somewhat) human-readable string. + std::string pinning_failure_log; }; // ProofVerifyContextChromium is the implementation-specific information that a @@ -44,7 +50,8 @@ struct ProofVerifyContextChromium : public ProofVerifyContext { // capable of handling multiple simultaneous requests. class NET_EXPORT_PRIVATE ProofVerifierChromium : public ProofVerifier { public: - explicit ProofVerifierChromium(CertVerifier* cert_verifier); + ProofVerifierChromium(CertVerifier* cert_verifier, + TransportSecurityState* transport_security_state); virtual ~ProofVerifierChromium(); // ProofVerifier interface @@ -70,6 +77,8 @@ class NET_EXPORT_PRIVATE ProofVerifierChromium : public ProofVerifier { // Underlying verifier used to verify certificates. CertVerifier* const cert_verifier_; + TransportSecurityState* transport_security_state_; + DISALLOW_COPY_AND_ASSIGN(ProofVerifierChromium); }; diff --git a/net/quic/quic_client_session.cc b/net/quic/quic_client_session.cc index 745692c..40b22cd 100644 --- a/net/quic/quic_client_session.cc +++ b/net/quic/quic_client_session.cc @@ -427,6 +427,7 @@ bool QuicClientSession::GetSSLInfo(SSLInfo* ssl_info) const { ssl_info->channel_id_sent = false; ssl_info->security_bits = security_bits; ssl_info->handshake_type = SSLInfo::HANDSHAKE_FULL; + ssl_info->pinning_failure_log = pinning_failure_log_; return true; } @@ -654,12 +655,12 @@ void QuicClientSession::OnProofValid( void QuicClientSession::OnProofVerifyDetailsAvailable( const ProofVerifyDetails& verify_details) { - const CertVerifyResult* cert_verify_result_other = - &(reinterpret_cast<const ProofVerifyDetailsChromium*>( - &verify_details))->cert_verify_result; + const ProofVerifyDetailsChromium* verify_details_chromium = + reinterpret_cast<const ProofVerifyDetailsChromium*>(&verify_details); CertVerifyResult* result_copy = new CertVerifyResult; - result_copy->CopyFrom(*cert_verify_result_other); + result_copy->CopyFrom(verify_details_chromium->cert_verify_result); cert_verify_result_.reset(result_copy); + pinning_failure_log_ = verify_details_chromium->pinning_failure_log; } void QuicClientSession::StartReading() { diff --git a/net/quic/quic_client_session.h b/net/quic/quic_client_session.h index 7fbe3db..29281b0 100644 --- a/net/quic/quic_client_session.h +++ b/net/quic/quic_client_session.h @@ -227,6 +227,7 @@ class NET_EXPORT_PRIVATE QuicClientSession : public QuicClientSessionBase { scoped_refptr<IOBufferWithSize> read_buffer_; scoped_ptr<QuicServerInfo> server_info_; scoped_ptr<CertVerifyResult> cert_verify_result_; + std::string pinning_failure_log_; ObserverSet observers_; StreamRequestQueue stream_requests_; bool read_pending_; diff --git a/net/quic/quic_stream_factory.cc b/net/quic/quic_stream_factory.cc index 2fc1b9e..5462d2a 100644 --- a/net/quic/quic_stream_factory.cc +++ b/net/quic/quic_stream_factory.cc @@ -450,6 +450,7 @@ QuicStreamFactory::QuicStreamFactory( ClientSocketFactory* client_socket_factory, base::WeakPtr<HttpServerProperties> http_server_properties, CertVerifier* cert_verifier, + TransportSecurityState* transport_security_state, QuicCryptoClientStreamFactory* quic_crypto_client_stream_factory, QuicRandom* random_generator, QuicClock* clock, @@ -479,7 +480,8 @@ QuicStreamFactory::QuicStreamFactory( crypto_config_.set_user_agent_id(user_agent_id); crypto_config_.AddCanonicalSuffix(".c.youtube.com"); crypto_config_.AddCanonicalSuffix(".googlevideo.com"); - crypto_config_.SetProofVerifier(new ProofVerifierChromium(cert_verifier)); + crypto_config_.SetProofVerifier( + new ProofVerifierChromium(cert_verifier, transport_security_state)); base::CPU cpu; if (cpu.has_aesni() && cpu.has_avx()) crypto_config_.PreferAesGcm(); diff --git a/net/quic/quic_stream_factory.h b/net/quic/quic_stream_factory.h index eb82659..b0280e2 100644 --- a/net/quic/quic_stream_factory.h +++ b/net/quic/quic_stream_factory.h @@ -38,6 +38,7 @@ class QuicRandom; class QuicServerInfoFactory; class QuicServerId; class QuicStreamFactory; +class TransportSecurityState; namespace test { class QuicStreamFactoryPeer; @@ -91,6 +92,7 @@ class NET_EXPORT_PRIVATE QuicStreamFactory ClientSocketFactory* client_socket_factory, base::WeakPtr<HttpServerProperties> http_server_properties, CertVerifier* cert_verifier, + TransportSecurityState* transport_security_state, QuicCryptoClientStreamFactory* quic_crypto_client_stream_factory, QuicRandom* random_generator, QuicClock* clock, diff --git a/net/quic/quic_stream_factory_test.cc b/net/quic/quic_stream_factory_test.cc index e88ea4b..ff8e4ce 100644 --- a/net/quic/quic_stream_factory_test.cc +++ b/net/quic/quic_stream_factory_test.cc @@ -12,6 +12,7 @@ #include "net/http/http_response_headers.h" #include "net/http/http_response_info.h" #include "net/http/http_util.h" +#include "net/http/transport_security_state.h" #include "net/quic/crypto/crypto_handshake.h" #include "net/quic/crypto/proof_verifier_chromium.h" #include "net/quic/crypto/quic_decrypter.h" @@ -91,6 +92,7 @@ class QuicStreamFactoryTest : public ::testing::TestWithParam<QuicVersion> { cert_verifier_(CertVerifier::CreateDefault()), factory_(&host_resolver_, &socket_factory_, base::WeakPtr<HttpServerProperties>(), cert_verifier_.get(), + &transport_security_state_, &crypto_client_stream_factory_, &random_generator_, clock_, kDefaultMaxPacketSize, std::string(), SupportedVersions(GetParam()), true, true, true), @@ -181,6 +183,7 @@ class QuicStreamFactoryTest : public ::testing::TestWithParam<QuicVersion> { QuicTestPacketMaker maker_; MockClock* clock_; // Owned by factory_. scoped_ptr<CertVerifier> cert_verifier_; + TransportSecurityState transport_security_state_; QuicStreamFactory factory_; HostPortPair host_port_pair_; bool is_https_; diff --git a/net/quic/test_tools/crypto_test_utils_chromium.cc b/net/quic/test_tools/crypto_test_utils_chromium.cc index 9deee83..a3c85fb 100644 --- a/net/quic/test_tools/crypto_test_utils_chromium.cc +++ b/net/quic/test_tools/crypto_test_utils_chromium.cc @@ -10,6 +10,7 @@ #include "net/cert/cert_verifier.h" #include "net/cert/test_root_certs.h" #include "net/cert/x509_certificate.h" +#include "net/http/transport_security_state.h" #include "net/quic/crypto/proof_source_chromium.h" #include "net/quic/crypto/proof_verifier_chromium.h" #include "net/test/cert_test_util.h" @@ -21,9 +22,11 @@ namespace test { class TestProofVerifierChromium : public ProofVerifierChromium { public: TestProofVerifierChromium(CertVerifier* cert_verifier, + TransportSecurityState* transport_security_state, const std::string& cert_file) - : ProofVerifierChromium(cert_verifier), - cert_verifier_(cert_verifier) { + : ProofVerifierChromium(cert_verifier, transport_security_state), + cert_verifier_(cert_verifier), + transport_security_state_(transport_security_state) { // Load and install the root for the validated chain. scoped_refptr<X509Certificate> root_cert = ImportCertFromFile(GetTestCertsDirectory(), cert_file); @@ -34,6 +37,7 @@ class TestProofVerifierChromium : public ProofVerifierChromium { private: ScopedTestRoot scoped_root_; scoped_ptr<CertVerifier> cert_verifier_; + scoped_ptr<TransportSecurityState> transport_security_state_; }; // static @@ -43,8 +47,10 @@ ProofSource* CryptoTestUtils::ProofSourceForTesting() { // static ProofVerifier* CryptoTestUtils::ProofVerifierForTesting() { - TestProofVerifierChromium* proof_verifier = new TestProofVerifierChromium( - CertVerifier::CreateDefault(), "quic_root.crt"); + TestProofVerifierChromium* proof_verifier = + new TestProofVerifierChromium(CertVerifier::CreateDefault(), + new TransportSecurityState, + "quic_root.crt"); return proof_verifier; } |