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()->ProcessRawData(message_data_
->data(), message_data_
->length());
87 TEST_F(QuicCryptoClientStreamTest
, BadMessageType
) {
88 stream()->CryptoConnect();
90 message_
.set_tag(kCHLO
);
91 ConstructHandshakeMessage();
93 EXPECT_CALL(*connection_
, SendConnectionCloseWithDetails(
94 QUIC_INVALID_CRYPTO_MESSAGE_TYPE
, "Expected REJ"));
95 stream()->ProcessRawData(message_data_
->data(), message_data_
->length());
98 TEST_F(QuicCryptoClientStreamTest
, NegotiatedParameters
) {
99 CompleteCryptoHandshake();
101 const QuicConfig
* config
= session_
->config();
102 EXPECT_EQ(kMaximumIdleTimeoutSecs
,
103 config
->IdleConnectionStateLifetime().ToSeconds());
104 EXPECT_EQ(kDefaultMaxStreamsPerConnection
,
105 config
->MaxStreamsPerConnection());
107 const QuicCryptoNegotiatedParameters
& crypto_params(
108 stream()->crypto_negotiated_params());
109 EXPECT_EQ(crypto_config_
.aead
[0], crypto_params
.aead
);
110 EXPECT_EQ(crypto_config_
.kexs
[0], crypto_params
.key_exchange
);
113 TEST_F(QuicCryptoClientStreamTest
, InvalidHostname
) {
115 QuicServerId("invalid", kServerPort
, false, PRIVACY_MODE_DISABLED
);
119 CompleteCryptoHandshake();
120 EXPECT_TRUE(stream()->encryption_established());
121 EXPECT_TRUE(stream()->handshake_confirmed());
124 TEST_F(QuicCryptoClientStreamTest
, ExpiredServerConfig
) {
125 // Seed the config with a cached server config.
126 CompleteCryptoHandshake();
128 // Recreate connection with the new config.
131 // Advance time 5 years to ensure that we pass the expiry time of the cached
133 connection_
->AdvanceTime(
134 QuicTime::Delta::FromSeconds(60 * 60 * 24 * 365 * 5));
136 stream()->CryptoConnect();
137 // Check that a client hello was sent.
138 ASSERT_EQ(1u, connection_
->encrypted_packets_
.size());
141 TEST_F(QuicCryptoClientStreamTest
, ServerConfigUpdate
) {
142 // Test that the crypto client stream can receive server config updates after
143 // the connection has been established.
144 CompleteCryptoHandshake();
146 QuicCryptoClientConfig::CachedState
* state
=
147 crypto_config_
.LookupOrCreate(server_id_
);
149 // Ensure cached STK is different to what we send in the handshake.
150 EXPECT_NE("xstk", state
->source_address_token());
152 // Initialize using {...} syntax to avoid trailing \0 if converting from
154 unsigned char stk
[] = { 'x', 's', 't', 'k' };
156 // Minimum SCFG that passes config validation checks.
157 unsigned char scfg
[] = {
159 0x53, 0x43, 0x46, 0x47,
165 0x45, 0x58, 0x50, 0x59,
167 0x08, 0x00, 0x00, 0x00,
173 CryptoHandshakeMessage server_config_update
;
174 server_config_update
.set_tag(kSCUP
);
175 server_config_update
.SetValue(kSourceAddressTokenTag
, stk
);
176 server_config_update
.SetValue(kSCFG
, scfg
);
178 scoped_ptr
<QuicData
> data(
179 CryptoFramer::ConstructHandshakeMessage(server_config_update
));
180 stream()->ProcessRawData(data
->data(), data
->length());
182 // Make sure that the STK and SCFG are cached correctly.
183 EXPECT_EQ("xstk", state
->source_address_token());
185 string cached_scfg
= state
->server_config();
186 test::CompareCharArraysWithHexError(
187 "scfg", cached_scfg
.data(), cached_scfg
.length(),
188 QuicUtils::AsChars(scfg
), arraysize(scfg
));
191 TEST_F(QuicCryptoClientStreamTest
, ServerConfigUpdateBeforeHandshake
) {
192 EXPECT_CALL(*connection_
, SendConnectionClose(
193 QUIC_CRYPTO_UPDATE_BEFORE_HANDSHAKE_COMPLETE
));
194 CryptoHandshakeMessage server_config_update
;
195 server_config_update
.set_tag(kSCUP
);
196 scoped_ptr
<QuicData
> data(
197 CryptoFramer::ConstructHandshakeMessage(server_config_update
));
198 stream()->ProcessRawData(data
->data(), data
->length());
201 class QuicCryptoClientStreamStatelessTest
: public ::testing::Test
{
203 QuicCryptoClientStreamStatelessTest()
204 : server_crypto_config_(QuicCryptoServerConfig::TESTING
,
205 QuicRandom::GetInstance()),
206 server_id_(kServerHostname
, kServerPort
, false, PRIVACY_MODE_DISABLED
) {
207 TestQuicSpdyClientSession
* client_session
= nullptr;
208 CreateClientSessionForTest(server_id_
,
209 /* supports_stateless_rejects= */ true,
210 QuicTime::Delta::FromSeconds(100000),
211 &client_crypto_config_
, &client_connection_
,
213 CHECK(client_session
);
214 client_session_
.reset(client_session
);
217 QuicCryptoServerStream
* server_stream() {
218 return server_session_
->GetCryptoStream();
221 void AdvanceHandshakeWithFakeServer() {
222 client_session_
->GetCryptoStream()->CryptoConnect();
223 CryptoTestUtils::AdvanceHandshake(client_connection_
,
224 client_session_
->GetCryptoStream(), 0,
225 server_connection_
, server_stream(), 0);
228 // Initializes the server_stream_ for stateless rejects.
229 void InitializeFakeStatelessRejectServer() {
230 TestQuicSpdyServerSession
* server_session
= nullptr;
231 CreateServerSessionForTest(server_id_
, QuicTime::Delta::FromSeconds(100000),
232 &server_crypto_config_
, &server_connection_
,
234 CHECK(server_session
);
235 server_session_
.reset(server_session
);
236 CryptoTestUtils::SetupCryptoServerConfigForTest(
237 server_connection_
->clock(), server_connection_
->random_generator(),
238 server_session_
->config(), &server_crypto_config_
);
239 server_stream()->set_use_stateless_rejects_if_peer_supported(true);
242 // Client crypto stream state
243 PacketSavingConnection
* client_connection_
;
244 scoped_ptr
<TestQuicSpdyClientSession
> client_session_
;
245 QuicCryptoClientConfig client_crypto_config_
;
247 // Server crypto stream state
248 PacketSavingConnection
* server_connection_
;
249 scoped_ptr
<TestQuicSpdyServerSession
> server_session_
;
250 QuicCryptoServerConfig server_crypto_config_
;
251 QuicServerId server_id_
;
254 TEST_F(QuicCryptoClientStreamStatelessTest
, StatelessReject
) {
255 ValueRestore
<bool> old_flag(&FLAGS_enable_quic_stateless_reject_support
,
258 QuicCryptoClientConfig::CachedState
* client_state
=
259 client_crypto_config_
.LookupOrCreate(server_id_
);
261 EXPECT_FALSE(client_state
->has_server_designated_connection_id());
262 EXPECT_CALL(*client_session_
, OnProofValid(testing::_
));
264 InitializeFakeStatelessRejectServer();
265 AdvanceHandshakeWithFakeServer();
267 EXPECT_EQ(1, server_stream()->num_handshake_messages());
268 EXPECT_EQ(0, server_stream()->num_handshake_messages_with_server_nonces());
270 EXPECT_FALSE(client_session_
->GetCryptoStream()->encryption_established());
271 EXPECT_FALSE(client_session_
->GetCryptoStream()->handshake_confirmed());
272 // Even though the handshake was not complete, the cached client_state is
273 // complete, and can be used for a subsequent successful handshake.
274 EXPECT_TRUE(client_state
->IsComplete(QuicWallTime::FromUNIXSeconds(0)));
276 ASSERT_TRUE(client_state
->has_server_nonce());
277 ASSERT_FALSE(client_state
->GetNextServerNonce().empty());
278 ASSERT_TRUE(client_state
->has_server_designated_connection_id());
279 QuicConnectionId server_designated_id
=
280 client_state
->GetNextServerDesignatedConnectionId();
281 QuicConnectionId expected_id
=
282 server_session_
->connection()->random_generator()->RandUint64();
283 EXPECT_EQ(expected_id
, server_designated_id
);
284 EXPECT_FALSE(client_state
->has_server_designated_connection_id());