diff options
author | rch@chromium.org <rch@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-03-13 03:23:57 +0000 |
---|---|---|
committer | rch@chromium.org <rch@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-03-13 03:23:57 +0000 |
commit | 72818ea6b7334c2a4b94aa78c4907c01e9720c1c (patch) | |
tree | 43520232e1d1a3a2d834d102af8984a67ecd61ce /net/quic | |
parent | 1ba66adaad90e014692e02290cdb83c7b038a286 (diff) | |
download | chromium_src-72818ea6b7334c2a4b94aa78c4907c01e9720c1c.zip chromium_src-72818ea6b7334c2a4b94aa78c4907c01e9720c1c.tar.gz chromium_src-72818ea6b7334c2a4b94aa78c4907c01e9720c1c.tar.bz2 |
Add QuicCryptoServerStream (and test) and get CryptoUtils working.
Review URL: https://chromiumcodereview.appspot.com/12452007
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@187757 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'net/quic')
-rw-r--r-- | net/quic/quic_crypto_client_stream_test.cc | 155 | ||||
-rw-r--r-- | net/quic/quic_crypto_server_stream.cc | 73 | ||||
-rw-r--r-- | net/quic/quic_crypto_server_stream.h | 41 | ||||
-rw-r--r-- | net/quic/quic_crypto_server_stream_test.cc | 122 | ||||
-rw-r--r-- | net/quic/test_tools/crypto_test_utils.cc | 12 |
5 files changed, 309 insertions, 94 deletions
diff --git a/net/quic/quic_crypto_client_stream_test.cc b/net/quic/quic_crypto_client_stream_test.cc index ed59716..29ae7cb 100644 --- a/net/quic/quic_crypto_client_stream_test.cc +++ b/net/quic/quic_crypto_client_stream_test.cc @@ -4,12 +4,14 @@ #include "net/quic/quic_crypto_client_stream.h" +#include "base/memory/scoped_ptr.h" #include "net/quic/crypto/quic_decrypter.h" #include "net/quic/crypto/quic_encrypter.h" +#include "net/quic/test_tools/crypto_test_utils.h" #include "net/quic/test_tools/quic_test_utils.h" - -using base::StringPiece; -using std::vector; +#include "net/quic/test_tools/simple_quic_framer.h" +#include "testing/gmock/include/gmock/gmock.h" +#include "testing/gtest/include/gtest/gtest.h" namespace net { namespace test { @@ -19,61 +21,85 @@ const char kServerHostname[] = "localhost"; class TestQuicVisitor : public NoOpFramerVisitor { public: - TestQuicVisitor() {} + TestQuicVisitor() + : frame_valid_(false) { + } // NoOpFramerVisitor - virtual void OnStreamFrame(const QuicStreamFrame& frame) OVERRIDE { + virtual void OnStreamFrame(const QuicStreamFrame& frame) { frame_ = frame; + frame_valid_ = true; } + bool frame_valid() const { + return frame_valid_; + } QuicStreamFrame* frame() { return &frame_; } private: QuicStreamFrame frame_; + bool frame_valid_; DISALLOW_COPY_AND_ASSIGN(TestQuicVisitor); }; -// The same as MockHelper, except that WritePacketToWire() checks whether -// the packet has the expected contents. -class TestMockHelper : public MockHelper { +// The same as MockSession, except that WriteData() is not mocked. +class TestMockSession : public MockSession { public: - TestMockHelper() : packet_count_(0) {} - virtual ~TestMockHelper() {} + TestMockSession(QuicConnection* connection, bool is_server) + : MockSession(connection, is_server) { + } + virtual ~TestMockSession() {} - virtual int WritePacketToWire(const QuicEncryptedPacket& packet, - int* error) OVERRIDE { - packet_count_++; + virtual QuicConsumedData WriteData(QuicStreamId id, base::StringPiece data, + QuicStreamOffset offset, bool fin) { + return QuicSession::WriteData(id, data, offset, fin); + } +}; - // The first packet should be ClientHello. - if (packet_count_ == 1) { - CheckClientHelloPacket(packet); - } +class QuicCryptoClientStreamTest : public ::testing::Test { + public: + QuicCryptoClientStreamTest() + : addr_(), + connection_(new PacketSavingConnection(1, addr_)), + session_(connection_, true), + stream_(&session_, kServerHostname) { + } - return MockHelper::WritePacketToWire(packet, error); + void CompleteCryptoHandshake() { + EXPECT_TRUE(stream_.CryptoConnect()); + CryptoTestUtils::HandshakeWithFakeServer(connection_, &stream_); } - private: - void CheckClientHelloPacket(const QuicEncryptedPacket& packet); + void ConstructHandshakeMessage() { + CryptoFramer framer; + message_data_.reset(framer.ConstructHandshakeMessage(message_)); + } - int packet_count_; + IPEndPoint addr_; + PacketSavingConnection* connection_; + TestMockSession session_; + QuicCryptoClientStream stream_; + CryptoHandshakeMessage message_; + scoped_ptr<QuicData> message_data_; }; -void TestMockHelper::CheckClientHelloPacket( - const QuicEncryptedPacket& packet) { - QuicFramer quic_framer(kQuicVersion1, - QuicDecrypter::Create(kNULL), - QuicEncrypter::Create(kNULL)); - TestQuicVisitor quic_visitor; - quic_framer.set_visitor(&quic_visitor); - ASSERT_TRUE(quic_framer.ProcessPacket(packet)); - EXPECT_EQ(kCryptoStreamId, quic_visitor.frame()->stream_id); - EXPECT_FALSE(quic_visitor.frame()->fin); - EXPECT_EQ(0u, quic_visitor.frame()->offset); - - // Check quic_visitor.frame()->data. - scoped_ptr<CryptoHandshakeMessage> chlo( - CryptoFramer::ParseMessage(quic_visitor.frame()->data)); +TEST_F(QuicCryptoClientStreamTest, NotInitiallyConected) { + EXPECT_FALSE(stream_.handshake_complete()); +} + +TEST_F(QuicCryptoClientStreamTest, ClientHelloContents) { + EXPECT_TRUE(stream_.CryptoConnect()); + + SimpleQuicFramer framer; + ASSERT_TRUE(framer.ProcessPacket(*connection_->packets_[0])); + ASSERT_EQ(1u, framer.stream_frames().size()); + const QuicStreamFrame& frame(framer.stream_frames()[0]); + EXPECT_EQ(kCryptoStreamId, frame.stream_id); + EXPECT_FALSE(frame.fin); + EXPECT_EQ(0u, frame.offset); + + scoped_ptr<CryptoHandshakeMessage> chlo(framer.HandshakeMessage(0)); EXPECT_EQ(kCHLO, chlo->tag); CryptoTagValueMap& tag_value_map = chlo->tag_value_map; @@ -103,9 +129,6 @@ void TestMockHelper::CheckClientHelloPacket( memcpy(&cipher[0], &tag_value_map[kAEAD][0], 4); EXPECT_EQ(kAESG, cipher[0]); - // TODO(agl): reenable these once the non-crypto parts of the handshake have - // been split from crypto/ -#if 0 // kICSL ASSERT_EQ(4u, tag_value_map[kICSL].size()); uint32 idle_lifetime; @@ -123,66 +146,20 @@ void TestMockHelper::CheckClientHelloPacket( CryptoTag congestion[1]; memcpy(&congestion[0], &tag_value_map[kCGST][0], 4); EXPECT_EQ(kQBIC, congestion[0]); -#endif -} - -// The same as MockSession, except that WriteData() is not mocked. -class TestMockSession : public MockSession { - public: - TestMockSession(QuicConnection* connection, bool is_server) - : MockSession(connection, is_server) { - } - virtual ~TestMockSession() {} - - virtual QuicConsumedData WriteData(QuicStreamId id, - StringPiece data, - QuicStreamOffset offset, - bool fin) OVERRIDE { - return QuicSession::WriteData(id, data, offset, fin); - } -}; - -class QuicCryptoClientStreamTest : public ::testing::Test { - public: - QuicCryptoClientStreamTest() - : connection_(new MockConnection(1, addr_, new TestMockHelper())), - session_(connection_, true), - stream_(&session_, kServerHostname) { - message_ = CreateShloMessage(&clock_, &random_, "www.google.com"); - ConstructHandshakeMessage(); - } - - void ConstructHandshakeMessage() { - CryptoFramer framer; - message_data_.reset(framer.ConstructHandshakeMessage(message_)); - } - - IPEndPoint addr_; - MockConnection* connection_; - TestMockSession session_; - MockClock clock_; - MockRandom random_; - QuicCryptoClientStream stream_; - CryptoHandshakeMessage message_; - scoped_ptr<QuicData> message_data_; -}; - -TEST_F(QuicCryptoClientStreamTest, NotInitiallyConected) { - EXPECT_FALSE(stream_.handshake_complete()); } TEST_F(QuicCryptoClientStreamTest, ConnectedAfterSHLO) { - stream_.CryptoConnect(); - stream_.ProcessData(message_data_->data(), message_data_->length()); + CompleteCryptoHandshake(); EXPECT_TRUE(stream_.handshake_complete()); } TEST_F(QuicCryptoClientStreamTest, MessageAfterHandshake) { - stream_.CryptoConnect(); - stream_.ProcessData(message_data_->data(), message_data_->length()); + CompleteCryptoHandshake(); EXPECT_CALL(*connection_, SendConnectionClose( QUIC_CRYPTO_MESSAGE_AFTER_HANDSHAKE_COMPLETE)); + message_.tag = kCHLO; + ConstructHandshakeMessage(); stream_.ProcessData(message_data_->data(), message_data_->length()); } diff --git a/net/quic/quic_crypto_server_stream.cc b/net/quic/quic_crypto_server_stream.cc new file mode 100644 index 0000000..0f4d4f4 --- /dev/null +++ b/net/quic/quic_crypto_server_stream.cc @@ -0,0 +1,73 @@ +// Copyright (c) 2012 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/quic/quic_crypto_server_stream.h" + +#include "net/quic/crypto/crypto_protocol.h" +#include "net/quic/crypto/crypto_utils.h" +#include "net/quic/quic_protocol.h" +#include "net/quic/quic_session.h" + +namespace net { + +QuicCryptoServerStream::QuicCryptoServerStream(QuicSession* session) + : QuicCryptoStream(session) { + config_.SetDefaults(); + // Use hardcoded crypto parameters for now. + CryptoHandshakeMessage extra_tags; + config_.ToHandshakeMessage(&extra_tags); + // TODO(agl): AddTestingConfig generates a new, random config. In the future + // this will be replaced with a real source of configs. + scoped_ptr<CryptoTagValueMap> config_tags( + crypto_config_.AddTestingConfig(session->connection()->random_generator(), + session->connection()->clock(), + extra_tags)); + // If we were using the same config in many servers then we would have to + // parse a QuicConfig from config_tags here. +} + +QuicCryptoServerStream::~QuicCryptoServerStream() { +} + +void QuicCryptoServerStream::OnHandshakeMessage( + const CryptoHandshakeMessage& message) { + // Do not process handshake messages after the handshake is complete. + if (handshake_complete()) { + CloseConnection(QUIC_CRYPTO_MESSAGE_AFTER_HANDSHAKE_COMPLETE); + return; + } + + if (message.tag != kCHLO) { + CloseConnection(QUIC_INVALID_CRYPTO_MESSAGE_TYPE); + return; + } + + string error_details; + QuicErrorCode error = config_.ProcessPeerHandshake( + message, CryptoUtils::LOCAL_PRIORITY, &negotiated_params_, + &error_details); + if (error != QUIC_NO_ERROR) { + CloseConnectionWithDetails(error, "negotiated params"); + return; + } + + CryptoHandshakeMessage shlo; + CryptoUtils::GenerateNonce(session()->connection()->clock(), + session()->connection()->random_generator(), + &server_nonce_); + QuicCryptoNegotiatedParams params; + crypto_config_.ProcessClientHello(message, server_nonce_, &shlo, ¶ms, + &error_details); + if (!error_details.empty()) { + DLOG(INFO) << "Rejecting CHLO: " << error_details; + } + config_.ToHandshakeMessage(&shlo); + SendHandshakeMessage(shlo); + + // TODO(rch): correctly validate the message + SetHandshakeComplete(QUIC_NO_ERROR); + return; +} + +} // namespace net diff --git a/net/quic/quic_crypto_server_stream.h b/net/quic/quic_crypto_server_stream.h new file mode 100644 index 0000000..5f9ddd1 --- /dev/null +++ b/net/quic/quic_crypto_server_stream.h @@ -0,0 +1,41 @@ +// Copyright (c) 2012 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_QUIC_QUIC_CRYPTO_SERVER_STREAM_H_ +#define NET_QUIC_QUIC_CRYPTO_SERVER_STREAM_H_ + +#include <string> + +#include "net/quic/crypto/crypto_handshake.h" +#include "net/quic/quic_crypto_stream.h" + +namespace net { + +class QuicSession; +struct CryptoHandshakeMessage; + +class NET_EXPORT_PRIVATE QuicCryptoServerStream : public QuicCryptoStream { + public: + explicit QuicCryptoServerStream(QuicSession* session); + virtual ~QuicCryptoServerStream(); + + // CryptoFramerVisitorInterface implementation + virtual void OnHandshakeMessage( + const CryptoHandshakeMessage& message) OVERRIDE; + + private: + // config_ contains non-crypto parameters that are negotiated in the crypto + // handshake. + QuicConfig config_; + // crypto_config_ contains crypto parameters for the handshake. + QuicCryptoServerConfig crypto_config_; + std::string server_nonce_; + + QuicNegotiatedParameters negotiated_params_; + QuicCryptoNegotiatedParams crypto_negotiated_params_; +}; + +} // namespace net + +#endif // NET_QUIC_QUIC_CRYPTO_SERVER_STREAM_H_ diff --git a/net/quic/quic_crypto_server_stream_test.cc b/net/quic/quic_crypto_server_stream_test.cc new file mode 100644 index 0000000..995cb6b --- /dev/null +++ b/net/quic/quic_crypto_server_stream_test.cc @@ -0,0 +1,122 @@ +// Copyright (c) 2012 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/quic/quic_crypto_server_stream.h" + +#include <map> +#include <vector> + +#include "base/memory/scoped_ptr.h" +#include "net/quic/crypto/crypto_framer.h" +#include "net/quic/crypto/crypto_handshake.h" +#include "net/quic/crypto/crypto_protocol.h" +#include "net/quic/crypto/crypto_utils.h" +#include "net/quic/crypto/quic_decrypter.h" +#include "net/quic/crypto/quic_encrypter.h" +#include "net/quic/quic_protocol.h" +#include "net/quic/quic_session.h" +#include "net/quic/test_tools/crypto_test_utils.h" +#include "net/quic/test_tools/quic_test_utils.h" +#include "testing/gmock/include/gmock/gmock.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace net { +class QuicConnection; +class ReliableQuicStream; +} // namespace net + +using testing::_; + +namespace net { +namespace test { +namespace { + +// TODO(agl): Use rch's utility class for parsing a message when committed. +class TestQuicVisitor : public NoOpFramerVisitor { + public: + TestQuicVisitor() {} + + // NoOpFramerVisitor + virtual void OnStreamFrame(const QuicStreamFrame& frame) { + frame_ = frame; + } + + QuicStreamFrame* frame() { return &frame_; } + + private: + QuicStreamFrame frame_; + + DISALLOW_COPY_AND_ASSIGN(TestQuicVisitor); +}; + +class TestSession: public QuicSession { + public: + TestSession(QuicConnection* connection, bool is_server) + : QuicSession(connection, is_server) { + } + + MOCK_METHOD1(CreateIncomingReliableStream, + ReliableQuicStream*(QuicStreamId id)); + MOCK_METHOD0(GetCryptoStream, QuicCryptoStream*()); + MOCK_METHOD0(CreateOutgoingReliableStream, ReliableQuicStream*()); +}; + +class QuicCryptoServerStreamTest : public ::testing::Test { + public: + QuicCryptoServerStreamTest() + : guid_(1), + addr_(), + connection_(new PacketSavingConnection(guid_, addr_)), + session_(connection_, true), + stream_(&session_) { + } + + void ConstructHandshakeMessage() { + CryptoFramer framer; + message_data_.reset(framer.ConstructHandshakeMessage(message_)); + } + + void CompleteCryptoHandshake() { + CryptoTestUtils::HandshakeWithFakeClient(connection_, &stream_); + } + + protected: + QuicGuid guid_; + IPEndPoint addr_; + PacketSavingConnection* connection_; + TestSession session_; + QuicCryptoServerStream stream_; + CryptoHandshakeMessage message_; + scoped_ptr<QuicData> message_data_; +}; + +TEST_F(QuicCryptoServerStreamTest, NotInitiallyConected) { + EXPECT_FALSE(stream_.handshake_complete()); +} + +TEST_F(QuicCryptoServerStreamTest, ConnectedAfterCHLO) { + CompleteCryptoHandshake(); + EXPECT_TRUE(stream_.handshake_complete()); +} + +TEST_F(QuicCryptoServerStreamTest, MessageAfterHandshake) { + CompleteCryptoHandshake(); + EXPECT_CALL(*connection_, SendConnectionClose( + QUIC_CRYPTO_MESSAGE_AFTER_HANDSHAKE_COMPLETE)); + message_.tag = kCHLO; + ConstructHandshakeMessage(); + stream_.ProcessData(message_data_->data(), message_data_->length()); +} + +TEST_F(QuicCryptoServerStreamTest, BadMessageType) { + message_.tag = kSHLO; + ConstructHandshakeMessage(); + EXPECT_CALL(*connection_, SendConnectionClose( + QUIC_INVALID_CRYPTO_MESSAGE_TYPE)); + stream_.ProcessData(message_data_->data(), message_data_->length()); +} + +} // namespace +} // namespace test +} // namespace net diff --git a/net/quic/test_tools/crypto_test_utils.cc b/net/quic/test_tools/crypto_test_utils.cc index 3da238b..a9c5e0d 100644 --- a/net/quic/test_tools/crypto_test_utils.cc +++ b/net/quic/test_tools/crypto_test_utils.cc @@ -3,13 +3,12 @@ // found in the LICENSE file. #include "net/quic/test_tools/crypto_test_utils.h" -/* + #include "net/quic/quic_crypto_client_stream.h" #include "net/quic/quic_crypto_server_stream.h" #include "net/quic/quic_crypto_stream.h" #include "net/quic/test_tools/quic_test_utils.h" #include "net/quic/test_tools/simple_quic_framer.h" -#include "net/util/ipaddress.h" namespace net { namespace test { @@ -64,7 +63,9 @@ void CryptoTestUtils::HandshakeWithFakeServer( PacketSavingConnection* client_conn, QuicCryptoStream* client) { QuicGuid guid(1); - SocketAddress addr(IPAddress::Loopback4(), 1); + IPAddressNumber ip; + CHECK(ParseIPLiteralToNumber("192.0.2.33", &ip)); + IPEndPoint addr = IPEndPoint(ip, 1); PacketSavingConnection* server_conn = new PacketSavingConnection(guid, addr); TestSession server_session(server_conn, true); @@ -81,7 +82,9 @@ void CryptoTestUtils::HandshakeWithFakeClient( PacketSavingConnection* server_conn, QuicCryptoStream* server) { QuicGuid guid(1); - SocketAddress addr(IPAddress::Loopback4(), 1); + IPAddressNumber ip; + CHECK(ParseIPLiteralToNumber("192.0.2.33", &ip)); + IPEndPoint addr = IPEndPoint(ip, 1); PacketSavingConnection* client_conn = new PacketSavingConnection(guid, addr); TestSession client_session(client_conn, true); @@ -94,4 +97,3 @@ void CryptoTestUtils::HandshakeWithFakeClient( } } // namespace test } // namespace net -*/ |