blob: 7f6d7770eb66f445ef0ecf12109db8451ee60592 [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_flags.h"
QUICHE teama6ef0a62019-03-07 20:34:33 -050018#include "net/third_party/quiche/src/quic/platform/api/quic_test.h"
19#include "net/third_party/quiche/src/quic/test_tools/crypto_test_utils.h"
20#include "net/third_party/quiche/src/quic/test_tools/quic_stream_peer.h"
21#include "net/third_party/quiche/src/quic/test_tools/quic_stream_sequencer_peer.h"
22#include "net/third_party/quiche/src/quic/test_tools/quic_test_utils.h"
23#include "net/third_party/quiche/src/quic/test_tools/simple_quic_framer.h"
nharperdf7a77b2019-11-11 13:12:45 -080024#include "net/third_party/quiche/src/quic/test_tools/simple_session_cache.h"
bnc4e9283d2019-12-17 07:08:57 -080025#include "net/third_party/quiche/src/common/platform/api/quiche_arraysize.h"
dmcardle8f7df532020-01-07 13:28:57 -080026#include "net/third_party/quiche/src/common/test_tools/quiche_test_utils.h"
QUICHE teama6ef0a62019-03-07 20:34:33 -050027
28using testing::_;
29
30namespace quic {
31namespace test {
32namespace {
33
34const char kServerHostname[] = "test.example.com";
35const uint16_t kServerPort = 443;
36
nharperc1873ae2020-04-15 11:24:25 -070037// This test tests the client-side of the QUIC crypto handshake. It does not
38// test the TLS handshake - that is in tls_client_handshaker_test.cc.
QUICHE teama6ef0a62019-03-07 20:34:33 -050039class QuicCryptoClientStreamTest : public QuicTest {
40 public:
41 QuicCryptoClientStreamTest()
nharperc1873ae2020-04-15 11:24:25 -070042 : supported_versions_(AllSupportedVersionsWithQuicCrypto()),
QUICHE teama6ef0a62019-03-07 20:34:33 -050043 server_id_(kServerHostname, kServerPort, false),
nharperdf7a77b2019-11-11 13:12:45 -080044 crypto_config_(crypto_test_utils::ProofVerifierForTesting(),
45 std::make_unique<test::SimpleSessionCache>()),
46 server_crypto_config_(
47 crypto_test_utils::CryptoServerConfigForTesting()) {
QUICHE teama6ef0a62019-03-07 20:34:33 -050048 CreateConnection();
49 }
50
dschinazidffd2982020-03-02 10:25:11 -080051 void CreateSession() {
vasilvv0fc587f2019-09-06 13:33:08 -070052 session_ = std::make_unique<TestQuicSpdyClientSession>(
QUICHE teama6ef0a62019-03-07 20:34:33 -050053 connection_, DefaultQuicConfig(), supported_versions_, server_id_,
54 &crypto_config_);
vasilvvefc6af82019-10-11 12:46:56 -070055 EXPECT_CALL(*session_, GetAlpnsToOffer())
56 .WillRepeatedly(testing::Return(std::vector<std::string>(
57 {AlpnForVersion(connection_->version())})));
QUICHE teama6ef0a62019-03-07 20:34:33 -050058 }
59
dschinazidffd2982020-03-02 10:25:11 -080060 void CreateConnection() {
61 connection_ =
62 new PacketSavingConnection(&client_helper_, &alarm_factory_,
63 Perspective::IS_CLIENT, supported_versions_);
64 // Advance the time, because timers do not like uninitialized times.
65 connection_->AdvanceTime(QuicTime::Delta::FromSeconds(1));
66 CreateSession();
67 }
68
QUICHE teama6ef0a62019-03-07 20:34:33 -050069 void CompleteCryptoHandshake() {
nharper1473c092019-11-11 13:13:19 -080070 int proof_verify_details_calls = 1;
QUICHE teama6ef0a62019-03-07 20:34:33 -050071 if (stream()->handshake_protocol() != PROTOCOL_TLS1_3) {
72 EXPECT_CALL(*session_, OnProofValid(testing::_));
nharper1473c092019-11-11 13:13:19 -080073 proof_verify_details_calls = 0;
QUICHE teama6ef0a62019-03-07 20:34:33 -050074 }
75 EXPECT_CALL(*session_, OnProofVerifyDetailsAvailable(testing::_))
nharper1473c092019-11-11 13:13:19 -080076 .Times(testing::AtLeast(proof_verify_details_calls));
QUICHE teama6ef0a62019-03-07 20:34:33 -050077 stream()->CryptoConnect();
78 QuicConfig config;
nharperba5f32c2019-05-13 12:21:31 -070079 crypto_test_utils::HandshakeWithFakeServer(
rch83f29bd2019-11-13 11:47:34 -080080 &config, server_crypto_config_.get(), &server_helper_, &alarm_factory_,
nharperdf7a77b2019-11-11 13:12:45 -080081 connection_, stream(), AlpnForVersion(connection_->version()));
QUICHE teama6ef0a62019-03-07 20:34:33 -050082 }
83
84 QuicCryptoClientStream* stream() {
85 return session_->GetMutableCryptoStream();
86 }
87
88 MockQuicConnectionHelper server_helper_;
89 MockQuicConnectionHelper client_helper_;
90 MockAlarmFactory alarm_factory_;
91 PacketSavingConnection* connection_;
92 ParsedQuicVersionVector supported_versions_;
93 std::unique_ptr<TestQuicSpdyClientSession> session_;
94 QuicServerId server_id_;
95 CryptoHandshakeMessage message_;
96 QuicCryptoClientConfig crypto_config_;
rch83f29bd2019-11-13 11:47:34 -080097 std::unique_ptr<QuicCryptoServerConfig> server_crypto_config_;
QUICHE teama6ef0a62019-03-07 20:34:33 -050098};
99
100TEST_F(QuicCryptoClientStreamTest, NotInitiallyConected) {
101 EXPECT_FALSE(stream()->encryption_established());
fayang685367a2020-01-14 10:40:15 -0800102 EXPECT_FALSE(stream()->one_rtt_keys_available());
QUICHE teama6ef0a62019-03-07 20:34:33 -0500103}
104
105TEST_F(QuicCryptoClientStreamTest, ConnectedAfterSHLO) {
106 CompleteCryptoHandshake();
107 EXPECT_TRUE(stream()->encryption_established());
fayang685367a2020-01-14 10:40:15 -0800108 EXPECT_TRUE(stream()->one_rtt_keys_available());
nharper02703962019-11-07 12:23:13 -0800109 EXPECT_FALSE(stream()->IsResumption());
QUICHE teama6ef0a62019-03-07 20:34:33 -0500110}
111
QUICHE teama6ef0a62019-03-07 20:34:33 -0500112TEST_F(QuicCryptoClientStreamTest, MessageAfterHandshake) {
113 CompleteCryptoHandshake();
114
115 EXPECT_CALL(
116 *connection_,
117 CloseConnection(QUIC_CRYPTO_MESSAGE_AFTER_HANDSHAKE_COMPLETE, _, _));
118 message_.set_tag(kCHLO);
119 crypto_test_utils::SendHandshakeMessageToStream(stream(), message_,
120 Perspective::IS_CLIENT);
121}
122
123TEST_F(QuicCryptoClientStreamTest, BadMessageType) {
124 stream()->CryptoConnect();
125
126 message_.set_tag(kCHLO);
127
128 EXPECT_CALL(*connection_, CloseConnection(QUIC_INVALID_CRYPTO_MESSAGE_TYPE,
129 "Expected REJ", _));
130 crypto_test_utils::SendHandshakeMessageToStream(stream(), message_,
131 Perspective::IS_CLIENT);
132}
133
134TEST_F(QuicCryptoClientStreamTest, NegotiatedParameters) {
135 CompleteCryptoHandshake();
136
137 const QuicConfig* config = session_->config();
138 EXPECT_EQ(kMaximumIdleTimeoutSecs, config->IdleNetworkTimeout().ToSeconds());
139
140 const QuicCryptoNegotiatedParameters& crypto_params(
141 stream()->crypto_negotiated_params());
142 EXPECT_EQ(crypto_config_.aead[0], crypto_params.aead);
143 EXPECT_EQ(crypto_config_.kexs[0], crypto_params.key_exchange);
144}
145
146TEST_F(QuicCryptoClientStreamTest, ExpiredServerConfig) {
147 // Seed the config with a cached server config.
148 CompleteCryptoHandshake();
149
150 // Recreate connection with the new config.
151 CreateConnection();
152
153 // Advance time 5 years to ensure that we pass the expiry time of the cached
154 // server config.
155 connection_->AdvanceTime(
156 QuicTime::Delta::FromSeconds(60 * 60 * 24 * 365 * 5));
157
158 EXPECT_CALL(*session_, OnProofValid(testing::_));
159 stream()->CryptoConnect();
160 // Check that a client hello was sent.
161 ASSERT_EQ(1u, connection_->encrypted_packets_.size());
QUICHE team6987b4a2019-03-15 16:23:04 -0700162 EXPECT_EQ(ENCRYPTION_INITIAL, connection_->encryption_level());
QUICHE teama6ef0a62019-03-07 20:34:33 -0500163}
164
renjietang1b5d1e12020-06-23 17:45:20 -0700165TEST_F(QuicCryptoClientStreamTest, ClientTurnedOffZeroRtt) {
166 // Seed the config with a cached server config.
167 CompleteCryptoHandshake();
168
169 // Recreate connection with the new config.
170 CreateConnection();
171
172 // Set connection option.
173 QuicTagVector options;
174 options.push_back(kQNZR);
175 session_->config()->SetClientConnectionOptions(options);
176
177 EXPECT_CALL(*session_, OnProofValid(testing::_));
178 stream()->CryptoConnect();
179 // Check that a client hello was sent.
180 ASSERT_EQ(1u, connection_->encrypted_packets_.size());
181 EXPECT_EQ(ENCRYPTION_INITIAL, connection_->encryption_level());
182}
183
QUICHE teama6ef0a62019-03-07 20:34:33 -0500184TEST_F(QuicCryptoClientStreamTest, ClockSkew) {
185 // Test that if the client's clock is skewed with respect to the server,
186 // the handshake succeeds. In the past, the client would get the server
187 // config, notice that it had already expired and then close the connection.
188
189 // Advance time 5 years to ensure that we pass the expiry time in the server
190 // config, but the TTL is used instead.
191 connection_->AdvanceTime(
192 QuicTime::Delta::FromSeconds(60 * 60 * 24 * 365 * 5));
193
194 // The handshakes completes!
195 CompleteCryptoHandshake();
196}
197
198TEST_F(QuicCryptoClientStreamTest, InvalidCachedServerConfig) {
199 // Seed the config with a cached server config.
200 CompleteCryptoHandshake();
201
202 // Recreate connection with the new config.
203 CreateConnection();
204
205 QuicCryptoClientConfig::CachedState* state =
206 crypto_config_.LookupOrCreate(server_id_);
207
vasilvvc48c8712019-03-11 13:38:16 -0700208 std::vector<std::string> certs = state->certs();
209 std::string cert_sct = state->cert_sct();
210 std::string signature = state->signature();
211 std::string chlo_hash = state->chlo_hash();
QUICHE teama6ef0a62019-03-07 20:34:33 -0500212 state->SetProof(certs, cert_sct, chlo_hash, signature + signature);
213
214 EXPECT_CALL(*session_, OnProofVerifyDetailsAvailable(testing::_))
215 .Times(testing::AnyNumber());
216 stream()->CryptoConnect();
217 // Check that a client hello was sent.
218 ASSERT_EQ(1u, connection_->encrypted_packets_.size());
219}
220
221TEST_F(QuicCryptoClientStreamTest, ServerConfigUpdate) {
222 // Test that the crypto client stream can receive server config updates after
223 // the connection has been established.
224 CompleteCryptoHandshake();
225
226 QuicCryptoClientConfig::CachedState* state =
227 crypto_config_.LookupOrCreate(server_id_);
228
229 // Ensure cached STK is different to what we send in the handshake.
230 EXPECT_NE("xstk", state->source_address_token());
231
232 // Initialize using {...} syntax to avoid trailing \0 if converting from
233 // string.
234 unsigned char stk[] = {'x', 's', 't', 'k'};
235
236 // Minimum SCFG that passes config validation checks.
237 unsigned char scfg[] = {// SCFG
238 0x53, 0x43, 0x46, 0x47,
239 // num entries
240 0x01, 0x00,
241 // padding
242 0x00, 0x00,
243 // EXPY
244 0x45, 0x58, 0x50, 0x59,
245 // EXPY end offset
246 0x08, 0x00, 0x00, 0x00,
247 // Value
248 '1', '2', '3', '4', '5', '6', '7', '8'};
249
250 CryptoHandshakeMessage server_config_update;
251 server_config_update.set_tag(kSCUP);
252 server_config_update.SetValue(kSourceAddressTokenTag, stk);
253 server_config_update.SetValue(kSCFG, scfg);
254 const uint64_t expiry_seconds = 60 * 60 * 24 * 2;
255 server_config_update.SetValue(kSTTL, expiry_seconds);
256
257 crypto_test_utils::SendHandshakeMessageToStream(
258 stream(), server_config_update, Perspective::IS_SERVER);
259
260 // Make sure that the STK and SCFG are cached correctly.
261 EXPECT_EQ("xstk", state->source_address_token());
262
vasilvvc48c8712019-03-11 13:38:16 -0700263 const std::string& cached_scfg = state->server_config();
dmcardle8f7df532020-01-07 13:28:57 -0800264 quiche::test::CompareCharArraysWithHexError(
QUICHE teama6ef0a62019-03-07 20:34:33 -0500265 "scfg", cached_scfg.data(), cached_scfg.length(),
bnc4e9283d2019-12-17 07:08:57 -0800266 reinterpret_cast<char*>(scfg), QUICHE_ARRAYSIZE(scfg));
QUICHE teama6ef0a62019-03-07 20:34:33 -0500267
268 QuicStreamSequencer* sequencer = QuicStreamPeer::sequencer(stream());
269 EXPECT_FALSE(QuicStreamSequencerPeer::IsUnderlyingBufferAllocated(sequencer));
270}
271
272TEST_F(QuicCryptoClientStreamTest, ServerConfigUpdateWithCert) {
273 // Test that the crypto client stream can receive and use server config
274 // updates with certificates after the connection has been established.
275 CompleteCryptoHandshake();
276
277 // Build a server config update message with certificates
278 QuicCryptoServerConfig crypto_config(
279 QuicCryptoServerConfig::TESTING, QuicRandom::GetInstance(),
nharper6ebe83b2019-06-13 17:43:52 -0700280 crypto_test_utils::ProofSourceForTesting(), KeyExchangeSource::Default());
QUICHE teama6ef0a62019-03-07 20:34:33 -0500281 crypto_test_utils::SetupCryptoServerConfigForTest(
nharperba5f32c2019-05-13 12:21:31 -0700282 connection_->clock(), QuicRandom::GetInstance(), &crypto_config);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500283 SourceAddressTokens tokens;
284 QuicCompressedCertsCache cache(1);
285 CachedNetworkParameters network_params;
286 CryptoHandshakeMessage server_config_update;
287
288 class Callback : public BuildServerConfigUpdateMessageResultCallback {
289 public:
290 Callback(bool* ok, CryptoHandshakeMessage* message)
291 : ok_(ok), message_(message) {}
292 void Run(bool ok, const CryptoHandshakeMessage& message) override {
293 *ok_ = ok;
294 *message_ = message;
295 }
296
297 private:
298 bool* ok_;
299 CryptoHandshakeMessage* message_;
300 };
301
302 // Note: relies on the callback being invoked synchronously
303 bool ok = false;
304 crypto_config.BuildServerConfigUpdateMessage(
renjietangd1d00852019-09-06 10:43:12 -0700305 session_->transport_version(), stream()->chlo_hash(), tokens,
306 QuicSocketAddress(QuicIpAddress::Loopback6(), 1234),
danzhd1fc5912020-05-01 15:29:04 -0700307 QuicSocketAddress(QuicIpAddress::Loopback6(), 4321), connection_->clock(),
QUICHE teama6ef0a62019-03-07 20:34:33 -0500308 QuicRandom::GetInstance(), &cache, stream()->crypto_negotiated_params(),
309 &network_params,
310 std::unique_ptr<BuildServerConfigUpdateMessageResultCallback>(
311 new Callback(&ok, &server_config_update)));
312 EXPECT_TRUE(ok);
313
314 EXPECT_CALL(*session_, OnProofValid(testing::_));
315 crypto_test_utils::SendHandshakeMessageToStream(
316 stream(), server_config_update, Perspective::IS_SERVER);
317
318 // Recreate connection with the new config and verify a 0-RTT attempt.
319 CreateConnection();
320
QUICHE teama6ef0a62019-03-07 20:34:33 -0500321 EXPECT_CALL(*session_, OnProofValid(testing::_));
322 EXPECT_CALL(*session_, OnProofVerifyDetailsAvailable(testing::_))
323 .Times(testing::AnyNumber());
324 stream()->CryptoConnect();
325 EXPECT_TRUE(session_->IsEncryptionEstablished());
326}
327
328TEST_F(QuicCryptoClientStreamTest, ServerConfigUpdateBeforeHandshake) {
329 EXPECT_CALL(
330 *connection_,
331 CloseConnection(QUIC_CRYPTO_UPDATE_BEFORE_HANDSHAKE_COMPLETE, _, _));
332 CryptoHandshakeMessage server_config_update;
333 server_config_update.set_tag(kSCUP);
334 crypto_test_utils::SendHandshakeMessageToStream(
335 stream(), server_config_update, Perspective::IS_SERVER);
336}
337
QUICHE teama6ef0a62019-03-07 20:34:33 -0500338TEST_F(QuicCryptoClientStreamTest, PreferredVersion) {
339 // This mimics the case where client receives version negotiation packet, such
340 // that, the preferred version is different from the packets' version.
341 connection_ = new PacketSavingConnection(
342 &client_helper_, &alarm_factory_, Perspective::IS_CLIENT,
343 ParsedVersionOfIndex(supported_versions_, 1));
344 connection_->AdvanceTime(QuicTime::Delta::FromSeconds(1));
345
dschinazidffd2982020-03-02 10:25:11 -0800346 CreateSession();
QUICHE teama6ef0a62019-03-07 20:34:33 -0500347 CompleteCryptoHandshake();
348 // 2 CHLOs are sent.
349 ASSERT_EQ(2u, session_->sent_crypto_handshake_messages().size());
350 // Verify preferred version is the highest version that session supports, and
351 // is different from connection's version.
352 QuicVersionLabel client_version_label;
bncf54082a2019-11-27 10:19:47 -0800353 EXPECT_THAT(session_->sent_crypto_handshake_messages()[0].GetVersionLabel(
354 kVER, &client_version_label),
355 IsQuicNoError());
QUICHE teama6ef0a62019-03-07 20:34:33 -0500356 EXPECT_EQ(CreateQuicVersionLabel(supported_versions_[0]),
357 client_version_label);
bncf54082a2019-11-27 10:19:47 -0800358 EXPECT_THAT(session_->sent_crypto_handshake_messages()[1].GetVersionLabel(
359 kVER, &client_version_label),
360 IsQuicNoError());
QUICHE teama6ef0a62019-03-07 20:34:33 -0500361 EXPECT_EQ(CreateQuicVersionLabel(supported_versions_[0]),
362 client_version_label);
363 EXPECT_NE(CreateQuicVersionLabel(connection_->version()),
364 client_version_label);
365}
366
QUICHE teama6ef0a62019-03-07 20:34:33 -0500367} // namespace
368} // namespace test
369} // namespace quic