Commit 4f342e0f authored by agl@chromium.org's avatar agl@chromium.org

net: move pinning checks into the SSL socket.

Previously we would reject requests with pinning errors at the URLRequest layer
but, by that time, we would already have sent cookies.

The commenting of the #ifdef is deliberate - it allows the builders to chew the
code over. Once the builders are happy I'll land another change to uncomment
the #ifdefs.

This also happens to start unpicking the DNS certificate provenance stuff.

BUG=none
TEST=Verify that https://pinningtest.appspot.com fails to load in offical builds.

Review URL: http://codereview.chromium.org/8865006

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@113823 0039d316-1c4b-4281-b951-d872f2087c98
parent 1835ef8a
......@@ -66,6 +66,7 @@
#include "base/bind.h"
#include "base/bind_helpers.h"
#include "base/build_time.h"
#include "base/compiler_specific.h"
#include "base/logging.h"
#include "base/memory/singleton.h"
......@@ -96,7 +97,6 @@
#include "net/base/x509_certificate_net_log_param.h"
#include "net/ocsp/nss_ocsp.h"
#include "net/socket/client_socket_handle.h"
#include "net/socket/dns_cert_provenance_checker.h"
#include "net/socket/nss_ssl_util.h"
#include "net/socket/ssl_error_params.h"
#include "net/socket/ssl_host_info.h"
......@@ -468,7 +468,7 @@ SSLClientSocketNSS::SSLClientSocketNSS(ClientSocketHandle* transport_socket,
nss_bufs_(NULL),
net_log_(transport_socket->socket()->NetLog()),
ssl_host_info_(ssl_host_info),
dns_cert_checker_(context.dns_cert_checker),
transport_security_state_(context.transport_security_state),
next_proto_status_(kNextProtoUnsupported),
valid_thread_id_(base::kInvalidThreadId) {
EnterFunction("");
......@@ -1721,13 +1721,6 @@ int SSLClientSocketNSS::DoGetOBCertComplete(int result) {
}
int SSLClientSocketNSS::DoVerifyDNSSEC(int result) {
if (ssl_config_.dns_cert_provenance_checking_enabled &&
dns_cert_checker_) {
PeerCertificateChain certs(nss_fd_);
dns_cert_checker_->DoAsyncVerification(
host_and_port_.host(), certs.AsStringPieceVector());
}
DNSValidationResult r = CheckDNSSECChain(host_and_port_.host(),
server_cert_nss_,
host_and_port_.port());
......@@ -1889,7 +1882,7 @@ int SSLClientSocketNSS::DoVerifyCertComplete(int result) {
// http://crbug.com/15630 for more info.
// TODO(hclam): Skip logging if server cert was expected to be bad because
// |server_cert_verify_results_| doesn't contain all the information about
// |server_cert_verify_result_| doesn't contain all the information about
// the cert.
if (result == OK)
LogConnectionTypeMetrics();
......@@ -1902,6 +1895,47 @@ int SSLClientSocketNSS::DoVerifyCertComplete(int result) {
DoReadCallback(rv);
}
//#if defined(OFFICIAL_BUILD) && !defined(OS_ANDROID)
// 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.
const CertStatus cert_status = server_cert_verify_result_->cert_status;
if ((result == OK || (IsCertificateError(result) &&
IsCertStatusMinorError(cert_status))) &&
server_cert_verify_result_->is_issued_by_known_root &&
transport_security_state_) {
bool sni_available = ssl_config_.tls1_enabled || ssl_config_.ssl3_fallback;
const std::string& host = host_and_port_.host();
TransportSecurityState::DomainState domain_state;
if (transport_security_state_->HasPinsForHost(
&domain_state, host, sni_available)) {
if (!domain_state.IsChainOfPublicKeysPermitted(
server_cert_verify_result_->public_key_hashes)) {
const base::Time build_time = base::GetBuildTime();
// Pins are not enforced if the build is sufficiently old. Chrome
// users should get updates every six weeks or so, but it's possible
// that some users will stop getting updates for some reason. We
// don't want those users building up as a pool of people with bad
// pins.
if ((base::Time::Now() - build_time).InDays() < 70 /* 10 weeks */) {
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
// Exit DoHandshakeLoop and return the result to the caller to Connect.
DCHECK(next_handshake_state_ == STATE_NONE);
return result;
......
......@@ -35,10 +35,10 @@ namespace net {
class BoundNetLog;
class CertVerifier;
class ClientSocketHandle;
class DnsCertProvenanceChecker;
class OriginBoundCertService;
class SingleRequestCertVerifier;
class SSLHostInfo;
class TransportSecurityState;
class X509Certificate;
// An SSL client socket implemented with Mozilla NSS.
......@@ -305,7 +305,8 @@ class SSLClientSocketNSS : public SSLClientSocket {
base::TimeTicks start_cert_verification_time_;
scoped_ptr<SSLHostInfo> ssl_host_info_;
DnsCertProvenanceChecker* const dns_cert_checker_;
TransportSecurityState* transport_security_state_;
// next_proto_ is the protocol that we selected by NPN.
std::string next_proto_;
......
......@@ -7,7 +7,6 @@
#include "base/base_switches.h"
#include "base/bind.h"
#include "base/bind_helpers.h"
#include "base/build_time.h"
#include "base/command_line.h"
#include "base/compiler_specific.h"
#include "base/file_util.h"
......@@ -30,7 +29,6 @@
#include "net/base/sdch_manager.h"
#include "net/base/ssl_cert_request_info.h"
#include "net/base/ssl_config_service.h"
#include "net/base/transport_security_state.h"
#include "net/http/http_mac_signature.h"
#include "net/http/http_request_headers.h"
#include "net/http/http_response_headers.h"
......@@ -661,53 +659,19 @@ void URLRequestHttpJob::OnStartCompleted(int result) {
// Clear the IO_PENDING status
SetStatus(URLRequestStatus());
#if defined(OFFICIAL_BUILD) && !defined(OS_ANDROID)
// 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.
if (transaction_->GetResponseInfo() != NULL) {
const SSLInfo& ssl_info = transaction_->GetResponseInfo()->ssl_info;
if (ssl_info.is_valid() &&
(result == OK || (IsCertificateError(result) &&
IsCertStatusMinorError(ssl_info.cert_status))) &&
ssl_info.is_issued_by_known_root &&
context_->transport_security_state()) {
TransportSecurityState::DomainState domain_state;
if (result == ERR_SSL_PINNED_KEY_NOT_IN_CERT_CHAIN &&
transaction_->GetResponseInfo() != NULL) {
FraudulentCertificateReporter* reporter =
context_->fraudulent_certificate_reporter();
if (reporter != NULL) {
const SSLInfo& ssl_info = transaction_->GetResponseInfo()->ssl_info;
bool sni_available = SSLConfigService::IsSNIAvailable(
context_->ssl_config_service());
std::string host = request_->url().host();
if (context_->transport_security_state()->HasPinsForHost(
&domain_state, host, sni_available)) {
if (!domain_state.IsChainOfPublicKeysPermitted(
ssl_info.public_key_hashes)) {
const base::Time build_time = base::GetBuildTime();
// Pins are not enforced if the build is sufficiently old. Chrome
// users should get updates every six weeks or so, but it's possible
// that some users will stop getting updates for some reason. We
// don't want those users building up as a pool of people with bad
// pins.
if ((base::Time::Now() - build_time).InDays() < 70 /* 10 weeks */) {
result = ERR_SSL_PINNED_KEY_NOT_IN_CERT_CHAIN;
UMA_HISTOGRAM_BOOLEAN("Net.PublicKeyPinSuccess", false);
TransportSecurityState::ReportUMAOnPinFailure(host);
FraudulentCertificateReporter* reporter =
context_->fraudulent_certificate_reporter();
if (reporter != NULL)
reporter->SendReport(host, ssl_info, sni_available);
}
} else {
UMA_HISTOGRAM_BOOLEAN("Net.PublicKeyPinSuccess", true);
}
}
const std::string& host = request_->url().host();
reporter->SendReport(host, ssl_info, sni_available);
}
}
#endif
if (result == OK) {
scoped_refptr<HttpResponseHeaders> headers = GetResponseHeaders();
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment