blob: b58d987e6eee39d92c122de10dcd72ac6e4631b7 [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_server_stream.h"
6
7#include <map>
8#include <memory>
9#include <vector>
10
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/crypto_framer.h"
13#include "net/third_party/quiche/src/quic/core/crypto/crypto_handshake.h"
14#include "net/third_party/quiche/src/quic/core/crypto/crypto_protocol.h"
15#include "net/third_party/quiche/src/quic/core/crypto/crypto_utils.h"
16#include "net/third_party/quiche/src/quic/core/crypto/quic_crypto_server_config.h"
17#include "net/third_party/quiche/src/quic/core/crypto/quic_decrypter.h"
18#include "net/third_party/quiche/src/quic/core/crypto/quic_encrypter.h"
19#include "net/third_party/quiche/src/quic/core/crypto/quic_random.h"
20#include "net/third_party/quiche/src/quic/core/quic_crypto_client_stream.h"
21#include "net/third_party/quiche/src/quic/core/quic_packets.h"
22#include "net/third_party/quiche/src/quic/core/quic_session.h"
23#include "net/third_party/quiche/src/quic/core/quic_utils.h"
QUICHE teama6ef0a62019-03-07 20:34:33 -050024#include "net/third_party/quiche/src/quic/platform/api/quic_flags.h"
25#include "net/third_party/quiche/src/quic/platform/api/quic_logging.h"
26#include "net/third_party/quiche/src/quic/platform/api/quic_ptr_util.h"
27#include "net/third_party/quiche/src/quic/platform/api/quic_socket_address.h"
28#include "net/third_party/quiche/src/quic/platform/api/quic_test.h"
29#include "net/third_party/quiche/src/quic/test_tools/crypto_test_utils.h"
30#include "net/third_party/quiche/src/quic/test_tools/failing_proof_source.h"
31#include "net/third_party/quiche/src/quic/test_tools/fake_proof_source.h"
32#include "net/third_party/quiche/src/quic/test_tools/quic_crypto_server_config_peer.h"
33#include "net/third_party/quiche/src/quic/test_tools/quic_test_utils.h"
34
35namespace quic {
36class QuicConnection;
37class QuicStream;
38} // namespace quic
39
40using testing::_;
41using testing::NiceMock;
42
43namespace quic {
44namespace test {
45
QUICHE teama6ef0a62019-03-07 20:34:33 -050046namespace {
47
48const char kServerHostname[] = "test.example.com";
49const uint16_t kServerPort = 443;
50
51class QuicCryptoServerStreamTest : public QuicTestWithParam<bool> {
52 public:
53 QuicCryptoServerStreamTest()
54 : QuicCryptoServerStreamTest(crypto_test_utils::ProofSourceForTesting()) {
55 }
56
57 explicit QuicCryptoServerStreamTest(std::unique_ptr<ProofSource> proof_source)
58 : server_crypto_config_(QuicCryptoServerConfig::TESTING,
59 QuicRandom::GetInstance(),
60 std::move(proof_source),
nharper6ebe83b2019-06-13 17:43:52 -070061 KeyExchangeSource::Default()),
QUICHE teama6ef0a62019-03-07 20:34:33 -050062 server_compressed_certs_cache_(
63 QuicCompressedCertsCache::kQuicCompressedCertsCacheSize),
64 server_id_(kServerHostname, kServerPort, false),
nharper6ebe83b2019-06-13 17:43:52 -070065 client_crypto_config_(crypto_test_utils::ProofVerifierForTesting()) {}
QUICHE teama6ef0a62019-03-07 20:34:33 -050066
67 void Initialize() { InitializeServer(); }
68
69 ~QuicCryptoServerStreamTest() override {
70 // Ensure that anything that might reference |helpers_| is destroyed before
71 // |helpers_| is destroyed.
72 server_session_.reset();
73 client_session_.reset();
74 helpers_.clear();
75 alarm_factories_.clear();
76 }
77
78 // Initializes the crypto server stream state for testing. May be
79 // called multiple times.
80 void InitializeServer() {
81 TestQuicSpdyServerSession* server_session = nullptr;
82 helpers_.push_back(QuicMakeUnique<NiceMock<MockQuicConnectionHelper>>());
83 alarm_factories_.push_back(QuicMakeUnique<MockAlarmFactory>());
84 CreateServerSessionForTest(
85 server_id_, QuicTime::Delta::FromSeconds(100000), supported_versions_,
86 helpers_.back().get(), alarm_factories_.back().get(),
87 &server_crypto_config_, &server_compressed_certs_cache_,
88 &server_connection_, &server_session);
89 CHECK(server_session);
90 server_session_.reset(server_session);
91 EXPECT_CALL(*server_session_->helper(), CanAcceptClientHello(_, _, _, _, _))
92 .Times(testing::AnyNumber());
QUICHE teama6ef0a62019-03-07 20:34:33 -050093 crypto_test_utils::SetupCryptoServerConfigForTest(
94 server_connection_->clock(), server_connection_->random_generator(),
nharperba5f32c2019-05-13 12:21:31 -070095 &server_crypto_config_);
QUICHE teama6ef0a62019-03-07 20:34:33 -050096 server_session_->GetMutableCryptoStream()->OnSuccessfulVersionNegotiation(
97 supported_versions_.front());
98 }
99
100 QuicCryptoServerStream* server_stream() {
101 return server_session_->GetMutableCryptoStream();
102 }
103
104 QuicCryptoClientStream* client_stream() {
105 return client_session_->GetMutableCryptoStream();
106 }
107
108 // Initializes a fake client, and all its associated state, for
109 // testing. May be called multiple times.
wube9dc7da2019-05-22 06:08:54 -0700110 void InitializeFakeClient() {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500111 TestQuicSpdyClientSession* client_session = nullptr;
112 helpers_.push_back(QuicMakeUnique<NiceMock<MockQuicConnectionHelper>>());
113 alarm_factories_.push_back(QuicMakeUnique<MockAlarmFactory>());
114 CreateClientSessionForTest(
wube9dc7da2019-05-22 06:08:54 -0700115 server_id_, QuicTime::Delta::FromSeconds(100000), supported_versions_,
QUICHE teama6ef0a62019-03-07 20:34:33 -0500116 helpers_.back().get(), alarm_factories_.back().get(),
117 &client_crypto_config_, &client_connection_, &client_session);
118 CHECK(client_session);
119 client_session_.reset(client_session);
120 }
121
122 int CompleteCryptoHandshake() {
123 CHECK(server_connection_);
124 CHECK(server_session_ != nullptr);
125
126 return crypto_test_utils::HandshakeWithFakeClient(
127 helpers_.back().get(), alarm_factories_.back().get(),
128 server_connection_, server_stream(), server_id_, client_options_);
129 }
130
131 // Performs a single round of handshake message-exchange between the
132 // client and server.
133 void AdvanceHandshakeWithFakeClient() {
134 CHECK(server_connection_);
135 CHECK(client_session_ != nullptr);
136
137 EXPECT_CALL(*client_session_, OnProofValid(_)).Times(testing::AnyNumber());
138 EXPECT_CALL(*client_session_, OnProofVerifyDetailsAvailable(_))
139 .Times(testing::AnyNumber());
140 EXPECT_CALL(*client_connection_, OnCanWrite()).Times(testing::AnyNumber());
141 EXPECT_CALL(*server_connection_, OnCanWrite()).Times(testing::AnyNumber());
142 client_stream()->CryptoConnect();
143 crypto_test_utils::AdvanceHandshake(client_connection_, client_stream(), 0,
144 server_connection_, server_stream(), 0);
145 }
146
147 protected:
148 // Every connection gets its own MockQuicConnectionHelper and
149 // MockAlarmFactory, tracked separately from the server and client state so
150 // their lifetimes persist through the whole test.
151 std::vector<std::unique_ptr<MockQuicConnectionHelper>> helpers_;
152 std::vector<std::unique_ptr<MockAlarmFactory>> alarm_factories_;
153
154 // Server state.
155 PacketSavingConnection* server_connection_;
156 std::unique_ptr<TestQuicSpdyServerSession> server_session_;
157 QuicCryptoServerConfig server_crypto_config_;
158 QuicCompressedCertsCache server_compressed_certs_cache_;
159 QuicServerId server_id_;
160
161 // Client state.
162 PacketSavingConnection* client_connection_;
163 QuicCryptoClientConfig client_crypto_config_;
164 std::unique_ptr<TestQuicSpdyClientSession> client_session_;
165
166 CryptoHandshakeMessage message_;
167 crypto_test_utils::FakeClientOptions client_options_;
168
169 // Which QUIC versions the client and server support.
170 ParsedQuicVersionVector supported_versions_ = AllSupportedVersions();
171};
172
173INSTANTIATE_TEST_SUITE_P(Tests, QuicCryptoServerStreamTest, testing::Bool());
174
175TEST_P(QuicCryptoServerStreamTest, NotInitiallyConected) {
176 Initialize();
177 EXPECT_FALSE(server_stream()->encryption_established());
178 EXPECT_FALSE(server_stream()->handshake_confirmed());
179}
180
QUICHE teama6ef0a62019-03-07 20:34:33 -0500181TEST_P(QuicCryptoServerStreamTest, ConnectedAfterCHLO) {
182 // CompleteCryptoHandshake returns the number of client hellos sent. This
183 // test should send:
184 // * One to get a source-address token and certificates.
185 // * One to complete the handshake.
186 Initialize();
187 EXPECT_EQ(2, CompleteCryptoHandshake());
188 EXPECT_TRUE(server_stream()->encryption_established());
189 EXPECT_TRUE(server_stream()->handshake_confirmed());
190}
191
192TEST_P(QuicCryptoServerStreamTest, ConnectedAfterTlsHandshake) {
wub49855982019-05-01 14:16:26 -0700193 SetQuicFlag(FLAGS_quic_supports_tls_handshake, true);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500194 client_options_.only_tls_versions = true;
195 supported_versions_.clear();
196 for (QuicTransportVersion transport_version :
197 AllSupportedTransportVersions()) {
198 supported_versions_.push_back(
199 ParsedQuicVersion(PROTOCOL_TLS1_3, transport_version));
200 }
201 Initialize();
202 CompleteCryptoHandshake();
203 EXPECT_EQ(PROTOCOL_TLS1_3, server_stream()->handshake_protocol());
204 EXPECT_TRUE(server_stream()->encryption_established());
205 EXPECT_TRUE(server_stream()->handshake_confirmed());
206}
207
208TEST_P(QuicCryptoServerStreamTest, ForwardSecureAfterCHLO) {
209 Initialize();
wube9dc7da2019-05-22 06:08:54 -0700210 InitializeFakeClient();
QUICHE teama6ef0a62019-03-07 20:34:33 -0500211
212 // Do a first handshake in order to prime the client config with the server's
213 // information.
214 AdvanceHandshakeWithFakeClient();
215 EXPECT_FALSE(server_stream()->encryption_established());
216 EXPECT_FALSE(server_stream()->handshake_confirmed());
217
218 // Now do another handshake, with the blocking SHLO connection option.
219 InitializeServer();
wube9dc7da2019-05-22 06:08:54 -0700220 InitializeFakeClient();
QUICHE teama6ef0a62019-03-07 20:34:33 -0500221
222 AdvanceHandshakeWithFakeClient();
223 EXPECT_TRUE(server_stream()->encryption_established());
224 EXPECT_TRUE(server_stream()->handshake_confirmed());
225 EXPECT_EQ(ENCRYPTION_FORWARD_SECURE,
226 server_session_->connection()->encryption_level());
227}
228
QUICHE teama6ef0a62019-03-07 20:34:33 -0500229TEST_P(QuicCryptoServerStreamTest, ZeroRTT) {
230 Initialize();
wube9dc7da2019-05-22 06:08:54 -0700231 InitializeFakeClient();
QUICHE teama6ef0a62019-03-07 20:34:33 -0500232
233 // Do a first handshake in order to prime the client config with the server's
234 // information.
235 AdvanceHandshakeWithFakeClient();
236 EXPECT_FALSE(server_stream()->ZeroRttAttempted());
237
238 // Now do another handshake, hopefully in 0-RTT.
239 QUIC_LOG(INFO) << "Resetting for 0-RTT handshake attempt";
wube9dc7da2019-05-22 06:08:54 -0700240 InitializeFakeClient();
QUICHE teama6ef0a62019-03-07 20:34:33 -0500241 InitializeServer();
242
243 EXPECT_CALL(*client_session_, OnProofValid(_)).Times(testing::AnyNumber());
244 EXPECT_CALL(*client_session_, OnProofVerifyDetailsAvailable(_))
245 .Times(testing::AnyNumber());
246 EXPECT_CALL(*client_connection_, OnCanWrite()).Times(testing::AnyNumber());
247 client_stream()->CryptoConnect();
248
249 EXPECT_CALL(*client_session_, OnProofValid(_)).Times(testing::AnyNumber());
250 EXPECT_CALL(*client_session_, OnProofVerifyDetailsAvailable(_))
251 .Times(testing::AnyNumber());
252 EXPECT_CALL(*client_connection_, OnCanWrite()).Times(testing::AnyNumber());
253 crypto_test_utils::CommunicateHandshakeMessages(
254 client_connection_, client_stream(), server_connection_, server_stream());
255
256 EXPECT_EQ(1, client_stream()->num_sent_client_hellos());
257 EXPECT_TRUE(server_stream()->ZeroRttAttempted());
258}
259
260TEST_P(QuicCryptoServerStreamTest, FailByPolicy) {
261 Initialize();
wube9dc7da2019-05-22 06:08:54 -0700262 InitializeFakeClient();
QUICHE teama6ef0a62019-03-07 20:34:33 -0500263
264 EXPECT_CALL(*server_session_->helper(), CanAcceptClientHello(_, _, _, _, _))
265 .WillOnce(testing::Return(false));
266 EXPECT_CALL(*server_connection_,
267 CloseConnection(QUIC_HANDSHAKE_FAILED, _, _));
268
269 AdvanceHandshakeWithFakeClient();
270}
271
272TEST_P(QuicCryptoServerStreamTest, MessageAfterHandshake) {
273 Initialize();
274 CompleteCryptoHandshake();
275 EXPECT_CALL(
276 *server_connection_,
277 CloseConnection(QUIC_CRYPTO_MESSAGE_AFTER_HANDSHAKE_COMPLETE, _, _));
278 message_.set_tag(kCHLO);
279 crypto_test_utils::SendHandshakeMessageToStream(server_stream(), message_,
280 Perspective::IS_CLIENT);
281}
282
283TEST_P(QuicCryptoServerStreamTest, BadMessageType) {
284 Initialize();
285
286 message_.set_tag(kSHLO);
287 EXPECT_CALL(*server_connection_,
288 CloseConnection(QUIC_INVALID_CRYPTO_MESSAGE_TYPE, _, _));
289 crypto_test_utils::SendHandshakeMessageToStream(server_stream(), message_,
290 Perspective::IS_SERVER);
291}
292
QUICHE teama6ef0a62019-03-07 20:34:33 -0500293TEST_P(QuicCryptoServerStreamTest, OnlySendSCUPAfterHandshakeComplete) {
294 // An attempt to send a SCUP before completing handshake should fail.
295 Initialize();
296
297 server_stream()->SendServerConfigUpdate(nullptr);
298 EXPECT_EQ(0, server_stream()->NumServerConfigUpdateMessagesSent());
299}
300
301TEST_P(QuicCryptoServerStreamTest, SendSCUPAfterHandshakeComplete) {
302 Initialize();
303
wube9dc7da2019-05-22 06:08:54 -0700304 InitializeFakeClient();
QUICHE teama6ef0a62019-03-07 20:34:33 -0500305
306 // Do a first handshake in order to prime the client config with the server's
307 // information.
308 AdvanceHandshakeWithFakeClient();
309
310 // Now do another handshake, with the blocking SHLO connection option.
311 InitializeServer();
wube9dc7da2019-05-22 06:08:54 -0700312 InitializeFakeClient();
QUICHE teama6ef0a62019-03-07 20:34:33 -0500313 AdvanceHandshakeWithFakeClient();
314
315 // Send a SCUP message and ensure that the client was able to verify it.
316 EXPECT_CALL(*client_connection_, CloseConnection(_, _, _)).Times(0);
317 server_stream()->SendServerConfigUpdate(nullptr);
318 crypto_test_utils::AdvanceHandshake(client_connection_, client_stream(), 1,
319 server_connection_, server_stream(), 1);
320
321 EXPECT_EQ(1, server_stream()->NumServerConfigUpdateMessagesSent());
322 EXPECT_EQ(1, client_stream()->num_scup_messages_received());
323}
324
QUICHE teama6ef0a62019-03-07 20:34:33 -0500325class QuicCryptoServerStreamTestWithFailingProofSource
326 : public QuicCryptoServerStreamTest {
327 public:
328 QuicCryptoServerStreamTestWithFailingProofSource()
329 : QuicCryptoServerStreamTest(
330 std::unique_ptr<FailingProofSource>(new FailingProofSource)) {}
331};
332
333INSTANTIATE_TEST_SUITE_P(MoreTests,
334 QuicCryptoServerStreamTestWithFailingProofSource,
335 testing::Bool());
336
337TEST_P(QuicCryptoServerStreamTestWithFailingProofSource, Test) {
338 Initialize();
wube9dc7da2019-05-22 06:08:54 -0700339 InitializeFakeClient();
QUICHE teama6ef0a62019-03-07 20:34:33 -0500340
341 EXPECT_CALL(*server_session_->helper(), CanAcceptClientHello(_, _, _, _, _))
342 .WillOnce(testing::Return(true));
343 EXPECT_CALL(*server_connection_,
344 CloseConnection(QUIC_HANDSHAKE_FAILED, "Failed to get proof", _));
345 // Regression test for b/31521252, in which a crash would happen here.
346 AdvanceHandshakeWithFakeClient();
347 EXPECT_FALSE(server_stream()->encryption_established());
348 EXPECT_FALSE(server_stream()->handshake_confirmed());
349}
350
351class QuicCryptoServerStreamTestWithFakeProofSource
352 : public QuicCryptoServerStreamTest {
353 public:
354 QuicCryptoServerStreamTestWithFakeProofSource()
355 : QuicCryptoServerStreamTest(
356 std::unique_ptr<FakeProofSource>(new FakeProofSource)),
357 crypto_config_peer_(&server_crypto_config_) {}
358
359 FakeProofSource* GetFakeProofSource() const {
360 return static_cast<FakeProofSource*>(crypto_config_peer_.GetProofSource());
361 }
362
363 protected:
364 QuicCryptoServerConfigPeer crypto_config_peer_;
365};
366
367INSTANTIATE_TEST_SUITE_P(YetMoreTests,
368 QuicCryptoServerStreamTestWithFakeProofSource,
369 testing::Bool());
370
371// Regression test for b/35422225, in which multiple CHLOs arriving on the same
372// connection in close succession could cause a crash, especially when the use
373// of Mentat signing meant that it took a while for each CHLO to be processed.
374TEST_P(QuicCryptoServerStreamTestWithFakeProofSource, MultipleChlo) {
375 Initialize();
376 GetFakeProofSource()->Activate();
377 EXPECT_CALL(*server_session_->helper(), CanAcceptClientHello(_, _, _, _, _))
378 .WillOnce(testing::Return(true));
379
380 // Create a minimal CHLO
381 MockClock clock;
382 QuicTransportVersion version = AllSupportedTransportVersions().front();
383 CryptoHandshakeMessage chlo = crypto_test_utils::GenerateDefaultInchoateCHLO(
384 &clock, version, &server_crypto_config_);
385
386 // Send in the CHLO, and check that a callback is now pending in the
387 // ProofSource.
388 crypto_test_utils::SendHandshakeMessageToStream(server_stream(), chlo,
389 Perspective::IS_CLIENT);
390 EXPECT_EQ(GetFakeProofSource()->NumPendingCallbacks(), 1);
391
392 // Send in a second CHLO while processing of the first is still pending.
393 // Verify that the server closes the connection rather than crashing. Note
394 // that the crash is a use-after-free, so it may only show up consistently in
395 // ASAN tests.
396 EXPECT_CALL(
397 *server_connection_,
398 CloseConnection(QUIC_CRYPTO_MESSAGE_WHILE_VALIDATING_CLIENT_HELLO,
399 "Unexpected handshake message while processing CHLO", _));
400 crypto_test_utils::SendHandshakeMessageToStream(server_stream(), chlo,
401 Perspective::IS_CLIENT);
402}
403
404} // namespace
405} // namespace test
406} // namespace quic