summaryrefslogtreecommitdiffstats
path: root/net/socket
diff options
context:
space:
mode:
authorBen Murdoch <benm@google.com>2010-11-18 18:32:45 +0000
committerBen Murdoch <benm@google.com>2010-11-18 18:38:07 +0000
commit513209b27ff55e2841eac0e4120199c23acce758 (patch)
treeaeba30bb08c5f47c57003544e378a377c297eee6 /net/socket
parent164f7496de0fbee436b385a79ead9e3cb81a50c1 (diff)
downloadexternal_chromium-513209b27ff55e2841eac0e4120199c23acce758.zip
external_chromium-513209b27ff55e2841eac0e4120199c23acce758.tar.gz
external_chromium-513209b27ff55e2841eac0e4120199c23acce758.tar.bz2
Merge Chromium at r65505: Initial merge by git.
Change-Id: I31d8f1d8cd33caaf7f47ffa7350aef42d5fbdb45
Diffstat (limited to 'net/socket')
-rw-r--r--net/socket/client_socket.cc8
-rw-r--r--net/socket/client_socket.h8
-rw-r--r--net/socket/client_socket_factory.cc24
-rw-r--r--net/socket/client_socket_factory.h7
-rw-r--r--net/socket/client_socket_handle.cc3
-rw-r--r--net/socket/client_socket_pool_base.cc26
-rw-r--r--net/socket/client_socket_pool_base_unittest.cc8
-rw-r--r--net/socket/deterministic_socket_data_unittest.cc4
-rw-r--r--net/socket/dns_cert_provenance_check.cc111
-rw-r--r--net/socket/dns_cert_provenance_check.h26
-rw-r--r--net/socket/socket_test_util.cc10
-rw-r--r--net/socket/socket_test_util.h9
-rw-r--r--net/socket/socks5_client_socket.cc37
-rw-r--r--net/socket/socks5_client_socket.h1
-rw-r--r--net/socket/socks5_client_socket_unittest.cc2
-rw-r--r--net/socket/socks_client_socket.cc9
-rw-r--r--net/socket/socks_client_socket.h1
-rw-r--r--net/socket/socks_client_socket_unittest.cc2
-rw-r--r--net/socket/ssl_client_socket_mac.cc12
-rw-r--r--net/socket/ssl_client_socket_mac.h1
-rw-r--r--net/socket/ssl_client_socket_mac_factory.cc3
-rw-r--r--net/socket/ssl_client_socket_mac_factory.h4
-rw-r--r--net/socket/ssl_client_socket_nss.cc882
-rw-r--r--net/socket/ssl_client_socket_nss.h48
-rw-r--r--net/socket/ssl_client_socket_nss_factory.cc17
-rw-r--r--net/socket/ssl_client_socket_nss_factory.h4
-rw-r--r--net/socket/ssl_client_socket_openssl.cc8
-rw-r--r--net/socket/ssl_client_socket_openssl.h1
-rw-r--r--net/socket/ssl_client_socket_pool.cc6
-rw-r--r--net/socket/ssl_client_socket_unittest.cc45
-rw-r--r--net/socket/ssl_client_socket_win.cc8
-rw-r--r--net/socket/ssl_client_socket_win.h1
-rw-r--r--net/socket/ssl_host_info.cc79
-rw-r--r--net/socket/ssl_host_info.h52
-rw-r--r--net/socket/tcp_client_socket.cc19
-rw-r--r--net/socket/tcp_client_socket.h7
-rw-r--r--net/socket/tcp_client_socket_libevent.cc77
-rw-r--r--net/socket/tcp_client_socket_libevent.h13
-rw-r--r--net/socket/tcp_client_socket_pool.cc8
-rw-r--r--net/socket/tcp_client_socket_pool_unittest.cc22
-rw-r--r--net/socket/tcp_client_socket_unittest.cc28
-rw-r--r--net/socket/tcp_client_socket_win.cc22
-rw-r--r--net/socket/tcp_client_socket_win.h4
43 files changed, 1196 insertions, 471 deletions
diff --git a/net/socket/client_socket.cc b/net/socket/client_socket.cc
index 6f38eae..6b12841 100644
--- a/net/socket/client_socket.cc
+++ b/net/socket/client_socket.cc
@@ -58,6 +58,14 @@ ClientSocket::UseHistory::~UseHistory() {
EmitPreconnectionHistograms();
}
+void ClientSocket::UseHistory::Reset() {
+ EmitPreconnectionHistograms();
+ was_ever_connected_ = false;
+ was_used_to_convey_data_ = false;
+ // omnibox_speculation_ and subresource_speculation_ values
+ // are intentionally preserved.
+}
+
void ClientSocket::UseHistory::EmitPreconnectionHistograms() const {
DCHECK(!subresource_speculation_ || !omnibox_speculation_);
// 0 ==> non-speculative, never connected.
diff --git a/net/socket/client_socket.h b/net/socket/client_socket.h
index b4173c0..358716c 100644
--- a/net/socket/client_socket.h
+++ b/net/socket/client_socket.h
@@ -69,6 +69,10 @@ class ClientSocket : public Socket {
// this call to the transport socket.
virtual bool WasEverUsed() const = 0;
+ // Returns true if the underlying transport socket is using TCP FastOpen.
+ // TCP FastOpen is an experiment with sending data in the TCP SYN packet.
+ virtual bool UsingTCPFastOpen() const = 0;
+
protected:
// The following class is only used to gather statistics about the history of
// a socket. It is only instantiated and used in basic sockets, such as
@@ -80,6 +84,10 @@ class ClientSocket : public Socket {
UseHistory();
~UseHistory();
+ // Resets the state of UseHistory and emits histograms for the
+ // current state.
+ void Reset();
+
void set_was_ever_connected();
void set_was_used_to_convey_data();
diff --git a/net/socket/client_socket_factory.cc b/net/socket/client_socket_factory.cc
index 3ac5a00..947a2fa 100644
--- a/net/socket/client_socket_factory.cc
+++ b/net/socket/client_socket_factory.cc
@@ -16,7 +16,6 @@
#elif defined(USE_OPENSSL) && defined(ANDROID)
#include "net/socket/ssl_client_socket_openssl.h"
#elif defined(OS_MACOSX)
-#include "net/socket/ssl_client_socket_mac.h"
#include "net/socket/ssl_client_socket_nss.h"
#endif
#include "net/socket/ssl_host_info.h"
@@ -24,13 +23,16 @@
namespace net {
+class DnsRRResolver;
+
namespace {
SSLClientSocket* DefaultSSLClientSocketFactory(
ClientSocketHandle* transport_socket,
const std::string& hostname,
const SSLConfig& ssl_config,
- SSLHostInfo* ssl_host_info) {
+ SSLHostInfo* ssl_host_info,
+ DnsRRResolver* dnsrr_resolver) {
scoped_ptr<SSLHostInfo> shi(ssl_host_info);
#if defined(OS_WIN)
return new SSLClientSocketWin(transport_socket, hostname, ssl_config);
@@ -38,16 +40,10 @@ SSLClientSocket* DefaultSSLClientSocketFactory(
return new SSLClientSocketOpenSSL(transport_socket, hostname, ssl_config);
#elif defined(USE_NSS)
return new SSLClientSocketNSS(transport_socket, hostname, ssl_config,
- shi.release());
+ shi.release(), dnsrr_resolver);
#elif defined(OS_MACOSX)
- // TODO(wtc): SSLClientSocketNSS can't do SSL client authentication using
- // Mac OS X CDSA/CSSM yet (http://crbug.com/45369), so fall back on
- // SSLClientSocketMac.
- if (ssl_config.send_client_cert)
- return new SSLClientSocketMac(transport_socket, hostname, ssl_config);
-
return new SSLClientSocketNSS(transport_socket, hostname, ssl_config,
- shi.release());
+ shi.release(), dnsrr_resolver);
#else
NOTIMPLEMENTED();
return NULL;
@@ -69,8 +65,10 @@ class DefaultClientSocketFactory : public ClientSocketFactory {
ClientSocketHandle* transport_socket,
const std::string& hostname,
const SSLConfig& ssl_config,
- SSLHostInfo* ssl_host_info) {
- return g_ssl_factory(transport_socket, hostname, ssl_config, ssl_host_info);
+ SSLHostInfo* ssl_host_info,
+ DnsRRResolver* dnsrr_resolver) {
+ return g_ssl_factory(transport_socket, hostname, ssl_config, ssl_host_info,
+ dnsrr_resolver);
}
};
@@ -96,7 +94,7 @@ SSLClientSocket* ClientSocketFactory::CreateSSLClientSocket(
ClientSocketHandle* socket_handle = new ClientSocketHandle();
socket_handle->set_socket(transport_socket);
return CreateSSLClientSocket(socket_handle, hostname, ssl_config,
- ssl_host_info);
+ ssl_host_info, NULL /* DnsRRResolver */);
}
} // namespace net
diff --git a/net/socket/client_socket_factory.h b/net/socket/client_socket_factory.h
index ad2cc54..4814b9c 100644
--- a/net/socket/client_socket_factory.h
+++ b/net/socket/client_socket_factory.h
@@ -15,6 +15,7 @@ namespace net {
class AddressList;
class ClientSocket;
class ClientSocketHandle;
+class DnsRRResolver;
class SSLClientSocket;
struct SSLConfig;
class SSLHostInfo;
@@ -24,7 +25,8 @@ typedef SSLClientSocket* (*SSLClientSocketFactory)(
ClientSocketHandle* transport_socket,
const std::string& hostname,
const SSLConfig& ssl_config,
- SSLHostInfo* ssl_host_info);
+ SSLHostInfo* ssl_host_info,
+ DnsRRResolver* dnsrr_resolver);
// An interface used to instantiate ClientSocket objects. Used to facilitate
// testing code with mock socket implementations.
@@ -43,7 +45,8 @@ class ClientSocketFactory {
ClientSocketHandle* transport_socket,
const std::string& hostname,
const SSLConfig& ssl_config,
- SSLHostInfo* ssl_host_info) = 0;
+ SSLHostInfo* ssl_host_info,
+ DnsRRResolver* dnsrr_resolver) = 0;
// Deprecated function (http://crbug.com/37810) that takes a ClientSocket.
virtual SSLClientSocket* CreateSSLClientSocket(ClientSocket* transport_socket,
diff --git a/net/socket/client_socket_handle.cc b/net/socket/client_socket_handle.cc
index 6184905..29b5bd3 100644
--- a/net/socket/client_socket_handle.cc
+++ b/net/socket/client_socket_handle.cc
@@ -116,7 +116,8 @@ void ClientSocketHandle::HandleInitCompletion(int result) {
DCHECK(socket_.get());
socket_->NetLog().BeginEvent(
NetLog::TYPE_SOCKET_IN_USE,
- new NetLogSourceParameter("source_dependency", requesting_source_));
+ make_scoped_refptr(new NetLogSourceParameter(
+ "source_dependency", requesting_source_)));
}
} // namespace net
diff --git a/net/socket/client_socket_pool_base.cc b/net/socket/client_socket_pool_base.cc
index 75abae6..2228729 100644
--- a/net/socket/client_socket_pool_base.cc
+++ b/net/socket/client_socket_pool_base.cc
@@ -87,9 +87,9 @@ void ConnectJob::UseForNormalRequest() {
void ConnectJob::set_socket(ClientSocket* socket) {
if (socket) {
- net_log().AddEvent(NetLog::TYPE_CONNECT_JOB_SET_SOCKET,
- new NetLogSourceParameter("source_dependency",
- socket->NetLog().source()));
+ net_log().AddEvent(NetLog::TYPE_CONNECT_JOB_SET_SOCKET, make_scoped_refptr(
+ new NetLogSourceParameter("source_dependency",
+ socket->NetLog().source())));
}
socket_.reset(socket);
}
@@ -110,7 +110,7 @@ void ConnectJob::ResetTimer(base::TimeDelta remaining_time) {
void ConnectJob::LogConnectStart() {
net_log().BeginEvent(NetLog::TYPE_SOCKET_POOL_CONNECT_JOB_CONNECT,
- new NetLogStringParameter("group_name", group_name_));
+ make_scoped_refptr(new NetLogStringParameter("group_name", group_name_)));
}
void ConnectJob::LogConnectCompletion(int net_error) {
@@ -239,7 +239,8 @@ void ClientSocketPoolBaseHelper::RequestSockets(
request.net_log().BeginEvent(
NetLog::TYPE_SOCKET_POOL_CONNECTING_N_SOCKETS,
- new NetLogIntegerParameter("num_sockets", num_sockets));
+ make_scoped_refptr(new NetLogIntegerParameter(
+ "num_sockets", num_sockets)));
Group* group = GetOrCreateGroup(group_name);
@@ -394,7 +395,8 @@ void ClientSocketPoolBaseHelper::LogBoundConnectJobToRequest(
const NetLog::Source& connect_job_source, const Request* request) {
request->net_log().AddEvent(
NetLog::TYPE_SOCKET_POOL_BOUND_TO_CONNECT_JOB,
- new NetLogSourceParameter("source_dependency", connect_job_source));
+ make_scoped_refptr(new NetLogSourceParameter(
+ "source_dependency", connect_job_source)));
}
void ClientSocketPoolBaseHelper::CancelRequest(
@@ -763,8 +765,8 @@ void ClientSocketPoolBaseHelper::OnConnectJobComplete(
HandOutSocket(socket.release(), false /* unused socket */, r->handle(),
base::TimeDelta(), group, r->net_log());
}
- r->net_log().EndEvent(NetLog::TYPE_SOCKET_POOL,
- new NetLogIntegerParameter("net_error", result));
+ r->net_log().EndEvent(NetLog::TYPE_SOCKET_POOL, make_scoped_refptr(
+ new NetLogIntegerParameter("net_error", result)));
InvokeUserCallbackLater(r->handle(), r->callback(), result);
} else {
RemoveConnectJob(job, group);
@@ -849,13 +851,13 @@ void ClientSocketPoolBaseHelper::HandOutSocket(
if (reused) {
net_log.AddEvent(
NetLog::TYPE_SOCKET_POOL_REUSED_AN_EXISTING_SOCKET,
- new NetLogIntegerParameter(
- "idle_ms", static_cast<int>(idle_time.InMilliseconds())));
+ make_scoped_refptr(new NetLogIntegerParameter(
+ "idle_ms", static_cast<int>(idle_time.InMilliseconds()))));
}
net_log.AddEvent(NetLog::TYPE_SOCKET_POOL_BOUND_TO_SOCKET,
- new NetLogSourceParameter(
- "source_dependency", socket->NetLog().source()));
+ make_scoped_refptr(new NetLogSourceParameter(
+ "source_dependency", socket->NetLog().source())));
handed_out_socket_count_++;
group->IncrementActiveSocketCount();
diff --git a/net/socket/client_socket_pool_base_unittest.cc b/net/socket/client_socket_pool_base_unittest.cc
index 820b030..7b83162 100644
--- a/net/socket/client_socket_pool_base_unittest.cc
+++ b/net/socket/client_socket_pool_base_unittest.cc
@@ -81,6 +81,7 @@ class MockClientSocket : public ClientSocket {
virtual void SetSubresourceSpeculation() {}
virtual void SetOmniboxSpeculation() {}
virtual bool WasEverUsed() const { return was_used_to_convey_data_; }
+ virtual bool UsingTCPFastOpen() const { return false; }
private:
bool connected_;
@@ -108,7 +109,8 @@ class MockClientSocketFactory : public ClientSocketFactory {
ClientSocketHandle* transport_socket,
const std::string& hostname,
const SSLConfig& ssl_config,
- SSLHostInfo* ssl_host_info) {
+ SSLHostInfo* ssl_host_info,
+ DnsRRResolver* dnsrr_resolver) {
NOTIMPLEMENTED();
delete ssl_host_info;
return NULL;
@@ -1280,7 +1282,7 @@ class RequestSocketCallback : public CallbackRunner< Tuple1<int> > {
}
within_callback_ = true;
TestCompletionCallback next_job_callback;
- scoped_refptr<TestSocketParams> params = new TestSocketParams();
+ scoped_refptr<TestSocketParams> params(new TestSocketParams());
int rv = handle_->Init("a",
params,
kDefaultPriority,
@@ -2086,7 +2088,7 @@ class TestReleasingSocketRequest : public CallbackRunner< Tuple1<int> > {
callback_.RunWithParams(params);
if (reset_releasing_handle_)
handle_.Reset();
- scoped_refptr<TestSocketParams> con_params = new TestSocketParams();
+ scoped_refptr<TestSocketParams> con_params(new TestSocketParams());
EXPECT_EQ(expected_result_, handle2_.Init("a",
con_params,
kDefaultPriority,
diff --git a/net/socket/deterministic_socket_data_unittest.cc b/net/socket/deterministic_socket_data_unittest.cc
index 199dd0b..5e25aa0 100644
--- a/net/socket/deterministic_socket_data_unittest.cc
+++ b/net/socket/deterministic_socket_data_unittest.cc
@@ -131,7 +131,7 @@ void DeterministicSocketDataTest::AssertReadBufferEquals(const char* data,
void DeterministicSocketDataTest::AssertSyncWriteEquals(const char* data,
int len) {
- scoped_refptr<IOBuffer> buf = new IOBuffer(len);
+ scoped_refptr<IOBuffer> buf(new IOBuffer(len));
memcpy(buf->data(), data, len);
// Issue the write, which will complete immediately
@@ -152,7 +152,7 @@ void DeterministicSocketDataTest::AssertAsyncWriteEquals(const char* data,
void DeterministicSocketDataTest::AssertWriteReturns(const char* data,
int len, int rv) {
- scoped_refptr<IOBuffer> buf = new IOBuffer(len);
+ scoped_refptr<IOBuffer> buf(new IOBuffer(len));
memcpy(buf->data(), data, len);
// Issue the read, which will complete asynchronously
diff --git a/net/socket/dns_cert_provenance_check.cc b/net/socket/dns_cert_provenance_check.cc
new file mode 100644
index 0000000..e83cb5e
--- /dev/null
+++ b/net/socket/dns_cert_provenance_check.cc
@@ -0,0 +1,111 @@
+// 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 "net/socket/dns_cert_provenance_check.h"
+
+#include <nspr.h>
+#include <hasht.h>
+#include <sechash.h>
+
+#include <string>
+
+#include "base/non_thread_safe.h"
+#include "net/base/completion_callback.h"
+#include "net/base/dns_util.h"
+#include "net/base/dnsrr_resolver.h"
+#include "net/base/net_log.h"
+#include "net/base/net_errors.h"
+
+namespace net {
+
+namespace {
+
+class DNSCertProvenanceChecker : public NonThreadSafe {
+ public:
+ DNSCertProvenanceChecker(const std::string hostname,
+ DnsRRResolver* dnsrr_resolver,
+ const std::vector<base::StringPiece>& der_certs)
+ : hostname_(hostname),
+ dnsrr_resolver_(dnsrr_resolver),
+ der_certs_(der_certs.size()),
+ handle_(DnsRRResolver::kInvalidHandle),
+ ALLOW_THIS_IN_INITIALIZER_LIST(callback_(
+ this, &DNSCertProvenanceChecker::ResolutionComplete)) {
+ for (size_t i = 0; i < der_certs.size(); i++)
+ der_certs_[i] = der_certs[i].as_string();
+ }
+
+ void Start() {
+ DCHECK(CalledOnValidThread());
+
+ if (der_certs_.empty())
+ return;
+
+ uint8 fingerprint[SHA1_LENGTH];
+ SECStatus rv = HASH_HashBuf(
+ HASH_AlgSHA1, fingerprint, (uint8*) der_certs_[0].data(),
+ der_certs_[0].size());
+ DCHECK_EQ(SECSuccess, rv);
+ char fingerprint_hex[SHA1_LENGTH * 2 + 1];
+ for (unsigned i = 0; i < sizeof(fingerprint); i++) {
+ static const char hextable[] = "0123456789abcdef";
+ fingerprint_hex[i*2] = hextable[fingerprint[i] >> 4];
+ fingerprint_hex[i*2 + 1] = hextable[fingerprint[i] & 15];
+ }
+ fingerprint_hex[SHA1_LENGTH * 2] = 0;
+
+ static const char kBaseCertName[] = ".certs.links.org";
+ domain_.assign(fingerprint_hex);
+ domain_.append(kBaseCertName);
+
+ handle_ = dnsrr_resolver_->Resolve(
+ domain_, kDNS_TXT, 0 /* flags */, &callback_, &response_,
+ 0 /* priority */, BoundNetLog());
+ if (handle_ == DnsRRResolver::kInvalidHandle) {
+ LOG(ERROR) << "Failed to resolve " << domain_ << " for " << hostname_;
+ delete this;
+ }
+ }
+
+ private:
+ void ResolutionComplete(int status) {
+ DCHECK(CalledOnValidThread());
+
+ if (status == ERR_NAME_NOT_RESOLVED ||
+ (status == OK && response_.rrdatas.empty())) {
+ LOG(ERROR) << "FAILED"
+ << " hostname:" << hostname_
+ << " domain:" << domain_;
+ } else if (status == OK) {
+ LOG(ERROR) << "GOOD"
+ << " hostname:" << hostname_
+ << " resp:" << response_.rrdatas[0];
+ } else {
+ LOG(ERROR) << "Unknown error " << status << " for " << domain_;
+ }
+
+ delete this;
+ }
+
+ const std::string hostname_;
+ std::string domain_;
+ DnsRRResolver* const dnsrr_resolver_;
+ std::vector<std::string> der_certs_;
+ RRResponse response_;
+ DnsRRResolver::Handle handle_;
+ CompletionCallbackImpl<DNSCertProvenanceChecker> callback_;
+};
+
+} // anonymous namespace
+
+void DoAsyncDNSCertProvenanceVerification(
+ const std::string& hostname,
+ DnsRRResolver* dnsrr_resolver,
+ const std::vector<base::StringPiece>& der_certs) {
+ DNSCertProvenanceChecker* c(new DNSCertProvenanceChecker(
+ hostname, dnsrr_resolver, der_certs));
+ c->Start();
+}
+
+} // namespace net
diff --git a/net/socket/dns_cert_provenance_check.h b/net/socket/dns_cert_provenance_check.h
new file mode 100644
index 0000000..289cccf
--- /dev/null
+++ b/net/socket/dns_cert_provenance_check.h
@@ -0,0 +1,26 @@
+// 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.
+
+#ifndef NET_SOCKET_DNS_CERT_PROVENANCE_CHECK_H
+#define NET_SOCKET_DNS_CERT_PROVENANCE_CHECK_H
+
+#include <string>
+#include <vector>
+
+#include "base/string_piece.h"
+
+namespace net {
+
+class DnsRRResolver;
+
+// DoAsyncDNSCertProvenanceVerification starts an asynchronous check for the
+// given certificate chain. It must be run on the network thread.
+void DoAsyncDNSCertProvenanceVerification(
+ const std::string& hostname,
+ DnsRRResolver* dnsrr_resolver,
+ const std::vector<base::StringPiece>& der_certs);
+
+} // namespace net
+
+#endif // NET_SOCKET_DNS_CERT_PROVENANCE_CHECK_H
diff --git a/net/socket/socket_test_util.cc b/net/socket/socket_test_util.cc
index 53bcf89..57aef05 100644
--- a/net/socket/socket_test_util.cc
+++ b/net/socket/socket_test_util.cc
@@ -513,6 +513,10 @@ bool MockSSLClientSocket::WasEverUsed() const {
return transport_->socket()->WasEverUsed();
}
+bool MockSSLClientSocket::UsingTCPFastOpen() const {
+ return transport_->socket()->UsingTCPFastOpen();
+}
+
int MockSSLClientSocket::Read(net::IOBuffer* buf, int buf_len,
net::CompletionCallback* callback) {
return transport_->socket()->Read(buf, buf_len, callback);
@@ -1011,7 +1015,8 @@ SSLClientSocket* MockClientSocketFactory::CreateSSLClientSocket(
ClientSocketHandle* transport_socket,
const std::string& hostname,
const SSLConfig& ssl_config,
- SSLHostInfo* ssl_host_info) {
+ SSLHostInfo* ssl_host_info,
+ DnsRRResolver* dnsrr_resolver) {
MockSSLClientSocket* socket =
new MockSSLClientSocket(transport_socket, hostname, ssl_config,
ssl_host_info, mock_ssl_data_.GetNext());
@@ -1060,7 +1065,8 @@ SSLClientSocket* DeterministicMockClientSocketFactory::CreateSSLClientSocket(
ClientSocketHandle* transport_socket,
const std::string& hostname,
const SSLConfig& ssl_config,
- SSLHostInfo* ssl_host_info) {
+ SSLHostInfo* ssl_host_info,
+ DnsRRResolver* dnsrr_resolver) {
MockSSLClientSocket* socket =
new MockSSLClientSocket(transport_socket, hostname, ssl_config,
ssl_host_info, mock_ssl_data_.GetNext());
diff --git a/net/socket/socket_test_util.h b/net/socket/socket_test_util.h
index a8e4537..349013e 100644
--- a/net/socket/socket_test_util.h
+++ b/net/socket/socket_test_util.h
@@ -534,7 +534,8 @@ class MockClientSocketFactory : public ClientSocketFactory {
ClientSocketHandle* transport_socket,
const std::string& hostname,
const SSLConfig& ssl_config,
- SSLHostInfo* ssl_host_info);
+ SSLHostInfo* ssl_host_info,
+ DnsRRResolver* dnsrr_resolver);
SocketDataProviderArray<SocketDataProvider>& mock_data() {
return mock_data_;
}
@@ -609,6 +610,7 @@ class MockTCPClientSocket : public MockClientSocket {
virtual bool IsConnected() const;
virtual bool IsConnectedAndIdle() const { return IsConnected(); }
virtual bool WasEverUsed() const { return was_used_to_convey_data_; }
+ virtual bool UsingTCPFastOpen() const { return false; }
// Socket methods:
virtual int Read(net::IOBuffer* buf, int buf_len,
@@ -654,6 +656,7 @@ class DeterministicMockTCPClientSocket : public MockClientSocket,
virtual bool IsConnected() const;
virtual bool IsConnectedAndIdle() const { return IsConnected(); }
virtual bool WasEverUsed() const { return was_used_to_convey_data_; }
+ virtual bool UsingTCPFastOpen() const { return false; }
// Socket methods:
virtual int Write(net::IOBuffer* buf, int buf_len,
@@ -698,6 +701,7 @@ class MockSSLClientSocket : public MockClientSocket {
virtual void Disconnect();
virtual bool IsConnected() const;
virtual bool WasEverUsed() const;
+ virtual bool UsingTCPFastOpen() const;
// Socket methods:
virtual int Read(net::IOBuffer* buf, int buf_len,
@@ -875,7 +879,8 @@ class DeterministicMockClientSocketFactory : public ClientSocketFactory {
ClientSocketHandle* transport_socket,
const std::string& hostname,
const SSLConfig& ssl_config,
- SSLHostInfo* ssl_host_info);
+ SSLHostInfo* ssl_host_info,
+ DnsRRResolver* dnsrr_resolver);
SocketDataProviderArray<DeterministicSocketData>& mock_data() {
return mock_data_;
diff --git a/net/socket/socks5_client_socket.cc b/net/socket/socks5_client_socket.cc
index 42bb859..02e5b1f 100644
--- a/net/socket/socks5_client_socket.cc
+++ b/net/socket/socks5_client_socket.cc
@@ -10,6 +10,7 @@
#include "base/basictypes.h"
#include "base/compiler_specific.h"
+#include "base/debug/trace_event.h"
#include "base/format_macros.h"
#include "base/string_util.h"
#include "net/base/io_buffer.h"
@@ -133,6 +134,14 @@ bool SOCKS5ClientSocket::WasEverUsed() const {
return false;
}
+bool SOCKS5ClientSocket::UsingTCPFastOpen() const {
+ if (transport_.get() && transport_->socket()) {
+ return transport_->socket()->UsingTCPFastOpen();
+ }
+ NOTREACHED();
+ return false;
+}
+
// Read is called by the transport layer above to read. This can only be done
// if the SOCKS handshake is complete.
int SOCKS5ClientSocket::Read(IOBuffer* buf, int buf_len,
@@ -303,13 +312,15 @@ int SOCKS5ClientSocket::DoGreetReadComplete(int result) {
// Got the greet data.
if (buffer_[0] != kSOCKS5Version) {
- net_log_.AddEvent(NetLog::TYPE_SOCKS_UNEXPECTED_VERSION,
- new NetLogIntegerParameter("version", buffer_[0]));
+ net_log_.AddEvent(
+ NetLog::TYPE_SOCKS_UNEXPECTED_VERSION,
+ make_scoped_refptr(new NetLogIntegerParameter("version", buffer_[0])));
return ERR_SOCKS_CONNECTION_FAILED;
}
if (buffer_[1] != 0x00) {
- net_log_.AddEvent(NetLog::TYPE_SOCKS_UNEXPECTED_AUTH,
- new NetLogIntegerParameter("method", buffer_[1]));
+ net_log_.AddEvent(
+ NetLog::TYPE_SOCKS_UNEXPECTED_AUTH,
+ make_scoped_refptr(new NetLogIntegerParameter("method", buffer_[1])));
return ERR_SOCKS_CONNECTION_FAILED;
}
@@ -412,13 +423,17 @@ int SOCKS5ClientSocket::DoHandshakeReadComplete(int result) {
// and accordingly increase them
if (bytes_received_ == kReadHeaderSize) {
if (buffer_[0] != kSOCKS5Version || buffer_[2] != kNullByte) {
- net_log_.AddEvent(NetLog::TYPE_SOCKS_UNEXPECTED_VERSION,
- new NetLogIntegerParameter("version", buffer_[0]));
+ net_log_.AddEvent(
+ NetLog::TYPE_SOCKS_UNEXPECTED_VERSION,
+ make_scoped_refptr(
+ new NetLogIntegerParameter("version", buffer_[0])));
return ERR_SOCKS_CONNECTION_FAILED;
}
if (buffer_[1] != 0x00) {
- net_log_.AddEvent(NetLog::TYPE_SOCKS_SERVER_ERROR,
- new NetLogIntegerParameter("error_code", buffer_[1]));
+ net_log_.AddEvent(
+ NetLog::TYPE_SOCKS_SERVER_ERROR,
+ make_scoped_refptr(
+ new NetLogIntegerParameter("error_code", buffer_[1])));
return ERR_SOCKS_CONNECTION_FAILED;
}
@@ -436,8 +451,10 @@ int SOCKS5ClientSocket::DoHandshakeReadComplete(int result) {
else if (address_type == kEndPointResolvedIPv6)
read_header_size += sizeof(struct in6_addr) - 1;
else {
- net_log_.AddEvent(NetLog::TYPE_SOCKS_UNKNOWN_ADDRESS_TYPE,
- new NetLogIntegerParameter("address_type", buffer_[3]));
+ net_log_.AddEvent(
+ NetLog::TYPE_SOCKS_UNKNOWN_ADDRESS_TYPE,
+ make_scoped_refptr(
+ new NetLogIntegerParameter("address_type", buffer_[3])));
return ERR_SOCKS_CONNECTION_FAILED;
}
diff --git a/net/socket/socks5_client_socket.h b/net/socket/socks5_client_socket.h
index 72e27db..5a918cc 100644
--- a/net/socket/socks5_client_socket.h
+++ b/net/socket/socks5_client_socket.h
@@ -59,6 +59,7 @@ class SOCKS5ClientSocket : public ClientSocket {
virtual void SetSubresourceSpeculation();
virtual void SetOmniboxSpeculation();
virtual bool WasEverUsed() const;
+ virtual bool UsingTCPFastOpen() const;
// Socket methods:
virtual int Read(IOBuffer* buf, int buf_len, CompletionCallback* callback);
diff --git a/net/socket/socks5_client_socket_unittest.cc b/net/socket/socks5_client_socket_unittest.cc
index 43a441d..2152c86 100644
--- a/net/socket/socks5_client_socket_unittest.cc
+++ b/net/socket/socks5_client_socket_unittest.cc
@@ -141,7 +141,7 @@ TEST_F(SOCKS5ClientSocketTest, CompleteHandshake) {
EXPECT_TRUE(LogContainsEndEvent(net_log_.entries(), -1,
NetLog::TYPE_SOCKS5_CONNECT));
- scoped_refptr<IOBuffer> buffer = new IOBuffer(payload_write.size());
+ scoped_refptr<IOBuffer> buffer(new IOBuffer(payload_write.size()));
memcpy(buffer->data(), payload_write.data(), payload_write.size());
rv = user_sock_->Write(buffer, payload_write.size(), &callback_);
EXPECT_EQ(ERR_IO_PENDING, rv);
diff --git a/net/socket/socks_client_socket.cc b/net/socket/socks_client_socket.cc
index 26cad34..4dad417 100644
--- a/net/socket/socks_client_socket.cc
+++ b/net/socket/socks_client_socket.cc
@@ -168,6 +168,15 @@ bool SOCKSClientSocket::WasEverUsed() const {
return false;
}
+bool SOCKSClientSocket::UsingTCPFastOpen() const {
+ if (transport_.get() && transport_->socket()) {
+ return transport_->socket()->UsingTCPFastOpen();
+ }
+ NOTREACHED();
+ return false;
+}
+
+
// Read is called by the transport layer above to read. This can only be done
// if the SOCKS handshake is complete.
int SOCKSClientSocket::Read(IOBuffer* buf, int buf_len,
diff --git a/net/socket/socks_client_socket.h b/net/socket/socks_client_socket.h
index e9e9695..86511cf 100644
--- a/net/socket/socks_client_socket.h
+++ b/net/socket/socks_client_socket.h
@@ -56,6 +56,7 @@ class SOCKSClientSocket : public ClientSocket {
virtual void SetSubresourceSpeculation();
virtual void SetOmniboxSpeculation();
virtual bool WasEverUsed() const;
+ virtual bool UsingTCPFastOpen() const;
// Socket methods:
virtual int Read(IOBuffer* buf, int buf_len, CompletionCallback* callback);
diff --git a/net/socket/socks_client_socket_unittest.cc b/net/socket/socks_client_socket_unittest.cc
index 086b21d..11a88ae 100644
--- a/net/socket/socks_client_socket_unittest.cc
+++ b/net/socket/socks_client_socket_unittest.cc
@@ -153,7 +153,7 @@ TEST_F(SOCKSClientSocketTest, CompleteHandshake) {
EXPECT_TRUE(LogContainsEndEvent(
log.entries(), -1, NetLog::TYPE_SOCKS_CONNECT));
- scoped_refptr<IOBuffer> buffer = new IOBuffer(payload_write.size());
+ scoped_refptr<IOBuffer> buffer(new IOBuffer(payload_write.size()));
memcpy(buffer->data(), payload_write.data(), payload_write.size());
rv = user_sock_->Write(buffer, payload_write.size(), &callback_);
EXPECT_EQ(ERR_IO_PENDING, rv);
diff --git a/net/socket/ssl_client_socket_mac.cc b/net/socket/ssl_client_socket_mac.cc
index 6a8270e..d6fca9b 100644
--- a/net/socket/ssl_client_socket_mac.cc
+++ b/net/socket/ssl_client_socket_mac.cc
@@ -614,6 +614,14 @@ bool SSLClientSocketMac::WasEverUsed() const {
return false;
}
+bool SSLClientSocketMac::UsingTCPFastOpen() const {
+ if (transport_.get() && transport_->socket()) {
+ return transport_->socket()->UsingTCPFastOpen();
+ }
+ NOTREACHED();
+ return false;
+}
+
int SSLClientSocketMac::Read(IOBuffer* buf, int buf_len,
CompletionCallback* callback) {
DCHECK(completed_handshake());
@@ -1124,8 +1132,8 @@ int SSLClientSocketMac::DidCompleteHandshake() {
DCHECK(!server_cert_ || renegotiating_);
VLOG(1) << "Handshake completed, next verify cert";
- scoped_refptr<X509Certificate> new_server_cert =
- GetServerCert(ssl_context_);
+ scoped_refptr<X509Certificate> new_server_cert(
+ GetServerCert(ssl_context_));
if (!new_server_cert)
return ERR_UNEXPECTED;
diff --git a/net/socket/ssl_client_socket_mac.h b/net/socket/ssl_client_socket_mac.h
index 00438fc..0763fd3 100644
--- a/net/socket/ssl_client_socket_mac.h
+++ b/net/socket/ssl_client_socket_mac.h
@@ -50,6 +50,7 @@ class SSLClientSocketMac : public SSLClientSocket {
virtual void SetSubresourceSpeculation();
virtual void SetOmniboxSpeculation();
virtual bool WasEverUsed() const;
+ virtual bool UsingTCPFastOpen() const;
// Socket methods:
virtual int Read(IOBuffer* buf, int buf_len, CompletionCallback* callback);
diff --git a/net/socket/ssl_client_socket_mac_factory.cc b/net/socket/ssl_client_socket_mac_factory.cc
index 7f0c5ce..d10e10d 100644
--- a/net/socket/ssl_client_socket_mac_factory.cc
+++ b/net/socket/ssl_client_socket_mac_factory.cc
@@ -13,7 +13,8 @@ SSLClientSocket* SSLClientSocketMacFactory(
ClientSocketHandle* transport_socket,
const std::string& hostname,
const SSLConfig& ssl_config,
- SSLHostInfo* ssl_host_info) {
+ SSLHostInfo* ssl_host_info,
+ DnsRRResolver* dnsrr_resolver) {
delete ssl_host_info;
return new SSLClientSocketMac(transport_socket, hostname, ssl_config);
}
diff --git a/net/socket/ssl_client_socket_mac_factory.h b/net/socket/ssl_client_socket_mac_factory.h
index ca97b00..6f12883 100644
--- a/net/socket/ssl_client_socket_mac_factory.h
+++ b/net/socket/ssl_client_socket_mac_factory.h
@@ -10,6 +10,7 @@
namespace net {
+class DnsRRResolver;
class SSLHostInfo;
// Creates SSLClientSocketMac objects.
@@ -17,7 +18,8 @@ SSLClientSocket* SSLClientSocketMacFactory(
ClientSocketHandle* transport_socket,
const std::string& hostname,
const SSLConfig& ssl_config,
- SSLHostInfo* ssl_host_info);
+ SSLHostInfo* ssl_host_info,
+ DnsRRResolver* dnsrr_resolver);
} // namespace net
diff --git a/net/socket/ssl_client_socket_nss.cc b/net/socket/ssl_client_socket_nss.cc
index 136f138..a6aa458 100644
--- a/net/socket/ssl_client_socket_nss.cc
+++ b/net/socket/ssl_client_socket_nss.cc
@@ -50,6 +50,9 @@
#if defined(USE_SYSTEM_SSL)
#include <dlfcn.h>
#endif
+#if defined(OS_MACOSX)
+#include <Security/Security.h>
+#endif
#include <certdb.h>
#include <hasht.h>
#include <keyhi.h>
@@ -60,6 +63,7 @@
#include <sechash.h>
#include <ssl.h>
#include <sslerr.h>
+#include <sslproto.h>
#include <limits>
@@ -71,10 +75,12 @@
#include "base/string_number_conversions.h"
#include "base/string_util.h"
#include "base/stringprintf.h"
+#include "base/thread_restrictions.h"
#include "base/values.h"
#include "net/base/address_list.h"
#include "net/base/cert_status_flags.h"
#include "net/base/cert_verifier.h"
+#include "net/base/connection_type_histograms.h"
#include "net/base/dns_util.h"
#include "net/base/dnsrr_resolver.h"
#include "net/base/dnssec_chain_verifier.h"
@@ -87,6 +93,7 @@
#include "net/base/sys_addrinfo.h"
#include "net/ocsp/nss_ocsp.h"
#include "net/socket/client_socket_handle.h"
+#include "net/socket/dns_cert_provenance_check.h"
#include "net/socket/ssl_host_info.h"
static const int kRecvBufferSize = 4096;
@@ -176,6 +183,11 @@ class NSSSSLInitSingleton {
// thread-safe, and the NSS SSL library will only ever be initialized once.
// The NSS SSL library will be properly shut down on program exit.
void EnsureNSSSSLInit() {
+ // Initializing SSL causes us to do blocking IO.
+ // Temporarily allow it until we fix
+ // http://code.google.com/p/chromium/issues/detail?id=59847
+ base::ThreadRestrictions::ScopedAllowIO allow_io;
+
Singleton<NSSSSLInitSingleton>::get();
}
@@ -206,6 +218,8 @@ int MapNSPRError(PRErrorCode err) {
return ERR_INVALID_ARGUMENT;
case PR_END_OF_FILE_ERROR:
return ERR_CONNECTION_CLOSED;
+ case PR_NOT_IMPLEMENTED_ERROR:
+ return ERR_NOT_IMPLEMENTED;
case SEC_ERROR_INVALID_ARGS:
return ERR_INVALID_ARGUMENT;
@@ -309,52 +323,13 @@ class SSLFailedNSSFunctionParams : public NetLog::EventParameters {
void LogFailedNSSFunction(const BoundNetLog& net_log,
const char* function,
const char* param) {
- net_log.AddEvent(NetLog::TYPE_SSL_NSS_ERROR,
- new SSLFailedNSSFunctionParams(function, param));
+ net_log.AddEvent(
+ NetLog::TYPE_SSL_NSS_ERROR,
+ make_scoped_refptr(new SSLFailedNSSFunctionParams(function, param)));
}
#if defined(OS_WIN)
-// A certificate for COMODO EV SGC CA, issued by AddTrust External CA Root,
-// causes CertGetCertificateChain to report CERT_TRUST_IS_NOT_VALID_FOR_USAGE.
-// It seems to be caused by the szOID_APPLICATION_CERT_POLICIES extension in
-// that certificate.
-//
-// This function is used in the workaround for http://crbug.com/43538
-bool IsProblematicComodoEVCACert(const CERTCertificate& cert) {
- // Issuer:
- // CN = AddTrust External CA Root
- // OU = AddTrust External TTP Network
- // O = AddTrust AB
- // C = SE
- static const uint8 kIssuer[] = {
- 0x30, 0x6f, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04,
- 0x06, 0x13, 0x02, 0x53, 0x45, 0x31, 0x14, 0x30, 0x12, 0x06,
- 0x03, 0x55, 0x04, 0x0a, 0x13, 0x0b, 0x41, 0x64, 0x64, 0x54,
- 0x72, 0x75, 0x73, 0x74, 0x20, 0x41, 0x42, 0x31, 0x26, 0x30,
- 0x24, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x1d, 0x41, 0x64,
- 0x64, 0x54, 0x72, 0x75, 0x73, 0x74, 0x20, 0x45, 0x78, 0x74,
- 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x20, 0x54, 0x54, 0x50, 0x20,
- 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x31, 0x22, 0x30,
- 0x20, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x19, 0x41, 0x64,
- 0x64, 0x54, 0x72, 0x75, 0x73, 0x74, 0x20, 0x45, 0x78, 0x74,
- 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x20, 0x43, 0x41, 0x20, 0x52,
- 0x6f, 0x6f, 0x74
- };
-
- // Serial number: 79:0A:83:4D:48:40:6B:AB:6C:35:2A:D5:1F:42:83:FE.
- static const uint8 kSerialNumber[] = {
- 0x79, 0x0a, 0x83, 0x4d, 0x48, 0x40, 0x6b, 0xab, 0x6c, 0x35,
- 0x2a, 0xd5, 0x1f, 0x42, 0x83, 0xfe
- };
-
- return cert.derIssuer.len == sizeof(kIssuer) &&
- memcmp(cert.derIssuer.data, kIssuer, cert.derIssuer.len) == 0 &&
- cert.serialNumber.len == sizeof(kSerialNumber) &&
- memcmp(cert.serialNumber.data, kSerialNumber,
- cert.serialNumber.len) == 0;
-}
-
// This callback is intended to be used with CertFindChainInStore. In addition
// to filtering by extended/enhanced key usage, we do not show expired
// certificates and require digital signature usage in the key usage
@@ -391,17 +366,61 @@ BOOL WINAPI ClientCertFindCallback(PCCERT_CONTEXT cert_context,
#endif
-} // namespace
+// PeerCertificateChain is a helper object which extracts the certificate
+// chain, as given by the server, from an NSS socket and performs the needed
+// resource management. The first element of the chain is the leaf certificate
+// and the other elements are in the order given by the server.
+class PeerCertificateChain {
+ public:
+ explicit PeerCertificateChain(PRFileDesc* nss_fd)
+ : num_certs_(0),
+ certs_(NULL) {
+ SECStatus rv = SSL_PeerCertificateChain(nss_fd, NULL, &num_certs_);
+ DCHECK_EQ(rv, SECSuccess);
-#if defined(OS_WIN)
-// static
-HCERTSTORE SSLClientSocketNSS::cert_store_ = NULL;
-#endif
+ certs_ = new CERTCertificate*[num_certs_];
+ const unsigned expected_num_certs = num_certs_;
+ rv = SSL_PeerCertificateChain(nss_fd, certs_, &num_certs_);
+ DCHECK_EQ(rv, SECSuccess);
+ DCHECK_EQ(num_certs_, expected_num_certs);
+ }
+
+ ~PeerCertificateChain() {
+ for (unsigned i = 0; i < num_certs_; i++)
+ CERT_DestroyCertificate(certs_[i]);
+ delete[] certs_;
+ }
+
+ unsigned size() const { return num_certs_; }
+
+ CERTCertificate* operator[](unsigned i) {
+ DCHECK_LT(i, num_certs_);
+ return certs_[i];
+ }
+
+ std::vector<base::StringPiece> AsStringPieceVector() const {
+ std::vector<base::StringPiece> v(size());
+ for (unsigned i = 0; i < size(); i++) {
+ v[i] = base::StringPiece(
+ reinterpret_cast<const char*>(certs_[i]->derCert.data),
+ certs_[i]->derCert.len);
+ }
+
+ return v;
+ }
+
+ private:
+ unsigned num_certs_;
+ CERTCertificate** certs_;
+};
+
+} // namespace
SSLClientSocketNSS::SSLClientSocketNSS(ClientSocketHandle* transport_socket,
const std::string& hostname,
const SSLConfig& ssl_config,
- SSLHostInfo* ssl_host_info)
+ SSLHostInfo* ssl_host_info,
+ DnsRRResolver* dnsrr_resolver)
: ALLOW_THIS_IN_INITIALIZER_LIST(buffer_send_callback_(
this, &SSLClientSocketNSS::BufferSendComplete)),
ALLOW_THIS_IN_INITIALIZER_LIST(buffer_recv_callback_(
@@ -420,12 +439,15 @@ SSLClientSocketNSS::SSLClientSocketNSS(ClientSocketHandle* transport_socket,
user_read_buf_len_(0),
user_write_buf_len_(0),
server_cert_nss_(NULL),
+ server_cert_verify_result_(NULL),
+ ssl_connection_status_(0),
client_auth_cert_needed_(false),
handshake_callback_called_(false),
completed_handshake_(false),
pseudo_connected_(false),
eset_mitm_detected_(false),
- netnanny_mitm_detected_(false),
+ predicted_cert_chain_correct_(false),
+ peername_initialized_(false),
dnssec_provider_(NULL),
next_handshake_state_(STATE_NONE),
nss_fd_(NULL),
@@ -433,7 +455,8 @@ SSLClientSocketNSS::SSLClientSocketNSS(ClientSocketHandle* transport_socket,
net_log_(transport_socket->socket()->NetLog()),
predicted_npn_status_(kNextProtoUnsupported),
predicted_npn_proto_used_(false),
- ssl_host_info_(ssl_host_info) {
+ ssl_host_info_(ssl_host_info),
+ dnsrr_resolver_(dnsrr_resolver) {
EnterFunction("");
}
@@ -475,6 +498,8 @@ void SSLClientSocketNSS::SaveSnapStartInfo() {
NOTREACHED();
return;
}
+ net_log_.AddEvent(NetLog::TYPE_SSL_SNAP_START,
+ new NetLogIntegerParameter("type", snap_start_type));
LOG(ERROR) << "Snap Start: " << snap_start_type << " " << hostname_;
if (snap_start_type == SSL_SNAP_START_FULL ||
snap_start_type == SSL_SNAP_START_RESUME) {
@@ -490,43 +515,32 @@ void SSLClientSocketNSS::SaveSnapStartInfo() {
NOTREACHED();
return;
}
- // If the server doesn't support Snap Start then |hello_data_len| is zero.
- if (!hello_data_len)
- return;
if (hello_data_len > std::numeric_limits<uint16>::max())
return;
SSLHostInfo::State* state = ssl_host_info_->mutable_state();
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);
-
- // TODO(wtc): CERT_GetCertChainFromCert might not return the same cert chain
- // that the Certificate message actually contained. http://crbug.com/48854
- CERTCertList* cert_list = CERT_GetCertChainFromCert(
- server_cert_nss_, PR_Now(), certUsageSSLCA);
- if (!cert_list)
- return;
+ if (hello_data_len > 0) {
+ state->npn_valid = true;
+ state->npn_status = GetNextProto(&state->npn_protocol);
+ } else {
+ state->npn_valid = false;
+ }
- for (CERTCertListNode* node = CERT_LIST_HEAD(cert_list);
- !CERT_LIST_END(node, cert_list);
- node = CERT_LIST_NEXT(node)) {
- if (node->cert->derCert.len > std::numeric_limits<uint16>::max()) {
- CERT_DestroyCertList(cert_list);
+ state->certs.clear();
+ PeerCertificateChain certs(nss_fd_);
+ for (unsigned i = 0; i < certs.size(); i++) {
+ if (certs[i]->derCert.len > std::numeric_limits<uint16>::max())
return;
- }
- if (node->cert->isRoot == PR_TRUE)
- continue;
+
state->certs.push_back(std::string(
- reinterpret_cast<char*>(node->cert->derCert.data),
- node->cert->derCert.len));
+ reinterpret_cast<char*>(certs[i]->derCert.data),
+ certs[i]->derCert.len));
}
LOG(ERROR) << "Setting Snap Start info " << hostname_;
ssl_host_info_->Persist();
-
- CERT_DestroyCertList(cert_list);
}
static void DestroyCertificates(CERTCertificate** certs, unsigned len) {
@@ -625,6 +639,16 @@ int SSLClientSocketNSS::Connect(CompletionCallback* callback) {
return rv;
}
+ // Attempt to initialize the peer name. In the case of TCP FastOpen,
+ // we don't have the peer yet.
+ if (!UsingTCPFastOpen()) {
+ rv = InitializeSSLPeerName();
+ if (rv != OK) {
+ net_log_.EndEvent(NetLog::TYPE_SSL_CONNECT, NULL);
+ return rv;
+ }
+ }
+
if (ssl_config_.snap_start_enabled && ssl_host_info_.get()) {
GotoState(STATE_SNAP_START_LOAD_INFO);
} else {
@@ -655,28 +679,6 @@ int SSLClientSocketNSS::InitializeSSLOptions() {
return ERR_OUT_OF_MEMORY; // TODO(port): map NSPR error code.
}
- // Tell NSS who we're connected to
- AddressList peer_address;
- int err = transport_->socket()->GetPeerAddress(&peer_address);
- if (err != OK)
- return err;
-
- const struct addrinfo* ai = peer_address.head();
-
- PRNetAddr peername;
- memset(&peername, 0, sizeof(peername));
- DCHECK_LE(ai->ai_addrlen, sizeof(peername));
- size_t len = std::min(static_cast<size_t>(ai->ai_addrlen), sizeof(peername));
- memcpy(&peername, ai->ai_addr, len);
-
- // Adjust the address family field for BSD, whose sockaddr
- // structure has a one-byte length and one-byte address family
- // field at the beginning. PRNetAddr has a two-byte address
- // family field at the beginning.
- peername.raw.family = ai->ai_addr->sa_family;
-
- memio_SetPeerName(nss_fd_, &peername);
-
// Grab pointer to buffers
nss_bufs_ = memio_GetSecret(nss_fd_);
@@ -761,7 +763,7 @@ int SSLClientSocketNSS::InitializeSSLOptions() {
// 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,
- SSLConfigService::snap_start_enabled());
+ ssl_config_.snap_start_enabled);
if (rv != SECSuccess)
VLOG(1) << "SSL_ENABLE_SNAP_START failed. Old system nss?";
#endif
@@ -816,7 +818,12 @@ int SSLClientSocketNSS::InitializeSSLOptions() {
return ERR_UNEXPECTED;
}
+#if defined(NSS_PLATFORM_CLIENT_AUTH)
+ rv = SSL_GetPlatformClientAuthDataHook(nss_fd_, PlatformClientAuthHandler,
+ this);
+#else
rv = SSL_GetClientAuthDataHook(nss_fd_, ClientAuthHandler, this);
+#endif
if (rv != SECSuccess) {
LogFailedNSSFunction(net_log_, "SSL_GetClientAuthDataHook", "");
return ERR_UNEXPECTED;
@@ -831,6 +838,36 @@ int SSLClientSocketNSS::InitializeSSLOptions() {
// Tell SSL the hostname we're trying to connect to.
SSL_SetURL(nss_fd_, hostname_.c_str());
+ // Tell SSL we're a client; needed if not letting NSPR do socket I/O
+ SSL_ResetHandshake(nss_fd_, 0);
+
+ return OK;
+}
+
+int SSLClientSocketNSS::InitializeSSLPeerName() {
+ // Tell NSS who we're connected to
+ AddressList peer_address;
+ int err = transport_->socket()->GetPeerAddress(&peer_address);
+ if (err != OK)
+ return err;
+
+ const struct addrinfo* ai = peer_address.head();
+
+ PRNetAddr peername;
+ memset(&peername, 0, sizeof(peername));
+ DCHECK_LE(ai->ai_addrlen, sizeof(peername));
+ size_t len = std::min(static_cast<size_t>(ai->ai_addrlen),
+ sizeof(peername));
+ memcpy(&peername, ai->ai_addr, len);
+
+ // Adjust the address family field for BSD, whose sockaddr
+ // structure has a one-byte length and one-byte address family
+ // field at the beginning. PRNetAddr has a two-byte address
+ // family field at the beginning.
+ peername.raw.family = ai->ai_addr->sa_family;
+
+ memio_SetPeerName(nss_fd_, &peername);
+
// Set the peer ID for session reuse. This is necessary when we create an
// SSL tunnel through a proxy -- GetPeerName returns the proxy's address
// rather than the destination server's address in that case.
@@ -838,13 +875,11 @@ int SSLClientSocketNSS::InitializeSSLOptions() {
// used.
std::string peer_id = base::StringPrintf("%s:%d", hostname_.c_str(),
peer_address.GetPort());
- rv = SSL_SetSockPeerID(nss_fd_, const_cast<char*>(peer_id.c_str()));
+ SECStatus rv = SSL_SetSockPeerID(nss_fd_, const_cast<char*>(peer_id.c_str()));
if (rv != SECSuccess)
LogFailedNSSFunction(net_log_, "SSL_SetSockPeerID", peer_id.c_str());
- // Tell SSL we're a client; needed if not letting NSPR do socket I/O
- SSL_ResetHandshake(nss_fd_, 0);
-
+ peername_initialized_ = true;
return OK;
}
@@ -885,11 +920,14 @@ void SSLClientSocketNSS::Disconnect() {
CERT_DestroyCertificate(server_cert_nss_);
server_cert_nss_ = NULL;
}
- server_cert_verify_result_.Reset();
+ local_server_cert_verify_result_.Reset();
+ server_cert_verify_result_ = NULL;
+ ssl_connection_status_ = 0;
completed_handshake_ = false;
pseudo_connected_ = false;
eset_mitm_detected_ = false;
- netnanny_mitm_detected_= false;
+ predicted_cert_chain_correct_ = false;
+ peername_initialized_ = false;
nss_bufs_ = NULL;
client_certs_.clear();
client_auth_cert_needed_ = false;
@@ -955,6 +993,14 @@ bool SSLClientSocketNSS::WasEverUsed() const {
return false;
}
+bool SSLClientSocketNSS::UsingTCPFastOpen() const {
+ if (transport_.get() && transport_->socket()) {
+ return transport_->socket()->UsingTCPFastOpen();
+ }
+ NOTREACHED();
+ return false;
+}
+
int SSLClientSocketNSS::Read(IOBuffer* buf, int buf_len,
CompletionCallback* callback) {
EnterFunction(buf_len);
@@ -1044,157 +1090,110 @@ bool SSLClientSocketNSS::SetSendBufferSize(int32 size) {
return transport_->socket()->SetSendBufferSize(size);
}
-#if defined(OS_WIN)
-// static
-X509Certificate::OSCertHandle SSLClientSocketNSS::CreateOSCert(
- const SECItem& der_cert) {
- // TODO(wtc): close cert_store_ at shutdown.
- if (!cert_store_)
- cert_store_ = CertOpenStore(CERT_STORE_PROV_MEMORY, 0, NULL, 0, NULL);
-
- X509Certificate::OSCertHandle cert_handle = NULL;
- BOOL ok = CertAddEncodedCertificateToStore(
- cert_store_, X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
- der_cert.data, der_cert.len, CERT_STORE_ADD_USE_EXISTING, &cert_handle);
- return ok ? cert_handle : NULL;
-}
-#elif defined(OS_MACOSX)
-// static
-X509Certificate::OSCertHandle SSLClientSocketNSS::CreateOSCert(
- const SECItem& der_cert) {
- return X509Certificate::CreateOSCertHandleFromBytes(
- reinterpret_cast<char*>(der_cert.data), der_cert.len);
-}
-#endif
-
+// Sets server_cert_ and server_cert_nss_ if not yet set.
+// Returns server_cert_.
X509Certificate *SSLClientSocketNSS::UpdateServerCert() {
- // We set the server_cert_ from HandshakeCallback(), but this handler
- // does not necessarily get called if we are continuing a cached SSL
- // session.
+ // We set the server_cert_ from HandshakeCallback().
if (server_cert_ == NULL) {
server_cert_nss_ = SSL_PeerCertificate(nss_fd_);
if (server_cert_nss_) {
-#if defined(OS_MACOSX) || defined(OS_WIN)
- // Get each of the intermediate certificates in the server's chain.
- // These will be added to the server's X509Certificate object, making
- // them available to X509Certificate::Verify() for chain building.
- X509Certificate::OSCertHandles intermediate_ca_certs;
- X509Certificate::OSCertHandle cert_handle = NULL;
- CERTCertList* cert_list = CERT_GetCertChainFromCert(
- server_cert_nss_, PR_Now(), certUsageSSLCA);
- if (cert_list) {
- for (CERTCertListNode* node = CERT_LIST_HEAD(cert_list);
- !CERT_LIST_END(node, cert_list);
- node = CERT_LIST_NEXT(node)) {
- if (node->cert == server_cert_nss_)
- continue;
-#if defined(OS_WIN)
- // Work around http://crbug.com/43538 by not importing the
- // problematic COMODO EV SGC CA certificate. CryptoAPI will
- // download a good certificate for that CA, issued by COMODO
- // Certification Authority, using the AIA extension in the server
- // certificate.
- if (IsProblematicComodoEVCACert(*node->cert))
- continue;
-#endif
- cert_handle = CreateOSCert(node->cert->derCert);
- DCHECK(cert_handle);
- intermediate_ca_certs.push_back(cert_handle);
- }
- CERT_DestroyCertList(cert_list);
- }
-
- // Finally create the X509Certificate object.
- cert_handle = CreateOSCert(server_cert_nss_->derCert);
- DCHECK(cert_handle);
- server_cert_ = X509Certificate::CreateFromHandle(
- cert_handle,
- X509Certificate::SOURCE_FROM_NETWORK,
- intermediate_ca_certs);
- X509Certificate::FreeOSCertHandle(cert_handle);
- for (size_t i = 0; i < intermediate_ca_certs.size(); ++i)
- X509Certificate::FreeOSCertHandle(intermediate_ca_certs[i]);
-#else
- server_cert_ = X509Certificate::CreateFromHandle(
- server_cert_nss_,
- X509Certificate::SOURCE_FROM_NETWORK,
- X509Certificate::OSCertHandles());
-#endif
+ PeerCertificateChain certs(nss_fd_);
+ server_cert_ = X509Certificate::CreateFromDERCertChain(
+ certs.AsStringPieceVector());
}
}
return server_cert_;
}
-// Log an informational message if the server does not support secure
-// renegotiation (RFC 5746).
-void SSLClientSocketNSS::CheckSecureRenegotiation() const {
- // SSL_HandshakeNegotiatedExtension was added in NSS 3.12.6.
- // Since SSL_MAX_EXTENSIONS was added at the same time, we can test
- // SSL_MAX_EXTENSIONS for the presence of SSL_HandshakeNegotiatedExtension.
-#if defined(SSL_MAX_EXTENSIONS)
- PRBool received_renego_info;
- if (SSL_HandshakeNegotiatedExtension(nss_fd_, ssl_renegotiation_info_xtn,
- &received_renego_info) == SECSuccess &&
- !received_renego_info) {
- VLOG(1) << "The server " << hostname_
- << " does not support the TLS renegotiation_info extension.";
- }
-#endif
-}
-
-void SSLClientSocketNSS::GetSSLInfo(SSLInfo* ssl_info) {
- EnterFunction("");
- ssl_info->Reset();
-
- if (!server_cert_) {
- LOG(DFATAL) << "!server_cert_";
- return;
- }
-
+// Sets ssl_connection_status_.
+void SSLClientSocketNSS::UpdateConnectionStatus() {
SSLChannelInfo channel_info;
SECStatus ok = SSL_GetChannelInfo(nss_fd_,
&channel_info, sizeof(channel_info));
if (ok == SECSuccess &&
channel_info.length == sizeof(channel_info) &&
channel_info.cipherSuite) {
- SSLCipherSuiteInfo cipher_info;
- ok = SSL_GetCipherSuiteInfo(channel_info.cipherSuite,
- &cipher_info, sizeof(cipher_info));
- if (ok == SECSuccess) {
- ssl_info->security_bits = cipher_info.effectiveKeyBits;
- } else {
- ssl_info->security_bits = -1;
- LOG(DFATAL) << "SSL_GetCipherSuiteInfo returned " << PR_GetError()
- << " for cipherSuite " << channel_info.cipherSuite;
- }
- ssl_info->connection_status |=
- (((int)channel_info.cipherSuite) & SSL_CONNECTION_CIPHERSUITE_MASK) <<
+ ssl_connection_status_ |=
+ (static_cast<int>(channel_info.cipherSuite) &
+ SSL_CONNECTION_CIPHERSUITE_MASK) <<
SSL_CONNECTION_CIPHERSUITE_SHIFT;
- ssl_info->connection_status |=
- (((int)channel_info.compressionMethod) &
+ ssl_connection_status_ |=
+ (static_cast<int>(channel_info.compressionMethod) &
SSL_CONNECTION_COMPRESSION_MASK) <<
SSL_CONNECTION_COMPRESSION_SHIFT;
- UpdateServerCert();
+ // NSS 3.12.x doesn't have version macros for TLS 1.1 and 1.2 (because NSS
+ // doesn't support them yet), so we use 0x0302 and 0x0303 directly.
+ int version = SSL_CONNECTION_VERSION_UNKNOWN;
+ if (channel_info.protocolVersion < SSL_LIBRARY_VERSION_3_0) {
+ // All versions less than SSL_LIBRARY_VERSION_3_0 are treated as SSL
+ // version 2.
+ version = SSL_CONNECTION_VERSION_SSL2;
+ } else if (channel_info.protocolVersion == SSL_LIBRARY_VERSION_3_0) {
+ version = SSL_CONNECTION_VERSION_SSL3;
+ } else if (channel_info.protocolVersion == SSL_LIBRARY_VERSION_3_1_TLS) {
+ version = SSL_CONNECTION_VERSION_TLS1;
+ } else if (channel_info.protocolVersion == 0x0302) {
+ version = SSL_CONNECTION_VERSION_TLS1_1;
+ } else if (channel_info.protocolVersion == 0x0303) {
+ version = SSL_CONNECTION_VERSION_TLS1_2;
+ }
+ ssl_connection_status_ |=
+ (version & SSL_CONNECTION_VERSION_MASK) <<
+ SSL_CONNECTION_VERSION_SHIFT;
}
- ssl_info->cert_status = server_cert_verify_result_.cert_status;
- DCHECK(server_cert_ != NULL);
- ssl_info->cert = server_cert_;
+ // SSL_HandshakeNegotiatedExtension was added in NSS 3.12.6.
+ // Since SSL_MAX_EXTENSIONS was added at the same time, we can test
+ // SSL_MAX_EXTENSIONS for the presence of SSL_HandshakeNegotiatedExtension.
+#if defined(SSL_MAX_EXTENSIONS)
PRBool peer_supports_renego_ext;
ok = SSL_HandshakeNegotiatedExtension(nss_fd_, ssl_renegotiation_info_xtn,
&peer_supports_renego_ext);
if (ok == SECSuccess) {
- if (!peer_supports_renego_ext)
- ssl_info->connection_status |= SSL_CONNECTION_NO_RENEGOTIATION_EXTENSION;
+ if (!peer_supports_renego_ext) {
+ ssl_connection_status_ |= SSL_CONNECTION_NO_RENEGOTIATION_EXTENSION;
+ // Log an informational message if the server does not support secure
+ // renegotiation (RFC 5746).
+ VLOG(1) << "The server " << hostname_
+ << " does not support the TLS renegotiation_info extension.";
+ }
UMA_HISTOGRAM_ENUMERATION("Net.RenegotiationExtensionSupported",
- (int)peer_supports_renego_ext, 2);
+ peer_supports_renego_ext, 2);
}
+#endif
if (ssl_config_.ssl3_fallback)
- ssl_info->connection_status |= SSL_CONNECTION_SSL3_FALLBACK;
+ ssl_connection_status_ |= SSL_CONNECTION_SSL3_FALLBACK;
+}
+
+void SSLClientSocketNSS::GetSSLInfo(SSLInfo* ssl_info) {
+ EnterFunction("");
+ ssl_info->Reset();
+ if (!server_cert_) {
+ LOG(DFATAL) << "!server_cert_";
+ return;
+ }
+
+ ssl_info->cert_status = server_cert_verify_result_->cert_status;
+ DCHECK(server_cert_ != NULL);
+ ssl_info->cert = server_cert_;
+ ssl_info->connection_status = ssl_connection_status_;
+
+ PRUint16 cipher_suite =
+ SSLConnectionStatusToCipherSuite(ssl_connection_status_);
+ SSLCipherSuiteInfo cipher_info;
+ SECStatus ok = SSL_GetCipherSuiteInfo(cipher_suite,
+ &cipher_info, sizeof(cipher_info));
+ if (ok == SECSuccess) {
+ ssl_info->security_bits = cipher_info.effectiveKeyBits;
+ } else {
+ ssl_info->security_bits = -1;
+ LOG(DFATAL) << "SSL_GetCipherSuiteInfo returned " << PR_GetError()
+ << " for cipherSuite " << cipher_suite;
+ }
LeaveFunction("");
}
@@ -1378,8 +1377,11 @@ static PRErrorCode MapErrorToNSS(int result) {
case ERR_IO_PENDING:
return PR_WOULD_BLOCK_ERROR;
case ERR_ACCESS_DENIED:
+ case ERR_NETWORK_ACCESS_DENIED:
// For connect, this could be mapped to PR_ADDRESS_NOT_SUPPORTED_ERROR.
return PR_NO_ACCESS_RIGHTS_ERROR;
+ case ERR_NOT_IMPLEMENTED:
+ return PR_NOT_IMPLEMENTED_ERROR;
case ERR_INTERNET_DISCONNECTED: // Equivalent to ENETDOWN.
return PR_NETWORK_UNREACHABLE_ERROR; // Best approximation.
case ERR_CONNECTION_TIMED_OUT:
@@ -1437,7 +1439,7 @@ int SSLClientSocketNSS::BufferSend(void) {
int rv = 0;
if (len) {
- scoped_refptr<IOBuffer> send_buffer = new IOBuffer(len);
+ scoped_refptr<IOBuffer> send_buffer(new IOBuffer(len));
memcpy(send_buffer->data(), buf1, len1);
memcpy(send_buffer->data() + len1, buf2, len2);
rv = transport_->socket()->Write(send_buffer, len,
@@ -1455,6 +1457,11 @@ int SSLClientSocketNSS::BufferSend(void) {
void SSLClientSocketNSS::BufferSendComplete(int result) {
EnterFunction(result);
+
+ // In the case of TCP FastOpen, connect is now finished.
+ if (!peername_initialized_ && UsingTCPFastOpen())
+ InitializeSSLPeerName();
+
memio_PutWriteResult(nss_bufs_, MapErrorToNSS(result));
transport_send_busy_ = false;
OnSendComplete(result);
@@ -1565,7 +1572,8 @@ int SSLClientSocketNSS::DoReadLoop(int result) {
if (!nss_bufs_) {
LOG(DFATAL) << "!nss_bufs_";
int rv = ERR_UNEXPECTED;
- net_log_.AddEvent(NetLog::TYPE_SSL_READ_ERROR, new SSLErrorParams(rv, 0));
+ net_log_.AddEvent(NetLog::TYPE_SSL_READ_ERROR,
+ make_scoped_refptr(new SSLErrorParams(rv, 0)));
return rv;
}
@@ -1591,7 +1599,8 @@ int SSLClientSocketNSS::DoWriteLoop(int result) {
if (!nss_bufs_) {
LOG(DFATAL) << "!nss_bufs_";
int rv = ERR_UNEXPECTED;
- net_log_.AddEvent(NetLog::TYPE_SSL_WRITE_ERROR, new SSLErrorParams(rv, 0));
+ net_log_.AddEvent(NetLog::TYPE_SSL_WRITE_ERROR,
+ make_scoped_refptr(new SSLErrorParams(rv, 0)));
return rv;
}
@@ -1624,16 +1633,10 @@ SECStatus SSLClientSocketNSS::OwnAuthCertHandler(void* arg,
// different reads or not, depending on network conditions.
PRBool false_start = 0;
SECStatus rv = SSL_OptionGet(socket, SSL_ENABLE_FALSE_START, &false_start);
- if (rv != SECSuccess)
- NOTREACHED();
+ DCHECK_EQ(SECSuccess, rv);
+
if (false_start) {
SSLClientSocketNSS* that = reinterpret_cast<SSLClientSocketNSS*>(arg);
- if (!that->handshake_callback_called_) {
- that->corked_ = true;
- that->uncork_timer_.Start(
- base::TimeDelta::FromMilliseconds(kCorkTimeoutMs),
- that, &SSLClientSocketNSS::UncorkAfterTimeout);
- }
// ESET anti-virus is capable of intercepting HTTPS connections on Windows.
// However, it is False Start intolerant and causes the connections to hang
@@ -1646,12 +1649,24 @@ SECStatus SSLClientSocketNSS::OwnAuthCertHandler(void* arg,
if (common_name) {
if (strcmp(common_name, "ESET_RootSslCert") == 0)
that->eset_mitm_detected_ = true;
- if (strcmp(common_name, "ContentWatch Root Certificate Authority") == 0)
- that->netnanny_mitm_detected_ = true;
+ if (strcmp(common_name, "ContentWatch Root Certificate Authority") == 0) {
+ // This is NetNanny. NetNanny are updating their product so we
+ // silently disable False Start for now.
+ rv = SSL_OptionSet(socket, SSL_ENABLE_FALSE_START, PR_FALSE);
+ DCHECK_EQ(SECSuccess, rv);
+ false_start = 0;
+ }
PORT_Free(common_name);
}
CERT_DestroyCertificate(cert);
}
+
+ if (false_start && !that->handshake_callback_called_) {
+ that->corked_ = true;
+ that->uncork_timer_.Start(
+ base::TimeDelta::FromMilliseconds(kCorkTimeoutMs),
+ that, &SSLClientSocketNSS::UncorkAfterTimeout);
+ }
}
#endif
@@ -1659,24 +1674,69 @@ SECStatus SSLClientSocketNSS::OwnAuthCertHandler(void* arg,
return SECSuccess;
}
+#if defined(NSS_PLATFORM_CLIENT_AUTH)
// static
// NSS calls this if a client certificate is needed.
-// Based on Mozilla's NSS_GetClientAuthData.
-SECStatus SSLClientSocketNSS::ClientAuthHandler(
+SECStatus SSLClientSocketNSS::PlatformClientAuthHandler(
void* arg,
PRFileDesc* socket,
CERTDistNames* ca_names,
- CERTCertificate** result_certificate,
- SECKEYPrivateKey** result_private_key) {
+ CERTCertList** result_certs,
+ void** result_private_key) {
SSLClientSocketNSS* that = reinterpret_cast<SSLClientSocketNSS*>(arg);
that->client_auth_cert_needed_ = !that->ssl_config_.send_client_cert;
-
#if defined(OS_WIN)
if (that->ssl_config_.send_client_cert) {
- // TODO(wtc): SSLClientSocketNSS can't do SSL client authentication using
- // CryptoAPI yet (http://crbug.com/37560), so client_cert must be NULL.
- DCHECK(!that->ssl_config_.client_cert);
+ if (that->ssl_config_.client_cert) {
+ PCCERT_CONTEXT cert_context =
+ that->ssl_config_.client_cert->os_cert_handle();
+ HCRYPTPROV provider = NULL;
+ DWORD key_spec = AT_KEYEXCHANGE;
+ BOOL must_free = FALSE;
+ BOOL acquired_key = CryptAcquireCertificatePrivateKey(
+ cert_context,
+ CRYPT_ACQUIRE_CACHE_FLAG | CRYPT_ACQUIRE_COMPARE_KEY_FLAG,
+ NULL, &provider, &key_spec, &must_free);
+ if (acquired_key && provider) {
+ DCHECK_NE(key_spec, CERT_NCRYPT_KEY_SPEC);
+
+ // The certificate cache may have been updated/used, in which case,
+ // duplicate the existing handle, since NSS will free it when no
+ // longer in use.
+ if (!must_free)
+ CryptContextAddRef(provider, NULL, 0);
+
+ SECItem der_cert;
+ der_cert.type = siDERCertBuffer;
+ der_cert.data = cert_context->pbCertEncoded;
+ der_cert.len = cert_context->cbCertEncoded;
+
+ // TODO(rsleevi): Error checking for NSS allocation errors.
+ *result_certs = CERT_NewCertList();
+ CERTCertDBHandle* db_handle = CERT_GetDefaultCertDB();
+ CERTCertificate* user_cert = CERT_NewTempCertificate(
+ db_handle, &der_cert, NULL, PR_FALSE, PR_TRUE);
+ CERT_AddCertToListTail(*result_certs, user_cert);
+
+ // Add the intermediates.
+ X509Certificate::OSCertHandles intermediates =
+ that->ssl_config_.client_cert->GetIntermediateCertificates();
+ for (X509Certificate::OSCertHandles::const_iterator it =
+ intermediates.begin(); it != intermediates.end(); ++it) {
+ der_cert.data = (*it)->pbCertEncoded;
+ der_cert.len = (*it)->cbCertEncoded;
+
+ CERTCertificate* intermediate = CERT_NewTempCertificate(
+ db_handle, &der_cert, NULL, PR_FALSE, PR_TRUE);
+ CERT_AddCertToListTail(*result_certs, intermediate);
+ }
+ // TODO(wtc): |key_spec| should be passed along with |provider|.
+ *result_private_key = reinterpret_cast<void*>(provider);
+ return SECSuccess;
+ }
+ LOG(WARNING) << "Client cert found without private key";
+ }
// Send no client certificate.
return SECFailure;
}
@@ -1708,10 +1768,6 @@ SECStatus SSLClientSocketNSS::ClientAuthHandler(
PCCERT_CHAIN_CONTEXT chain_context = NULL;
- // TODO(wtc): close cert_store_ at shutdown.
- if (!cert_store_)
- cert_store_ = CertOpenStore(CERT_STORE_PROV_MEMORY, 0, NULL, 0, NULL);
-
for (;;) {
// Find a certificate chain.
chain_context = CertFindChainInStore(my_cert_store,
@@ -1733,18 +1789,42 @@ SECStatus SSLClientSocketNSS::ClientAuthHandler(
// Copy it to our own certificate store, so that we can close the "MY"
// certificate store before returning from this function.
PCCERT_CONTEXT cert_context2;
- BOOL ok = CertAddCertificateContextToStore(cert_store_, cert_context,
+ BOOL ok = CertAddCertificateContextToStore(X509Certificate::cert_store(),
+ cert_context,
CERT_STORE_ADD_USE_EXISTING,
&cert_context2);
if (!ok) {
NOTREACHED();
continue;
}
+
+ // Copy the rest of the chain to our own store as well. Copying the chain
+ // stops gracefully if an error is encountered, with the partial chain
+ // being used as the intermediates, rather than failing to consider the
+ // client certificate.
+ net::X509Certificate::OSCertHandles intermediates;
+ for (DWORD i = 1; i < chain_context->rgpChain[0]->cElement; i++) {
+ PCCERT_CONTEXT intermediate_copy;
+ ok = CertAddCertificateContextToStore(X509Certificate::cert_store(),
+ chain_context->rgpChain[0]->rgpElement[i]->pCertContext,
+ CERT_STORE_ADD_USE_EXISTING, &intermediate_copy);
+ if (!ok) {
+ NOTREACHED();
+ break;
+ }
+ intermediates.push_back(intermediate_copy);
+ }
+
scoped_refptr<X509Certificate> cert = X509Certificate::CreateFromHandle(
cert_context2, X509Certificate::SOURCE_LONE_CERT_IMPORT,
- X509Certificate::OSCertHandles());
- X509Certificate::FreeOSCertHandle(cert_context2);
+ intermediates);
that->client_certs_.push_back(cert);
+
+ X509Certificate::FreeOSCertHandle(cert_context2);
+ for (net::X509Certificate::OSCertHandles::iterator it =
+ intermediates.begin(); it != intermediates.end(); ++it) {
+ net::X509Certificate::FreeOSCertHandle(*it);
+ }
}
BOOL ok = CertCloseStore(my_cert_store, CERT_CLOSE_STORE_CHECK_FLAG);
@@ -1755,9 +1835,63 @@ SECStatus SSLClientSocketNSS::ClientAuthHandler(
return SECWouldBlock;
#elif defined(OS_MACOSX)
if (that->ssl_config_.send_client_cert) {
- // TODO(wtc): SSLClientSocketNSS can't do SSL client authentication using
- // CDSA/CSSM yet (http://crbug.com/45369), so client_cert must be NULL.
- DCHECK(!that->ssl_config_.client_cert);
+ if (that->ssl_config_.client_cert) {
+ OSStatus os_error = noErr;
+ SecIdentityRef identity = NULL;
+ SecKeyRef private_key = NULL;
+ CFArrayRef chain =
+ that->ssl_config_.client_cert->CreateClientCertificateChain();
+ if (chain) {
+ identity = reinterpret_cast<SecIdentityRef>(
+ const_cast<void*>(CFArrayGetValueAtIndex(chain, 0)));
+ }
+ if (identity)
+ os_error = SecIdentityCopyPrivateKey(identity, &private_key);
+
+ if (chain && identity && os_error == noErr) {
+ // TODO(rsleevi): Error checking for NSS allocation errors.
+ *result_certs = CERT_NewCertList();
+ *result_private_key = reinterpret_cast<void*>(private_key);
+
+ for (CFIndex i = 0; i < CFArrayGetCount(chain); ++i) {
+ CSSM_DATA cert_data;
+ SecCertificateRef cert_ref;
+ if (i == 0) {
+ cert_ref = that->ssl_config_.client_cert->os_cert_handle();
+ } else {
+ cert_ref = reinterpret_cast<SecCertificateRef>(
+ const_cast<void*>(CFArrayGetValueAtIndex(chain, i)));
+ }
+ os_error = SecCertificateGetData(cert_ref, &cert_data);
+ if (os_error != noErr)
+ break;
+
+ SECItem der_cert;
+ der_cert.type = siDERCertBuffer;
+ der_cert.data = cert_data.Data;
+ der_cert.len = cert_data.Length;
+ CERTCertificate* nss_cert = CERT_NewTempCertificate(
+ CERT_GetDefaultCertDB(), &der_cert, NULL, PR_FALSE, PR_TRUE);
+ CERT_AddCertToListTail(*result_certs, nss_cert);
+ }
+ }
+ if (os_error == noErr) {
+ CFRelease(chain);
+ return SECSuccess;
+ }
+ LOG(WARNING) << "Client cert found, but could not be used: "
+ << os_error;
+ if (*result_certs) {
+ CERT_DestroyCertList(*result_certs);
+ *result_certs = NULL;
+ }
+ if (*result_private_key)
+ *result_private_key = NULL;
+ if (private_key)
+ CFRelease(private_key);
+ if (chain)
+ CFRelease(chain);
+ }
// Send no client certificate.
return SECFailure;
}
@@ -1785,6 +1919,24 @@ SECStatus SSLClientSocketNSS::ClientAuthHandler(
// handshake by returning ERR_SSL_CLIENT_AUTH_CERT_NEEDED.
return SECWouldBlock;
#else
+ return SECFailure;
+#endif
+}
+
+#else // NSS_PLATFORM_CLIENT_AUTH
+
+// static
+// NSS calls this if a client certificate is needed.
+// Based on Mozilla's NSS_GetClientAuthData.
+SECStatus SSLClientSocketNSS::ClientAuthHandler(
+ void* arg,
+ PRFileDesc* socket,
+ CERTDistNames* ca_names,
+ CERTCertificate** result_certificate,
+ SECKEYPrivateKey** result_private_key) {
+ SSLClientSocketNSS* that = reinterpret_cast<SSLClientSocketNSS*>(arg);
+
+ that->client_auth_cert_needed_ = !that->ssl_config_.send_client_cert;
void* wincx = SSL_RevealPinArg(socket);
// Second pass: a client certificate should have been selected.
@@ -1838,8 +1990,8 @@ SECStatus SSLClientSocketNSS::ClientAuthHandler(
// Tell NSS to suspend the client authentication. We will then abort the
// handshake by returning ERR_SSL_CLIENT_AUTH_CERT_NEEDED.
return SECWouldBlock;
-#endif
}
+#endif // NSS_PLATFORM_CLIENT_AUTH
// static
// NSS calls this when handshake is completed.
@@ -1852,22 +2004,32 @@ void SSLClientSocketNSS::HandshakeCallback(PRFileDesc* socket,
that->handshake_callback_called_ = true;
that->UpdateServerCert();
-
- that->CheckSecureRenegotiation();
+ that->UpdateConnectionStatus();
}
int SSLClientSocketNSS::DoSnapStartLoadInfo() {
EnterFunction("");
int rv = ssl_host_info_->WaitForDataReady(&handshake_io_callback_);
+ GotoState(STATE_HANDSHAKE);
if (rv == OK) {
- if (LoadSnapStartInfo()) {
- pseudo_connected_ = true;
- GotoState(STATE_SNAP_START_WAIT_FOR_WRITE);
- if (user_connect_callback_)
- DoConnectCallback(OK);
- } else {
- GotoState(STATE_HANDSHAKE);
+ 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);
@@ -1909,7 +2071,6 @@ int SSLClientSocketNSS::DoSnapStartWaitForWrite() {
nss_fd_, reinterpret_cast<const unsigned char*>(user_write_buf_->data()),
user_write_buf_len_);
DCHECK_EQ(SECSuccess, rv);
- user_write_buf_ = NULL;
GotoState(STATE_HANDSHAKE);
LeaveFunction("");
@@ -1924,7 +2085,7 @@ int SSLClientSocketNSS::DoHandshake() {
if (client_auth_cert_needed_) {
net_error = ERR_SSL_CLIENT_AUTH_CERT_NEEDED;
net_log_.AddEvent(NetLog::TYPE_SSL_HANDSHAKE_ERROR,
- new SSLErrorParams(net_error, 0));
+ make_scoped_refptr(new SSLErrorParams(net_error, 0)));
// If the handshake already succeeded (because the server requests but
// doesn't require a client cert), we need to invalidate the SSL session
// so that we won't try to resume the non-client-authenticated session in
@@ -1937,9 +2098,27 @@ int SSLClientSocketNSS::DoHandshake() {
if (handshake_callback_called_) {
if (eset_mitm_detected_) {
net_error = ERR_ESET_ANTI_VIRUS_SSL_INTERCEPTION;
- } else if (netnanny_mitm_detected_) {
- net_error = ERR_NETNANNY_SSL_INTERCEPTION;
} 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_|.
+ if (ssl_host_info_.get() && !ssl_host_info_->state().certs.empty()) {
+ PeerCertificateChain certs(nss_fd_);
+ const SSLHostInfo::State& state = ssl_host_info_->state();
+ predicted_cert_chain_correct_ = certs.size() == state.certs.size();
+ if (predicted_cert_chain_correct_) {
+ for (unsigned i = 0; i < certs.size(); i++) {
+ if (certs[i]->derCert.len != state.certs[i].size() ||
+ memcmp(certs[i]->derCert.data, state.certs[i].data(),
+ certs[i]->derCert.len) != 0) {
+ predicted_cert_chain_correct_ = false;
+ break;
+ }
+ }
+ }
+ }
+
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
@@ -1961,7 +2140,7 @@ int SSLClientSocketNSS::DoHandshake() {
rv = SECFailure;
net_error = ERR_SSL_PROTOCOL_ERROR;
net_log_.AddEvent(NetLog::TYPE_SSL_HANDSHAKE_ERROR,
- new SSLErrorParams(net_error, 0));
+ make_scoped_refptr(new SSLErrorParams(net_error, 0)));
}
} else {
PRErrorCode prerr = PR_GetError();
@@ -1973,8 +2152,9 @@ int SSLClientSocketNSS::DoHandshake() {
} else {
LOG(ERROR) << "handshake failed; NSS error code " << prerr
<< ", net_error " << net_error;
- net_log_.AddEvent(NetLog::TYPE_SSL_HANDSHAKE_ERROR,
- new SSLErrorParams(net_error, prerr));
+ net_log_.AddEvent(
+ NetLog::TYPE_SSL_HANDSHAKE_ERROR,
+ make_scoped_refptr(new SSLErrorParams(net_error, prerr)));
}
}
@@ -2135,10 +2315,19 @@ static DNSValidationResult CheckDNSSECChain(
}
int SSLClientSocketNSS::DoVerifyDNSSEC(int result) {
+#if !defined(USE_OPENSSL)
+ if (ssl_config_.dns_cert_provenance_checking_enabled && dnsrr_resolver_) {
+ PeerCertificateChain certs(nss_fd_);
+ DoAsyncDNSCertProvenanceVerification(
+ hostname_, dnsrr_resolver_, certs.AsStringPieceVector());
+ }
+#endif
+
if (ssl_config_.dnssec_enabled) {
DNSValidationResult r = CheckDNSSECChain(hostname_, server_cert_nss_);
if (r == DNSVR_SUCCESS) {
- server_cert_verify_result_.cert_status |= CERT_STATUS_IS_DNSSEC;
+ local_server_cert_verify_result_.cert_status |= CERT_STATUS_IS_DNSSEC;
+ server_cert_verify_result_ = &local_server_cert_verify_result_;
GotoState(STATE_VERIFY_CERT_COMPLETE);
return OK;
}
@@ -2183,13 +2372,15 @@ int SSLClientSocketNSS::DoVerifyDNSSECComplete(int result) {
switch (r) {
case DNSVR_FAILURE:
GotoState(STATE_VERIFY_CERT_COMPLETE);
- server_cert_verify_result_.cert_status |= CERT_STATUS_NOT_IN_DNS;
+ local_server_cert_verify_result_.cert_status |= CERT_STATUS_NOT_IN_DNS;
+ server_cert_verify_result_ = &local_server_cert_verify_result_;
return ERR_CERT_NOT_IN_DNS;
case DNSVR_CONTINUE:
GotoState(STATE_VERIFY_CERT);
break;
case DNSVR_SUCCESS:
- server_cert_verify_result_.cert_status |= CERT_STATUS_IS_DNSSEC;
+ local_server_cert_verify_result_.cert_status |= CERT_STATUS_IS_DNSSEC;
+ server_cert_verify_result_ = &local_server_cert_verify_result_;
GotoState(STATE_VERIFY_CERT_COMPLETE);
break;
default:
@@ -2202,16 +2393,35 @@ int SSLClientSocketNSS::DoVerifyDNSSECComplete(int result) {
int SSLClientSocketNSS::DoVerifyCert(int result) {
DCHECK(server_cert_);
+
GotoState(STATE_VERIFY_CERT_COMPLETE);
- int flags = 0;
+ if (ssl_host_info_.get() && !ssl_host_info_->state().certs.empty() &&
+ 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, NULL);
+ UMA_HISTOGRAM_ENUMERATION("Net.SSLVerificationMerged", 1 /* true */, 2);
+ base::TimeTicks now = base::TimeTicks::Now();
+ UMA_HISTOGRAM_TIMES("Net.SSLVerificationMergedMsSaved",
+ now - ssl_host_info_->verification_start_time());
+ server_cert_verify_result_ = &ssl_host_info_->cert_verify_result();
+ return ssl_host_info_->WaitForCertVerification(&handshake_io_callback_);
+ } else {
+ UMA_HISTOGRAM_ENUMERATION("Net.SSLVerificationMerged", 0 /* false */, 2);
+ }
+
+ int flags = 0;
if (ssl_config_.rev_checking_enabled)
flags |= X509Certificate::VERIFY_REV_CHECKING_ENABLED;
if (ssl_config_.verify_ev_cert)
flags |= X509Certificate::VERIFY_EV_CERT;
verifier_.reset(new CertVerifier);
+ server_cert_verify_result_ = &local_server_cert_verify_result_;
return verifier_->Verify(server_cert_, hostname_, flags,
- &server_cert_verify_result_,
+ &local_server_cert_verify_result_,
&handshake_io_callback_);
}
@@ -2220,45 +2430,15 @@ int SSLClientSocketNSS::DoVerifyCert(int result) {
int SSLClientSocketNSS::DoVerifyCertComplete(int result) {
verifier_.reset();
- // Using Snap Start disables certificate verification for now.
- if (SSLConfigService::snap_start_enabled())
- result = OK;
-
- if (result == OK) {
- // Remember the intermediate CA certs if the server sends them to us.
- //
- // We used to remember the intermediate CA certs in the NSS database
- // persistently. However, NSS opens a connection to the SQLite database
- // during NSS initialization and doesn't close the connection until NSS
- // shuts down. If the file system where the database resides is gone,
- // the database connection goes bad. What's worse, the connection won't
- // recover when the file system comes back. Until this NSS or SQLite bug
- // is fixed, we need to avoid using the NSS database for non-essential
- // purposes. See https://bugzilla.mozilla.org/show_bug.cgi?id=508081 and
- // http://crbug.com/15630 for more info.
- CERTCertList* cert_list = CERT_GetCertChainFromCert(
- server_cert_nss_, PR_Now(), certUsageSSLCA);
- if (cert_list) {
- for (CERTCertListNode* node = CERT_LIST_HEAD(cert_list);
- !CERT_LIST_END(node, cert_list);
- node = CERT_LIST_NEXT(node)) {
- if (node->cert->slot || node->cert->isRoot || node->cert->isperm ||
- node->cert == server_cert_nss_) {
- // Some certs we don't want to remember are:
- // - found on a token.
- // - the root cert.
- // - already stored in perm db.
- // - the server cert itself.
- continue;
- }
-
- // We have found a CA cert that we want to remember.
- // TODO(wtc): Remember the intermediate CA certs in a std::set
- // temporarily (http://crbug.com/15630).
- }
- CERT_DestroyCertList(cert_list);
- }
- }
+ // We used to remember the intermediate CA certs in the NSS database
+ // persistently. However, NSS opens a connection to the SQLite database
+ // during NSS initialization and doesn't close the connection until NSS
+ // shuts down. If the file system where the database resides is gone,
+ // the database connection goes bad. What's worse, the connection won't
+ // recover when the file system comes back. Until this NSS or SQLite bug
+ // is fixed, we need to avoid using the NSS database for non-essential
+ // purposes. See https://bugzilla.mozilla.org/show_bug.cgi?id=508081 and
+ // http://crbug.com/15630 for more info.
// If we have been explicitly told to accept this certificate, override the
// result of verifier_.Verify.
@@ -2272,16 +2452,45 @@ int SSLClientSocketNSS::DoVerifyCertComplete(int result) {
result = OK;
}
+ if (result == OK)
+ LogConnectionTypeMetrics();
+
completed_handshake_ = true;
// TODO(ukai): we may not need this call because it is now harmless to have a
// session with a bad cert.
InvalidateSessionIfBadCertificate();
- // Likewise, if we merged a Write call into the handshake we need to make the
+ // If we merged a Write call into the handshake we need to make the
// callback now.
if (user_write_callback_) {
corked_ = false;
- DoWriteCallback(user_write_buf_len_);
+ 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)
+ DoReadCallback(rv);
}
// Exit DoHandshakeLoop and return the result to the caller to Connect.
@@ -2300,7 +2509,7 @@ int SSLClientSocketNSS::DoPayloadRead() {
LeaveFunction("");
rv = ERR_SSL_CLIENT_AUTH_CERT_NEEDED;
net_log_.AddEvent(NetLog::TYPE_SSL_READ_ERROR,
- new SSLErrorParams(rv, 0));
+ make_scoped_refptr(new SSLErrorParams(rv, 0)));
return rv;
}
if (rv >= 0) {
@@ -2315,7 +2524,8 @@ int SSLClientSocketNSS::DoPayloadRead() {
}
LeaveFunction("");
rv = MapNSPRError(prerr);
- net_log_.AddEvent(NetLog::TYPE_SSL_READ_ERROR, new SSLErrorParams(rv, prerr));
+ net_log_.AddEvent(NetLog::TYPE_SSL_READ_ERROR,
+ make_scoped_refptr(new SSLErrorParams(rv, prerr)));
return rv;
}
@@ -2336,8 +2546,40 @@ int SSLClientSocketNSS::DoPayloadWrite() {
LeaveFunction("");
rv = MapNSPRError(prerr);
net_log_.AddEvent(NetLog::TYPE_SSL_WRITE_ERROR,
- new SSLErrorParams(rv, prerr));
+ make_scoped_refptr(new SSLErrorParams(rv, prerr)));
return rv;
}
+void SSLClientSocketNSS::LogConnectionTypeMetrics() const {
+ UpdateConnectionTypeHistograms(CONNECTION_SSL);
+ if (server_cert_verify_result_->has_md5)
+ UpdateConnectionTypeHistograms(CONNECTION_SSL_MD5);
+ if (server_cert_verify_result_->has_md2)
+ UpdateConnectionTypeHistograms(CONNECTION_SSL_MD2);
+ if (server_cert_verify_result_->has_md4)
+ UpdateConnectionTypeHistograms(CONNECTION_SSL_MD4);
+ if (server_cert_verify_result_->has_md5_ca)
+ UpdateConnectionTypeHistograms(CONNECTION_SSL_MD5_CA);
+ if (server_cert_verify_result_->has_md2_ca)
+ UpdateConnectionTypeHistograms(CONNECTION_SSL_MD2_CA);
+ int ssl_version = SSLConnectionStatusToVersion(ssl_connection_status_);
+ switch (ssl_version) {
+ case SSL_CONNECTION_VERSION_SSL2:
+ UpdateConnectionTypeHistograms(CONNECTION_SSL_SSL2);
+ break;
+ case SSL_CONNECTION_VERSION_SSL3:
+ UpdateConnectionTypeHistograms(CONNECTION_SSL_SSL3);
+ break;
+ case SSL_CONNECTION_VERSION_TLS1:
+ UpdateConnectionTypeHistograms(CONNECTION_SSL_TLS1);
+ break;
+ case SSL_CONNECTION_VERSION_TLS1_1:
+ UpdateConnectionTypeHistograms(CONNECTION_SSL_TLS1_1);
+ break;
+ case SSL_CONNECTION_VERSION_TLS1_2:
+ UpdateConnectionTypeHistograms(CONNECTION_SSL_TLS1_2);
+ break;
+ };
+}
+
} // namespace net
diff --git a/net/socket/ssl_client_socket_nss.h b/net/socket/ssl_client_socket_nss.h
index 56d16b2..87f7b92 100644
--- a/net/socket/ssl_client_socket_nss.h
+++ b/net/socket/ssl_client_socket_nss.h
@@ -30,6 +30,7 @@ namespace net {
class BoundNetLog;
class CertVerifier;
class ClientSocketHandle;
+class DnsRRResolver;
class SSLHostInfo;
class X509Certificate;
@@ -43,14 +44,15 @@ class SSLClientSocketNSS : public SSLClientSocket {
SSLClientSocketNSS(ClientSocketHandle* transport_socket,
const std::string& hostname,
const SSLConfig& ssl_config,
- SSLHostInfo* ssl_host_info);
+ SSLHostInfo* ssl_host_info,
+ DnsRRResolver* dnsrr_resolver);
~SSLClientSocketNSS();
// SSLClientSocket methods:
virtual void GetSSLInfo(SSLInfo* ssl_info);
virtual void GetSSLCertRequestInfo(SSLCertRequestInfo* cert_request_info);
virtual NextProtoStatus GetNextProto(std::string* proto);
- virtual void UseDNSSEC(DNSSECProvider*);
+ virtual void UseDNSSEC(DNSSECProvider* provider);
// ClientSocket methods:
virtual int Connect(CompletionCallback* callback);
@@ -62,6 +64,7 @@ class SSLClientSocketNSS : public SSLClientSocket {
virtual void SetSubresourceSpeculation();
virtual void SetOmniboxSpeculation();
virtual bool WasEverUsed() const;
+ virtual bool UsingTCPFastOpen() const;
// Socket methods:
virtual int Read(IOBuffer* buf, int buf_len, CompletionCallback* callback);
@@ -73,13 +76,16 @@ class SSLClientSocketNSS : public SSLClientSocket {
// Initializes NSS SSL options. Returns a net error code.
int InitializeSSLOptions();
+ // Initializes the socket peer name in SSL. Returns a net error code.
+ int InitializeSSLPeerName();
+
void InvalidateSessionIfBadCertificate();
#if defined(OS_MACOSX) || defined(OS_WIN)
// Creates an OS certificate from a DER-encoded certificate.
static X509Certificate::OSCertHandle CreateOSCert(const SECItem& der_cert);
#endif
X509Certificate* UpdateServerCert();
- void CheckSecureRenegotiation() const;
+ void UpdateConnectionStatus();
void DoReadCallback(int result);
void DoWriteCallback(int result);
void DoConnectCallback(int result);
@@ -101,6 +107,7 @@ class SSLClientSocketNSS : public SSLClientSocket {
int DoVerifyCertComplete(int result);
int DoPayloadRead();
int DoPayloadWrite();
+ void LogConnectionTypeMetrics() const;
int Init();
void SaveSnapStartInfo();
bool LoadSnapStartInfo();
@@ -118,11 +125,19 @@ class SSLClientSocketNSS : public SSLClientSocket {
static SECStatus OwnAuthCertHandler(void* arg, PRFileDesc* socket,
PRBool checksig, PRBool is_server);
// NSS calls this when client authentication is requested.
+#if defined(NSS_PLATFORM_CLIENT_AUTH)
+ static SECStatus PlatformClientAuthHandler(void* arg,
+ PRFileDesc* socket,
+ CERTDistNames* ca_names,
+ CERTCertList** result_certs,
+ void** result_private_key);
+#else
static SECStatus ClientAuthHandler(void* arg,
PRFileDesc* socket,
CERTDistNames* ca_names,
CERTCertificate** result_certificate,
SECKEYPrivateKey** result_private_key);
+#endif
// NSS calls this when handshake is completed. We pass 'this' as the second
// argument.
static void HandshakeCallback(PRFileDesc* socket, void* arg);
@@ -161,7 +176,12 @@ class SSLClientSocketNSS : public SSLClientSocket {
// converted into an X509Certificate object (server_cert_).
scoped_refptr<X509Certificate> server_cert_;
CERTCertificate* server_cert_nss_;
- CertVerifyResult server_cert_verify_result_;
+ // |server_cert_verify_result_| points at the verification result, which may,
+ // or may not be, |&local_server_cert_verify_result_|, depending on whether
+ // we used an SSLHostInfo's verification.
+ const CertVerifyResult* server_cert_verify_result_;
+ CertVerifyResult local_server_cert_verify_result_;
+ int ssl_connection_status_;
// Stores client authentication information between ClientAuthHandler and
// GetSSLCertRequestInfo calls.
@@ -184,9 +204,12 @@ class SSLClientSocketNSS : public SSLClientSocket {
// HTTPS connections.
bool eset_mitm_detected_;
- // True iff we believe that the user has NetNanny intercepting our HTTPS
- // connections.
- bool netnanny_mitm_detected_;
+ // True iff |ssl_host_info_| contained a predicted certificate chain and
+ // that we found the prediction to be correct.
+ bool predicted_cert_chain_correct_;
+
+ // True if the peer name has been initialized.
+ bool peername_initialized_;
// This pointer is owned by the caller of UseDNSSEC.
DNSSECProvider* dnssec_provider_;
@@ -222,16 +245,7 @@ class SSLClientSocketNSS : public SSLClientSocket {
bool predicted_npn_proto_used_;
scoped_ptr<SSLHostInfo> ssl_host_info_;
-
-#if defined(OS_WIN)
- // A CryptoAPI in-memory certificate store. We use it for two purposes:
- // 1. Import server certificates into this store so that we can verify and
- // display the certificates using CryptoAPI.
- // 2. Copy client certificates from the "MY" system certificate store into
- // this store so that we can close the system store when we finish
- // searching for client certificates.
- static HCERTSTORE cert_store_;
-#endif
+ DnsRRResolver* const dnsrr_resolver_;
};
} // namespace net
diff --git a/net/socket/ssl_client_socket_nss_factory.cc b/net/socket/ssl_client_socket_nss_factory.cc
index efa6e23..f4e8215 100644
--- a/net/socket/ssl_client_socket_nss_factory.cc
+++ b/net/socket/ssl_client_socket_nss_factory.cc
@@ -4,12 +4,8 @@
#include "net/socket/client_socket_factory.h"
-#include "build/build_config.h"
#include "net/socket/ssl_client_socket_nss.h"
#include "net/socket/ssl_host_info.h"
-#if defined(OS_WIN)
-#include "net/socket/ssl_client_socket_win.h"
-#endif
// This file is only used on platforms where NSS is not the system SSL
// library. When compiled, this file is the only object module that pulls
@@ -22,18 +18,11 @@ SSLClientSocket* SSLClientSocketNSSFactory(
ClientSocketHandle* transport_socket,
const std::string& hostname,
const SSLConfig& ssl_config,
- SSLHostInfo* ssl_host_info) {
+ SSLHostInfo* ssl_host_info,
+ DnsRRResolver* dnsrr_resolver) {
scoped_ptr<SSLHostInfo> shi(ssl_host_info);
- // TODO(wtc): SSLClientSocketNSS can't do SSL client authentication using
- // CryptoAPI yet (http://crbug.com/37560), so we fall back on
- // SSLClientSocketWin.
-#if defined(OS_WIN)
- if (ssl_config.send_client_cert)
- return new SSLClientSocketWin(transport_socket, hostname, ssl_config);
-#endif
-
return new SSLClientSocketNSS(transport_socket, hostname, ssl_config,
- shi.release());
+ shi.release(), dnsrr_resolver);
}
} // namespace net
diff --git a/net/socket/ssl_client_socket_nss_factory.h b/net/socket/ssl_client_socket_nss_factory.h
index d454bb9..29f9af4 100644
--- a/net/socket/ssl_client_socket_nss_factory.h
+++ b/net/socket/ssl_client_socket_nss_factory.h
@@ -10,6 +10,7 @@
namespace net {
+class DnsRRResolver;
class SSLHostInfo;
// Creates SSLClientSocketNSS objects.
@@ -17,7 +18,8 @@ SSLClientSocket* SSLClientSocketNSSFactory(
ClientSocketHandle* transport_socket,
const std::string& hostname,
const SSLConfig& ssl_config,
- SSLHostInfo* ssl_host_info);
+ SSLHostInfo* ssl_host_info,
+ DnsRRResolver* dnsrr_resolver);
} // namespace net
diff --git a/net/socket/ssl_client_socket_openssl.cc b/net/socket/ssl_client_socket_openssl.cc
index bbe3ee4..3aae457 100644
--- a/net/socket/ssl_client_socket_openssl.cc
+++ b/net/socket/ssl_client_socket_openssl.cc
@@ -631,6 +631,14 @@ bool SSLClientSocketOpenSSL::WasEverUsed() const {
return false;
}
+bool SSLClientSocketOpenSSL::UsingTCPFastOpen() const {
+ if (transport_.get() && transport_->socket())
+ return transport_->socket()->UsingTCPFastOpen();
+
+ NOTREACHED();
+ return false;
+}
+
// Socket methods
int SSLClientSocketOpenSSL::Read(IOBuffer* buf,
diff --git a/net/socket/ssl_client_socket_openssl.h b/net/socket/ssl_client_socket_openssl.h
index 20f321e..31d5c1c 100644
--- a/net/socket/ssl_client_socket_openssl.h
+++ b/net/socket/ssl_client_socket_openssl.h
@@ -51,6 +51,7 @@ class SSLClientSocketOpenSSL : public SSLClientSocket {
virtual void SetSubresourceSpeculation();
virtual void SetOmniboxSpeculation();
virtual bool WasEverUsed() const;
+ virtual bool UsingTCPFastOpen() const;
// Socket methods:
virtual int Read(IOBuffer* buf, int buf_len, CompletionCallback* callback);
diff --git a/net/socket/ssl_client_socket_pool.cc b/net/socket/ssl_client_socket_pool.cc
index 98e3b09..a7eea3a 100644
--- a/net/socket/ssl_client_socket_pool.cc
+++ b/net/socket/ssl_client_socket_pool.cc
@@ -193,7 +193,8 @@ int SSLConnectJob::DoTCPConnect() {
if (ssl_host_info_factory_ && SSLConfigService::snap_start_enabled()) {
ssl_host_info_.reset(
- ssl_host_info_factory_->GetForHost(params_->hostname()));
+ ssl_host_info_factory_->GetForHost(params_->hostname(),
+ params_->ssl_config()));
}
if (ssl_host_info_.get()) {
// This starts fetching the SSL host info from the disk cache for Snap
@@ -284,7 +285,8 @@ int SSLConnectJob::DoSSLConnect() {
ssl_socket_.reset(client_socket_factory_->CreateSSLClientSocket(
transport_socket_handle_.release(), params_->hostname(),
- params_->ssl_config(), ssl_host_info_.release()));
+ params_->ssl_config(), ssl_host_info_.release(),
+ dnsrr_resolver_));
return ssl_socket_->Connect(&callback_);
}
diff --git a/net/socket/ssl_client_socket_unittest.cc b/net/socket/ssl_client_socket_unittest.cc
index bfcbe81..a32d5df 100644
--- a/net/socket/ssl_client_socket_unittest.cc
+++ b/net/socket/ssl_client_socket_unittest.cc
@@ -93,8 +93,9 @@ TEST_F(SSLClientSocketTest, Connect) {
}
TEST_F(SSLClientSocketTest, ConnectExpired) {
- net::TestServer test_server(net::TestServer::TYPE_HTTPS_EXPIRED_CERTIFICATE,
- FilePath());
+ net::TestServer::HTTPSOptions https_options(
+ net::TestServer::HTTPSOptions::CERT_EXPIRED);
+ net::TestServer test_server(https_options, FilePath());
ASSERT_TRUE(test_server.Start());
net::AddressList addr;
@@ -136,8 +137,9 @@ TEST_F(SSLClientSocketTest, ConnectExpired) {
}
TEST_F(SSLClientSocketTest, ConnectMismatched) {
- net::TestServer test_server(net::TestServer::TYPE_HTTPS_MISMATCHED_HOSTNAME,
- FilePath());
+ net::TestServer::HTTPSOptions https_options(
+ net::TestServer::HTTPSOptions::CERT_MISMATCHED_NAME);
+ net::TestServer test_server(https_options, FilePath());
ASSERT_TRUE(test_server.Start());
net::AddressList addr;
@@ -181,9 +183,11 @@ TEST_F(SSLClientSocketTest, ConnectMismatched) {
// Attempt to connect to a page which requests a client certificate. It should
// return an error code on connect.
+// Flaky: http://crbug.com/54445
TEST_F(SSLClientSocketTest, FLAKY_ConnectClientAuthCertRequested) {
- net::TestServer test_server(net::TestServer::TYPE_HTTPS_CLIENT_AUTH,
- FilePath());
+ net::TestServer::HTTPSOptions https_options;
+ https_options.request_client_certificate = true;
+ net::TestServer test_server(https_options, FilePath());
ASSERT_TRUE(test_server.Start());
net::AddressList addr;
@@ -229,8 +233,9 @@ TEST_F(SSLClientSocketTest, FLAKY_ConnectClientAuthCertRequested) {
//
// TODO(davidben): Also test providing an actual certificate.
TEST_F(SSLClientSocketTest, ConnectClientAuthSendNullCert) {
- net::TestServer test_server(net::TestServer::TYPE_HTTPS_CLIENT_AUTH,
- FilePath());
+ net::TestServer::HTTPSOptions https_options;
+ https_options.request_client_certificate = true;
+ net::TestServer test_server(https_options, FilePath());
ASSERT_TRUE(test_server.Start());
net::AddressList addr;
@@ -315,8 +320,8 @@ TEST_F(SSLClientSocketTest, Read) {
EXPECT_TRUE(sock->IsConnected());
const char request_text[] = "GET / HTTP/1.0\r\n\r\n";
- scoped_refptr<net::IOBuffer> request_buffer =
- new net::IOBuffer(arraysize(request_text) - 1);
+ scoped_refptr<net::IOBuffer> request_buffer(
+ new net::IOBuffer(arraysize(request_text) - 1));
memcpy(request_buffer->data(), request_text, arraysize(request_text) - 1);
rv = sock->Write(request_buffer, arraysize(request_text) - 1, &callback);
@@ -326,7 +331,7 @@ TEST_F(SSLClientSocketTest, Read) {
rv = callback.WaitForResult();
EXPECT_EQ(static_cast<int>(arraysize(request_text) - 1), rv);
- scoped_refptr<net::IOBuffer> buf = new net::IOBuffer(4096);
+ scoped_refptr<net::IOBuffer> buf(new net::IOBuffer(4096));
for (;;) {
rv = sock->Read(buf, 4096, &callback);
EXPECT_TRUE(rv >= 0 || rv == net::ERR_IO_PENDING);
@@ -376,7 +381,7 @@ TEST_F(SSLClientSocketTest, Read_FullDuplex) {
EXPECT_TRUE(sock->IsConnected());
// Issue a "hanging" Read first.
- scoped_refptr<net::IOBuffer> buf = new net::IOBuffer(4096);
+ scoped_refptr<net::IOBuffer> buf(new net::IOBuffer(4096));
rv = sock->Read(buf, 4096, &callback);
// We haven't written the request, so there should be no response yet.
ASSERT_EQ(net::ERR_IO_PENDING, rv);
@@ -389,8 +394,8 @@ TEST_F(SSLClientSocketTest, Read_FullDuplex) {
for (int i = 0; i < 3800; ++i)
request_text.push_back('*');
request_text.append("\r\n\r\n");
- scoped_refptr<net::IOBuffer> request_buffer =
- new net::StringIOBuffer(request_text);
+ scoped_refptr<net::IOBuffer> request_buffer(
+ new net::StringIOBuffer(request_text));
rv = sock->Write(request_buffer, request_text.size(), &callback2);
EXPECT_TRUE(rv >= 0 || rv == net::ERR_IO_PENDING);
@@ -433,8 +438,8 @@ TEST_F(SSLClientSocketTest, Read_SmallChunks) {
}
const char request_text[] = "GET / HTTP/1.0\r\n\r\n";
- scoped_refptr<net::IOBuffer> request_buffer =
- new net::IOBuffer(arraysize(request_text) - 1);
+ scoped_refptr<net::IOBuffer> request_buffer(
+ new net::IOBuffer(arraysize(request_text) - 1));
memcpy(request_buffer->data(), request_text, arraysize(request_text) - 1);
rv = sock->Write(request_buffer, arraysize(request_text) - 1, &callback);
@@ -444,7 +449,7 @@ TEST_F(SSLClientSocketTest, Read_SmallChunks) {
rv = callback.WaitForResult();
EXPECT_EQ(static_cast<int>(arraysize(request_text) - 1), rv);
- scoped_refptr<net::IOBuffer> buf = new net::IOBuffer(1);
+ scoped_refptr<net::IOBuffer> buf(new net::IOBuffer(1));
for (;;) {
rv = sock->Read(buf, 1, &callback);
EXPECT_TRUE(rv >= 0 || rv == net::ERR_IO_PENDING);
@@ -487,8 +492,8 @@ TEST_F(SSLClientSocketTest, Read_Interrupted) {
}
const char request_text[] = "GET / HTTP/1.0\r\n\r\n";
- scoped_refptr<net::IOBuffer> request_buffer =
- new net::IOBuffer(arraysize(request_text) - 1);
+ scoped_refptr<net::IOBuffer> request_buffer(
+ new net::IOBuffer(arraysize(request_text) - 1));
memcpy(request_buffer->data(), request_text, arraysize(request_text) - 1);
rv = sock->Write(request_buffer, arraysize(request_text) - 1, &callback);
@@ -499,7 +504,7 @@ TEST_F(SSLClientSocketTest, Read_Interrupted) {
EXPECT_EQ(static_cast<int>(arraysize(request_text) - 1), rv);
// Do a partial read and then exit. This test should not crash!
- scoped_refptr<net::IOBuffer> buf = new net::IOBuffer(512);
+ scoped_refptr<net::IOBuffer> buf(new net::IOBuffer(512));
rv = sock->Read(buf, 512, &callback);
EXPECT_TRUE(rv > 0 || rv == net::ERR_IO_PENDING);
diff --git a/net/socket/ssl_client_socket_win.cc b/net/socket/ssl_client_socket_win.cc
index 7e8c29e..eead7ed 100644
--- a/net/socket/ssl_client_socket_win.cc
+++ b/net/socket/ssl_client_socket_win.cc
@@ -705,6 +705,14 @@ bool SSLClientSocketWin::WasEverUsed() const {
return false;
}
+bool SSLClientSocketWin::UsingTCPFastOpen() const {
+ if (transport_.get() && transport_->socket()) {
+ return transport_->socket()->UsingTCPFastOpen();
+ }
+ NOTREACHED();
+ return false;
+}
+
int SSLClientSocketWin::Read(IOBuffer* buf, int buf_len,
CompletionCallback* callback) {
DCHECK(completed_handshake());
diff --git a/net/socket/ssl_client_socket_win.h b/net/socket/ssl_client_socket_win.h
index 38cdb32..4f96e80 100644
--- a/net/socket/ssl_client_socket_win.h
+++ b/net/socket/ssl_client_socket_win.h
@@ -54,6 +54,7 @@ class SSLClientSocketWin : public SSLClientSocket {
virtual void SetSubresourceSpeculation();
virtual void SetOmniboxSpeculation();
virtual bool WasEverUsed() const;
+ virtual bool UsingTCPFastOpen() const;
// Socket methods:
virtual int Read(IOBuffer* buf, int buf_len, CompletionCallback* callback);
diff --git a/net/socket/ssl_host_info.cc b/net/socket/ssl_host_info.cc
index cc29545..4f6c1bb 100644
--- a/net/socket/ssl_host_info.cc
+++ b/net/socket/ssl_host_info.cc
@@ -4,6 +4,11 @@
#include "net/socket/ssl_host_info.h"
+#include "base/metrics/histogram.h"
+#include "base/string_piece.h"
+#include "net/base/cert_verifier.h"
+#include "net/base/ssl_config_service.h"
+#include "net/base/x509_certificate.h"
#include "net/socket/ssl_client_socket.h"
#ifdef ANDROID
// the android platform build system use a fixed include path relative to the
@@ -15,7 +20,25 @@
namespace net {
-SSLHostInfo::SSLHostInfo() {
+SSLHostInfo::State::State()
+ : npn_valid(false),
+ npn_status(SSLClientSocket::kNextProtoUnsupported) {
+}
+
+SSLHostInfo::State::~State() {}
+
+SSLHostInfo::SSLHostInfo(
+ const std::string& hostname,
+ const SSLConfig& ssl_config)
+ : hostname_(hostname),
+ cert_verification_complete_(false),
+ cert_parsing_failed_(false),
+ cert_verification_callback_(NULL),
+ rev_checking_enabled_(ssl_config.rev_checking_enabled),
+ verify_ev_cert_(ssl_config.verify_ev_cert),
+ callback_(new CancelableCompletionCallback<SSLHostInfo>(
+ ALLOW_THIS_IN_INITIALIZER_LIST(this),
+ &SSLHostInfo::VerifyCallback)) {
state_.npn_valid = false;
}
@@ -66,6 +89,7 @@ bool SSLHostInfo::Parse(const std::string& data) {
state->certs.clear();
state->server_hello.clear();
state->npn_valid = false;
+ cert_verification_complete_ = false;
if (!proto.ParseFromString(data))
return false;
@@ -80,6 +104,30 @@ bool SSLHostInfo::Parse(const std::string& data) {
state->npn_protocol = proto.npn_protocol();
}
+ if (state->certs.size() > 0) {
+ std::vector<base::StringPiece> der_certs(state->certs.size());
+ for (size_t i = 0; i < state->certs.size(); i++)
+ der_certs[i] = state->certs[i];
+ cert_ = X509Certificate::CreateFromDERCertChain(der_certs);
+ if (cert_.get()) {
+ int flags = 0;
+ if (verify_ev_cert_)
+ flags |= X509Certificate::VERIFY_EV_CERT;
+ if (rev_checking_enabled_)
+ flags |= X509Certificate::VERIFY_REV_CHECKING_ENABLED;
+ verifier_.reset(new CertVerifier);
+ VLOG(1) << "Kicking off verification for " << hostname_;
+ verification_start_time_ = base::TimeTicks::Now();
+ if (verifier_->Verify(cert_.get(), hostname_, flags,
+ &cert_verify_result_, callback_) == OK) {
+ VerifyCallback(OK);
+ }
+ } else {
+ cert_parsing_failed_ = true;
+ DCHECK(!cert_verification_callback_);
+ }
+ }
+
return true;
}
@@ -101,6 +149,35 @@ std::string SSLHostInfo::Serialize() const {
return proto.SerializeAsString();
}
+const CertVerifyResult& SSLHostInfo::cert_verify_result() const {
+ return cert_verify_result_;
+}
+
+int SSLHostInfo::WaitForCertVerification(CompletionCallback* callback) {
+ if (cert_verification_complete_)
+ return cert_verification_result_;
+ DCHECK(!cert_parsing_failed_);
+ DCHECK(!cert_verification_callback_);
+ DCHECK(!state_.certs.empty());
+ cert_verification_callback_ = callback;
+ return ERR_IO_PENDING;
+}
+
+void SSLHostInfo::VerifyCallback(int rv) {
+ DCHECK(!verification_start_time_.is_null());
+ base::TimeTicks now = base::TimeTicks::Now();
+ const base::TimeDelta duration = now - verification_start_time();
+ UMA_HISTOGRAM_TIMES("Net.SSLHostInfoVerificationTimeMs", duration);
+ VLOG(1) << "Verification took " << duration.InMilliseconds() << "ms";
+ cert_verification_complete_ = true;
+ cert_verification_result_ = rv;
+ if (cert_verification_callback_) {
+ CompletionCallback* callback = cert_verification_callback_;
+ cert_verification_callback_ = NULL;
+ callback->Run(rv);
+ }
+}
+
SSLHostInfoFactory::~SSLHostInfoFactory() {}
} // namespace net
diff --git a/net/socket/ssl_host_info.h b/net/socket/ssl_host_info.h
index 8065b47..5f515fb 100644
--- a/net/socket/ssl_host_info.h
+++ b/net/socket/ssl_host_info.h
@@ -9,18 +9,25 @@
#include <vector>
#include "base/ref_counted.h"
+#include "base/scoped_ptr.h"
+#include "base/time.h"
+#include "net/base/cert_verify_result.h"
#include "net/base/completion_callback.h"
#include "net/socket/ssl_client_socket.h"
namespace net {
+class CertVerifier;
+class X509Certificate;
+struct SSLConfig;
+
// SSLHostInfo is an interface for fetching information about an SSL server.
// This information may be stored on disk so does not include keys or session
// information etc. Primarily it's intended for caching the server's
// certificates.
class SSLHostInfo {
public:
- SSLHostInfo();
+ SSLHostInfo(const std::string& hostname, const SSLConfig& ssl_config);
virtual ~SSLHostInfo();
// Start will commence the lookup. This must be called before any other
@@ -48,6 +55,9 @@ class SSLHostInfo {
virtual void Persist() = 0;
struct State {
+ State();
+ ~State();
+
// 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;
@@ -59,6 +69,9 @@ class SSLHostInfo {
// 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);
};
// Once the data is ready, it can be read using the following members. These
@@ -66,6 +79,21 @@ class SSLHostInfo {
const State& state() const;
State* mutable_state();
+ // If |cert_valid()| returns true, then this contains the result of verifying
+ // the certificate.
+ const CertVerifyResult& cert_verify_result() const;
+
+ // WaitForCertVerification returns ERR_IO_PENDING if the certificate chain in
+ // |state().certs| is still being validated and arranges for the given
+ // callback to be called when the verification completes. If the verification has
+ // already finished then WaitForCertVerification returns the result of that
+ // verification.
+ int WaitForCertVerification(CompletionCallback* callback);
+
+ base::TimeTicks verification_start_time() const {
+ return verification_start_time_;
+ }
+
protected:
// Parse parses an opaque blob of data and fills out the public member fields
// of this object. It returns true iff the parse was successful. The public
@@ -73,6 +101,25 @@ class SSLHostInfo {
bool Parse(const std::string& data);
std::string Serialize() const;
State state_;
+
+ private:
+ // This is the callback function which the CertVerifier calls via |callback_|.
+ void VerifyCallback(int rv);
+
+ // This is the hostname that we'll validate the certificates against.
+ const std::string hostname_;
+ bool cert_verification_complete_;
+ bool cert_parsing_failed_;
+ int cert_verification_result_;
+ CompletionCallback* cert_verification_callback_;
+ // These two members are taken from the SSLConfig.
+ bool rev_checking_enabled_;
+ bool verify_ev_cert_;
+ base::TimeTicks verification_start_time_;
+ CertVerifyResult cert_verify_result_;
+ scoped_ptr<CertVerifier> verifier_;
+ scoped_refptr<X509Certificate> cert_;
+ scoped_refptr<CancelableCompletionCallback<SSLHostInfo> > callback_;
};
class SSLHostInfoFactory {
@@ -81,7 +128,8 @@ class SSLHostInfoFactory {
// GetForHost returns a fresh, allocated SSLHostInfo for the given hostname
// or NULL on failure.
- virtual SSLHostInfo* GetForHost(const std::string& hostname) = 0;
+ virtual SSLHostInfo* GetForHost(const std::string& hostname,
+ const SSLConfig& ssl_config) = 0;
};
} // namespace net
diff --git a/net/socket/tcp_client_socket.cc b/net/socket/tcp_client_socket.cc
new file mode 100644
index 0000000..d3d4e20
--- /dev/null
+++ b/net/socket/tcp_client_socket.cc
@@ -0,0 +1,19 @@
+// Copyright (c) 2006-2009 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 "net/socket/tcp_client_socket.h"
+
+namespace net {
+
+static bool g_tcp_fastopen_enabled = false;
+
+void set_tcp_fastopen_enabled(bool value) {
+ g_tcp_fastopen_enabled = value;
+}
+
+bool is_tcp_fastopen_enabled() {
+ return g_tcp_fastopen_enabled;
+}
+
+} // namespace net
diff --git a/net/socket/tcp_client_socket.h b/net/socket/tcp_client_socket.h
index 6139b5b..13d2dfb 100644
--- a/net/socket/tcp_client_socket.h
+++ b/net/socket/tcp_client_socket.h
@@ -23,6 +23,13 @@ typedef TCPClientSocketWin TCPClientSocket;
typedef TCPClientSocketLibevent TCPClientSocket;
#endif
+// Enable/disable experimental TCP FastOpen option.
+// Not thread safe. Must be called during initialization/startup only.
+void set_tcp_fastopen_enabled(bool value);
+
+// Check if the TCP FastOpen option is enabled.
+bool is_tcp_fastopen_enabled();
+
} // namespace net
#endif // NET_SOCKET_TCP_CLIENT_SOCKET_H_
diff --git a/net/socket/tcp_client_socket_libevent.cc b/net/socket/tcp_client_socket_libevent.cc
index aedbf8a..1bbe827 100644
--- a/net/socket/tcp_client_socket_libevent.cc
+++ b/net/socket/tcp_client_socket_libevent.cc
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "net/socket/tcp_client_socket_libevent.h"
+#include "net/socket/tcp_client_socket.h"
#include <errno.h>
#include <fcntl.h>
@@ -86,6 +86,8 @@ int MapPosixError(int os_error) {
int MapConnectError(int os_error) {
switch (os_error) {
+ case EACCES:
+ return ERR_NETWORK_ACCESS_DENIED;
case ETIMEDOUT:
return ERR_CONNECTION_TIMED_OUT;
default: {
@@ -120,11 +122,17 @@ TCPClientSocketLibevent::TCPClientSocketLibevent(
write_callback_(NULL),
next_connect_state_(CONNECT_STATE_NONE),
connect_os_error_(0),
- net_log_(BoundNetLog::Make(net_log, NetLog::SOURCE_SOCKET)) {
+ net_log_(BoundNetLog::Make(net_log, NetLog::SOURCE_SOCKET)),
+ previously_disconnected_(false),
+ use_tcp_fastopen_(false),
+ tcp_fastopen_connected_(false) {
scoped_refptr<NetLog::EventParameters> params;
if (source.is_valid())
params = new NetLogSourceParameter("source_dependency", source);
net_log_.BeginEvent(NetLog::TYPE_SOCKET_ALIVE, params);
+
+ if (is_tcp_fastopen_enabled())
+ use_tcp_fastopen_ = true;
}
TCPClientSocketLibevent::~TCPClientSocketLibevent() {
@@ -144,8 +152,9 @@ int TCPClientSocketLibevent::Connect(CompletionCallback* callback) {
DCHECK(!waiting_connect());
- net_log_.BeginEvent(NetLog::TYPE_TCP_CONNECT,
- new AddressListNetLogParam(addresses_));
+ net_log_.BeginEvent(
+ NetLog::TYPE_TCP_CONNECT,
+ make_scoped_refptr(new AddressListNetLogParam(addresses_)));
// We will try to connect to each address in addresses_. Start with the
// first one in the list.
@@ -194,9 +203,14 @@ int TCPClientSocketLibevent::DoConnect() {
DCHECK_EQ(0, connect_os_error_);
+ if (previously_disconnected_) {
+ use_history_.Reset();
+ previously_disconnected_ = false;
+ }
+
net_log_.BeginEvent(NetLog::TYPE_TCP_CONNECT_ATTEMPT,
- new NetLogStringParameter(
- "address", NetAddressToStringWithPort(current_ai_)));
+ make_scoped_refptr(new NetLogStringParameter(
+ "address", NetAddressToStringWithPort(current_ai_))));
next_connect_state_ = CONNECT_STATE_CONNECT_COMPLETE;
@@ -206,9 +220,15 @@ int TCPClientSocketLibevent::DoConnect() {
return MapPosixError(connect_os_error_);
// Connect the socket.
- if (!HANDLE_EINTR(connect(socket_, current_ai_->ai_addr,
- static_cast<int>(current_ai_->ai_addrlen)))) {
- // Connected without waiting!
+ if (!use_tcp_fastopen_) {
+ if (!HANDLE_EINTR(connect(socket_, current_ai_->ai_addr,
+ static_cast<int>(current_ai_->ai_addrlen)))) {
+ // Connected without waiting!
+ return OK;
+ }
+ } else {
+ // With TCP FastOpen, we pretend that the socket is connected.
+ DCHECK(!tcp_fastopen_connected_);
return OK;
}
@@ -278,6 +298,7 @@ void TCPClientSocketLibevent::DoDisconnect() {
if (HANDLE_EINTR(close(socket_)) < 0)
PLOG(ERROR) << "close";
socket_ = kInvalidSocket;
+ previously_disconnected_ = true;
}
bool TCPClientSocketLibevent::IsConnected() const {
@@ -365,7 +386,7 @@ int TCPClientSocketLibevent::Write(IOBuffer* buf,
DCHECK(callback);
DCHECK_GT(buf_len, 0);
- int nwrite = HANDLE_EINTR(write(socket_, buf->data(), buf_len));
+ int nwrite = InternalWrite(buf, buf_len);
if (nwrite >= 0) {
static base::StatsCounter write_bytes("tcp.write_bytes");
write_bytes.Add(nwrite);
@@ -391,6 +412,38 @@ int TCPClientSocketLibevent::Write(IOBuffer* buf,
return ERR_IO_PENDING;
}
+int TCPClientSocketLibevent::InternalWrite(IOBuffer* buf, int buf_len) {
+ int nwrite;
+ if (use_tcp_fastopen_ && !tcp_fastopen_connected_) {
+ // We have a limited amount of data to send in the SYN packet.
+ int kMaxFastOpenSendLength = 1420;
+
+ buf_len = std::min(kMaxFastOpenSendLength, buf_len);
+
+ int flags = 0x20000000; // Magic flag to enable TCP_FASTOPEN
+ nwrite = HANDLE_EINTR(sendto(socket_,
+ buf->data(),
+ buf_len,
+ flags,
+ current_ai_->ai_addr,
+ static_cast<int>(current_ai_->ai_addrlen)));
+ tcp_fastopen_connected_ = true;
+
+ if (nwrite < 0) {
+ // Non-blocking mode is returning EINPROGRESS rather than EAGAIN.
+ if (errno == EINPROGRESS)
+ errno = EAGAIN;
+
+ // Unlike "normal" nonblocking sockets, the data is already queued,
+ // so tell the app that we've consumed it.
+ return buf_len;
+ }
+ } else {
+ nwrite = HANDLE_EINTR(write(socket_, buf->data(), buf_len));
+ }
+ return nwrite;
+}
+
bool TCPClientSocketLibevent::SetReceiveBufferSize(int32 size) {
DCHECK(CalledOnValidThread());
int rv = setsockopt(socket_, SOL_SOCKET, SO_RCVBUF,
@@ -553,4 +606,8 @@ bool TCPClientSocketLibevent::WasEverUsed() const {
return use_history_.was_used_to_convey_data();
}
+bool TCPClientSocketLibevent::UsingTCPFastOpen() const {
+ return use_tcp_fastopen_;
+}
+
} // namespace net
diff --git a/net/socket/tcp_client_socket_libevent.h b/net/socket/tcp_client_socket_libevent.h
index 980e4cd..890d0c2 100644
--- a/net/socket/tcp_client_socket_libevent.h
+++ b/net/socket/tcp_client_socket_libevent.h
@@ -43,6 +43,7 @@ class TCPClientSocketLibevent : public ClientSocket, NonThreadSafe {
virtual void SetSubresourceSpeculation();
virtual void SetOmniboxSpeculation();
virtual bool WasEverUsed() const;
+ virtual bool UsingTCPFastOpen() const;
// Socket methods:
// Multiple outstanding requests are not supported.
@@ -127,6 +128,9 @@ class TCPClientSocketLibevent : public ClientSocket, NonThreadSafe {
// Helper to add a TCP_CONNECT (end) event to the NetLog.
void LogConnectCompletion(int net_error);
+ // Internal function to write to a socket.
+ int InternalWrite(IOBuffer* buf, int buf_len);
+
int socket_;
// The list of addresses we should try in order to establish a connection.
@@ -165,10 +169,19 @@ class TCPClientSocketLibevent : public ClientSocket, NonThreadSafe {
BoundNetLog net_log_;
+ // This socket was previously disconnected and has not been re-connected.
+ bool previously_disconnected_;
+
// Record of connectivity and transmissions, for use in speculative connection
// histograms.
UseHistory use_history_;
+ // Enables experimental TCP FastOpen option.
+ bool use_tcp_fastopen_;
+
+ // True when TCP FastOpen is in use and we have done the connect.
+ bool tcp_fastopen_connected_;
+
DISALLOW_COPY_AND_ASSIGN(TCPClientSocketLibevent);
};
diff --git a/net/socket/tcp_client_socket_pool.cc b/net/socket/tcp_client_socket_pool.cc
index 5f1f43f..8ec9cac 100644
--- a/net/socket/tcp_client_socket_pool.cc
+++ b/net/socket/tcp_client_socket_pool.cc
@@ -222,9 +222,9 @@ int TCPClientSocketPool::RequestSocket(
// TODO(eroman): Split out the host and port parameters.
net_log.AddEvent(
NetLog::TYPE_TCP_CLIENT_SOCKET_POOL_REQUESTED_SOCKET,
- new NetLogStringParameter(
+ make_scoped_refptr(new NetLogStringParameter(
"host_and_port",
- casted_params->get()->destination().host_port_pair().ToString()));
+ casted_params->get()->destination().host_port_pair().ToString())));
}
return base_.RequestSocket(group_name, *casted_params, priority, handle,
@@ -243,9 +243,9 @@ void TCPClientSocketPool::RequestSockets(
// TODO(eroman): Split out the host and port parameters.
net_log.AddEvent(
NetLog::TYPE_TCP_CLIENT_SOCKET_POOL_REQUESTED_SOCKETS,
- new NetLogStringParameter(
+ make_scoped_refptr(new NetLogStringParameter(
"host_and_port",
- casted_params->get()->destination().host_port_pair().ToString()));
+ casted_params->get()->destination().host_port_pair().ToString())));
}
base_.RequestSockets(group_name, *casted_params, num_sockets, net_log);
diff --git a/net/socket/tcp_client_socket_pool_unittest.cc b/net/socket/tcp_client_socket_pool_unittest.cc
index 80de0aa..e53e264 100644
--- a/net/socket/tcp_client_socket_pool_unittest.cc
+++ b/net/socket/tcp_client_socket_pool_unittest.cc
@@ -54,6 +54,7 @@ class MockClientSocket : public ClientSocket {
virtual void SetSubresourceSpeculation() {}
virtual void SetOmniboxSpeculation() {}
virtual bool WasEverUsed() const { return false; }
+ virtual bool UsingTCPFastOpen() const { return false; }
// Socket methods:
virtual int Read(IOBuffer* buf, int buf_len,
@@ -99,6 +100,7 @@ class MockFailingClientSocket : public ClientSocket {
virtual void SetSubresourceSpeculation() {}
virtual void SetOmniboxSpeculation() {}
virtual bool WasEverUsed() const { return false; }
+ virtual bool UsingTCPFastOpen() const { return false; }
// Socket methods:
virtual int Read(IOBuffer* buf, int buf_len,
@@ -157,6 +159,7 @@ class MockPendingClientSocket : public ClientSocket {
virtual void SetSubresourceSpeculation() {}
virtual void SetOmniboxSpeculation() {}
virtual bool WasEverUsed() const { return false; }
+ virtual bool UsingTCPFastOpen() const { return false; }
// Socket methods:
virtual int Read(IOBuffer* buf, int buf_len,
@@ -247,7 +250,8 @@ class MockClientSocketFactory : public ClientSocketFactory {
ClientSocketHandle* transport_socket,
const std::string& hostname,
const SSLConfig& ssl_config,
- SSLHostInfo* ssl_host_info) {
+ SSLHostInfo* ssl_host_info,
+ DnsRRResolver* dnsrr_resolver) {
NOTIMPLEMENTED();
delete ssl_host_info;
return NULL;
@@ -294,8 +298,8 @@ class TCPClientSocketPoolTest : public testing::Test {
}
int StartRequest(const std::string& group_name, RequestPriority priority) {
- scoped_refptr<TCPSocketParams> params = new TCPSocketParams(
- HostPortPair("www.google.com", 80), MEDIUM, GURL(), false);
+ scoped_refptr<TCPSocketParams> params(new TCPSocketParams(
+ HostPortPair("www.google.com", 80), MEDIUM, GURL(), false));
return test_base_.StartRequestUsingPool(
&pool_, group_name, priority, params);
}
@@ -343,8 +347,8 @@ TEST_F(TCPClientSocketPoolTest, InitHostResolutionFailure) {
host_resolver_->rules()->AddSimulatedFailure("unresolvable.host.name");
TestCompletionCallback callback;
ClientSocketHandle handle;
- scoped_refptr<TCPSocketParams> dest = new TCPSocketParams(
- "unresolvable.host.name", 80, kDefaultPriority, GURL(), false);
+ scoped_refptr<TCPSocketParams> dest(new TCPSocketParams(
+ "unresolvable.host.name", 80, kDefaultPriority, GURL(), false));
EXPECT_EQ(ERR_IO_PENDING,
handle.Init("a", dest, kDefaultPriority, &callback, &pool_,
BoundNetLog()));
@@ -602,8 +606,8 @@ class RequestSocketCallback : public CallbackRunner< Tuple1<int> > {
MessageLoop::current()->RunAllPending();
}
within_callback_ = true;
- scoped_refptr<TCPSocketParams> dest = new TCPSocketParams(
- HostPortPair("www.google.com", 80), LOWEST, GURL(), false);
+ scoped_refptr<TCPSocketParams> dest(new TCPSocketParams(
+ HostPortPair("www.google.com", 80), LOWEST, GURL(), false));
int rv = handle_->Init("a", dest, LOWEST, this, pool_, BoundNetLog());
EXPECT_EQ(OK, rv);
}
@@ -623,8 +627,8 @@ class RequestSocketCallback : public CallbackRunner< Tuple1<int> > {
TEST_F(TCPClientSocketPoolTest, RequestTwice) {
ClientSocketHandle handle;
RequestSocketCallback callback(&handle, &pool_);
- scoped_refptr<TCPSocketParams> dest = new TCPSocketParams(
- HostPortPair("www.google.com", 80), LOWEST, GURL(), false);
+ scoped_refptr<TCPSocketParams> dest(new TCPSocketParams(
+ HostPortPair("www.google.com", 80), LOWEST, GURL(), false));
int rv = handle.Init("a", dest, LOWEST, &callback, &pool_,
BoundNetLog());
ASSERT_EQ(ERR_IO_PENDING, rv);
diff --git a/net/socket/tcp_client_socket_unittest.cc b/net/socket/tcp_client_socket_unittest.cc
index fdd966c..64d78f3 100644
--- a/net/socket/tcp_client_socket_unittest.cc
+++ b/net/socket/tcp_client_socket_unittest.cc
@@ -93,7 +93,7 @@ void TCPClientSocketTest::SetUp() {
AddressList addr;
scoped_ptr<HostResolver> resolver(
CreateSystemHostResolver(HostResolver::kDefaultParallelism,
- NULL));
+ NULL, NULL));
HostResolver::RequestInfo info(HostPortPair("localhost", listen_port_));
int rv = resolver->Resolve(info, &addr, NULL, NULL, BoundNetLog());
CHECK_EQ(rv, OK);
@@ -138,8 +138,8 @@ TEST_F(TCPClientSocketTest, Read) {
}
const char request_text[] = "GET / HTTP/1.0\r\n\r\n";
- scoped_refptr<IOBuffer> request_buffer =
- new IOBuffer(arraysize(request_text) - 1);
+ 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) - 1, &callback);
@@ -150,7 +150,7 @@ TEST_F(TCPClientSocketTest, Read) {
EXPECT_EQ(rv, static_cast<int>(arraysize(request_text) - 1));
}
- scoped_refptr<IOBuffer> buf = new IOBuffer(4096);
+ scoped_refptr<IOBuffer> buf(new IOBuffer(4096));
uint32 bytes_read = 0;
while (bytes_read < arraysize(kServerReply) - 1) {
rv = sock_->Read(buf, 4096, &callback);
@@ -183,8 +183,8 @@ TEST_F(TCPClientSocketTest, Read_SmallChunks) {
}
const char request_text[] = "GET / HTTP/1.0\r\n\r\n";
- scoped_refptr<IOBuffer> request_buffer =
- new IOBuffer(arraysize(request_text) - 1);
+ 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) - 1, &callback);
@@ -195,7 +195,7 @@ TEST_F(TCPClientSocketTest, Read_SmallChunks) {
EXPECT_EQ(rv, static_cast<int>(arraysize(request_text) - 1));
}
- scoped_refptr<IOBuffer> buf = new IOBuffer(1);
+ scoped_refptr<IOBuffer> buf(new IOBuffer(1));
uint32 bytes_read = 0;
while (bytes_read < arraysize(kServerReply) - 1) {
rv = sock_->Read(buf, 1, &callback);
@@ -228,8 +228,8 @@ TEST_F(TCPClientSocketTest, Read_Interrupted) {
}
const char request_text[] = "GET / HTTP/1.0\r\n\r\n";
- scoped_refptr<IOBuffer> request_buffer =
- new IOBuffer(arraysize(request_text) - 1);
+ 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) - 1, &callback);
@@ -241,7 +241,7 @@ TEST_F(TCPClientSocketTest, Read_Interrupted) {
}
// Do a partial read and then exit. This test should not crash!
- scoped_refptr<IOBuffer> buf = new IOBuffer(16);
+ scoped_refptr<IOBuffer> buf(new IOBuffer(16));
rv = sock_->Read(buf, 16, &callback);
EXPECT_TRUE(rv >= 0 || rv == ERR_IO_PENDING);
@@ -263,13 +263,13 @@ TEST_F(TCPClientSocketTest, DISABLED_FullDuplex_ReadFirst) {
// Read first. There's no data, so it should return ERR_IO_PENDING.
const int kBufLen = 4096;
- scoped_refptr<IOBuffer> buf = new IOBuffer(kBufLen);
+ scoped_refptr<IOBuffer> buf(new IOBuffer(kBufLen));
rv = sock_->Read(buf, kBufLen, &callback);
EXPECT_EQ(ERR_IO_PENDING, rv);
PauseServerReads();
const int kWriteBufLen = 64 * 1024;
- scoped_refptr<IOBuffer> request_buffer = new IOBuffer(kWriteBufLen);
+ scoped_refptr<IOBuffer> request_buffer(new IOBuffer(kWriteBufLen));
char* request_data = request_buffer->data();
memset(request_data, 'A', kWriteBufLen);
TestCompletionCallback write_callback;
@@ -305,7 +305,7 @@ TEST_F(TCPClientSocketTest, DISABLED_FullDuplex_WriteFirst) {
PauseServerReads();
const int kWriteBufLen = 64 * 1024;
- scoped_refptr<IOBuffer> request_buffer = new IOBuffer(kWriteBufLen);
+ scoped_refptr<IOBuffer> request_buffer(new IOBuffer(kWriteBufLen));
char* request_data = request_buffer->data();
memset(request_data, 'A', kWriteBufLen);
TestCompletionCallback write_callback;
@@ -322,7 +322,7 @@ TEST_F(TCPClientSocketTest, DISABLED_FullDuplex_WriteFirst) {
// Read() to block on ERR_IO_PENDING too.
const int kBufLen = 4096;
- scoped_refptr<IOBuffer> buf = new IOBuffer(kBufLen);
+ scoped_refptr<IOBuffer> buf(new IOBuffer(kBufLen));
while (true) {
rv = sock_->Read(buf, kBufLen, &callback);
ASSERT_TRUE(rv >= 0 || rv == ERR_IO_PENDING);
diff --git a/net/socket/tcp_client_socket_win.cc b/net/socket/tcp_client_socket_win.cc
index 9143b81..b3b79a0 100644
--- a/net/socket/tcp_client_socket_win.cc
+++ b/net/socket/tcp_client_socket_win.cc
@@ -64,8 +64,6 @@ int MapWinsockError(int os_error) {
// There are numerous Winsock error codes, but these are the ones we thus far
// find interesting.
switch (os_error) {
- // connect fails with WSAEACCES when Windows Firewall blocks the
- // connection.
case WSAEACCES:
return ERR_ACCESS_DENIED;
case WSAENETDOWN:
@@ -104,6 +102,10 @@ int MapWinsockError(int os_error) {
int MapConnectError(int os_error) {
switch (os_error) {
+ // connect fails with WSAEACCES when Windows Firewall blocks the
+ // connection.
+ case WSAEACCES:
+ return ERR_NETWORK_ACCESS_DENIED;
case WSAETIMEDOUT:
return ERR_CONNECTION_TIMED_OUT;
default: {
@@ -290,8 +292,8 @@ TCPClientSocketWin::TCPClientSocketWin(const AddressList& addresses,
write_callback_(NULL),
next_connect_state_(CONNECT_STATE_NONE),
connect_os_error_(0),
- net_log_(BoundNetLog::Make(net_log, NetLog::SOURCE_SOCKET)) {
-
+ net_log_(BoundNetLog::Make(net_log, NetLog::SOURCE_SOCKET)),
+ previously_disconnected_(false) {
scoped_refptr<NetLog::EventParameters> params;
if (source.is_valid())
params = new NetLogSourceParameter("source_dependency", source);
@@ -364,6 +366,11 @@ int TCPClientSocketWin::DoConnect() {
DCHECK(ai);
DCHECK_EQ(0, connect_os_error_);
+ if (previously_disconnected_) {
+ use_history_.Reset();
+ previously_disconnected_ = false;
+ }
+
net_log_.BeginEvent(NetLog::TYPE_TCP_CONNECT_ATTEMPT,
new NetLogStringParameter(
"address", NetAddressToStringWithPort(current_ai_)));
@@ -478,6 +485,8 @@ void TCPClientSocketWin::DoDisconnect() {
core_->Detach();
core_ = NULL;
+
+ previously_disconnected_ = true;
}
bool TCPClientSocketWin::IsConnected() const {
@@ -536,6 +545,11 @@ bool TCPClientSocketWin::WasEverUsed() const {
return use_history_.was_used_to_convey_data();
}
+bool TCPClientSocketWin::UsingTCPFastOpen() const {
+ // Not supported on windows.
+ return false;
+}
+
int TCPClientSocketWin::Read(IOBuffer* buf,
int buf_len,
CompletionCallback* callback) {
diff --git a/net/socket/tcp_client_socket_win.h b/net/socket/tcp_client_socket_win.h
index be25157..cd6b066 100644
--- a/net/socket/tcp_client_socket_win.h
+++ b/net/socket/tcp_client_socket_win.h
@@ -40,6 +40,7 @@ class TCPClientSocketWin : public ClientSocket, NonThreadSafe {
virtual void SetSubresourceSpeculation();
virtual void SetOmniboxSpeculation();
virtual bool WasEverUsed() const;
+ virtual bool UsingTCPFastOpen() const;
// Socket methods:
// Multiple outstanding requests are not supported.
@@ -117,6 +118,9 @@ class TCPClientSocketWin : public ClientSocket, NonThreadSafe {
BoundNetLog net_log_;
+ // This socket was previously disconnected and has not been re-connected.
+ bool previously_disconnected_;
+
// Record of connectivity and transmissions, for use in speculative connection
// histograms.
UseHistory use_history_;