Extend ProofVerifierChromium and ProofVerifyDetailsChromium.
Original code review: https://codereview.chromium.org/436753002/
[email protected],[email protected]
BUG=399457
Review URL: https://codereview.chromium.org/439133002
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@287275 0039d316-1c4b-4281-b951-d872f2087c98
diff --git a/net/quic/crypto/proof_verifier_chromium.cc b/net/quic/crypto/proof_verifier_chromium.cc
index 443c0e352..5f70199 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 @@
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 @@
// 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 @@
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::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 != OK) {
error_details_ = StringPrintf("Failed to verify certificate chain: %s",
ErrorToString(result));
@@ -315,8 +376,12 @@
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 @@
}
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);