Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(328)

Unified Diff: net/socket/ssl_client_socket_nss.cc

Issue 135373002: Added SSLHostInfo. Storing of server host info to our standard disk cache. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Merge with TOT Created 6 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: net/socket/ssl_client_socket_nss.cc
diff --git a/net/socket/ssl_client_socket_nss.cc b/net/socket/ssl_client_socket_nss.cc
index b46ebbdfd3e03497c5733d16bd510e16121da252..2c85e2928ecf7622c2331aa65cdae5a732b1e9cc 100644
--- a/net/socket/ssl_client_socket_nss.cc
+++ b/net/socket/ssl_client_socket_nss.cc
@@ -106,7 +106,9 @@
#include "net/socket/client_socket_handle.h"
#include "net/socket/nss_ssl_util.h"
#include "net/socket/ssl_error_params.h"
+#include "net/socket/ssl_host_info.h"
#include "net/ssl/ssl_cert_request_info.h"
+#include "net/ssl/ssl_config_service.h"
wtc 2014/01/15 19:08:59 I assume it is necessary to add this header? It's
ramant (doing other things) 2014/01/18 00:21:56 Done.
#include "net/ssl/ssl_connection_status_flags.h"
#include "net/ssl/ssl_info.h"
@@ -413,6 +415,7 @@ struct HandshakeState {
channel_id_sent = false;
server_cert_chain.Reset(NULL);
server_cert = NULL;
+ predicted_cert_chain_correct = false;
sct_list_from_tls_extension.clear();
stapled_ocsp_response.clear();
resumed_handshake = false;
@@ -449,6 +452,11 @@ struct HandshakeState {
// Stapled OCSP response received.
std::string stapled_ocsp_response;
+ // True if we predicted a certificate chain (via
+ // Core::SetPredictedCertificates) and that prediction matched what the
+ // server sent.
+ bool predicted_cert_chain_correct;
wtc 2014/01/15 19:08:59 List this right after server_cert.
ramant (doing other things) 2014/01/18 00:21:56 Done.
+
// True if the current handshake was the result of TLS session resumption.
bool resumed_handshake;
@@ -1653,6 +1661,26 @@ void SSLClientSocketNSS::Core::HandshakeSucceeded() {
UpdateConnectionStatus();
UpdateNextProto();
+ // We need to see if the predicted certificate chain (from
+ // SetPredictedCertificates) matches the actual certificate chain.
+ nss_handshake_state_.predicted_cert_chain_correct = false;
+ if (!predicted_certs_.empty()) {
+ PeerCertificateChain& certs = nss_handshake_state_.server_cert_chain;
+ nss_handshake_state_.predicted_cert_chain_correct =
+ certs.size() == predicted_certs_.size();
+
+ if (nss_handshake_state_.predicted_cert_chain_correct) {
+ for (unsigned i = 0; i < certs.size(); i++) {
+ if (certs[i]->derCert.len != predicted_certs_[i].size() ||
+ memcmp(certs[i]->derCert.data, predicted_certs_[i].data(),
+ certs[i]->derCert.len) != 0) {
+ nss_handshake_state_.predicted_cert_chain_correct = false;
+ break;
+ }
+ }
+ }
+ }
+
// Update the network task runners view of the handshake state whenever
// a handshake has completed.
PostOrRunCallback(
@@ -2398,7 +2426,8 @@ void SSLClientSocketNSS::Core::UpdateStapledOCSPResponse() {
// TODO(agl): figure out how to plumb an OCSP response into the Mac
// system library and update IsOCSPStaplingSupported for Mac.
- if (IsOCSPStaplingSupported()) {
+ if (!nss_handshake_state_.predicted_cert_chain_correct &&
+ IsOCSPStaplingSupported()) {
#if defined(OS_WIN)
if (nss_handshake_state_.server_cert) {
CRYPT_DATA_BLOB ocsp_response_blob;
@@ -2769,11 +2798,13 @@ SSLClientSocketNSS::SSLClientSocketNSS(
scoped_ptr<ClientSocketHandle> transport_socket,
const HostPortPair& host_and_port,
const SSLConfig& ssl_config,
+ SSLHostInfo* ssl_host_info,
const SSLClientSocketContext& context)
: nss_task_runner_(nss_task_runner),
transport_(transport_socket.Pass()),
host_and_port_(host_and_port),
ssl_config_(ssl_config),
+ server_cert_verify_result_(NULL),
cert_verifier_(context.cert_verifier),
cert_transparency_verifier_(context.cert_transparency_verifier),
server_bound_cert_service_(context.server_bound_cert_service),
@@ -2782,6 +2813,7 @@ SSLClientSocketNSS::SSLClientSocketNSS(
next_handshake_state_(STATE_NONE),
nss_fd_(NULL),
net_log_(transport_->socket()->NetLog()),
+ ssl_host_info_(ssl_host_info),
transport_security_state_(context.transport_security_state),
valid_thread_id_(base::kInvalidThreadId) {
EnterFunction("");
@@ -2813,16 +2845,16 @@ bool SSLClientSocketNSS::GetSSLInfo(SSLInfo* ssl_info) {
return false;
}
- ssl_info->cert_status = server_cert_verify_result_.cert_status;
- ssl_info->cert = server_cert_verify_result_.verified_cert;
+ ssl_info->cert_status = server_cert_verify_result_->cert_status;
+ ssl_info->cert = server_cert_verify_result_->verified_cert;
AddSCTInfoToSSLInfo(ssl_info);
ssl_info->connection_status =
core_->state().ssl_connection_status;
- ssl_info->public_key_hashes = server_cert_verify_result_.public_key_hashes;
+ ssl_info->public_key_hashes = server_cert_verify_result_->public_key_hashes;
ssl_info->is_issued_by_known_root =
- server_cert_verify_result_.is_issued_by_known_root;
+ server_cert_verify_result_->is_issued_by_known_root;
ssl_info->client_cert_sent =
ssl_config_.send_client_cert && ssl_config_.client_cert.get();
ssl_info->channel_id_sent = WasChannelIDSent();
@@ -2932,7 +2964,11 @@ int SSLClientSocketNSS::Connect(const CompletionCallback& callback) {
return rv;
}
- GotoState(STATE_HANDSHAKE);
+ if (ssl_host_info_.get()) {
+ GotoState(STATE_LOAD_SSL_HOST_INFO);
+ } else {
+ GotoState(STATE_HANDSHAKE);
+ }
rv = DoHandshakeLoop(OK);
if (rv == ERR_IO_PENDING) {
@@ -2957,7 +2993,8 @@ void SSLClientSocketNSS::Disconnect() {
// Reset object state.
user_connect_callback_.Reset();
- server_cert_verify_result_.Reset();
+ local_server_cert_verify_result_.Reset();
+ server_cert_verify_result_ = NULL;
completed_handshake_ = false;
start_cert_verification_time_ = base::TimeTicks();
InitCore();
@@ -3286,6 +3323,35 @@ void SSLClientSocketNSS::OnHandshakeIOComplete(int result) {
LeaveFunction("");
}
+void SSLClientSocketNSS::LoadSSLHostInfo() {
+ const SSLHostInfo::State& state(ssl_host_info_->state());
+
+ if (state.certs.empty())
+ return;
+
+ /* TODO(rtenneti): Implement the following */
+ // const std::vector<std::string>& certs_in = state.certs;
+ // core_->SetPredictedCertificates(certs_in);
+}
+
+int SSLClientSocketNSS::DoLoadSSLHostInfo() {
+ EnterFunction("");
+ int rv = ssl_host_info_->WaitForDataReady(
+ base::Bind(&SSLClientSocketNSS::OnHandshakeIOComplete,
+ base::Unretained(this)));
+ GotoState(STATE_HANDSHAKE);
+
+ if (rv == OK) {
+ LoadSSLHostInfo();
+ } else {
+ DCHECK_EQ(ERR_IO_PENDING, rv);
+ GotoState(STATE_LOAD_SSL_HOST_INFO);
+ }
+
+ LeaveFunction("");
+ return rv;
+}
+
int SSLClientSocketNSS::DoHandshakeLoop(int last_io_result) {
EnterFunction(last_io_result);
int rv = last_io_result;
@@ -3298,6 +3364,10 @@ int SSLClientSocketNSS::DoHandshakeLoop(int last_io_result) {
State state = next_handshake_state_;
GotoState(STATE_NONE);
switch (state) {
+ case STATE_LOAD_SSL_HOST_INFO:
+ DCHECK(rv == OK || rv == ERR_IO_PENDING);
+ rv = DoLoadSSLHostInfo();
+ break;
case STATE_HANDSHAKE:
rv = DoHandshake();
break;
@@ -3337,6 +3407,7 @@ int SSLClientSocketNSS::DoHandshakeComplete(int result) {
EnterFunction(result);
if (result == OK) {
+ SaveSSLHostInfo();
// SSL handshake is completed. Let's verify the certificate.
GotoState(STATE_VERIFY_CERT);
// Done!
@@ -3367,22 +3438,46 @@ int SSLClientSocketNSS::DoVerifyCert(int result) {
if (ssl_config_.IsAllowedBadCert(der_cert, &cert_status)) {
DCHECK(start_cert_verification_time_.is_null());
VLOG(1) << "Received an expected bad cert with status: " << cert_status;
- server_cert_verify_result_.Reset();
- server_cert_verify_result_.cert_status = cert_status;
- server_cert_verify_result_.verified_cert = core_->state().server_cert;
+ server_cert_verify_result_ = &local_server_cert_verify_result_;
+ local_server_cert_verify_result_.Reset();
+ local_server_cert_verify_result_.cert_status = cert_status;
+ local_server_cert_verify_result_.verified_cert =
+ core_->state().server_cert;
return OK;
}
// We may have failed to create X509Certificate object if we are
// running inside sandbox.
if (!core_->state().server_cert.get()) {
- server_cert_verify_result_.Reset();
- server_cert_verify_result_.cert_status = CERT_STATUS_INVALID;
+ server_cert_verify_result_ = &local_server_cert_verify_result_;
+ local_server_cert_verify_result_.Reset();
+ local_server_cert_verify_result_.cert_status = CERT_STATUS_INVALID;
return ERR_CERT_INVALID;
}
start_cert_verification_time_ = base::TimeTicks::Now();
+ if (ssl_host_info_.get() && !ssl_host_info_->state().certs.empty() &&
+ core_->state().predicted_cert_chain_correct) {
+ // If the SSLHostInfo had a prediction for the certificate chain of this
+ // server then it will have optimistically started a verification of that
+ // chain. So, if the prediction was correct, we should wait for that
+ // verification to finish rather than start our own.
+ net_log_.AddEvent(NetLog::TYPE_SSL_VERIFICATION_MERGED);
+ UMA_HISTOGRAM_ENUMERATION("Net.SSLVerificationMerged", 1 /* true */, 2);
+ base::TimeTicks end_time = ssl_host_info_->verification_end_time();
+ if (end_time.is_null())
+ end_time = base::TimeTicks::Now();
+ UMA_HISTOGRAM_TIMES("Net.SSLVerificationMergedMsSaved",
+ end_time - ssl_host_info_->verification_start_time());
+ server_cert_verify_result_ = &ssl_host_info_->cert_verify_result();
+ return ssl_host_info_->WaitForCertVerification(
+ base::Bind(&SSLClientSocketNSS::OnHandshakeIOComplete,
+ base::Unretained(this)));
+ } else {
+ UMA_HISTOGRAM_ENUMERATION("Net.SSLVerificationMerged", 0 /* false */, 2);
+ }
+
int flags = 0;
if (ssl_config_.rev_checking_enabled)
flags |= CertVerifier::VERIFY_REV_CHECKING_ENABLED;
@@ -3393,12 +3488,13 @@ int SSLClientSocketNSS::DoVerifyCert(int result) {
if (ssl_config_.rev_checking_required_local_anchors)
flags |= CertVerifier::VERIFY_REV_CHECKING_REQUIRED_LOCAL_ANCHORS;
verifier_.reset(new SingleRequestCertVerifier(cert_verifier_));
+ server_cert_verify_result_ = &local_server_cert_verify_result_;
return verifier_->Verify(
core_->state().server_cert.get(),
host_and_port_.host(),
flags,
SSLConfigService::GetCRLSet().get(),
- &server_cert_verify_result_,
+ &local_server_cert_verify_result_,
base::Bind(&SSLClientSocketNSS::OnHandshakeIOComplete,
base::Unretained(this)),
net_log_);
@@ -3454,11 +3550,11 @@ int SSLClientSocketNSS::DoVerifyCertComplete(int result) {
// * the build is recent (very old builds should fail open so that users
// have some chance to recover).
//
- const CertStatus cert_status = server_cert_verify_result_.cert_status;
+ const CertStatus cert_status = server_cert_verify_result_->cert_status;
if (transport_security_state_ &&
(result == OK ||
(IsCertificateError(result) && IsCertStatusMinorError(cert_status))) &&
- server_cert_verify_result_.is_issued_by_known_root &&
+ server_cert_verify_result_->is_issued_by_known_root &&
TransportSecurityState::IsBuildTimely()) {
bool sni_available =
ssl_config_.version_max >= SSL_PROTOCOL_VERSION_TLS1 ||
@@ -3470,7 +3566,7 @@ int SSLClientSocketNSS::DoVerifyCertComplete(int result) {
&domain_state) &&
domain_state.HasPublicKeyPins()) {
if (!domain_state.CheckPublicKeyPins(
- server_cert_verify_result_.public_key_hashes)) {
+ server_cert_verify_result_->public_key_hashes)) {
result = ERR_SSL_PINNED_KEY_NOT_IN_CERT_CHAIN;
UMA_HISTOGRAM_BOOLEAN("Net.PublicKeyPinSuccess", false);
TransportSecurityState::ReportUMAOnPinFailure(host);
@@ -3505,7 +3601,7 @@ void SSLClientSocketNSS::VerifyCT() {
// gets all the data it needs for SCT verification and does not do any
// external communication.
int result = cert_transparency_verifier_->Verify(
- server_cert_verify_result_.verified_cert,
+ server_cert_verify_result_->verified_cert,
core_->state().stapled_ocsp_response,
core_->state().sct_list_from_tls_extension,
&ct_verify_result_,
@@ -3543,6 +3639,35 @@ void SSLClientSocketNSS::LogConnectionTypeMetrics() const {
};
}
+// SaveSSLHostInfo saves the certificate chain of the connection so that we can
+// start verification faster in the future.
+void SSLClientSocketNSS::SaveSSLHostInfo() {
+ if (!ssl_host_info_.get())
+ return;
+
+ // If the SSLHostInfo hasn't managed to load from disk yet then we can't save
+ // anything.
+ if (ssl_host_info_->WaitForDataReady(net::CompletionCallback()) != OK)
+ return;
+
+ SSLHostInfo::State* state = ssl_host_info_->mutable_state();
+
+ state->certs.clear();
+ const PeerCertificateChain& certs = core_->state().server_cert_chain;
+ for (unsigned i = 0; i < certs.size(); i++) {
+ if (certs[i] == NULL ||
+ certs[i]->derCert.len > std::numeric_limits<uint16>::max()) {
+ return;
+ }
+
+ state->certs.push_back(std::string(
+ reinterpret_cast<char*>(certs[i]->derCert.data),
+ certs[i]->derCert.len));
+ }
+
+ ssl_host_info_->Persist();
+}
+
void SSLClientSocketNSS::EnsureThreadIdAssigned() const {
base::AutoLock auto_lock(lock_);
if (valid_thread_id_ != base::kInvalidThreadId)

Powered by Google App Engine
This is Rietveld 408576698