diff options
author | agl@chromium.org <agl@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-04-12 19:46:27 +0000 |
---|---|---|
committer | agl@chromium.org <agl@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-04-12 19:46:27 +0000 |
commit | 8d3718970504d75dea10ba8a523f5d2219627071 (patch) | |
tree | 5c148f80c5fe5cc768c79c52f292a72707041a37 /net/socket | |
parent | 37779e0d685e3e8cf948ebae2bb7dc9c04aa876f (diff) | |
download | chromium_src-8d3718970504d75dea10ba8a523f5d2219627071.zip chromium_src-8d3718970504d75dea10ba8a523f5d2219627071.tar.gz chromium_src-8d3718970504d75dea10ba8a523f5d2219627071.tar.bz2 |
Revert r61181.
This reverts r61181 although, due to the age of that revision, the revert was
mostly done manually. This is the start of ripping out Snap Start support.
BUG=none
TEST=none
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@81288 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'net/socket')
-rw-r--r-- | net/socket/ssl_client_socket_nss.cc | 316 | ||||
-rw-r--r-- | net/socket/ssl_client_socket_nss.h | 20 | ||||
-rw-r--r-- | net/socket/ssl_client_socket_snapstart_unittest.cc | 369 | ||||
-rw-r--r-- | net/socket/ssl_host_info.cc | 34 | ||||
-rw-r--r-- | net/socket/ssl_host_info.h | 8 | ||||
-rw-r--r-- | net/socket/ssl_server_socket_unittest.cc | 1 |
6 files changed, 34 insertions, 714 deletions
diff --git a/net/socket/ssl_client_socket_nss.cc b/net/socket/ssl_client_socket_nss.cc index 173fe36..a5fe5b1 100644 --- a/net/socket/ssl_client_socket_nss.cc +++ b/net/socket/ssl_client_socket_nss.cc @@ -485,7 +485,6 @@ SSLClientSocketNSS::SSLClientSocketNSS(ClientSocketHandle* transport_socket, cert_verifier_(cert_verifier), handshake_callback_called_(false), completed_handshake_(false), - pseudo_connected_(false), eset_mitm_detected_(false), predicted_cert_chain_correct_(false), peername_initialized_(false), @@ -494,8 +493,6 @@ SSLClientSocketNSS::SSLClientSocketNSS(ClientSocketHandle* transport_socket, nss_fd_(NULL), nss_bufs_(NULL), net_log_(transport_socket->socket()->NetLog()), - predicted_npn_status_(kNextProtoUnsupported), - predicted_npn_proto_used_(false), ssl_host_info_(ssl_host_info), dns_cert_checker_(dns_ctx), valid_thread_id_(base::kInvalidThreadId) { @@ -517,10 +514,8 @@ void SSLClientSocketNSS::GetSSLInfo(SSLInfo* ssl_info) { EnterFunction(""); ssl_info->Reset(); - if (!server_cert_) { - LOG(DFATAL) << "!server_cert_"; + if (!server_cert_) return; - } ssl_info->cert_status = server_cert_verify_result_->cert_status; DCHECK(server_cert_ != NULL); @@ -554,13 +549,6 @@ void SSLClientSocketNSS::GetSSLCertRequestInfo( SSLClientSocket::NextProtoStatus SSLClientSocketNSS::GetNextProto(std::string* proto) { #if defined(SSL_NEXT_PROTO_NEGOTIATED) - if (!handshake_callback_called_) { - DCHECK(pseudo_connected_); - predicted_npn_proto_used_ = true; - *proto = predicted_npn_proto_; - return predicted_npn_status_; - } - unsigned char buf[255]; int state; unsigned len; @@ -607,7 +595,6 @@ int SSLClientSocketNSS::Connect(CompletionCallback* callback) { DCHECK(!user_connect_callback_); DCHECK(!user_read_buf_); DCHECK(!user_write_buf_); - DCHECK(!pseudo_connected_); EnsureThreadIdAssigned(); @@ -635,20 +622,11 @@ int SSLClientSocketNSS::Connect(CompletionCallback* callback) { } } - if (ssl_config_.snap_start_enabled && ssl_host_info_.get()) { - GotoState(STATE_SNAP_START_LOAD_INFO); - } else { - GotoState(STATE_HANDSHAKE); - } + GotoState(STATE_HANDSHAKE); rv = DoHandshakeLoop(OK); if (rv == ERR_IO_PENDING) { - if (pseudo_connected_) { - net_log_.EndEvent(NetLog::TYPE_SSL_CONNECT, NULL); - rv = OK; - } else { - user_connect_callback_ = callback; - } + user_connect_callback_ = callback; } else { net_log_.EndEventWithNetErrorCode(NetLog::TYPE_SSL_CONNECT, rv); } @@ -692,7 +670,6 @@ void SSLClientSocketNSS::Disconnect() { server_cert_verify_result_ = NULL; ssl_connection_status_ = 0; completed_handshake_ = false; - pseudo_connected_ = false; eset_mitm_detected_ = false; start_cert_verification_time_ = base::TimeTicks(); predicted_cert_chain_correct_ = false; @@ -712,8 +689,7 @@ bool SSLClientSocketNSS::IsConnected() const { // closed by the server when we send a request anyway, a false positive in // exchange for simpler code is a good trade-off. EnterFunction(""); - bool ret = (pseudo_connected_ || completed_handshake_) && - transport_->socket()->IsConnected(); + bool ret = completed_handshake_ && transport_->socket()->IsConnected(); LeaveFunction(""); return ret; } @@ -728,8 +704,7 @@ bool SSLClientSocketNSS::IsConnectedAndIdle() const { // transport_->socket()->IsConnectedAndIdle() returns the desired false // when we receive close_notify. EnterFunction(""); - bool ret = (pseudo_connected_ || completed_handshake_) && - transport_->socket()->IsConnectedAndIdle(); + bool ret = completed_handshake_ && transport_->socket()->IsConnectedAndIdle(); LeaveFunction(""); return ret; } @@ -777,6 +752,8 @@ bool SSLClientSocketNSS::UsingTCPFastOpen() const { int SSLClientSocketNSS::Read(IOBuffer* buf, int buf_len, CompletionCallback* callback) { EnterFunction(buf_len); + DCHECK(completed_handshake_); + DCHECK(next_handshake_state_ == STATE_NONE); DCHECK(!user_read_callback_); DCHECK(!user_connect_callback_); DCHECK(!user_read_buf_); @@ -785,17 +762,6 @@ int SSLClientSocketNSS::Read(IOBuffer* buf, int buf_len, user_read_buf_ = buf; user_read_buf_len_ = buf_len; - if (!completed_handshake_) { - // In this case we have lied about being connected in order to merge the - // first Write into a Snap Start handshake. We'll leave the read hanging - // until the handshake has completed. - DCHECK(pseudo_connected_); - - user_read_callback_ = callback; - LeaveFunction(ERR_IO_PENDING); - return ERR_IO_PENDING; - } - int rv = DoReadLoop(OK); if (rv == ERR_IO_PENDING) { @@ -811,34 +777,16 @@ int SSLClientSocketNSS::Read(IOBuffer* buf, int buf_len, int SSLClientSocketNSS::Write(IOBuffer* buf, int buf_len, CompletionCallback* callback) { EnterFunction(buf_len); - if (!pseudo_connected_) { - DCHECK(completed_handshake_); - DCHECK(next_handshake_state_ == STATE_NONE); - DCHECK(!user_connect_callback_); - } + DCHECK(completed_handshake_); + DCHECK(next_handshake_state_ == STATE_NONE); DCHECK(!user_write_callback_); + DCHECK(!user_connect_callback_); DCHECK(!user_write_buf_); DCHECK(nss_bufs_); user_write_buf_ = buf; user_write_buf_len_ = buf_len; - if (next_handshake_state_ == STATE_SNAP_START_WAIT_FOR_WRITE) { - // We lied about being connected and we have been waiting for this write in - // order to merge it into the Snap Start handshake. We'll leave the write - // pending until the handshake completes. - DCHECK(pseudo_connected_); - int rv = DoHandshakeLoop(OK); - if (rv == ERR_IO_PENDING) { - user_write_callback_ = callback; - } else { - user_write_buf_ = NULL; - user_write_buf_len_ = 0; - } - if (rv != OK) - return rv; - } - if (corked_) { corked_ = false; uncork_timer_.Reset(); @@ -973,15 +921,6 @@ int SSLClientSocketNSS::InitializeSSLOptions() { LogFailedNSSFunction(net_log_, "SSL_OptionSet", "SSL_ENABLE_FALSE_START"); #endif -#ifdef SSL_ENABLE_SNAP_START - // TODO(agl): check that SSL_ENABLE_SNAP_START actually does something in the - // current NSS code. - rv = SSL_OptionSet(nss_fd_, SSL_ENABLE_SNAP_START, - ssl_config_.snap_start_enabled); - if (rv != SECSuccess) - VLOG(1) << "SSL_ENABLE_SNAP_START failed. Old system nss?"; -#endif - #ifdef SSL_ENABLE_RENEGOTIATION // We allow servers to request renegotiation. Since we're a client, // prohibiting this is rather a waste of time. Only servers are in a @@ -1008,7 +947,7 @@ int SSLClientSocketNSS::InitializeSSLOptions() { #endif #ifdef SSL_ENABLE_OCSP_STAPLING - if (IsOCSPStaplingSupported() && !ssl_config_.snap_start_enabled) { + if (IsOCSPStaplingSupported()) { rv = SSL_OptionSet(nss_fd_, SSL_ENABLE_OCSP_STAPLING, PR_TRUE); if (rv != SECSuccess) LogFailedNSSFunction(net_log_, "SSL_OptionSet (OCSP stapling)", ""); @@ -1208,6 +1147,7 @@ void SSLClientSocketNSS::DoWriteCallback(int rv) { void SSLClientSocketNSS::DoConnectCallback(int rv) { EnterFunction(rv); DCHECK_NE(rv, ERR_IO_PENDING); + DCHECK(user_connect_callback_); CompletionCallback* c = user_connect_callback_; user_connect_callback_ = NULL; @@ -1220,10 +1160,7 @@ void SSLClientSocketNSS::OnHandshakeIOComplete(int result) { int rv = DoHandshakeLoop(result); if (rv != ERR_IO_PENDING) { net_log_.EndEventWithNetErrorCode(net::NetLog::TYPE_SSL_CONNECT, rv); - // If we pseudo connected for Snap Start, then we won't have a connect - // callback. - if (user_connect_callback_) - DoConnectCallback(rv); + DoConnectCallback(rv); } LeaveFunction(""); } @@ -1270,8 +1207,8 @@ void SSLClientSocketNSS::OnRecvComplete(int result) { } // Network layer received some data, check if client requested to read - // decrypted data or if we're waiting for the first write for Snap Start. - if (!user_read_buf_ || !completed_handshake_) { + // decrypted data. + if (!user_read_buf_) { LeaveFunction(""); return; } @@ -1298,12 +1235,6 @@ int SSLClientSocketNSS::DoHandshakeLoop(int last_io_result) { case STATE_NONE: // we're just pumping data between the buffer and the network break; - case STATE_SNAP_START_LOAD_INFO: - rv = DoSnapStartLoadInfo(); - break; - case STATE_SNAP_START_WAIT_FOR_WRITE: - rv = DoSnapStartWaitForWrite(); - break; case STATE_HANDSHAKE: rv = DoHandshake(); break; @@ -1388,76 +1319,6 @@ int SSLClientSocketNSS::DoWriteLoop(int result) { return rv; } -int SSLClientSocketNSS::DoSnapStartLoadInfo() { - EnterFunction(""); - int rv = ssl_host_info_->WaitForDataReady(&handshake_io_callback_); - GotoState(STATE_HANDSHAKE); - - if (rv == OK) { - if (ssl_host_info_->WaitForCertVerification(NULL) == OK) { - if (LoadSnapStartInfo()) { - pseudo_connected_ = true; - GotoState(STATE_SNAP_START_WAIT_FOR_WRITE); - if (user_connect_callback_) - DoConnectCallback(OK); - } - } else if (!ssl_host_info_->state().server_hello.empty()) { - // A non-empty ServerHello suggests that we would have tried a Snap Start - // connection. - base::TimeTicks now = base::TimeTicks::Now(); - const base::TimeDelta duration = - now - ssl_host_info_->verification_start_time(); - UMA_HISTOGRAM_TIMES("Net.SSLSnapStartNeededVerificationInMs", duration); - VLOG(1) << "Cannot snap start because verification isn't ready. " - << "Wanted verification after " - << duration.InMilliseconds() << "ms"; - } - } else { - DCHECK_EQ(ERR_IO_PENDING, rv); - GotoState(STATE_SNAP_START_LOAD_INFO); - } - - LeaveFunction(""); - return rv; -} - -int SSLClientSocketNSS::DoSnapStartWaitForWrite() { - EnterFunction(""); - // In this state, we're waiting for the first Write call so that we can merge - // it into the Snap Start handshake. - if (!user_write_buf_) { - // We'll lie and say that we're connected in order that someone will call - // Write. - GotoState(STATE_SNAP_START_WAIT_FOR_WRITE); - DCHECK(!user_connect_callback_); - LeaveFunction(""); - return ERR_IO_PENDING; - } - - // This is the largest Snap Start application data payload that we'll try to - // use. A TCP client can only send three frames of data without an ACK and, - // at 2048 bytes, this leaves some space for the rest of the ClientHello - // (including possible session ticket). - static const int kMaxSnapStartPayloadSize = 2048; - - if (user_write_buf_len_ > kMaxSnapStartPayloadSize) { - user_write_buf_len_ = kMaxSnapStartPayloadSize; - // When we complete the handshake and call user_write_callback_ we'll say - // that we only wrote |kMaxSnapStartPayloadSize| bytes. That way the rest - // of the payload will be presented to |Write| again and transmitted as - // normal application data. - } - - SECStatus rv = SSL_SetSnapStartApplicationData( - nss_fd_, reinterpret_cast<const unsigned char*>(user_write_buf_->data()), - user_write_buf_len_); - DCHECK_EQ(SECSuccess, rv); - - GotoState(STATE_HANDSHAKE); - LeaveFunction(""); - return OK; -} - int SSLClientSocketNSS::DoHandshake() { EnterFunction(""); int net_error = net::OK; @@ -1482,8 +1343,7 @@ int SSLClientSocketNSS::DoHandshake() { } else { // We need to see if the predicted certificate chain (in // |ssl_host_info_->state().certs) matches the actual certificate chain - // before we call SaveSnapStartInfo, as that will update - // |ssl_host_info_|. + // before we try to save it before we update |ssl_host_info_|. if (ssl_host_info_.get() && !ssl_host_info_->state().certs.empty()) { PeerCertificateChain certs(nss_fd_); const SSLHostInfo::State& state = ssl_host_info_->state(); @@ -1541,20 +1401,9 @@ int SSLClientSocketNSS::DoHandshake() { } #endif - SaveSnapStartInfo(); - // SSL handshake is completed. It's possible that we mispredicted the - // NPN agreed protocol. In this case, we've just sent a request in the - // wrong protocol! The higher levels of this network stack aren't - // prepared for switching the protocol like that so we make up an error - // and rely on the fact that the request will be retried. - if (IsNPNProtocolMispredicted()) { - LOG(WARNING) << "Mispredicted NPN protocol for " - << host_and_port_.ToString(); - net_error = ERR_SSL_SNAP_START_NPN_MISPREDICTION; - } else { - // Let's verify the certificate. - GotoState(STATE_VERIFY_DNSSEC); - } + SaveSSLHostInfo(); + // SSL handshake is completed. Let's verify the certificate. + GotoState(STATE_VERIFY_DNSSEC); } // Done! } else { @@ -1740,33 +1589,6 @@ int SSLClientSocketNSS::DoVerifyCertComplete(int result) { completed_handshake_ = true; - // If we merged a Write call into the handshake we need to make the - // callback now. - if (user_write_callback_) { - corked_ = false; - if (result != OK) { - DoWriteCallback(result); - } else { - SSLSnapStartResult snap_start_type; - SECStatus rv = SSL_GetSnapStartResult(nss_fd_, &snap_start_type); - DCHECK_EQ(rv, SECSuccess); - DCHECK_NE(snap_start_type, SSL_SNAP_START_NONE); - if (snap_start_type == SSL_SNAP_START_RECOVERY || - snap_start_type == SSL_SNAP_START_RESUME_RECOVERY) { - // If we mispredicted the server's handshake then Snap Start will have - // triggered a recovery mode. The misprediction could have been caused - // by the server having a different certificate so the application data - // wasn't resent. Now that we have verified the certificate, we need to - // resend the application data. - int bytes_written = DoPayloadWrite(); - if (bytes_written != ERR_IO_PENDING) - DoWriteCallback(bytes_written); - } else { - DoWriteCallback(user_write_buf_len_); - } - } - } - if (user_read_callback_) { int rv = DoReadLoop(OK); if (rv != ERR_IO_PENDING) @@ -1862,10 +1684,9 @@ void SSLClientSocketNSS::LogConnectionTypeMetrics() const { }; } -// SaveSnapStartInfo extracts the information needed to perform a Snap Start -// with this server in the future (if any) and tells |ssl_host_info_| to -// preserve it. -void SSLClientSocketNSS::SaveSnapStartInfo() { +// 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; @@ -1874,43 +1695,8 @@ void SSLClientSocketNSS::SaveSnapStartInfo() { if (ssl_host_info_->WaitForDataReady(NULL) != OK) return; - SECStatus rv; - SSLSnapStartResult snap_start_type; - rv = SSL_GetSnapStartResult(nss_fd_, &snap_start_type); - if (rv != SECSuccess) { - NOTREACHED(); - return; - } - net_log_.AddEvent(NetLog::TYPE_SSL_SNAP_START, - new NetLogIntegerParameter("type", snap_start_type)); - if (snap_start_type == SSL_SNAP_START_FULL || - snap_start_type == SSL_SNAP_START_RESUME) { - // If we did a successful Snap Start then our information was correct and - // there's no point saving it again. - return; - } - - const unsigned char* hello_data; - unsigned hello_data_len; - rv = SSL_GetPredictedServerHelloData(nss_fd_, &hello_data, &hello_data_len); - if (rv != SECSuccess) { - NOTREACHED(); - return; - } - if (hello_data_len > std::numeric_limits<uint16>::max()) - return; SSLHostInfo::State* state = ssl_host_info_->mutable_state(); - if (hello_data_len > 0) { - state->server_hello = - std::string(reinterpret_cast<const char *>(hello_data), hello_data_len); - state->npn_valid = true; - state->npn_status = GetNextProto(&state->npn_protocol); - } else { - state->server_hello.clear(); - state->npn_valid = false; - } - state->certs.clear(); PeerCertificateChain certs(nss_fd_); for (unsigned i = 0; i < certs.size(); i++) { @@ -1925,64 +1711,6 @@ void SSLClientSocketNSS::SaveSnapStartInfo() { ssl_host_info_->Persist(); } -// LoadSnapStartInfo parses |info|, which contains data previously serialised -// by |SaveSnapStartInfo|, and sets the predicted certificates and ServerHello -// data on the NSS socket. Returns true on success. If this function returns -// false, the caller should try a normal TLS handshake. -bool SSLClientSocketNSS::LoadSnapStartInfo() { - const SSLHostInfo::State& state(ssl_host_info_->state()); - - if (state.server_hello.empty() || - state.certs.empty() || - !state.npn_valid) { - return false; - } - - SECStatus rv; - rv = SSL_SetPredictedServerHelloData( - nss_fd_, - reinterpret_cast<const uint8*>(state.server_hello.data()), - state.server_hello.size()); - DCHECK_EQ(SECSuccess, rv); - - const std::vector<std::string>& certs_in = state.certs; - scoped_array<CERTCertificate*> certs(new CERTCertificate*[certs_in.size()]); - for (size_t i = 0; i < certs_in.size(); i++) { - SECItem derCert; - derCert.data = - const_cast<uint8*>(reinterpret_cast<const uint8*>(certs_in[i].data())); - derCert.len = certs_in[i].size(); - certs[i] = CERT_NewTempCertificate( - CERT_GetDefaultCertDB(), &derCert, NULL /* no nickname given */, - PR_FALSE /* not permanent */, PR_TRUE /* copy DER data */); - if (!certs[i]) { - DestroyCertificates(&certs[0], i); - NOTREACHED(); - return false; - } - } - - rv = SSL_SetPredictedPeerCertificates(nss_fd_, certs.get(), certs_in.size()); - DestroyCertificates(&certs[0], certs_in.size()); - DCHECK_EQ(SECSuccess, rv); - - if (state.npn_valid) { - predicted_npn_status_ = state.npn_status; - predicted_npn_proto_ = state.npn_protocol; - } - - return true; -} - -bool SSLClientSocketNSS::IsNPNProtocolMispredicted() { - DCHECK(handshake_callback_called_); - if (!predicted_npn_proto_used_) - return false; - std::string npn_proto; - GetNextProto(&npn_proto); - return predicted_npn_proto_ != npn_proto; -} - void SSLClientSocketNSS::UncorkAfterTimeout() { corked_ = false; int nsent; diff --git a/net/socket/ssl_client_socket_nss.h b/net/socket/ssl_client_socket_nss.h index 35941ff..88f1f79 100644 --- a/net/socket/ssl_client_socket_nss.h +++ b/net/socket/ssl_client_socket_nss.h @@ -85,8 +85,6 @@ class SSLClientSocketNSS : public SSLClientSocket { private: enum State { STATE_NONE, - STATE_SNAP_START_LOAD_INFO, - STATE_SNAP_START_WAIT_FOR_WRITE, STATE_HANDSHAKE, STATE_VERIFY_DNSSEC, STATE_VERIFY_DNSSEC_COMPLETE, @@ -119,8 +117,6 @@ class SSLClientSocketNSS : public SSLClientSocket { int DoReadLoop(int result); int DoWriteLoop(int result); - int DoSnapStartLoadInfo(); - int DoSnapStartWaitForWrite(); int DoHandshake(); int DoVerifyDNSSEC(int result); @@ -130,9 +126,7 @@ class SSLClientSocketNSS : public SSLClientSocket { int DoPayloadRead(); int DoPayloadWrite(); void LogConnectionTypeMetrics() const; - void SaveSnapStartInfo(); - bool LoadSnapStartInfo(); - bool IsNPNProtocolMispredicted(); + void SaveSSLHostInfo(); void UncorkAfterTimeout(); bool DoTransportIO(); @@ -227,10 +221,6 @@ class SSLClientSocketNSS : public SSLClientSocket { // True if the SSL handshake has been completed. bool completed_handshake_; - // True if we are lying about being connected in order to merge the first - // Write call into a Snap Start handshake. - bool pseudo_connected_; - // True iff we believe that the user has an ESET product intercepting our // HTTPS connections. bool eset_mitm_detected_; @@ -257,14 +247,6 @@ class SSLClientSocketNSS : public SSLClientSocket { BoundNetLog net_log_; - // When performing Snap Start we need to predict the NPN protocol which the - // server is going to speak before we actually perform the handshake. Thus - // the last NPN protocol used is serialised in |ssl_host_info_| - // and kept in these fields: - SSLClientSocket::NextProtoStatus predicted_npn_status_; - std::string predicted_npn_proto_; - bool predicted_npn_proto_used_; - base::TimeTicks start_cert_verification_time_; scoped_ptr<SSLHostInfo> ssl_host_info_; diff --git a/net/socket/ssl_client_socket_snapstart_unittest.cc b/net/socket/ssl_client_socket_snapstart_unittest.cc deleted file mode 100644 index d782993..0000000 --- a/net/socket/ssl_client_socket_snapstart_unittest.cc +++ /dev/null @@ -1,369 +0,0 @@ -// Copyright (c) 2010 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include <arpa/inet.h> -#include <netinet/tcp.h> -#include <stdarg.h> -#include <sys/socket.h> -#include <sys/types.h> - -#include <sslt.h> - -#include <vector> -#include <string> - -#include "base/eintr_wrapper.h" -#include "base/base64.h" -#include "base/file_path.h" -#include "base/file_util.h" -#include "base/path_service.h" -#include "base/process_util.h" -#include "base/string_util.h" -#include "base/values.h" -#include "net/base/io_buffer.h" -#include "net/base/net_errors.h" -#include "net/base/net_log.h" -#include "net/base/net_log_unittest.h" -#include "net/base/ssl_config_service.h" -#include "net/base/test_completion_callback.h" -#include "net/socket/client_socket_factory.h" -#include "net/socket/ssl_client_socket.h" -#include "net/socket/ssl_client_socket_nss.h" -#include "net/socket/ssl_host_info.h" -#include "net/socket/tcp_client_socket.h" -#include "testing/gtest/include/gtest/gtest.h" -#include "testing/platform_test.h" - -namespace net { - -// TestSSLHostInfo is an SSLHostInfo which stores a single state in memory and -// pretends that certificate verification always succeeds. -class TestSSLHostInfo : public SSLHostInfo { - public: - explicit TestSSLHostInfo(CertVerifier* cert_verifier) - : SSLHostInfo("example.com", kDefaultSSLConfig, cert_verifier) { - if (!saved_.empty()) - Parse(saved_); - cert_verification_complete_ = true; - cert_verification_error_ = OK; - } - - virtual void Start() { - } - - virtual int WaitForDataReady(CompletionCallback*) { return OK; } - - virtual void Persist() { - saved_ = Serialize(); - } - - static void Reset() { - saved_.clear(); - } - - private: - static SSLConfig kDefaultSSLConfig; - static std::string saved_; -}; - -std::string TestSSLHostInfo::saved_; - -SSLConfig TestSSLHostInfo::kDefaultSSLConfig; - -class SSLClientSocketSnapStartTest : public PlatformTest { - public: - SSLClientSocketSnapStartTest() - : child_(base::kNullProcessHandle), - socket_factory_(ClientSocketFactory::GetDefaultFactory()), - log_(CapturingNetLog::kUnbounded) { - TestSSLHostInfo::Reset(); - ssl_config_.snap_start_enabled = true; - } - - virtual void TearDown() { - if (child_ != base::kNullProcessHandle) { - int exit_code; - EXPECT_TRUE(base::WaitForExitCode(child_, &exit_code)); - EXPECT_EQ(0, exit_code); - } - } - - protected: - void StartSnapStartServer(const char* arg, ...) { - FilePath dir_exe; - PathService::Get(base::DIR_EXE, &dir_exe); - FilePath helper_binary = dir_exe.Append("openssl_helper"); - - std::vector<std::string> args; - args.push_back(helper_binary.value()); - - va_list ap; - va_start(ap, arg); - while (arg) { - args.push_back(arg); - arg = va_arg(ap, const char*); - } - va_end(ap); - - const int listener = socket(AF_INET, SOCK_STREAM, 0); - ASSERT_GE(listener, 0); - struct sockaddr_in sin; - memset(&sin, 0, sizeof(sin)); - sin.sin_family = PF_INET; - ASSERT_EQ(0, bind(listener, (struct sockaddr*) &sin, sizeof(sin))); - socklen_t socklen = sizeof(remote_); - ASSERT_EQ(0, getsockname(listener, (struct sockaddr*) &remote_, &socklen)); - ASSERT_EQ(sizeof(remote_), socklen); - ASSERT_EQ(0, listen(listener, 1)); - - base::file_handle_mapping_vector mapping; - // The listening socket is installed as the child's fd 3. - mapping.push_back(std::make_pair(listener, 3)); - base::LaunchApp(args, mapping, false /* don't wait */, &child_); - ASSERT_EQ(0, HANDLE_EINTR(close(listener))); - } - - // LoadDefaultCert returns the DER encoded default certificate. - std::string LoadDefaultCert() { - FilePath path; - PathService::Get(base::DIR_SOURCE_ROOT, &path); - path = path.Append("net"); - path = path.Append("data"); - path = path.Append("ssl"); - path = path.Append("certificates"); - path = path.Append("ok_cert.pem"); - - std::string pem; - bool r = file_util::ReadFileToString(path, &pem); - CHECK(r) << "failed to read " << path.value(); - - static const char kStartMarker[] = "-----BEGIN CERTIFICATE-----\n"; - static const char kEndMarker[] = "-----END CERTIFICATE-----\n"; - - std::string::size_type i = pem.find(kStartMarker); - std::string::size_type j = pem.find(kEndMarker); - CHECK(i != std::string::npos); - CHECK(j != std::string::npos); - CHECK_GT(j, i); - i += sizeof(kStartMarker) - 1; - - std::string b64data = pem.substr(i, j - i); - ReplaceSubstringsAfterOffset(&b64data, 0 /* start offset */, "\n", ""); - - std::string der; - base::Base64Decode(b64data, &der); - return der; - } - - void SetupSSLConfig() { - if (ssl_config_.allowed_bad_certs.size()) - return; - const std::string der = LoadDefaultCert(); - SSLConfig::CertAndStatus cert_and_status; - cert_and_status.cert = - X509Certificate::CreateFromBytes(der.data(), der.size()); - cert_and_status.cert_status = ERR_CERT_AUTHORITY_INVALID; - - ssl_config_.allowed_bad_certs.push_back(cert_and_status); - } - - // PerformConnection makes an SSL connection to the openssl_helper binary and - // does a ping-pong test to check the the SSL socket is working correctly. - void PerformConnection() { - client_ = socket(AF_INET, SOCK_STREAM, 0); - ASSERT_LE(0, client_); - ASSERT_EQ( - 0, connect(client_, (struct sockaddr*) &remote_, sizeof(remote_))); - int on = 1; - setsockopt(client_, IPPROTO_TCP, TCP_NODELAY, &on, sizeof(on)); - - SetupSSLConfig(); - log_.Clear(); - - std::vector<uint8> localhost; - localhost.push_back(127); - localhost.push_back(0); - localhost.push_back(0); - localhost.push_back(1); - AddressList addr_list(localhost, 443, false); - TCPClientSocket* transport = new TCPClientSocket( - addr_list, &log_, NetLog::Source()); - - transport->AdoptSocket(client_); - scoped_ptr<SSLClientSocket> sock( - socket_factory_->CreateSSLClientSocket( - transport, HostPortPair("example.com", 443), ssl_config_, - new TestSSLHostInfo(&cert_verifier_), &cert_verifier_)); - - TestCompletionCallback callback; - int rv = sock->Connect(&callback); - if (rv != OK) { - ASSERT_EQ(ERR_IO_PENDING, rv); - EXPECT_FALSE(sock->IsConnected()); - rv = callback.WaitForResult(); - EXPECT_EQ(OK, rv); - } - EXPECT_TRUE(sock->IsConnected()); - - static const char request_text[] = "hello!"; - scoped_refptr<IOBuffer> request_buffer = - new IOBuffer(arraysize(request_text) - 1); - memcpy(request_buffer->data(), request_text, arraysize(request_text) - 1); - rv = sock->Write(request_buffer, arraysize(request_text), &callback); - if (rv < 0) { - ASSERT_EQ(ERR_IO_PENDING, rv); - rv = callback.WaitForResult(); - } - EXPECT_EQ(7, rv); - - scoped_refptr<IOBuffer> reply_buffer = new IOBuffer(8); - rv = sock->Read(reply_buffer, 8, &callback); - if (rv < 0) { - ASSERT_EQ(ERR_IO_PENDING, rv); - rv = callback.WaitForResult(); - } - EXPECT_EQ(8, rv); - EXPECT_TRUE(memcmp(reply_buffer->data(), "goodbye!", 8) == 0); - - next_proto_status_ = sock->GetNextProto(&next_proto_); - - sock->Disconnect(); - } - - // SnapStartEventType extracts the type of Snap Start from the NetLog. See - // the SSL_SNAP_START_* defines in sslt.h - int SnapStartEventType() { - CapturingNetLog::EntryList entries; - log_.GetEntries(&entries); - for (CapturingNetLog::EntryList::const_iterator - i = entries.begin(); i != entries.end(); i++) { - if (i->type == NetLog::TYPE_SSL_SNAP_START) { - scoped_ptr<Value> value(i->extra_parameters->ToValue()); - CHECK(value->GetType() == Value::TYPE_DICTIONARY); - DictionaryValue* dict = reinterpret_cast<DictionaryValue*>(value.get()); - int ret; - CHECK(dict->GetInteger("type", &ret)); - return ret; - } - } - return -1; - } - - // DidMerge returns true if the NetLog suggests the the SSL connection merged - // it's certificate validation with the optimistic validation from the - // SSLHostInfo. - bool DidMerge() { - CapturingNetLog::EntryList entries; - log_.GetEntries(&entries); - for (CapturingNetLog::EntryList::const_iterator - i = entries.begin(); i != entries.end(); i++) { - if (i->type == NetLog::TYPE_SSL_VERIFICATION_MERGED) - return true; - } - return false; - } - - base::ProcessHandle child_; - CertVerifier cert_verifier_; - ClientSocketFactory* const socket_factory_; - struct sockaddr_in remote_; - int client_; - SSLConfig ssl_config_; - CapturingNetLog log_; - SSLClientSocket::NextProtoStatus next_proto_status_; - std::string next_proto_; -}; - -TEST_F(SSLClientSocketSnapStartTest, Basic) { - // Not a Snap Start connection. - StartSnapStartServer(NULL); - PerformConnection(); - EXPECT_EQ(SSL_SNAP_START_NONE, SnapStartEventType()); - EXPECT_FALSE(DidMerge()); -} - -TEST_F(SSLClientSocketSnapStartTest, SnapStart) { - StartSnapStartServer("snap-start", NULL); - PerformConnection(); - EXPECT_EQ(SSL_SNAP_START_NONE, SnapStartEventType()); - EXPECT_FALSE(DidMerge()); - SSLClientSocketNSS::ClearSessionCache(); - PerformConnection(); - EXPECT_EQ(SSL_SNAP_START_FULL, SnapStartEventType()); - EXPECT_TRUE(DidMerge()); -} - -TEST_F(SSLClientSocketSnapStartTest, SnapStartResume) { - StartSnapStartServer("snap-start", NULL); - PerformConnection(); - EXPECT_EQ(SSL_SNAP_START_NONE, SnapStartEventType()); - EXPECT_FALSE(DidMerge()); - PerformConnection(); - EXPECT_EQ(SSL_SNAP_START_RESUME, SnapStartEventType()); - EXPECT_TRUE(DidMerge()); -} - -TEST_F(SSLClientSocketSnapStartTest, SnapStartRecovery) { - StartSnapStartServer("snap-start-recovery", NULL); - PerformConnection(); - EXPECT_EQ(SSL_SNAP_START_NONE, SnapStartEventType()); - EXPECT_FALSE(DidMerge()); - SSLClientSocketNSS::ClearSessionCache(); - PerformConnection(); - EXPECT_EQ(SSL_SNAP_START_RECOVERY, SnapStartEventType()); - EXPECT_TRUE(DidMerge()); -} - -TEST_F(SSLClientSocketSnapStartTest, SnapStartResumeRecovery) { - StartSnapStartServer("snap-start-recovery", NULL); - PerformConnection(); - EXPECT_EQ(SSL_SNAP_START_NONE, SnapStartEventType()); - EXPECT_FALSE(DidMerge()); - PerformConnection(); - EXPECT_EQ(SSL_SNAP_START_RESUME_RECOVERY, SnapStartEventType()); - EXPECT_TRUE(DidMerge()); -} - -TEST_F(SSLClientSocketSnapStartTest, SnapStartWithNPN) { - ssl_config_.next_protos.assign("\003foo\003bar"); - StartSnapStartServer("snap-start", "npn", NULL); - PerformConnection(); - EXPECT_EQ(SSLClientSocket::kNextProtoNegotiated, next_proto_status_); - EXPECT_EQ("foo", next_proto_); - EXPECT_EQ(SSL_SNAP_START_NONE, SnapStartEventType()); - EXPECT_FALSE(DidMerge()); - SSLClientSocketNSS::ClearSessionCache(); - PerformConnection(); - EXPECT_EQ(SSL_SNAP_START_FULL, SnapStartEventType()); - EXPECT_EQ(SSLClientSocket::kNextProtoNegotiated, next_proto_status_); - EXPECT_EQ("foo", next_proto_); - EXPECT_TRUE(DidMerge()); -} - -TEST_F(SSLClientSocketSnapStartTest, SnapStartWithNPNMispredict) { - // This tests that we recover in the event of a misprediction. - ssl_config_.next_protos.assign("\003foo\003baz"); - StartSnapStartServer("snap-start", "npn-mispredict", NULL); - PerformConnection(); - EXPECT_EQ(SSLClientSocket::kNextProtoNegotiated, next_proto_status_); - EXPECT_EQ("foo", next_proto_); - EXPECT_EQ(SSL_SNAP_START_NONE, SnapStartEventType()); - EXPECT_FALSE(DidMerge()); - - SSLClientSocketNSS::ClearSessionCache(); - PerformConnection(); - EXPECT_EQ(SSL_SNAP_START_RECOVERY, SnapStartEventType()); - EXPECT_EQ(SSLClientSocket::kNextProtoNegotiated, next_proto_status_); - EXPECT_EQ("baz", next_proto_); - EXPECT_TRUE(DidMerge()); - - SSLClientSocketNSS::ClearSessionCache(); - PerformConnection(); - EXPECT_EQ(SSL_SNAP_START_FULL, SnapStartEventType()); - EXPECT_EQ(SSLClientSocket::kNextProtoNegotiated, next_proto_status_); - EXPECT_EQ("baz", next_proto_); - EXPECT_TRUE(DidMerge()); -} - -} // namespace net diff --git a/net/socket/ssl_host_info.cc b/net/socket/ssl_host_info.cc index 9d631bb..8e08054 100644 --- a/net/socket/ssl_host_info.cc +++ b/net/socket/ssl_host_info.cc @@ -15,17 +15,12 @@ namespace net { -SSLHostInfo::State::State() - : npn_valid(false), - npn_status(SSLClientSocket::kNextProtoUnsupported) { -} +SSLHostInfo::State::State() {} SSLHostInfo::State::~State() {} void SSLHostInfo::State::Clear() { certs.clear(); - server_hello.clear(); - npn_valid = false; } SSLHostInfo::SSLHostInfo( @@ -46,7 +41,6 @@ SSLHostInfo::SSLHostInfo( dnsrr_resolver_(NULL), dns_callback_(NULL), dns_handle_(DnsRRResolver::kInvalidHandle) { - state_.npn_valid = false; } SSLHostInfo::~SSLHostInfo() { @@ -100,19 +94,20 @@ bool SSLHostInfo::ParseInner(const std::string& data) { state->certs.push_back(der_cert); } - if (!p.ReadString(&iter, &state->server_hello)) + std::string throwaway_string; + bool throwaway_bool; + if (!p.ReadString(&iter, &throwaway_string)) return false; - if (!p.ReadBool(&iter, &state->npn_valid)) + if (!p.ReadBool(&iter, &throwaway_bool)) return false; - if (state->npn_valid) { - int status; - if (!p.ReadInt(&iter, &status) || - !p.ReadString(&iter, &state->npn_protocol)) { + if (throwaway_bool) { + int throwaway_int; + if (!p.ReadInt(&iter, &throwaway_int) || + !p.ReadString(&iter, &throwaway_string)) { return false; } - state->npn_status = static_cast<SSLClientSocket::NextProtoStatus>(status); } if (!state->certs.empty()) { @@ -166,18 +161,11 @@ std::string SSLHostInfo::Serialize() const { return ""; } - if (!p.WriteString(state_.server_hello) || - !p.WriteBool(state_.npn_valid)) { + if (!p.WriteString("") || + !p.WriteBool(false)) { return ""; } - if (state_.npn_valid) { - if (!p.WriteInt(state_.npn_status) || - !p.WriteString(state_.npn_protocol)) { - return ""; - } - } - return std::string(reinterpret_cast<const char *>(p.data()), p.size()); } diff --git a/net/socket/ssl_host_info.h b/net/socket/ssl_host_info.h index 8fe75c0..b91eb56 100644 --- a/net/socket/ssl_host_info.h +++ b/net/socket/ssl_host_info.h @@ -69,14 +69,6 @@ class SSLHostInfo { // certs is a vector of DER encoded X.509 certificates, as the server // returned them and in the same order. std::vector<std::string> certs; - // server_hello contains the bytes of the ServerHello message (or may be - // empty if the server doesn't support Snap Start.) - std::string server_hello; - // npn_valid is true iff |npn_status| and |npn_protocol| is successful. - bool npn_valid; - // these members contain the NPN result of a connection to the server. - SSLClientSocket::NextProtoStatus npn_status; - std::string npn_protocol; private: DISALLOW_COPY_AND_ASSIGN(State); diff --git a/net/socket/ssl_server_socket_unittest.cc b/net/socket/ssl_server_socket_unittest.cc index 792d2d8..1668bfe 100644 --- a/net/socket/ssl_server_socket_unittest.cc +++ b/net/socket/ssl_server_socket_unittest.cc @@ -239,7 +239,6 @@ class SSLServerSocketTest : public PlatformTest { net::SSLConfig ssl_config; ssl_config.false_start_enabled = false; - ssl_config.snap_start_enabled = false; ssl_config.ssl3_enabled = true; ssl_config.tls1_enabled = true; |