diff options
author | rch@chromium.org <rch@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2014-07-02 07:15:12 +0000 |
---|---|---|
committer | rch@chromium.org <rch@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2014-07-02 07:15:12 +0000 |
commit | f21ec37668eed3a25ac75df2b10c3b2c97b144d6 (patch) | |
tree | eb952f904159287b0b55537c13c9aec6d4f9e507 | |
parent | 744c011c8de25dd3d6450533d9265a0bc0562118 (diff) | |
download | chromium_src-f21ec37668eed3a25ac75df2b10c3b2c97b144d6.zip chromium_src-f21ec37668eed3a25ac75df2b10c3b2c97b144d6.tar.gz chromium_src-f21ec37668eed3a25ac75df2b10c3b2c97b144d6.tar.bz2 |
Restrict QUIC session pool when channel ID is present.
Review URL: https://codereview.chromium.org/355293003
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@280963 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r-- | net/quic/quic_client_session.cc | 30 | ||||
-rw-r--r-- | net/quic/quic_client_session.h | 5 | ||||
-rw-r--r-- | net/quic/quic_client_session_test.cc | 67 | ||||
-rw-r--r-- | net/quic/quic_crypto_client_stream.cc | 6 | ||||
-rw-r--r-- | net/quic/quic_crypto_client_stream.h | 5 | ||||
-rw-r--r-- | net/quic/test_tools/quic_client_session_peer.cc | 6 | ||||
-rw-r--r-- | net/quic/test_tools/quic_client_session_peer.h | 4 |
7 files changed, 112 insertions, 11 deletions
diff --git a/net/quic/quic_client_session.cc b/net/quic/quic_client_session.cc index 24b6db2..39c2e71 100644 --- a/net/quic/quic_client_session.cc +++ b/net/quic/quic_client_session.cc @@ -20,6 +20,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/ssl/server_bound_cert_service.h" #include "net/ssl/ssl_connection_status_flags.h" #include "net/ssl/ssl_info.h" #include "net/udp/datagram_client_socket.h" @@ -145,6 +146,7 @@ QuicClientSession::QuicClientSession( NetLog* net_log) : QuicClientSessionBase(connection, config), + server_host_port_(server_id.host_port_pair()), require_confirmation_(false), stream_factory_(stream_factory), socket_(socket.Pass()), @@ -424,7 +426,7 @@ bool QuicClientSession::GetSSLInfo(SSLInfo* ssl_info) const { ssl_info->connection_status = ssl_connection_status; ssl_info->client_cert_sent = false; - ssl_info->channel_id_sent = false; + ssl_info->channel_id_sent = crypto_stream_->WasChannelIDSent(); ssl_info->security_bits = security_bits; ssl_info->handshake_type = SSLInfo::HANDSHAKE_FULL; return true; @@ -479,17 +481,31 @@ int QuicClientSession::GetNumSentClientHellos() const { } bool QuicClientSession::CanPool(const std::string& hostname) const { - // TODO(rch): When QUIC supports channel ID or client certificates, this - // logic will need to be revised. DCHECK(connection()->connected()); SSLInfo ssl_info; - bool unused = false; if (!GetSSLInfo(&ssl_info) || !ssl_info.cert) { // We can always pool with insecure QUIC sessions. return true; } - // Only pool secure QUIC sessions if the cert matches the new hostname. - return ssl_info.cert->VerifyNameMatch(hostname, &unused); + + bool unused = false; + // Pooling is prohibited for connections on which client certs were + // sent. It is also prohibited for when channel ID was sent if the + // hosts are from different eTLDs. And of course, it is prohibited + // if the server cert is not valid for the new domain. + if (!ssl_info.cert->VerifyNameMatch(hostname, &unused)) + return false; + + if (ssl_info.client_cert_sent) + return false; + + if (ssl_info.channel_id_sent && + ServerBoundCertService::GetDomainForHost(hostname) != + ServerBoundCertService::GetDomainForHost(server_host_port_.host())) { + return false; + } + + return true; } QuicDataStream* QuicClientSession::CreateIncomingDataStream( @@ -725,8 +741,6 @@ void QuicClientSession::CloseAllObservers(int net_error) { base::Value* QuicClientSession::GetInfoAsValue( const std::set<HostPortPair>& aliases) { base::DictionaryValue* dict = new base::DictionaryValue(); - // TODO(rch): remove "host_port_pair" when Chrome 34 is stable. - dict->SetString("host_port_pair", aliases.begin()->ToString()); dict->SetString("version", QuicVersionToString(connection()->version())); dict->SetInteger("open_streams", GetNumOpenStreams()); base::ListValue* stream_list = new base::ListValue(); diff --git a/net/quic/quic_client_session.h b/net/quic/quic_client_session.h index 7fbe3db..b46c0ab 100644 --- a/net/quic/quic_client_session.h +++ b/net/quic/quic_client_session.h @@ -87,8 +87,8 @@ class NET_EXPORT_PRIVATE QuicClientSession : public QuicClientSessionBase { DISALLOW_COPY_AND_ASSIGN(StreamRequest); }; - // Constructs a new session which will own |connection| and |helper|, but - // not |stream_factory|, which must outlive this session. + // Constructs a new session connected to |server_id| which will own + // |connection|, but not |stream_factory|, which must outlive this session. // TODO(rch): decouple the factory from the session via a Delegate interface. QuicClientSession(QuicConnection* connection, scoped_ptr<DatagramClientSocket> socket, @@ -219,6 +219,7 @@ class NET_EXPORT_PRIVATE QuicClientSession : public QuicClientSessionBase { void OnConnectTimeout(); + const HostPortPair server_host_port_; bool require_confirmation_; scoped_ptr<QuicCryptoClientStream> crypto_stream_; QuicStreamFactory* stream_factory_; diff --git a/net/quic/quic_client_session_test.cc b/net/quic/quic_client_session_test.cc index 264fbfa..d93ecd3 100644 --- a/net/quic/quic_client_session_test.cc +++ b/net/quic/quic_client_session_test.cc @@ -6,11 +6,15 @@ #include <vector> +#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/quic/crypto/aes_128_gcm_12_encrypter.h" #include "net/quic/crypto/crypto_protocol.h" +#include "net/quic/crypto/proof_verifier_chromium.h" #include "net/quic/crypto/quic_decrypter.h" #include "net/quic/crypto/quic_encrypter.h" #include "net/quic/crypto/quic_server_info.h" @@ -20,6 +24,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/test/cert_test_util.h" #include "net/udp/datagram_client_socket.h" using testing::_; @@ -28,7 +33,7 @@ namespace net { namespace test { namespace { -const char kServerHostname[] = "www.example.com"; +const char kServerHostname[] = "www.example.org"; const uint16 kServerPort = 80; class TestPacketWriter : public QuicDefaultPacketWriter { @@ -61,6 +66,20 @@ class TestPacketWriter : public QuicDefaultPacketWriter { QuicPacketHeader header_; }; +class FakeChannelIDKey : public ChannelIDKey { + public: + // ChannelIDKey implementation + virtual bool Sign(base::StringPiece signed_data, + std::string* out_signature) const OVERRIDE { + *out_signature = ""; + return true; + } + + virtual std::string SerializeKey() const OVERRIDE { + return ""; + } +}; + class QuicClientSessionTest : public ::testing::TestWithParam<QuicVersion> { protected: QuicClientSessionTest() @@ -166,6 +185,52 @@ TEST_P(QuicClientSessionTest, GoAwayReceived) { EXPECT_EQ(NULL, session_.CreateOutgoingDataStream()); } +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"); + ASSERT_TRUE(details.cert_verify_result.verified_cert); + + session_.OnProofVerifyDetailsAvailable(details); + CompleteCryptoHandshake(); + + + EXPECT_TRUE(session_.CanPool("www.example.org")); + EXPECT_TRUE(session_.CanPool("mail.example.org")); + EXPECT_TRUE(session_.CanPool("mail.example.com")); + EXPECT_FALSE(session_.CanPool("mail.google.com")); +} + +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"); + ASSERT_TRUE(details.cert_verify_result.verified_cert); + + session_.OnProofVerifyDetailsAvailable(details); + CompleteCryptoHandshake(); + QuicClientSessionPeer::SetChannelIDKey(&session_, new FakeChannelIDKey); + + EXPECT_TRUE(session_.CanPool("www.example.org")); + EXPECT_TRUE(session_.CanPool("mail.example.org")); + EXPECT_FALSE(session_.CanPool("mail.example.com")); + EXPECT_FALSE(session_.CanPool("mail.google.com")); +} + } // namespace } // namespace test } // namespace net diff --git a/net/quic/quic_crypto_client_stream.cc b/net/quic/quic_crypto_client_stream.cc index f221fb6..f3a924b 100644 --- a/net/quic/quic_crypto_client_stream.cc +++ b/net/quic/quic_crypto_client_stream.cc @@ -109,6 +109,12 @@ int QuicCryptoClientStream::num_sent_client_hellos() const { return num_client_hellos_; } +bool QuicCryptoClientStream::WasChannelIDSent() const { + // TODO(rch): we should replace this with a boolean member so we + // can free the memory associated with the key after we're finished with it. + return channel_id_key_.get() != NULL; +} + // kMaxClientHellos is the maximum number of times that we'll send a client // hello. The value 3 accounts for: // * One failure due to an incorrect or missing source-address token. diff --git a/net/quic/quic_crypto_client_stream.h b/net/quic/quic_crypto_client_stream.h index 9a6ebb2..edb0c35 100644 --- a/net/quic/quic_crypto_client_stream.h +++ b/net/quic/quic_crypto_client_stream.h @@ -20,6 +20,7 @@ class QuicClientSessionBase; namespace test { class CryptoTestUtils; +class QuicClientSessionPeer; } // namespace test class NET_EXPORT_PRIVATE QuicCryptoClientStream : public QuicCryptoStream { @@ -44,6 +45,9 @@ class NET_EXPORT_PRIVATE QuicCryptoClientStream : public QuicCryptoStream { // than the number of round-trips needed for the handshake. int num_sent_client_hellos() const; + // Returns true if a channel ID was sent on this connection. + bool WasChannelIDSent() const; + private: // ChannelIDSourceCallbackImpl is passed as the callback method to // GetChannelIDKey. The ChannelIDSource calls this class with the result of @@ -86,6 +90,7 @@ class NET_EXPORT_PRIVATE QuicCryptoClientStream : public QuicCryptoStream { }; friend class test::CryptoTestUtils; + friend class test::QuicClientSessionPeer; enum State { STATE_IDLE, diff --git a/net/quic/test_tools/quic_client_session_peer.cc b/net/quic/test_tools/quic_client_session_peer.cc index e88da49..bf6c6c5 100644 --- a/net/quic/test_tools/quic_client_session_peer.cc +++ b/net/quic/test_tools/quic_client_session_peer.cc @@ -17,5 +17,11 @@ void QuicClientSessionPeer::SetMaxOpenStreams(QuicClientSession* session, default_streams); } +// static +void QuicClientSessionPeer::SetChannelIDKey(QuicClientSession* session, + ChannelIDKey* channel_id_key) { + session->crypto_stream_->channel_id_key_.reset(channel_id_key); +} + } // namespace test } // namespace net diff --git a/net/quic/test_tools/quic_client_session_peer.h b/net/quic/test_tools/quic_client_session_peer.h index 7217d9d..440982a 100644 --- a/net/quic/test_tools/quic_client_session_peer.h +++ b/net/quic/test_tools/quic_client_session_peer.h @@ -9,6 +9,7 @@ namespace net { +class ChannelIDKey; class QuicClientSession; namespace test { @@ -19,6 +20,9 @@ class QuicClientSessionPeer { size_t max_streams, size_t default_streams); + static void SetChannelIDKey(QuicClientSession* session, + ChannelIDKey* channel_id_key); + private: DISALLOW_COPY_AND_ASSIGN(QuicClientSessionPeer); }; |