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_client_stream.h"
7 #include "base/memory/scoped_ptr.h"
8 #include "net/quic/crypto/aes_128_gcm_12_encrypter.h"
9 #include "net/quic/crypto/quic_decrypter.h"
10 #include "net/quic/crypto/quic_encrypter.h"
11 #include "net/quic/quic_flags.h"
12 #include "net/quic/quic_protocol.h"
13 #include "net/quic/quic_server_id.h"
14 #include "net/quic/quic_utils.h"
15 #include "net/quic/test_tools/crypto_test_utils.h"
16 #include "net/quic/test_tools/quic_test_utils.h"
17 #include "net/quic/test_tools/simple_quic_framer.h"
18 #include "testing/gmock/include/gmock/gmock.h"
19 #include "testing/gtest/include/gtest/gtest.h"
27 const char kServerHostname
[] = "example.com";
28 const uint16 kServerPort
= 80;
30 class QuicCryptoClientStreamTest
: public ::testing::Test
{
32 QuicCryptoClientStreamTest()
33 : server_id_(kServerHostname
, kServerPort
, false, PRIVACY_MODE_DISABLED
) {
37 void CreateConnection() {
38 connection_
= new PacketSavingConnection(Perspective::IS_CLIENT
);
39 // Advance the time, because timers do not like uninitialized times.
40 connection_
->AdvanceTime(QuicTime::Delta::FromSeconds(1));
42 session_
.reset(new TestQuicSpdyClientSession(
43 connection_
, DefaultQuicConfig(), server_id_
, &crypto_config_
));
46 void CompleteCryptoHandshake() {
47 stream()->CryptoConnect();
48 CryptoTestUtils::HandshakeWithFakeServer(connection_
, stream());
51 void ConstructHandshakeMessage() {
53 message_data_
.reset(framer
.ConstructHandshakeMessage(message_
));
56 QuicCryptoClientStream
* stream() { return session_
->GetCryptoStream(); }
58 PacketSavingConnection
* connection_
;
59 scoped_ptr
<TestQuicSpdyClientSession
> session_
;
60 QuicServerId server_id_
;
61 CryptoHandshakeMessage message_
;
62 scoped_ptr
<QuicData
> message_data_
;
63 QuicCryptoClientConfig crypto_config_
;
66 TEST_F(QuicCryptoClientStreamTest
, NotInitiallyConected
) {
67 EXPECT_FALSE(stream()->encryption_established());
68 EXPECT_FALSE(stream()->handshake_confirmed());
71 TEST_F(QuicCryptoClientStreamTest
, ConnectedAfterSHLO
) {
72 CompleteCryptoHandshake();
73 EXPECT_TRUE(stream()->encryption_established());
74 EXPECT_TRUE(stream()->handshake_confirmed());
77 TEST_F(QuicCryptoClientStreamTest
, MessageAfterHandshake
) {
78 CompleteCryptoHandshake();
80 EXPECT_CALL(*connection_
, SendConnectionClose(
81 QUIC_CRYPTO_MESSAGE_AFTER_HANDSHAKE_COMPLETE
));
82 message_
.set_tag(kCHLO
);
83 ConstructHandshakeMessage();
84 stream()->OnStreamFrame(QuicStreamFrame(kCryptoStreamId
, /*fin=*/false,
86 message_data_
->AsStringPiece()));
89 TEST_F(QuicCryptoClientStreamTest
, BadMessageType
) {
90 stream()->CryptoConnect();
92 message_
.set_tag(kCHLO
);
93 ConstructHandshakeMessage();
95 EXPECT_CALL(*connection_
, SendConnectionCloseWithDetails(
96 QUIC_INVALID_CRYPTO_MESSAGE_TYPE
, "Expected REJ"));
97 stream()->OnStreamFrame(QuicStreamFrame(kCryptoStreamId
, /*fin=*/false,
99 message_data_
->AsStringPiece()));
102 TEST_F(QuicCryptoClientStreamTest
, NegotiatedParameters
) {
103 CompleteCryptoHandshake();
105 const QuicConfig
* config
= session_
->config();
106 EXPECT_EQ(kMaximumIdleTimeoutSecs
,
107 config
->IdleConnectionStateLifetime().ToSeconds());
108 EXPECT_EQ(kDefaultMaxStreamsPerConnection
,
109 config
->MaxStreamsPerConnection());
111 const QuicCryptoNegotiatedParameters
& crypto_params(
112 stream()->crypto_negotiated_params());
113 EXPECT_EQ(crypto_config_
.aead
[0], crypto_params
.aead
);
114 EXPECT_EQ(crypto_config_
.kexs
[0], crypto_params
.key_exchange
);
117 TEST_F(QuicCryptoClientStreamTest
, InvalidHostname
) {
119 QuicServerId("invalid", kServerPort
, false, PRIVACY_MODE_DISABLED
);
123 CompleteCryptoHandshake();
124 EXPECT_TRUE(stream()->encryption_established());
125 EXPECT_TRUE(stream()->handshake_confirmed());
128 TEST_F(QuicCryptoClientStreamTest
, ExpiredServerConfig
) {
129 // Seed the config with a cached server config.
130 CompleteCryptoHandshake();
132 // Recreate connection with the new config.
135 // Advance time 5 years to ensure that we pass the expiry time of the cached
137 connection_
->AdvanceTime(
138 QuicTime::Delta::FromSeconds(60 * 60 * 24 * 365 * 5));
140 stream()->CryptoConnect();
141 // Check that a client hello was sent.
142 ASSERT_EQ(1u, connection_
->encrypted_packets_
.size());
145 TEST_F(QuicCryptoClientStreamTest
, ServerConfigUpdate
) {
146 // Test that the crypto client stream can receive server config updates after
147 // the connection has been established.
148 CompleteCryptoHandshake();
150 QuicCryptoClientConfig::CachedState
* state
=
151 crypto_config_
.LookupOrCreate(server_id_
);
153 // Ensure cached STK is different to what we send in the handshake.
154 EXPECT_NE("xstk", state
->source_address_token());
156 // Initialize using {...} syntax to avoid trailing \0 if converting from
158 unsigned char stk
[] = { 'x', 's', 't', 'k' };
160 // Minimum SCFG that passes config validation checks.
161 unsigned char scfg
[] = {
163 0x53, 0x43, 0x46, 0x47,
169 0x45, 0x58, 0x50, 0x59,
171 0x08, 0x00, 0x00, 0x00,
177 CryptoHandshakeMessage server_config_update
;
178 server_config_update
.set_tag(kSCUP
);
179 server_config_update
.SetValue(kSourceAddressTokenTag
, stk
);
180 server_config_update
.SetValue(kSCFG
, scfg
);
182 scoped_ptr
<QuicData
> data(
183 CryptoFramer::ConstructHandshakeMessage(server_config_update
));
184 stream()->OnStreamFrame(QuicStreamFrame(kCryptoStreamId
, /*fin=*/false,
185 /*offset=*/0, data
->AsStringPiece()));
187 // Make sure that the STK and SCFG are cached correctly.
188 EXPECT_EQ("xstk", state
->source_address_token());
190 string cached_scfg
= state
->server_config();
191 test::CompareCharArraysWithHexError(
192 "scfg", cached_scfg
.data(), cached_scfg
.length(),
193 QuicUtils::AsChars(scfg
), arraysize(scfg
));
196 TEST_F(QuicCryptoClientStreamTest
, ServerConfigUpdateBeforeHandshake
) {
197 EXPECT_CALL(*connection_
, SendConnectionClose(
198 QUIC_CRYPTO_UPDATE_BEFORE_HANDSHAKE_COMPLETE
));
199 CryptoHandshakeMessage server_config_update
;
200 server_config_update
.set_tag(kSCUP
);
201 scoped_ptr
<QuicData
> data(
202 CryptoFramer::ConstructHandshakeMessage(server_config_update
));
203 stream()->OnStreamFrame(QuicStreamFrame(kCryptoStreamId
, /*fin=*/false,
204 /*offset=*/0, data
->AsStringPiece()));
207 class QuicCryptoClientStreamStatelessTest
: public ::testing::Test
{
209 QuicCryptoClientStreamStatelessTest()
210 : server_crypto_config_(QuicCryptoServerConfig::TESTING
,
211 QuicRandom::GetInstance()),
212 server_id_(kServerHostname
, kServerPort
, false, PRIVACY_MODE_DISABLED
) {
213 TestQuicSpdyClientSession
* client_session
= nullptr;
214 CreateClientSessionForTest(server_id_
,
215 /* supports_stateless_rejects= */ true,
216 QuicTime::Delta::FromSeconds(100000),
217 &client_crypto_config_
, &client_connection_
,
219 CHECK(client_session
);
220 client_session_
.reset(client_session
);
223 QuicCryptoServerStream
* server_stream() {
224 return server_session_
->GetCryptoStream();
227 void AdvanceHandshakeWithFakeServer() {
228 client_session_
->GetCryptoStream()->CryptoConnect();
229 CryptoTestUtils::AdvanceHandshake(client_connection_
,
230 client_session_
->GetCryptoStream(), 0,
231 server_connection_
, server_stream(), 0);
234 // Initializes the server_stream_ for stateless rejects.
235 void InitializeFakeStatelessRejectServer() {
236 TestQuicSpdyServerSession
* server_session
= nullptr;
237 CreateServerSessionForTest(server_id_
, QuicTime::Delta::FromSeconds(100000),
238 &server_crypto_config_
, &server_connection_
,
240 CHECK(server_session
);
241 server_session_
.reset(server_session
);
242 CryptoTestUtils::SetupCryptoServerConfigForTest(
243 server_connection_
->clock(), server_connection_
->random_generator(),
244 server_session_
->config(), &server_crypto_config_
);
245 server_stream()->set_use_stateless_rejects_if_peer_supported(true);
248 // Client crypto stream state
249 PacketSavingConnection
* client_connection_
;
250 scoped_ptr
<TestQuicSpdyClientSession
> client_session_
;
251 QuicCryptoClientConfig client_crypto_config_
;
253 // Server crypto stream state
254 PacketSavingConnection
* server_connection_
;
255 scoped_ptr
<TestQuicSpdyServerSession
> server_session_
;
256 QuicCryptoServerConfig server_crypto_config_
;
257 QuicServerId server_id_
;
260 TEST_F(QuicCryptoClientStreamStatelessTest
, StatelessReject
) {
261 ValueRestore
<bool> old_flag(&FLAGS_enable_quic_stateless_reject_support
,
264 QuicCryptoClientConfig::CachedState
* client_state
=
265 client_crypto_config_
.LookupOrCreate(server_id_
);
267 EXPECT_FALSE(client_state
->has_server_designated_connection_id());
268 EXPECT_CALL(*client_session_
, OnProofValid(testing::_
));
270 InitializeFakeStatelessRejectServer();
271 AdvanceHandshakeWithFakeServer();
273 EXPECT_EQ(1, server_stream()->num_handshake_messages());
274 EXPECT_EQ(0, server_stream()->num_handshake_messages_with_server_nonces());
276 EXPECT_FALSE(client_session_
->GetCryptoStream()->encryption_established());
277 EXPECT_FALSE(client_session_
->GetCryptoStream()->handshake_confirmed());
278 // Even though the handshake was not complete, the cached client_state is
279 // complete, and can be used for a subsequent successful handshake.
280 EXPECT_TRUE(client_state
->IsComplete(QuicWallTime::FromUNIXSeconds(0)));
282 ASSERT_TRUE(client_state
->has_server_nonce());
283 ASSERT_FALSE(client_state
->GetNextServerNonce().empty());
284 ASSERT_TRUE(client_state
->has_server_designated_connection_id());
285 QuicConnectionId server_designated_id
=
286 client_state
->GetNextServerDesignatedConnectionId();
287 QuicConnectionId expected_id
=
288 server_session_
->connection()->random_generator()->RandUint64();
289 EXPECT_EQ(expected_id
, server_designated_id
);
290 EXPECT_FALSE(client_state
->has_server_designated_connection_id());