blob: 827cb03e3a37bca75e7ffce0d2bd1f125e947f97 [file] [log] [blame]
QUICHE teama6ef0a62019-03-07 20:34:33 -05001// 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.
4
5#include "net/third_party/quiche/src/quic/core/quic_crypto_client_stream.h"
6
7#include <memory>
vasilvv872e7a32019-03-12 16:42:44 -07008#include <string>
bnc463f2352019-10-10 04:49:34 -07009#include <utility>
QUICHE teama6ef0a62019-03-07 20:34:33 -050010
11#include "net/third_party/quiche/src/quic/core/crypto/aes_128_gcm_12_encrypter.h"
12#include "net/third_party/quiche/src/quic/core/crypto/quic_decrypter.h"
13#include "net/third_party/quiche/src/quic/core/crypto/quic_encrypter.h"
14#include "net/third_party/quiche/src/quic/core/quic_packets.h"
15#include "net/third_party/quiche/src/quic/core/quic_server_id.h"
16#include "net/third_party/quiche/src/quic/core/quic_utils.h"
QUICHE teama6ef0a62019-03-07 20:34:33 -050017#include "net/third_party/quiche/src/quic/platform/api/quic_arraysize.h"
18#include "net/third_party/quiche/src/quic/platform/api/quic_flags.h"
QUICHE teama6ef0a62019-03-07 20:34:33 -050019#include "net/third_party/quiche/src/quic/platform/api/quic_test.h"
20#include "net/third_party/quiche/src/quic/test_tools/crypto_test_utils.h"
21#include "net/third_party/quiche/src/quic/test_tools/quic_stream_peer.h"
22#include "net/third_party/quiche/src/quic/test_tools/quic_stream_sequencer_peer.h"
23#include "net/third_party/quiche/src/quic/test_tools/quic_test_utils.h"
24#include "net/third_party/quiche/src/quic/test_tools/simple_quic_framer.h"
nharperdf7a77b2019-11-11 13:12:45 -080025#include "net/third_party/quiche/src/quic/test_tools/simple_session_cache.h"
QUICHE teama6ef0a62019-03-07 20:34:33 -050026
27using testing::_;
28
29namespace quic {
30namespace test {
31namespace {
32
33const char kServerHostname[] = "test.example.com";
34const uint16_t kServerPort = 443;
35
36class QuicCryptoClientStreamTest : public QuicTest {
37 public:
38 QuicCryptoClientStreamTest()
39 : supported_versions_(AllSupportedVersions()),
40 server_id_(kServerHostname, kServerPort, false),
nharperdf7a77b2019-11-11 13:12:45 -080041 crypto_config_(crypto_test_utils::ProofVerifierForTesting(),
42 std::make_unique<test::SimpleSessionCache>()),
43 server_crypto_config_(
44 crypto_test_utils::CryptoServerConfigForTesting()) {
QUICHE teama6ef0a62019-03-07 20:34:33 -050045 CreateConnection();
46 }
47
48 void CreateConnection() {
49 connection_ =
50 new PacketSavingConnection(&client_helper_, &alarm_factory_,
51 Perspective::IS_CLIENT, supported_versions_);
52 // Advance the time, because timers do not like uninitialized times.
53 connection_->AdvanceTime(QuicTime::Delta::FromSeconds(1));
54
vasilvv0fc587f2019-09-06 13:33:08 -070055 session_ = std::make_unique<TestQuicSpdyClientSession>(
QUICHE teama6ef0a62019-03-07 20:34:33 -050056 connection_, DefaultQuicConfig(), supported_versions_, server_id_,
57 &crypto_config_);
vasilvvefc6af82019-10-11 12:46:56 -070058 EXPECT_CALL(*session_, GetAlpnsToOffer())
59 .WillRepeatedly(testing::Return(std::vector<std::string>(
60 {AlpnForVersion(connection_->version())})));
QUICHE teama6ef0a62019-03-07 20:34:33 -050061 }
62
nharperdf7a77b2019-11-11 13:12:45 -080063 void UseTlsHandshake() {
64 SetQuicReloadableFlag(quic_supports_tls_handshake, true);
65 supported_versions_.clear();
66 for (ParsedQuicVersion version : AllSupportedVersions()) {
67 if (version.handshake_protocol != PROTOCOL_TLS1_3) {
68 continue;
69 }
70 supported_versions_.push_back(version);
71 }
72 }
73
QUICHE teama6ef0a62019-03-07 20:34:33 -050074 void CompleteCryptoHandshake() {
nharper1473c092019-11-11 13:13:19 -080075 int proof_verify_details_calls = 1;
QUICHE teama6ef0a62019-03-07 20:34:33 -050076 if (stream()->handshake_protocol() != PROTOCOL_TLS1_3) {
77 EXPECT_CALL(*session_, OnProofValid(testing::_));
nharper1473c092019-11-11 13:13:19 -080078 proof_verify_details_calls = 0;
QUICHE teama6ef0a62019-03-07 20:34:33 -050079 }
80 EXPECT_CALL(*session_, OnProofVerifyDetailsAvailable(testing::_))
nharper1473c092019-11-11 13:13:19 -080081 .Times(testing::AtLeast(proof_verify_details_calls));
QUICHE teama6ef0a62019-03-07 20:34:33 -050082 stream()->CryptoConnect();
83 QuicConfig config;
nharperba5f32c2019-05-13 12:21:31 -070084 crypto_test_utils::HandshakeWithFakeServer(
rch83f29bd2019-11-13 11:47:34 -080085 &config, server_crypto_config_.get(), &server_helper_, &alarm_factory_,
nharperdf7a77b2019-11-11 13:12:45 -080086 connection_, stream(), AlpnForVersion(connection_->version()));
QUICHE teama6ef0a62019-03-07 20:34:33 -050087 }
88
89 QuicCryptoClientStream* stream() {
90 return session_->GetMutableCryptoStream();
91 }
92
93 MockQuicConnectionHelper server_helper_;
94 MockQuicConnectionHelper client_helper_;
95 MockAlarmFactory alarm_factory_;
96 PacketSavingConnection* connection_;
97 ParsedQuicVersionVector supported_versions_;
98 std::unique_ptr<TestQuicSpdyClientSession> session_;
99 QuicServerId server_id_;
100 CryptoHandshakeMessage message_;
101 QuicCryptoClientConfig crypto_config_;
rch83f29bd2019-11-13 11:47:34 -0800102 std::unique_ptr<QuicCryptoServerConfig> server_crypto_config_;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500103};
104
105TEST_F(QuicCryptoClientStreamTest, NotInitiallyConected) {
106 EXPECT_FALSE(stream()->encryption_established());
107 EXPECT_FALSE(stream()->handshake_confirmed());
108}
109
110TEST_F(QuicCryptoClientStreamTest, ConnectedAfterSHLO) {
111 CompleteCryptoHandshake();
112 EXPECT_TRUE(stream()->encryption_established());
113 EXPECT_TRUE(stream()->handshake_confirmed());
nharper02703962019-11-07 12:23:13 -0800114 EXPECT_FALSE(stream()->IsResumption());
QUICHE teama6ef0a62019-03-07 20:34:33 -0500115}
116
117TEST_F(QuicCryptoClientStreamTest, ConnectedAfterTlsHandshake) {
nharperdf7a77b2019-11-11 13:12:45 -0800118 UseTlsHandshake();
QUICHE teama6ef0a62019-03-07 20:34:33 -0500119 CreateConnection();
120 CompleteCryptoHandshake();
121 EXPECT_EQ(PROTOCOL_TLS1_3, stream()->handshake_protocol());
122 EXPECT_TRUE(stream()->encryption_established());
123 EXPECT_TRUE(stream()->handshake_confirmed());
nharper02703962019-11-07 12:23:13 -0800124 EXPECT_FALSE(stream()->IsResumption());
QUICHE teama6ef0a62019-03-07 20:34:33 -0500125}
126
nharper40bdf532019-10-03 11:16:22 -0700127TEST_F(QuicCryptoClientStreamTest,
128 ProofVerifyDetailsAvailableAfterTlsHandshake) {
nharperdf7a77b2019-11-11 13:12:45 -0800129 UseTlsHandshake();
nharper40bdf532019-10-03 11:16:22 -0700130 CreateConnection();
131
132 EXPECT_CALL(*session_, OnProofVerifyDetailsAvailable(testing::_));
133 stream()->CryptoConnect();
134 QuicConfig config;
135 crypto_test_utils::HandshakeWithFakeServer(
rch83f29bd2019-11-13 11:47:34 -0800136 &config, server_crypto_config_.get(), &server_helper_, &alarm_factory_,
nharperdf7a77b2019-11-11 13:12:45 -0800137 connection_, stream(), AlpnForVersion(connection_->version()));
nharper40bdf532019-10-03 11:16:22 -0700138 EXPECT_EQ(PROTOCOL_TLS1_3, stream()->handshake_protocol());
139 EXPECT_TRUE(stream()->encryption_established());
140 EXPECT_TRUE(stream()->handshake_confirmed());
141}
142
nharperdf7a77b2019-11-11 13:12:45 -0800143TEST_F(QuicCryptoClientStreamTest, TlsResumption) {
144 UseTlsHandshake();
145 // Enable resumption on the server:
rch83f29bd2019-11-13 11:47:34 -0800146 SSL_CTX_clear_options(server_crypto_config_->ssl_ctx(), SSL_OP_NO_TICKET);
nharperdf7a77b2019-11-11 13:12:45 -0800147 CreateConnection();
148
149 // Finish establishing the first connection:
150 CompleteCryptoHandshake();
151
152 EXPECT_EQ(PROTOCOL_TLS1_3, stream()->handshake_protocol());
153 EXPECT_TRUE(stream()->encryption_established());
154 EXPECT_TRUE(stream()->handshake_confirmed());
155 EXPECT_FALSE(stream()->IsResumption());
156
157 // Create a second connection
158 CreateConnection();
159 CompleteCryptoHandshake();
160
161 EXPECT_EQ(PROTOCOL_TLS1_3, stream()->handshake_protocol());
162 EXPECT_TRUE(stream()->encryption_established());
163 EXPECT_TRUE(stream()->handshake_confirmed());
164 EXPECT_TRUE(stream()->IsResumption());
165}
166
QUICHE teama6ef0a62019-03-07 20:34:33 -0500167TEST_F(QuicCryptoClientStreamTest, MessageAfterHandshake) {
168 CompleteCryptoHandshake();
169
170 EXPECT_CALL(
171 *connection_,
172 CloseConnection(QUIC_CRYPTO_MESSAGE_AFTER_HANDSHAKE_COMPLETE, _, _));
173 message_.set_tag(kCHLO);
174 crypto_test_utils::SendHandshakeMessageToStream(stream(), message_,
175 Perspective::IS_CLIENT);
176}
177
178TEST_F(QuicCryptoClientStreamTest, BadMessageType) {
179 stream()->CryptoConnect();
180
181 message_.set_tag(kCHLO);
182
183 EXPECT_CALL(*connection_, CloseConnection(QUIC_INVALID_CRYPTO_MESSAGE_TYPE,
184 "Expected REJ", _));
185 crypto_test_utils::SendHandshakeMessageToStream(stream(), message_,
186 Perspective::IS_CLIENT);
187}
188
189TEST_F(QuicCryptoClientStreamTest, NegotiatedParameters) {
190 CompleteCryptoHandshake();
191
192 const QuicConfig* config = session_->config();
193 EXPECT_EQ(kMaximumIdleTimeoutSecs, config->IdleNetworkTimeout().ToSeconds());
194
195 const QuicCryptoNegotiatedParameters& crypto_params(
196 stream()->crypto_negotiated_params());
197 EXPECT_EQ(crypto_config_.aead[0], crypto_params.aead);
198 EXPECT_EQ(crypto_config_.kexs[0], crypto_params.key_exchange);
199}
200
201TEST_F(QuicCryptoClientStreamTest, ExpiredServerConfig) {
202 // Seed the config with a cached server config.
203 CompleteCryptoHandshake();
204
205 // Recreate connection with the new config.
206 CreateConnection();
207
208 // Advance time 5 years to ensure that we pass the expiry time of the cached
209 // server config.
210 connection_->AdvanceTime(
211 QuicTime::Delta::FromSeconds(60 * 60 * 24 * 365 * 5));
212
213 EXPECT_CALL(*session_, OnProofValid(testing::_));
214 stream()->CryptoConnect();
215 // Check that a client hello was sent.
216 ASSERT_EQ(1u, connection_->encrypted_packets_.size());
QUICHE team6987b4a2019-03-15 16:23:04 -0700217 EXPECT_EQ(ENCRYPTION_INITIAL, connection_->encryption_level());
QUICHE teama6ef0a62019-03-07 20:34:33 -0500218}
219
220TEST_F(QuicCryptoClientStreamTest, ClockSkew) {
221 // Test that if the client's clock is skewed with respect to the server,
222 // the handshake succeeds. In the past, the client would get the server
223 // config, notice that it had already expired and then close the connection.
224
225 // Advance time 5 years to ensure that we pass the expiry time in the server
226 // config, but the TTL is used instead.
227 connection_->AdvanceTime(
228 QuicTime::Delta::FromSeconds(60 * 60 * 24 * 365 * 5));
229
230 // The handshakes completes!
231 CompleteCryptoHandshake();
232}
233
234TEST_F(QuicCryptoClientStreamTest, InvalidCachedServerConfig) {
235 // Seed the config with a cached server config.
236 CompleteCryptoHandshake();
237
238 // Recreate connection with the new config.
239 CreateConnection();
240
241 QuicCryptoClientConfig::CachedState* state =
242 crypto_config_.LookupOrCreate(server_id_);
243
vasilvvc48c8712019-03-11 13:38:16 -0700244 std::vector<std::string> certs = state->certs();
245 std::string cert_sct = state->cert_sct();
246 std::string signature = state->signature();
247 std::string chlo_hash = state->chlo_hash();
QUICHE teama6ef0a62019-03-07 20:34:33 -0500248 state->SetProof(certs, cert_sct, chlo_hash, signature + signature);
249
250 EXPECT_CALL(*session_, OnProofVerifyDetailsAvailable(testing::_))
251 .Times(testing::AnyNumber());
252 stream()->CryptoConnect();
253 // Check that a client hello was sent.
254 ASSERT_EQ(1u, connection_->encrypted_packets_.size());
255}
256
257TEST_F(QuicCryptoClientStreamTest, ServerConfigUpdate) {
258 // Test that the crypto client stream can receive server config updates after
259 // the connection has been established.
260 CompleteCryptoHandshake();
261
262 QuicCryptoClientConfig::CachedState* state =
263 crypto_config_.LookupOrCreate(server_id_);
264
265 // Ensure cached STK is different to what we send in the handshake.
266 EXPECT_NE("xstk", state->source_address_token());
267
268 // Initialize using {...} syntax to avoid trailing \0 if converting from
269 // string.
270 unsigned char stk[] = {'x', 's', 't', 'k'};
271
272 // Minimum SCFG that passes config validation checks.
273 unsigned char scfg[] = {// SCFG
274 0x53, 0x43, 0x46, 0x47,
275 // num entries
276 0x01, 0x00,
277 // padding
278 0x00, 0x00,
279 // EXPY
280 0x45, 0x58, 0x50, 0x59,
281 // EXPY end offset
282 0x08, 0x00, 0x00, 0x00,
283 // Value
284 '1', '2', '3', '4', '5', '6', '7', '8'};
285
286 CryptoHandshakeMessage server_config_update;
287 server_config_update.set_tag(kSCUP);
288 server_config_update.SetValue(kSourceAddressTokenTag, stk);
289 server_config_update.SetValue(kSCFG, scfg);
290 const uint64_t expiry_seconds = 60 * 60 * 24 * 2;
291 server_config_update.SetValue(kSTTL, expiry_seconds);
292
293 crypto_test_utils::SendHandshakeMessageToStream(
294 stream(), server_config_update, Perspective::IS_SERVER);
295
296 // Make sure that the STK and SCFG are cached correctly.
297 EXPECT_EQ("xstk", state->source_address_token());
298
vasilvvc48c8712019-03-11 13:38:16 -0700299 const std::string& cached_scfg = state->server_config();
QUICHE teama6ef0a62019-03-07 20:34:33 -0500300 test::CompareCharArraysWithHexError(
301 "scfg", cached_scfg.data(), cached_scfg.length(),
302 reinterpret_cast<char*>(scfg), QUIC_ARRAYSIZE(scfg));
303
304 QuicStreamSequencer* sequencer = QuicStreamPeer::sequencer(stream());
305 EXPECT_FALSE(QuicStreamSequencerPeer::IsUnderlyingBufferAllocated(sequencer));
306}
307
308TEST_F(QuicCryptoClientStreamTest, ServerConfigUpdateWithCert) {
309 // Test that the crypto client stream can receive and use server config
310 // updates with certificates after the connection has been established.
311 CompleteCryptoHandshake();
312
313 // Build a server config update message with certificates
314 QuicCryptoServerConfig crypto_config(
315 QuicCryptoServerConfig::TESTING, QuicRandom::GetInstance(),
nharper6ebe83b2019-06-13 17:43:52 -0700316 crypto_test_utils::ProofSourceForTesting(), KeyExchangeSource::Default());
QUICHE teama6ef0a62019-03-07 20:34:33 -0500317 crypto_test_utils::SetupCryptoServerConfigForTest(
nharperba5f32c2019-05-13 12:21:31 -0700318 connection_->clock(), QuicRandom::GetInstance(), &crypto_config);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500319 SourceAddressTokens tokens;
320 QuicCompressedCertsCache cache(1);
321 CachedNetworkParameters network_params;
322 CryptoHandshakeMessage server_config_update;
323
324 class Callback : public BuildServerConfigUpdateMessageResultCallback {
325 public:
326 Callback(bool* ok, CryptoHandshakeMessage* message)
327 : ok_(ok), message_(message) {}
328 void Run(bool ok, const CryptoHandshakeMessage& message) override {
329 *ok_ = ok;
330 *message_ = message;
331 }
332
333 private:
334 bool* ok_;
335 CryptoHandshakeMessage* message_;
336 };
337
338 // Note: relies on the callback being invoked synchronously
339 bool ok = false;
340 crypto_config.BuildServerConfigUpdateMessage(
renjietangd1d00852019-09-06 10:43:12 -0700341 session_->transport_version(), stream()->chlo_hash(), tokens,
342 QuicSocketAddress(QuicIpAddress::Loopback6(), 1234),
QUICHE teama6ef0a62019-03-07 20:34:33 -0500343 QuicIpAddress::Loopback6(), connection_->clock(),
344 QuicRandom::GetInstance(), &cache, stream()->crypto_negotiated_params(),
345 &network_params,
346 std::unique_ptr<BuildServerConfigUpdateMessageResultCallback>(
347 new Callback(&ok, &server_config_update)));
348 EXPECT_TRUE(ok);
349
350 EXPECT_CALL(*session_, OnProofValid(testing::_));
351 crypto_test_utils::SendHandshakeMessageToStream(
352 stream(), server_config_update, Perspective::IS_SERVER);
353
354 // Recreate connection with the new config and verify a 0-RTT attempt.
355 CreateConnection();
356
357 EXPECT_CALL(*connection_, OnCanWrite());
358 EXPECT_CALL(*session_, OnProofValid(testing::_));
359 EXPECT_CALL(*session_, OnProofVerifyDetailsAvailable(testing::_))
360 .Times(testing::AnyNumber());
361 stream()->CryptoConnect();
362 EXPECT_TRUE(session_->IsEncryptionEstablished());
363}
364
365TEST_F(QuicCryptoClientStreamTest, ServerConfigUpdateBeforeHandshake) {
366 EXPECT_CALL(
367 *connection_,
368 CloseConnection(QUIC_CRYPTO_UPDATE_BEFORE_HANDSHAKE_COMPLETE, _, _));
369 CryptoHandshakeMessage server_config_update;
370 server_config_update.set_tag(kSCUP);
371 crypto_test_utils::SendHandshakeMessageToStream(
372 stream(), server_config_update, Perspective::IS_SERVER);
373}
374
QUICHE teama6ef0a62019-03-07 20:34:33 -0500375TEST_F(QuicCryptoClientStreamTest, PreferredVersion) {
376 // This mimics the case where client receives version negotiation packet, such
377 // that, the preferred version is different from the packets' version.
378 connection_ = new PacketSavingConnection(
379 &client_helper_, &alarm_factory_, Perspective::IS_CLIENT,
380 ParsedVersionOfIndex(supported_versions_, 1));
381 connection_->AdvanceTime(QuicTime::Delta::FromSeconds(1));
382
vasilvv0fc587f2019-09-06 13:33:08 -0700383 session_ = std::make_unique<TestQuicSpdyClientSession>(
QUICHE teama6ef0a62019-03-07 20:34:33 -0500384 connection_, DefaultQuicConfig(), supported_versions_, server_id_,
385 &crypto_config_);
386 CompleteCryptoHandshake();
387 // 2 CHLOs are sent.
388 ASSERT_EQ(2u, session_->sent_crypto_handshake_messages().size());
389 // Verify preferred version is the highest version that session supports, and
390 // is different from connection's version.
391 QuicVersionLabel client_version_label;
bncf54082a2019-11-27 10:19:47 -0800392 EXPECT_THAT(session_->sent_crypto_handshake_messages()[0].GetVersionLabel(
393 kVER, &client_version_label),
394 IsQuicNoError());
QUICHE teama6ef0a62019-03-07 20:34:33 -0500395 EXPECT_EQ(CreateQuicVersionLabel(supported_versions_[0]),
396 client_version_label);
bncf54082a2019-11-27 10:19:47 -0800397 EXPECT_THAT(session_->sent_crypto_handshake_messages()[1].GetVersionLabel(
398 kVER, &client_version_label),
399 IsQuicNoError());
QUICHE teama6ef0a62019-03-07 20:34:33 -0500400 EXPECT_EQ(CreateQuicVersionLabel(supported_versions_[0]),
401 client_version_label);
402 EXPECT_NE(CreateQuicVersionLabel(connection_->version()),
403 client_version_label);
404}
405
QUICHE teama6ef0a62019-03-07 20:34:33 -0500406} // namespace
407} // namespace test
408} // namespace quic