summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorrch@chromium.org <rch@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2014-07-02 07:15:12 +0000
committerrch@chromium.org <rch@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2014-07-02 07:15:12 +0000
commitf21ec37668eed3a25ac75df2b10c3b2c97b144d6 (patch)
treeeb952f904159287b0b55537c13c9aec6d4f9e507
parent744c011c8de25dd3d6450533d9265a0bc0562118 (diff)
downloadchromium_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.cc30
-rw-r--r--net/quic/quic_client_session.h5
-rw-r--r--net/quic/quic_client_session_test.cc67
-rw-r--r--net/quic/quic_crypto_client_stream.cc6
-rw-r--r--net/quic/quic_crypto_client_stream.h5
-rw-r--r--net/quic/test_tools/quic_client_session_peer.cc6
-rw-r--r--net/quic/test_tools/quic_client_session_peer.h4
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);
};