summaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorrch@chromium.org <rch@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2014-08-14 01:00:11 +0000
committerrch@chromium.org <rch@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2014-08-14 01:00:11 +0000
commit0b620f4b8d4e0b4f0bb5d76a78b0aca431b9eb75 (patch)
tree7a728b838a7028eca227949722fc66b9e9e1ce3b /net
parent9d363dd55297354292489000b2bdf5623bca8d63 (diff)
downloadchromium_src-0b620f4b8d4e0b4f0bb5d76a78b0aca431b9eb75.zip
chromium_src-0b620f4b8d4e0b4f0bb5d76a78b0aca431b9eb75.tar.gz
chromium_src-0b620f4b8d4e0b4f0bb5d76a78b0aca431b9eb75.tar.bz2
Refactor pooling logic into a helper method
Disable pooling when there are cert errors. Disable pooling when pinning does not match for the new host. BUG=398925 Review URL: https://codereview.chromium.org/425803014 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@289433 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'net')
-rw-r--r--net/http/http_network_session.cc1
-rw-r--r--net/quic/quic_client_session.cc28
-rw-r--r--net/quic/quic_client_session.h3
-rw-r--r--net/quic/quic_client_session_test.cc64
-rw-r--r--net/quic/quic_http_stream_test.cc3
-rw-r--r--net/quic/quic_stream_factory.cc4
-rw-r--r--net/quic/quic_stream_factory.h1
-rw-r--r--net/quic/quic_stream_factory_test.cc6
-rw-r--r--net/socket/ssl_client_socket_pool_unittest.cc3
-rw-r--r--net/spdy/spdy_session.cc55
-rw-r--r--net/spdy/spdy_session.h11
-rw-r--r--net/spdy/spdy_session_pool.cc3
-rw-r--r--net/spdy/spdy_session_pool.h4
-rw-r--r--net/spdy/spdy_session_unittest.cc110
-rw-r--r--net/spdy/spdy_test_utils.cc33
-rw-r--r--net/spdy/spdy_test_utils.h18
16 files changed, 292 insertions, 55 deletions
diff --git a/net/http/http_network_session.cc b/net/http/http_network_session.cc
index b48d660..d1a7236 100644
--- a/net/http/http_network_session.cc
+++ b/net/http/http_network_session.cc
@@ -135,6 +135,7 @@ HttpNetworkSession::HttpNetworkSession(const Params& params)
spdy_session_pool_(params.host_resolver,
params.ssl_config_service,
params.http_server_properties,
+ params.transport_security_state,
params.force_spdy_single_domain,
params.enable_spdy_compression,
params.enable_spdy_ping_based_connection_checking,
diff --git a/net/quic/quic_client_session.cc b/net/quic/quic_client_session.cc
index c6699f1..b136724 100644
--- a/net/quic/quic_client_session.cc
+++ b/net/quic/quic_client_session.cc
@@ -13,6 +13,7 @@
#include "base/values.h"
#include "net/base/io_buffer.h"
#include "net/base/net_errors.h"
+#include "net/http/transport_security_state.h"
#include "net/quic/crypto/proof_verifier_chromium.h"
#include "net/quic/crypto/quic_server_info.h"
#include "net/quic/quic_connection_helper.h"
@@ -20,6 +21,7 @@
#include "net/quic/quic_default_packet_writer.h"
#include "net/quic/quic_server_id.h"
#include "net/quic/quic_stream_factory.h"
+#include "net/spdy/spdy_session.h"
#include "net/ssl/channel_id_service.h"
#include "net/ssl/ssl_connection_status_flags.h"
#include "net/ssl/ssl_info.h"
@@ -138,6 +140,7 @@ QuicClientSession::QuicClientSession(
scoped_ptr<QuicDefaultPacketWriter> writer,
QuicStreamFactory* stream_factory,
QuicCryptoClientStreamFactory* crypto_client_stream_factory,
+ TransportSecurityState* transport_security_state,
scoped_ptr<QuicServerInfo> server_info,
const QuicServerId& server_id,
const QuicConfig& config,
@@ -151,6 +154,7 @@ QuicClientSession::QuicClientSession(
socket_(socket.Pass()),
writer_(writer.Pass()),
read_buffer_(new IOBufferWithSize(kMaxPacketSize)),
+ transport_security_state_(transport_security_state),
server_info_(server_info.Pass()),
read_pending_(false),
num_total_streams_(0),
@@ -489,28 +493,8 @@ bool QuicClientSession::CanPool(const std::string& hostname) const {
return true;
}
- // Disable pooling for secure sessions.
- // TODO(rch): re-enable this.
- return false;
-#if 0
- bool unused = false;
- // Pooling is prohibited if the server cert is not valid for the new domain,
- // and for connections on which client certs were sent. It is also prohibited
- // when channel ID was sent if the hosts are from different eTLDs+1.
- if (!ssl_info.cert->VerifyNameMatch(hostname, &unused))
- return false;
-
- if (ssl_info.client_cert_sent)
- return false;
-
- if (ssl_info.channel_id_sent &&
- ChannelIDService::GetDomainForHost(hostname) !=
- ChannelIDService::GetDomainForHost(server_host_port_.host())) {
- return false;
- }
-
- return true;
-#endif
+ return SpdySession::CanPool(transport_security_state_, ssl_info,
+ server_host_port_.host(), hostname);
}
QuicDataStream* QuicClientSession::CreateIncomingDataStream(
diff --git a/net/quic/quic_client_session.h b/net/quic/quic_client_session.h
index 6112e1e..9808cac 100644
--- a/net/quic/quic_client_session.h
+++ b/net/quic/quic_client_session.h
@@ -35,6 +35,7 @@ class QuicServerId;
class QuicServerInfo;
class QuicStreamFactory;
class SSLInfo;
+class TransportSecurityState;
namespace test {
class QuicClientSessionPeer;
@@ -95,6 +96,7 @@ class NET_EXPORT_PRIVATE QuicClientSession : public QuicClientSessionBase {
scoped_ptr<QuicDefaultPacketWriter> writer,
QuicStreamFactory* stream_factory,
QuicCryptoClientStreamFactory* crypto_client_stream_factory,
+ TransportSecurityState* transport_security_state,
scoped_ptr<QuicServerInfo> server_info,
const QuicServerId& server_id,
const QuicConfig& config,
@@ -226,6 +228,7 @@ class NET_EXPORT_PRIVATE QuicClientSession : public QuicClientSessionBase {
scoped_ptr<DatagramClientSocket> socket_;
scoped_ptr<QuicDefaultPacketWriter> writer_;
scoped_refptr<IOBufferWithSize> read_buffer_;
+ TransportSecurityState* transport_security_state_;
scoped_ptr<QuicServerInfo> server_info_;
scoped_ptr<CertVerifyResult> cert_verify_result_;
std::string pinning_failure_log_;
diff --git a/net/quic/quic_client_session_test.cc b/net/quic/quic_client_session_test.cc
index ae1aea6..1e13e89 100644
--- a/net/quic/quic_client_session_test.cc
+++ b/net/quic/quic_client_session_test.cc
@@ -6,12 +6,14 @@
#include <vector>
+#include "base/base64.h"
#include "base/files/file_path.h"
#include "base/rand_util.h"
#include "net/base/capturing_net_log.h"
#include "net/base/test_completion_callback.h"
#include "net/base/test_data_directory.h"
#include "net/cert/cert_verify_result.h"
+#include "net/http/transport_security_state.h"
#include "net/quic/crypto/aes_128_gcm_12_encrypter.h"
#include "net/quic/crypto/crypto_protocol.h"
#include "net/quic/crypto/proof_verifier_chromium.h"
@@ -24,6 +26,7 @@
#include "net/quic/test_tools/quic_test_utils.h"
#include "net/quic/test_tools/simple_quic_framer.h"
#include "net/socket/socket_test_util.h"
+#include "net/spdy/spdy_test_utils.h"
#include "net/test/cert_test_util.h"
#include "net/udp/datagram_client_socket.h"
@@ -73,6 +76,7 @@ class QuicClientSessionTest : public ::testing::TestWithParam<QuicVersion> {
connection_(
new PacketSavingConnection(false, SupportedVersions(GetParam()))),
session_(connection_, GetSocket().Pass(), writer_.Pass(), NULL, NULL,
+ &transport_security_state_,
make_scoped_ptr((QuicServerInfo*)NULL),
QuicServerId(kServerHostname, kServerPort, false,
PRIVACY_MODE_DISABLED),
@@ -108,6 +112,7 @@ class QuicClientSessionTest : public ::testing::TestWithParam<QuicVersion> {
CapturingNetLog net_log_;
MockClientSocketFactory socket_factory_;
StaticSocketDataProvider socket_data_;
+ TransportSecurityState transport_security_state_;
QuicClientSession session_;
MockClock clock_;
MockRandom random_;
@@ -172,18 +177,15 @@ TEST_P(QuicClientSessionTest, GoAwayReceived) {
EXPECT_EQ(NULL, session_.CreateOutgoingDataStream());
}
-// TODO(rch): re-enable this.
-TEST_P(QuicClientSessionTest, DISABLED_CanPool) {
+TEST_P(QuicClientSessionTest, CanPool) {
// Load a cert that is valid for:
// www.example.org
// mail.example.org
// www.example.com
- base::FilePath certs_dir = GetTestCertsDirectory();
- CertVerifyResult result;
ProofVerifyDetailsChromium details;
details.cert_verify_result.verified_cert =
- ImportCertFromFile(certs_dir, "spdy_pooling.pem");
+ ImportCertFromFile(GetTestCertsDirectory(), "spdy_pooling.pem");
ASSERT_TRUE(details.cert_verify_result.verified_cert);
session_.OnProofVerifyDetailsAvailable(details);
@@ -196,18 +198,15 @@ TEST_P(QuicClientSessionTest, DISABLED_CanPool) {
EXPECT_FALSE(session_.CanPool("mail.google.com"));
}
-// TODO(rch): re-enable this.
-TEST_P(QuicClientSessionTest, DISABLED_ConnectionPooledWithTlsChannelId) {
+TEST_P(QuicClientSessionTest, ConnectionPooledWithTlsChannelId) {
// Load a cert that is valid for:
// www.example.org
// mail.example.org
// www.example.com
- base::FilePath certs_dir = GetTestCertsDirectory();
- CertVerifyResult result;
ProofVerifyDetailsChromium details;
details.cert_verify_result.verified_cert =
- ImportCertFromFile(certs_dir, "spdy_pooling.pem");
+ ImportCertFromFile(GetTestCertsDirectory(), "spdy_pooling.pem");
ASSERT_TRUE(details.cert_verify_result.verified_cert);
session_.OnProofVerifyDetailsAvailable(details);
@@ -220,6 +219,51 @@ TEST_P(QuicClientSessionTest, DISABLED_ConnectionPooledWithTlsChannelId) {
EXPECT_FALSE(session_.CanPool("mail.google.com"));
}
+TEST_P(QuicClientSessionTest, ConnectionNotPooledWithDifferentPin) {
+ uint8 primary_pin = 1;
+ uint8 backup_pin = 2;
+ uint8 bad_pin = 3;
+ AddPin(&transport_security_state_, "mail.example.org", primary_pin,
+ backup_pin);
+
+ ProofVerifyDetailsChromium details;
+ details.cert_verify_result.verified_cert =
+ ImportCertFromFile(GetTestCertsDirectory(), "spdy_pooling.pem");
+ details.cert_verify_result.is_issued_by_known_root = true;
+ details.cert_verify_result.public_key_hashes.push_back(
+ GetTestHashValue(bad_pin));
+
+ ASSERT_TRUE(details.cert_verify_result.verified_cert);
+
+ session_.OnProofVerifyDetailsAvailable(details);
+ CompleteCryptoHandshake();
+ QuicClientSessionPeer::SetChannelIDSent(&session_, true);
+
+ EXPECT_FALSE(session_.CanPool("mail.example.org"));
+}
+
+TEST_P(QuicClientSessionTest, ConnectionPooledWithMatchingPin) {
+ uint8 primary_pin = 1;
+ uint8 backup_pin = 2;
+ AddPin(&transport_security_state_, "mail.example.org", primary_pin,
+ backup_pin);
+
+ ProofVerifyDetailsChromium details;
+ details.cert_verify_result.verified_cert =
+ ImportCertFromFile(GetTestCertsDirectory(), "spdy_pooling.pem");
+ details.cert_verify_result.is_issued_by_known_root = true;
+ details.cert_verify_result.public_key_hashes.push_back(
+ GetTestHashValue(primary_pin));
+
+ ASSERT_TRUE(details.cert_verify_result.verified_cert);
+
+ session_.OnProofVerifyDetailsAvailable(details);
+ CompleteCryptoHandshake();
+ QuicClientSessionPeer::SetChannelIDSent(&session_, true);
+
+ EXPECT_TRUE(session_.CanPool("mail.example.org"));
+}
+
} // namespace
} // namespace test
} // namespace net
diff --git a/net/quic/quic_http_stream_test.cc b/net/quic/quic_http_stream_test.cc
index 5e46258..932f566 100644
--- a/net/quic/quic_http_stream_test.cc
+++ b/net/quic/quic_http_stream_test.cc
@@ -11,6 +11,7 @@
#include "net/base/upload_bytes_element_reader.h"
#include "net/base/upload_data_stream.h"
#include "net/http/http_response_headers.h"
+#include "net/http/transport_security_state.h"
#include "net/quic/congestion_control/receive_algorithm_interface.h"
#include "net/quic/congestion_control/send_algorithm_interface.h"
#include "net/quic/crypto/crypto_protocol.h"
@@ -214,6 +215,7 @@ class QuicHttpStreamTest : public ::testing::TestWithParam<QuicVersion> {
scoped_ptr<DatagramClientSocket>(socket),
writer_.Pass(), NULL,
&crypto_client_stream_factory_,
+ &transport_security_state_,
make_scoped_ptr((QuicServerInfo*)NULL),
QuicServerId(kServerHostname, kServerPort,
false, PRIVACY_MODE_DISABLED),
@@ -299,6 +301,7 @@ class QuicHttpStreamTest : public ::testing::TestWithParam<QuicVersion> {
testing::StrictMock<MockConnectionVisitor> visitor_;
scoped_ptr<QuicHttpStream> stream_;
scoped_ptr<QuicDefaultPacketWriter> writer_;
+ TransportSecurityState transport_security_state_;
scoped_ptr<QuicClientSession> session_;
QuicCryptoClientConfig crypto_config_;
TestCompletionCallback callback_;
diff --git a/net/quic/quic_stream_factory.cc b/net/quic/quic_stream_factory.cc
index ea30b2e..1baf4c8 100644
--- a/net/quic/quic_stream_factory.cc
+++ b/net/quic/quic_stream_factory.cc
@@ -861,8 +861,8 @@ int QuicStreamFactory::CreateSession(
*session = new QuicClientSession(
connection, socket.Pass(), writer.Pass(), this,
- quic_crypto_client_stream_factory_, server_info.Pass(), server_id,
- config, &crypto_config_,
+ quic_crypto_client_stream_factory_, transport_security_state_,
+ server_info.Pass(), server_id, config, &crypto_config_,
base::MessageLoop::current()->message_loop_proxy().get(),
net_log.net_log());
(*session)->InitializeSession();
diff --git a/net/quic/quic_stream_factory.h b/net/quic/quic_stream_factory.h
index 574bf6f..262e276 100644
--- a/net/quic/quic_stream_factory.h
+++ b/net/quic/quic_stream_factory.h
@@ -238,6 +238,7 @@ class NET_EXPORT_PRIVATE QuicStreamFactory
HostResolver* host_resolver_;
ClientSocketFactory* client_socket_factory_;
base::WeakPtr<HttpServerProperties> http_server_properties_;
+ TransportSecurityState* transport_security_state_;
QuicServerInfoFactory* quic_server_info_factory_;
QuicCryptoClientStreamFactory* quic_crypto_client_stream_factory_;
QuicRandom* random_generator_;
diff --git a/net/quic/quic_stream_factory_test.cc b/net/quic/quic_stream_factory_test.cc
index df66134..59f97f5 100644
--- a/net/quic/quic_stream_factory_test.cc
+++ b/net/quic/quic_stream_factory_test.cc
@@ -360,8 +360,7 @@ TEST_P(QuicStreamFactoryTest, CreateHttpVsHttps) {
EXPECT_TRUE(socket_data2.at_write_eof());
}
-// TODO(rch): re-enable this.
-TEST_P(QuicStreamFactoryTest, DISABLED_Pooling) {
+TEST_P(QuicStreamFactoryTest, Pooling) {
MockRead reads[] = {
MockRead(ASYNC, OK, 0) // EOF
};
@@ -477,8 +476,7 @@ TEST_P(QuicStreamFactoryTest, NoPoolingAfterGoAway) {
EXPECT_TRUE(socket_data2.at_write_eof());
}
-// TODO(rch): re-enable this.
-TEST_P(QuicStreamFactoryTest, DISABLED_HttpsPooling) {
+TEST_P(QuicStreamFactoryTest, HttpsPooling) {
MockRead reads[] = {
MockRead(ASYNC, OK, 0) // EOF
};
diff --git a/net/socket/ssl_client_socket_pool_unittest.cc b/net/socket/ssl_client_socket_pool_unittest.cc
index 14b0662..ad59889 100644
--- a/net/socket/ssl_client_socket_pool_unittest.cc
+++ b/net/socket/ssl_client_socket_pool_unittest.cc
@@ -1257,8 +1257,7 @@ TEST_P(SSLClientSocketPoolTest, NeedProxyAuth) {
EXPECT_FALSE(tunnel_handle->socket()->IsConnected());
}
-// TODO(rch): re-enable this.
-TEST_P(SSLClientSocketPoolTest, DISABLED_IPPooling) {
+TEST_P(SSLClientSocketPoolTest, IPPooling) {
const int kTestPort = 80;
struct TestHosts {
std::string name;
diff --git a/net/spdy/spdy_session.cc b/net/spdy/spdy_session.cc
index 64e2c04..51c6ee7 100644
--- a/net/spdy/spdy_session.cc
+++ b/net/spdy/spdy_session.cc
@@ -29,10 +29,12 @@
#include "net/base/net_log.h"
#include "net/base/net_util.h"
#include "net/cert/asn1_util.h"
+#include "net/cert/cert_verify_result.h"
#include "net/http/http_log_util.h"
#include "net/http/http_network_session.h"
#include "net/http/http_server_properties.h"
#include "net/http/http_util.h"
+#include "net/http/transport_security_state.h"
#include "net/spdy/spdy_buffer_producer.h"
#include "net/spdy/spdy_frame_builder.h"
#include "net/spdy/spdy_http_utils.h"
@@ -529,9 +531,47 @@ SpdySession::PushedStreamInfo::PushedStreamInfo(
SpdySession::PushedStreamInfo::~PushedStreamInfo() {}
+// static
+bool SpdySession::CanPool(TransportSecurityState* transport_security_state,
+ const SSLInfo& ssl_info,
+ const std::string& old_hostname,
+ const std::string& new_hostname) {
+ // Pooling is prohibited if the server cert is not valid for the new domain,
+ // and for connections on which client certs were sent. It is also prohibited
+ // when channel ID was sent if the hosts are from different eTLDs+1.
+ if (IsCertStatusError(ssl_info.cert_status))
+ return false;
+
+ if (ssl_info.client_cert_sent)
+ return false;
+
+ if (ssl_info.channel_id_sent &&
+ ChannelIDService::GetDomainForHost(new_hostname) !=
+ ChannelIDService::GetDomainForHost(old_hostname)) {
+ return false;
+ }
+
+ bool unused = false;
+ if (!ssl_info.cert->VerifyNameMatch(new_hostname, &unused))
+ return false;
+
+ std::string pinning_failure_log;
+ if (!transport_security_state->CheckPublicKeyPins(
+ new_hostname,
+ true, /* sni_available */
+ ssl_info.is_issued_by_known_root,
+ ssl_info.public_key_hashes,
+ &pinning_failure_log)) {
+ return false;
+ }
+
+ return true;
+}
+
SpdySession::SpdySession(
const SpdySessionKey& spdy_session_key,
const base::WeakPtr<HttpServerProperties>& http_server_properties,
+ TransportSecurityState* transport_security_state,
bool verify_domain_authentication,
bool enable_sending_initial_data,
bool enable_compression,
@@ -547,6 +587,7 @@ SpdySession::SpdySession(
spdy_session_key_(spdy_session_key),
pool_(NULL),
http_server_properties_(http_server_properties),
+ transport_security_state_(transport_security_state),
read_buffer_(new IOBuffer(kReadBufferSize)),
stream_hi_water_mark_(kFirstStreamId),
num_pushed_streams_(0u),
@@ -714,18 +755,8 @@ bool SpdySession::VerifyDomainAuthentication(const std::string& domain) {
if (!GetSSLInfo(&ssl_info, &was_npn_negotiated, &protocol_negotiated))
return true; // This is not a secure session, so all domains are okay.
- // Disable pooling for secure sessions.
- // TODO(rch): re-enable this.
- return false;
-#if 0
- bool unused = false;
- return
- !ssl_info.client_cert_sent &&
- (!ssl_info.channel_id_sent ||
- (ChannelIDService::GetDomainForHost(domain) ==
- ChannelIDService::GetDomainForHost(host_port_pair().host()))) &&
- ssl_info.cert->VerifyNameMatch(domain, &unused);
-#endif
+ return CanPool(transport_security_state_, ssl_info,
+ host_port_pair().host(), domain);
}
int SpdySession::GetPushStream(
diff --git a/net/spdy/spdy_session.h b/net/spdy/spdy_session.h
index 4037e03..d2da863 100644
--- a/net/spdy/spdy_session.h
+++ b/net/spdy/spdy_session.h
@@ -70,6 +70,7 @@ class BoundNetLog;
struct LoadTimingInfo;
class SpdyStream;
class SSLInfo;
+class TransportSecurityState;
// NOTE: There's an enum of the same name (also with numeric suffixes)
// in histograms.xml. Be sure to add new values there also.
@@ -222,6 +223,13 @@ class NET_EXPORT SpdySession : public BufferedSpdyFramerVisitorInterface,
FLOW_CONTROL_STREAM_AND_SESSION
};
+ // Returns true if |hostname| can be pooled into an existing connection
+ // associated with |ssl_info|.
+ static bool CanPool(TransportSecurityState* transport_security_state,
+ const SSLInfo& ssl_info,
+ const std::string& old_hostname,
+ const std::string& new_hostname);
+
// Create a new SpdySession.
// |spdy_session_key| is the host/port that this session connects to, privacy
// and proxy configuration settings that it's using.
@@ -229,6 +237,7 @@ class NET_EXPORT SpdySession : public BufferedSpdyFramerVisitorInterface,
// network events to.
SpdySession(const SpdySessionKey& spdy_session_key,
const base::WeakPtr<HttpServerProperties>& http_server_properties,
+ TransportSecurityState* transport_security_state,
bool verify_domain_authentication,
bool enable_sending_initial_data,
bool enable_compression,
@@ -963,6 +972,8 @@ class NET_EXPORT SpdySession : public BufferedSpdyFramerVisitorInterface,
SpdySessionPool* pool_;
const base::WeakPtr<HttpServerProperties> http_server_properties_;
+ TransportSecurityState* transport_security_state_;
+
// The socket handle for this session.
scoped_ptr<ClientSocketHandle> connection_;
diff --git a/net/spdy/spdy_session_pool.cc b/net/spdy/spdy_session_pool.cc
index 189c945..d839785 100644
--- a/net/spdy/spdy_session_pool.cc
+++ b/net/spdy/spdy_session_pool.cc
@@ -31,6 +31,7 @@ SpdySessionPool::SpdySessionPool(
HostResolver* resolver,
SSLConfigService* ssl_config_service,
const base::WeakPtr<HttpServerProperties>& http_server_properties,
+ TransportSecurityState* transport_security_state,
bool force_single_domain,
bool enable_compression,
bool enable_ping_based_connection_checking,
@@ -41,6 +42,7 @@ SpdySessionPool::SpdySessionPool(
SpdySessionPool::TimeFunc time_func,
const std::string& trusted_spdy_proxy)
: http_server_properties_(http_server_properties),
+ transport_security_state_(transport_security_state),
ssl_config_service_(ssl_config_service),
resolver_(resolver),
verify_domain_authentication_(true),
@@ -98,6 +100,7 @@ base::WeakPtr<SpdySession> SpdySessionPool::CreateAvailableSessionFromSocket(
scoped_ptr<SpdySession> new_session(
new SpdySession(key,
http_server_properties_,
+ transport_security_state_,
verify_domain_authentication_,
enable_sending_initial_data_,
enable_compression_,
diff --git a/net/spdy/spdy_session_pool.h b/net/spdy/spdy_session_pool.h
index 0fad5d2..2fbb030 100644
--- a/net/spdy/spdy_session_pool.h
+++ b/net/spdy/spdy_session_pool.h
@@ -34,6 +34,7 @@ class ClientSocketHandle;
class HostResolver;
class HttpServerProperties;
class SpdySession;
+class TransportSecurityState;
// This is a very simple pool for open SpdySessions.
class NET_EXPORT SpdySessionPool
@@ -50,6 +51,7 @@ class NET_EXPORT SpdySessionPool
HostResolver* host_resolver,
SSLConfigService* ssl_config_service,
const base::WeakPtr<HttpServerProperties>& http_server_properties,
+ TransportSecurityState* transport_security_state,
bool force_single_domain,
bool enable_compression,
bool enable_ping_based_connection_checking,
@@ -191,6 +193,8 @@ class NET_EXPORT SpdySessionPool
const base::WeakPtr<HttpServerProperties> http_server_properties_;
+ TransportSecurityState* transport_security_state_;
+
// The set of all sessions. This is a superset of the sessions in
// |available_sessions_|.
//
diff --git a/net/spdy/spdy_session_unittest.cc b/net/spdy/spdy_session_unittest.cc
index 1fa5f2e..8194fe7 100644
--- a/net/spdy/spdy_session_unittest.cc
+++ b/net/spdy/spdy_session_unittest.cc
@@ -4,6 +4,7 @@
#include "net/spdy/spdy_session.h"
+#include "base/base64.h"
#include "base/bind.h"
#include "base/callback.h"
#include "base/memory/scoped_ptr.h"
@@ -2375,7 +2376,7 @@ TEST_P(SpdySessionTest, CloseActivatedStreamThatClosesSession) {
EXPECT_TRUE(session == NULL);
}
-TEST_P(SpdySessionTest, DISABLED_VerifyDomainAuthentication) {
+TEST_P(SpdySessionTest, VerifyDomainAuthentication) {
session_deps_.host_resolver->set_synchronous_mode(true);
MockConnect connect_data(SYNCHRONOUS, OK);
@@ -2417,8 +2418,7 @@ TEST_P(SpdySessionTest, DISABLED_VerifyDomainAuthentication) {
EXPECT_FALSE(session->VerifyDomainAuthentication("mail.google.com"));
}
-// TODO(rch): re-enable this.
-TEST_P(SpdySessionTest, DISABLED_ConnectionPooledWithTlsChannelId) {
+TEST_P(SpdySessionTest, ConnectionPooledWithTlsChannelId) {
session_deps_.host_resolver->set_synchronous_mode(true);
MockConnect connect_data(SYNCHRONOUS, OK);
@@ -5001,4 +5001,108 @@ TEST(MapNetErrorToGoAwayStatus, MapsValue) {
CHECK_EQ(GOAWAY_PROTOCOL_ERROR, MapNetErrorToGoAwayStatus(ERR_UNEXPECTED));
}
+TEST(CanPoolTest, CanPool) {
+ // Load a cert that is valid for:
+ // www.example.org
+ // mail.example.org
+ // www.example.com
+
+ TransportSecurityState tss;
+ SSLInfo ssl_info;
+ ssl_info.cert = ImportCertFromFile(GetTestCertsDirectory(),
+ "spdy_pooling.pem");
+
+ EXPECT_TRUE(SpdySession::CanPool(
+ &tss, ssl_info, "www.example.org", "www.example.org"));
+ EXPECT_TRUE(SpdySession::CanPool(
+ &tss, ssl_info, "www.example.org", "mail.example.org"));
+ EXPECT_TRUE(SpdySession::CanPool(
+ &tss, ssl_info, "www.example.org", "mail.example.com"));
+ EXPECT_FALSE(SpdySession::CanPool(
+ &tss, ssl_info, "www.example.org", "mail.google.com"));
+}
+
+TEST(CanPoolTest, CanNotPoolWithCertErrors) {
+ // Load a cert that is valid for:
+ // www.example.org
+ // mail.example.org
+ // www.example.com
+
+ TransportSecurityState tss;
+ SSLInfo ssl_info;
+ ssl_info.cert = ImportCertFromFile(GetTestCertsDirectory(),
+ "spdy_pooling.pem");
+ ssl_info.cert_status = CERT_STATUS_REVOKED;
+
+ EXPECT_FALSE(SpdySession::CanPool(
+ &tss, ssl_info, "www.example.org", "mail.example.org"));
+}
+
+TEST(CanPoolTest, CanNotPoolWithClientCerts) {
+ // Load a cert that is valid for:
+ // www.example.org
+ // mail.example.org
+ // www.example.com
+
+ TransportSecurityState tss;
+ SSLInfo ssl_info;
+ ssl_info.cert = ImportCertFromFile(GetTestCertsDirectory(),
+ "spdy_pooling.pem");
+ ssl_info.client_cert_sent = true;
+
+ EXPECT_FALSE(SpdySession::CanPool(
+ &tss, ssl_info, "www.example.org", "mail.example.org"));
+}
+
+TEST(CanPoolTest, CanNotPoolAcrossETLDsWithChannelID) {
+ // Load a cert that is valid for:
+ // www.example.org
+ // mail.example.org
+ // www.example.com
+
+ TransportSecurityState tss;
+ SSLInfo ssl_info;
+ ssl_info.cert = ImportCertFromFile(GetTestCertsDirectory(),
+ "spdy_pooling.pem");
+ ssl_info.channel_id_sent = true;
+
+ EXPECT_TRUE(SpdySession::CanPool(
+ &tss, ssl_info, "www.example.org", "mail.example.org"));
+ EXPECT_FALSE(SpdySession::CanPool(
+ &tss, ssl_info, "www.example.org", "www.example.com"));
+}
+
+TEST(CanPoolTest, CanNotPoolWithBadPins) {
+ uint8 primary_pin = 1;
+ uint8 backup_pin = 2;
+ uint8 bad_pin = 3;
+ TransportSecurityState tss;
+ test::AddPin(&tss, "mail.example.org", primary_pin, backup_pin);
+
+ SSLInfo ssl_info;
+ ssl_info.cert = ImportCertFromFile(GetTestCertsDirectory(),
+ "spdy_pooling.pem");
+ ssl_info.is_issued_by_known_root = true;
+ ssl_info.public_key_hashes.push_back(test::GetTestHashValue(bad_pin));
+
+ EXPECT_FALSE(SpdySession::CanPool(
+ &tss, ssl_info, "www.example.org", "mail.example.org"));
+}
+
+TEST(CanPoolTest, CanPoolWithAcceptablePins) {
+ uint8 primary_pin = 1;
+ uint8 backup_pin = 2;
+ TransportSecurityState tss;
+ test::AddPin(&tss, "mail.example.org", primary_pin, backup_pin);
+
+ SSLInfo ssl_info;
+ ssl_info.cert = ImportCertFromFile(GetTestCertsDirectory(),
+ "spdy_pooling.pem");
+ ssl_info.is_issued_by_known_root = true;
+ ssl_info.public_key_hashes.push_back(test::GetTestHashValue(primary_pin));
+
+ EXPECT_TRUE(SpdySession::CanPool(
+ &tss, ssl_info, "www.example.org", "mail.example.org"));
+}
+
} // namespace net
diff --git a/net/spdy/spdy_test_utils.cc b/net/spdy/spdy_test_utils.cc
index e33a08b..7627abe 100644
--- a/net/spdy/spdy_test_utils.cc
+++ b/net/spdy/spdy_test_utils.cc
@@ -7,10 +7,13 @@
#include <cstring>
#include <vector>
+#include "base/base64.h"
#include "base/logging.h"
#include "base/memory/scoped_ptr.h"
#include "base/strings/string_number_conversions.h"
#include "base/sys_byteorder.h"
+#include "net/http/transport_security_state.h"
+#include "net/ssl/ssl_info.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace net {
@@ -139,6 +142,36 @@ std::string a2b_hex(const char* hex_data) {
return result;
}
+HashValue GetTestHashValue(uint8_t label) {
+ HashValue hash_value(HASH_VALUE_SHA256);
+ memset(hash_value.data(), label, hash_value.size());
+ return hash_value;
+}
+
+std::string GetTestPin(uint8_t label) {
+ HashValue hash_value = GetTestHashValue(label);
+ std::string base64;
+ base::Base64Encode(base::StringPiece(
+ reinterpret_cast<char*>(hash_value.data()), hash_value.size()), &base64);
+
+ return std::string("pin-sha256=\"") + base64 + "\"";
+}
+
+void AddPin(TransportSecurityState* state,
+ const std::string& host,
+ uint8_t primary_label,
+ uint8_t backup_label) {
+ std::string primary_pin = GetTestPin(primary_label);
+ std::string backup_pin = GetTestPin(backup_label);
+ std::string header = "max-age = 10000; " + primary_pin + "; " + backup_pin;
+
+ // Construct a fake SSLInfo that will pass AddHPKPHeader's checks.
+ SSLInfo ssl_info;
+ ssl_info.is_issued_by_known_root = true;
+ ssl_info.public_key_hashes.push_back(GetTestHashValue(primary_label));
+ EXPECT_TRUE(state->AddHPKPHeader(host, header, ssl_info));
+}
+
} // namespace test
} // namespace net
diff --git a/net/spdy/spdy_test_utils.h b/net/spdy/spdy_test_utils.h
index 439311e..14bc8ef 100644
--- a/net/spdy/spdy_test_utils.h
+++ b/net/spdy/spdy_test_utils.h
@@ -5,12 +5,17 @@
#ifndef NET_SPDY_TEST_UTILS_H_
#define NET_SPDY_TEST_UTILS_H_
+#include <stdint.h>
+
#include <string>
#include "net/spdy/spdy_protocol.h"
namespace net {
+class HashValue;
+class TransportSecurityState;
+
namespace test {
std::string HexDumpWithMarks(const unsigned char* data, int length,
@@ -33,6 +38,19 @@ void SetFrameLength(SpdyFrame* frame,
std::string a2b_hex(const char* hex_data);
+// Returns a SHA1 HashValue in which each byte has the value |label|.
+HashValue GetTestHashValue(uint8_t label);
+
+// Returns SHA1 pinning header for the of the base64 encoding of
+// GetTestHashValue(|label|).
+std::string GetTestPin(uint8_t label);
+
+// Adds a pin for |host| to |state|.
+void AddPin(TransportSecurityState* state,
+ const std::string& host,
+ uint8_t primary_label,
+ uint8_t backup_label);
+
} // namespace test
} // namespace net