1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "net/quic/quic_crypto_server_stream.h"
10 #include "base/memory/scoped_ptr.h"
11 #include "net/quic/crypto/aes_128_gcm_encrypter.h"
12 #include "net/quic/crypto/crypto_framer.h"
13 #include "net/quic/crypto/crypto_handshake.h"
14 #include "net/quic/crypto/crypto_protocol.h"
15 #include "net/quic/crypto/crypto_server_config.h"
16 #include "net/quic/crypto/crypto_utils.h"
17 #include "net/quic/crypto/quic_decrypter.h"
18 #include "net/quic/crypto/quic_encrypter.h"
19 #include "net/quic/quic_crypto_client_stream.h"
20 #include "net/quic/quic_protocol.h"
21 #include "net/quic/quic_session.h"
22 #include "net/quic/test_tools/crypto_test_utils.h"
23 #include "net/quic/test_tools/quic_test_utils.h"
24 #include "testing/gmock/include/gmock/gmock.h"
25 #include "testing/gtest/include/gtest/gtest.h"
29 class ReliableQuicStream
;
38 // TODO(agl): Use rch's utility class for parsing a message when committed.
39 class TestQuicVisitor
: public NoOpFramerVisitor
{
44 virtual bool OnStreamFrame(const QuicStreamFrame
& frame
) OVERRIDE
{
49 QuicStreamFrame
* frame() { return &frame_
; }
52 QuicStreamFrame frame_
;
54 DISALLOW_COPY_AND_ASSIGN(TestQuicVisitor
);
57 class TestSession
: public QuicSession
{
59 TestSession(QuicConnection
* connection
, bool is_server
)
60 : QuicSession(connection
, is_server
) {
63 MOCK_METHOD1(CreateIncomingReliableStream
,
64 ReliableQuicStream
*(QuicStreamId id
));
65 MOCK_METHOD0(GetCryptoStream
, QuicCryptoStream
*());
66 MOCK_METHOD0(CreateOutgoingReliableStream
, ReliableQuicStream
*());
69 class QuicCryptoServerStreamTest
: public ::testing::Test
{
71 QuicCryptoServerStreamTest()
73 addr_(ParseIPLiteralToNumber("192.0.2.33", &ip_
) ?
74 ip_
: IPAddressNumber(), 1),
75 connection_(new PacketSavingConnection(guid_
, addr_
, true)),
76 session_(connection_
, true),
77 crypto_config_(QuicCryptoServerConfig::TESTING
),
78 stream_(config_
, crypto_config_
, &session_
) {
79 // We advance the clock initially because the default time is zero and the
80 // strike register worries that we've just overflowed a uint32 time.
81 connection_
->AdvanceTime(QuicTime::Delta::FromSeconds(100000));
82 // TODO(rtenneti): Enable testing of ProofSource.
83 // crypto_config_.SetProofSource(CryptoTestUtils::ProofSourceForTesting());
85 CryptoTestUtils::SetupCryptoServerConfigForTest(
86 connection_
->clock(), connection_
->random_generator(), &config_
,
90 void ConstructHandshakeMessage() {
92 message_data_
.reset(framer
.ConstructHandshakeMessage(message_
));
95 int CompleteCryptoHandshake() {
96 return CryptoTestUtils::HandshakeWithFakeClient(connection_
, &stream_
);
103 PacketSavingConnection
* connection_
;
104 TestSession session_
;
106 QuicCryptoServerConfig crypto_config_
;
107 QuicCryptoServerStream stream_
;
108 CryptoHandshakeMessage message_
;
109 scoped_ptr
<QuicData
> message_data_
;
112 TEST_F(QuicCryptoServerStreamTest
, NotInitiallyConected
) {
113 if (!Aes128GcmEncrypter::IsSupported()) {
114 LOG(INFO
) << "AES GCM not supported. Test skipped.";
118 EXPECT_FALSE(stream_
.handshake_complete());
121 TEST_F(QuicCryptoServerStreamTest
, ConnectedAfterCHLO
) {
122 if (!Aes128GcmEncrypter::IsSupported()) {
123 LOG(INFO
) << "AES GCM not supported. Test skipped.";
127 // CompleteCryptoHandshake returns the number of client hellos sent. This
129 // * One to get a source-address token.
130 // * One to complete the handshake.
131 // TODO(rtenneti): Until we set the crypto_config.SetProofVerifier to enable
132 // ProofVerifier in CryptoTestUtils::HandshakeWithFakeClient, we would not
133 // have sent the following client hello.
134 // * One to get the server's certificates
135 EXPECT_EQ(2, CompleteCryptoHandshake());
136 EXPECT_TRUE(stream_
.handshake_complete());
139 TEST_F(QuicCryptoServerStreamTest
, ZeroRTT
) {
140 if (!Aes128GcmEncrypter::IsSupported()) {
141 LOG(INFO
) << "AES GCM not supported. Test skipped.";
147 ParseIPLiteralToNumber("127.0.0.1", &ip
);
148 IPEndPoint
addr(ip
, 0);
149 PacketSavingConnection
* client_conn
=
150 new PacketSavingConnection(guid
, addr
, false);
151 PacketSavingConnection
* server_conn
=
152 new PacketSavingConnection(guid
, addr
, false);
153 client_conn
->AdvanceTime(QuicTime::Delta::FromSeconds(1000000));
154 server_conn
->AdvanceTime(QuicTime::Delta::FromSeconds(1000000));
156 scoped_ptr
<TestSession
> client_session(new TestSession(client_conn
, true));
157 scoped_ptr
<TestSession
> server_session(new TestSession(server_conn
, true));
159 QuicConfig client_config
;
160 QuicCryptoClientConfig client_crypto_config
;
162 client_config
.SetDefaults();
163 client_crypto_config
.SetDefaults();
165 scoped_ptr
<QuicCryptoClientStream
> client(new QuicCryptoClientStream(
166 "test.example.com", client_config
, client_session
.get(),
167 &client_crypto_config
));
169 // Do a first handshake in order to prime the client config with the server's
171 CHECK(client
->CryptoConnect());
172 CHECK_EQ(1u, client_conn
->packets_
.size());
174 scoped_ptr
<QuicCryptoServerStream
> server(
175 new QuicCryptoServerStream(config_
, crypto_config_
,
176 server_session
.get()));
178 CryptoTestUtils::CommunicateHandshakeMessages(
179 client_conn
, client
.get(), server_conn
, server
.get());
180 EXPECT_EQ(2, client
->num_sent_client_hellos());
182 // Now do another handshake, hopefully in 0-RTT.
183 LOG(INFO
) << "Resetting for 0-RTT handshake attempt";
185 client_conn
= new PacketSavingConnection(guid
, addr
, false);
186 server_conn
= new PacketSavingConnection(guid
, addr
, false);
187 // We need to advance time past the strike-server window so that it's
188 // authoritative in this time span.
189 client_conn
->AdvanceTime(QuicTime::Delta::FromSeconds(1002000));
190 server_conn
->AdvanceTime(QuicTime::Delta::FromSeconds(1002000));
192 // This causes the client's nonce to be different and thus stops the
193 // strike-register from rejecting the repeated nonce.
194 client_conn
->random_generator()->Reseed(NULL
, 0);
195 client_session
.reset(new TestSession(client_conn
, true));
196 server_session
.reset(new TestSession(server_conn
, true));
197 client
.reset(new QuicCryptoClientStream(
198 "test.example.com", client_config
, client_session
.get(),
199 &client_crypto_config
));
200 server
.reset(new QuicCryptoServerStream(config_
, crypto_config_
,
201 server_session
.get()));
203 CHECK(client
->CryptoConnect());
205 CryptoTestUtils::CommunicateHandshakeMessages(
206 client_conn
, client
.get(), server_conn
, server
.get());
207 EXPECT_EQ(1, client
->num_sent_client_hellos());
210 TEST_F(QuicCryptoServerStreamTest
, MessageAfterHandshake
) {
211 if (!Aes128GcmEncrypter::IsSupported()) {
212 LOG(INFO
) << "AES GCM not supported. Test skipped.";
216 CompleteCryptoHandshake();
217 EXPECT_CALL(*connection_
, SendConnectionClose(
218 QUIC_CRYPTO_MESSAGE_AFTER_HANDSHAKE_COMPLETE
));
219 message_
.set_tag(kCHLO
);
220 ConstructHandshakeMessage();
221 stream_
.ProcessData(message_data_
->data(), message_data_
->length());
224 TEST_F(QuicCryptoServerStreamTest
, BadMessageType
) {
225 if (!Aes128GcmEncrypter::IsSupported()) {
226 LOG(INFO
) << "AES GCM not supported. Test skipped.";
230 message_
.set_tag(kSHLO
);
231 ConstructHandshakeMessage();
232 EXPECT_CALL(*connection_
, SendConnectionClose(
233 QUIC_INVALID_CRYPTO_MESSAGE_TYPE
));
234 stream_
.ProcessData(message_data_
->data(), message_data_
->length());