Chromium Code Reviews| Index: net/quic/crypto/proof_verifier_chromium.cc |
| diff --git a/net/quic/crypto/proof_verifier_chromium.cc b/net/quic/crypto/proof_verifier_chromium.cc |
| index 443c0e352ea5336987ff7142e1609d4dd99c108b..5f70199a5058af1ebecaa2a03411d3006171e858 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" |
| @@ -44,6 +46,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 |
| @@ -78,6 +81,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_; |
| @@ -95,11 +100,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) { |
| } |
| @@ -228,6 +236,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) |
|
wtc
2014/08/01 21:46:36
Adam: I didn't have time to test this patch yester
|
| + // 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 != OK) { |
| error_details_ = StringPrintf("Failed to verify certificate chain: %s", |
| ErrorToString(result)); |
| @@ -315,8 +376,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_); |
| @@ -337,7 +402,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); |