1 // Copyright 2013 The Chromium Authors
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/quic/mock_crypto_client_stream.h"
6
7 #include "net/base/ip_endpoint.h"
8 #include "net/quic/address_utils.h"
9 #include "net/quic/mock_decrypter.h"
10 #include "net/quic/mock_encrypter.h"
11 #include "net/quic/quic_chromium_client_session.h"
12 #include "net/third_party/quiche/src/quiche/quic/core/crypto/quic_decrypter.h"
13 #include "net/third_party/quiche/src/quiche/quic/core/crypto/quic_encrypter.h"
14 #include "net/third_party/quiche/src/quiche/quic/core/http/quic_spdy_client_session_base.h"
15 #include "net/third_party/quiche/src/quiche/quic/core/quic_utils.h"
16 #include "net/third_party/quiche/src/quiche/quic/test_tools/quic_config_peer.h"
17 #include "net/third_party/quiche/src/quiche/quic/test_tools/quic_connection_peer.h"
18 #include "net/third_party/quiche/src/quiche/quic/test_tools/quic_test_utils.h"
19 #include "testing/gtest/include/gtest/gtest.h"
20 #include "third_party/boringssl/src/include/openssl/ssl.h"
21
22 using quic::CLIENT;
23 using quic::ConnectionCloseBehavior;
24 using quic::CryptoHandshakeMessage;
25 using quic::CryptoMessageParser;
26 using quic::ENCRYPTION_FORWARD_SECURE;
27 using quic::ENCRYPTION_INITIAL;
28 using quic::ENCRYPTION_ZERO_RTT;
29 using quic::kAESG;
30 using quic::kC255;
31 using quic::kDefaultMaxStreamsPerConnection;
32 using quic::kQBIC;
33 using quic::Perspective;
34 using quic::ProofVerifyContext;
35 using quic::QUIC_CRYPTO_MESSAGE_AFTER_HANDSHAKE_COMPLETE;
36 using quic::QUIC_NO_ERROR;
37 using quic::QUIC_PROOF_INVALID;
38 using quic::QuicConfig;
39 using quic::QuicCryptoClientConfig;
40 using quic::QuicCryptoNegotiatedParameters;
41 using quic::QuicErrorCode;
42 using quic::QuicServerId;
43 using quic::QuicSession;
44 using quic::QuicSpdyClientSessionBase;
45 using quic::QuicTagVector;
46 using quic::QuicTime;
47 using quic::TransportParameters;
48 using quic::test::StrictTaggingDecrypter;
49 using quic::test::TaggingEncrypter;
50 using std::string;
51
52 namespace net {
53 namespace {
54
55 static constexpr int k8ByteConnectionId = 8;
56
57 } // namespace
58
MockCryptoClientStream(const QuicServerId & server_id,QuicSpdyClientSessionBase * session,std::unique_ptr<ProofVerifyContext> verify_context,const QuicConfig & config,QuicCryptoClientConfig * crypto_config,HandshakeMode handshake_mode,const net::ProofVerifyDetailsChromium * proof_verify_details,bool use_mock_crypter)59 MockCryptoClientStream::MockCryptoClientStream(
60 const QuicServerId& server_id,
61 QuicSpdyClientSessionBase* session,
62 std::unique_ptr<ProofVerifyContext> verify_context,
63 const QuicConfig& config,
64 QuicCryptoClientConfig* crypto_config,
65 HandshakeMode handshake_mode,
66 const net::ProofVerifyDetailsChromium* proof_verify_details,
67 bool use_mock_crypter)
68 : QuicCryptoClientStream(server_id,
69 session,
70 std::move(verify_context),
71 crypto_config,
72 session,
73 /*has_application_state = */ true),
74 QuicCryptoHandshaker(this, session),
75 handshake_mode_(handshake_mode),
76 crypto_negotiated_params_(new QuicCryptoNegotiatedParameters),
77 use_mock_crypter_(use_mock_crypter),
78 server_id_(server_id),
79 proof_verify_details_(proof_verify_details),
80 config_(config) {
81 crypto_framer_.set_visitor(this);
82 // Simulate a negotiated cipher_suite with a fake value.
83 crypto_negotiated_params_->cipher_suite = 1;
84 }
85
86 MockCryptoClientStream::~MockCryptoClientStream() = default;
87
OnHandshakeMessage(const CryptoHandshakeMessage & message)88 void MockCryptoClientStream::OnHandshakeMessage(
89 const CryptoHandshakeMessage& message) {
90 OnUnrecoverableError(QUIC_CRYPTO_MESSAGE_AFTER_HANDSHAKE_COMPLETE,
91 "Forced mock failure");
92 }
93
CryptoConnect()94 bool MockCryptoClientStream::CryptoConnect() {
95 DCHECK(session()->version().UsesTls());
96 IPEndPoint local_ip;
97 static_cast<QuicChromiumClientSession*>(session())
98 ->GetDefaultSocket()
99 ->GetLocalAddress(&local_ip);
100 session()->connection()->SetSelfAddress(ToQuicSocketAddress(local_ip));
101
102 IPEndPoint peer_ip;
103 static_cast<QuicChromiumClientSession*>(session())
104 ->GetDefaultSocket()
105 ->GetPeerAddress(&peer_ip);
106 quic::test::QuicConnectionPeer::SetEffectivePeerAddress(
107 session()->connection(), ToQuicSocketAddress(peer_ip));
108
109 if (session()->connection()->version().KnowsWhichDecrypterToUse()) {
110 session()->connection()->InstallDecrypter(
111 ENCRYPTION_FORWARD_SECURE,
112 std::make_unique<StrictTaggingDecrypter>(ENCRYPTION_FORWARD_SECURE));
113 } else {
114 session()->connection()->SetAlternativeDecrypter(
115 ENCRYPTION_FORWARD_SECURE,
116 std::make_unique<StrictTaggingDecrypter>(ENCRYPTION_FORWARD_SECURE),
117 /*latch_once_used=*/false);
118 }
119 if (proof_verify_details_) {
120 if (!proof_verify_details_->cert_verify_result.verified_cert
121 ->VerifyNameMatch(server_id_.host())) {
122 handshake_confirmed_ = false;
123 encryption_established_ = false;
124 session()->connection()->CloseConnection(
125 QUIC_PROOF_INVALID, "proof invalid",
126 ConnectionCloseBehavior::SILENT_CLOSE);
127 return false;
128 }
129 }
130
131 switch (handshake_mode_) {
132 case ZERO_RTT: {
133 encryption_established_ = true;
134 handshake_confirmed_ = false;
135 FillCryptoParams();
136 if (proof_verify_details_) {
137 reinterpret_cast<QuicSpdyClientSessionBase*>(session())
138 ->OnProofVerifyDetailsAvailable(*proof_verify_details_);
139 }
140 if (use_mock_crypter_) {
141 if (session()->connection()->version().KnowsWhichDecrypterToUse()) {
142 session()->connection()->InstallDecrypter(
143 ENCRYPTION_ZERO_RTT,
144 std::make_unique<MockDecrypter>(Perspective::IS_CLIENT));
145 } else {
146 session()->connection()->SetDecrypter(
147 ENCRYPTION_ZERO_RTT,
148 std::make_unique<MockDecrypter>(Perspective::IS_CLIENT));
149 }
150 session()->connection()->SetEncrypter(
151 ENCRYPTION_ZERO_RTT,
152 std::make_unique<MockEncrypter>(Perspective::IS_CLIENT));
153 } else {
154 if (session()->connection()->version().KnowsWhichDecrypterToUse()) {
155 session()->connection()->InstallDecrypter(
156 ENCRYPTION_ZERO_RTT,
157 std::make_unique<StrictTaggingDecrypter>(ENCRYPTION_ZERO_RTT));
158 } else {
159 session()->connection()->SetDecrypter(
160 ENCRYPTION_ZERO_RTT,
161 std::make_unique<StrictTaggingDecrypter>(ENCRYPTION_ZERO_RTT));
162 }
163 SetConfigNegotiated();
164 session()->OnNewEncryptionKeyAvailable(
165 ENCRYPTION_ZERO_RTT,
166 std::make_unique<TaggingEncrypter>(ENCRYPTION_ZERO_RTT));
167 }
168 if (!session()->connection()->connected()) {
169 break;
170 }
171 session()->DiscardOldEncryptionKey(ENCRYPTION_INITIAL);
172 break;
173 }
174
175 case ASYNC_ZERO_RTT: {
176 handshake_confirmed_ = false;
177 FillCryptoParams();
178 if (proof_verify_details_) {
179 reinterpret_cast<QuicSpdyClientSessionBase*>(session())
180 ->OnProofVerifyDetailsAvailable(*proof_verify_details_);
181 }
182 break;
183 }
184
185 case CONFIRM_HANDSHAKE: {
186 encryption_established_ = true;
187 handshake_confirmed_ = true;
188 FillCryptoParams();
189 if (proof_verify_details_) {
190 reinterpret_cast<QuicSpdyClientSessionBase*>(session())
191 ->OnProofVerifyDetailsAvailable(*proof_verify_details_);
192 }
193 SetConfigNegotiated();
194 if (use_mock_crypter_) {
195 if (session()->connection()->version().KnowsWhichDecrypterToUse()) {
196 session()->connection()->InstallDecrypter(
197 ENCRYPTION_FORWARD_SECURE,
198 std::make_unique<MockDecrypter>(Perspective::IS_CLIENT));
199 } else {
200 session()->connection()->SetDecrypter(
201 ENCRYPTION_FORWARD_SECURE,
202 std::make_unique<MockDecrypter>(Perspective::IS_CLIENT));
203 }
204 session()->connection()->SetEncrypter(
205 ENCRYPTION_FORWARD_SECURE,
206 std::make_unique<MockEncrypter>(Perspective::IS_CLIENT));
207 } else {
208 if (session()->connection()->version().KnowsWhichDecrypterToUse()) {
209 session()->connection()->InstallDecrypter(
210 ENCRYPTION_FORWARD_SECURE,
211 std::make_unique<StrictTaggingDecrypter>(
212 ENCRYPTION_FORWARD_SECURE));
213 } else {
214 session()->connection()->SetDecrypter(
215 ENCRYPTION_FORWARD_SECURE,
216 std::make_unique<StrictTaggingDecrypter>(
217 ENCRYPTION_FORWARD_SECURE));
218 }
219 session()->connection()->SetEncrypter(ENCRYPTION_INITIAL, nullptr);
220 }
221 session()->OnNewEncryptionKeyAvailable(
222 ENCRYPTION_FORWARD_SECURE,
223 std::make_unique<TaggingEncrypter>(ENCRYPTION_FORWARD_SECURE));
224 if (!session()->connection()->connected()) {
225 break;
226 }
227 session()->OnTlsHandshakeComplete();
228 session()->DiscardOldEncryptionKey(ENCRYPTION_INITIAL);
229 session()->NeuterHandshakeData();
230 break;
231 }
232
233 case COLD_START: {
234 handshake_confirmed_ = false;
235 encryption_established_ = false;
236 break;
237 }
238
239 case COLD_START_WITH_CHLO_SENT: {
240 handshake_confirmed_ = false;
241 encryption_established_ = false;
242 SendHandshakeMessage(GetDummyCHLOMessage(), ENCRYPTION_INITIAL);
243 break;
244 }
245 }
246
247 return session()->connection()->connected();
248 }
249
encryption_established() const250 bool MockCryptoClientStream::encryption_established() const {
251 return encryption_established_;
252 }
253
one_rtt_keys_available() const254 bool MockCryptoClientStream::one_rtt_keys_available() const {
255 return handshake_confirmed_;
256 }
257
GetHandshakeState() const258 quic::HandshakeState MockCryptoClientStream::GetHandshakeState() const {
259 return handshake_confirmed_ ? quic::HANDSHAKE_CONFIRMED
260 : quic::HANDSHAKE_START;
261 }
262
setHandshakeConfirmedForce(bool state)263 void MockCryptoClientStream::setHandshakeConfirmedForce(bool state) {
264 handshake_confirmed_ = state;
265 }
266
EarlyDataAccepted() const267 bool MockCryptoClientStream::EarlyDataAccepted() const {
268 // This value is only used for logging. The return value doesn't matter.
269 return false;
270 }
271
272 const QuicCryptoNegotiatedParameters&
crypto_negotiated_params() const273 MockCryptoClientStream::crypto_negotiated_params() const {
274 return *crypto_negotiated_params_;
275 }
276
crypto_message_parser()277 CryptoMessageParser* MockCryptoClientStream::crypto_message_parser() {
278 return &crypto_framer_;
279 }
280
281 // Tests using MockCryptoClientStream() do not care about the handshaker's
282 // state. Intercept and ignore the calls calls to prevent DCHECKs within the
283 // handshaker from failing.
OnOneRttPacketAcknowledged()284 void MockCryptoClientStream::OnOneRttPacketAcknowledged() {}
285
286 std::unique_ptr<quic::QuicDecrypter>
AdvanceKeysAndCreateCurrentOneRttDecrypter()287 MockCryptoClientStream::AdvanceKeysAndCreateCurrentOneRttDecrypter() {
288 return std::make_unique<StrictTaggingDecrypter>(ENCRYPTION_FORWARD_SECURE);
289 }
290
NotifySessionZeroRttComplete()291 void MockCryptoClientStream::NotifySessionZeroRttComplete() {
292 DCHECK(session()->version().UsesTls());
293 encryption_established_ = true;
294 handshake_confirmed_ = false;
295 session()->connection()->InstallDecrypter(
296 ENCRYPTION_ZERO_RTT,
297 std::make_unique<StrictTaggingDecrypter>(ENCRYPTION_ZERO_RTT));
298 SetConfigNegotiated();
299 session()->OnNewEncryptionKeyAvailable(
300 ENCRYPTION_ZERO_RTT,
301 std::make_unique<TaggingEncrypter>(ENCRYPTION_ZERO_RTT));
302
303 session()->DiscardOldEncryptionKey(ENCRYPTION_INITIAL);
304 }
305
NotifySessionOneRttKeyAvailable()306 void MockCryptoClientStream::NotifySessionOneRttKeyAvailable() {
307 encryption_established_ = true;
308 handshake_confirmed_ = true;
309 DCHECK(session()->version().UsesTls());
310 if (use_mock_crypter_) {
311 if (session()->connection()->version().KnowsWhichDecrypterToUse()) {
312 session()->connection()->InstallDecrypter(
313 ENCRYPTION_FORWARD_SECURE,
314 std::make_unique<MockDecrypter>(Perspective::IS_CLIENT));
315 } else {
316 session()->connection()->SetDecrypter(
317 ENCRYPTION_FORWARD_SECURE,
318 std::make_unique<MockDecrypter>(Perspective::IS_CLIENT));
319 }
320 session()->connection()->SetEncrypter(
321 ENCRYPTION_FORWARD_SECURE,
322 std::make_unique<MockEncrypter>(Perspective::IS_CLIENT));
323 } else {
324 if (session()->connection()->version().KnowsWhichDecrypterToUse()) {
325 session()->connection()->InstallDecrypter(
326 ENCRYPTION_FORWARD_SECURE,
327 std::make_unique<StrictTaggingDecrypter>(ENCRYPTION_FORWARD_SECURE));
328 } else {
329 session()->connection()->SetDecrypter(
330 ENCRYPTION_FORWARD_SECURE,
331 std::make_unique<StrictTaggingDecrypter>(ENCRYPTION_FORWARD_SECURE));
332 }
333 session()->connection()->SetEncrypter(ENCRYPTION_INITIAL, nullptr);
334 session()->OnNewEncryptionKeyAvailable(
335 ENCRYPTION_FORWARD_SECURE,
336 std::make_unique<TaggingEncrypter>(ENCRYPTION_FORWARD_SECURE));
337 }
338 SetConfigNegotiated();
339 session()->OnTlsHandshakeComplete();
340 session()->DiscardOldEncryptionKey(ENCRYPTION_INITIAL);
341 session()->DiscardOldEncryptionKey(ENCRYPTION_ZERO_RTT);
342 session()->NeuterHandshakeData();
343 }
344
345 // static
GetDummyCHLOMessage()346 CryptoHandshakeMessage MockCryptoClientStream::GetDummyCHLOMessage() {
347 CryptoHandshakeMessage message;
348 message.set_tag(quic::kCHLO);
349 return message;
350 }
351
SetConfigNegotiated()352 void MockCryptoClientStream::SetConfigNegotiated() {
353 DCHECK(session()->version().UsesTls());
354 QuicTagVector cgst;
355 // TODO(rtenneti): Enable the following code after BBR code is checked in.
356 #if 0
357 cgst.push_back(kTBBR);
358 #endif
359 cgst.push_back(kQBIC);
360 QuicConfig config(config_);
361 config.SetBytesForConnectionIdToSend(k8ByteConnectionId);
362 config.SetMaxBidirectionalStreamsToSend(kDefaultMaxStreamsPerConnection / 2);
363 config.SetMaxUnidirectionalStreamsToSend(kDefaultMaxStreamsPerConnection / 2);
364 config.SetInitialMaxStreamDataBytesIncomingBidirectionalToSend(
365 quic::kMinimumFlowControlSendWindow);
366 config.SetInitialMaxStreamDataBytesOutgoingBidirectionalToSend(
367 quic::kMinimumFlowControlSendWindow);
368 config.SetInitialMaxStreamDataBytesUnidirectionalToSend(
369 quic::kMinimumFlowControlSendWindow);
370
371 auto connection_id = quic::test::TestConnectionId();
372 config.SetStatelessResetTokenToSend(
373 quic::QuicUtils::GenerateStatelessResetToken(connection_id));
374 if (session()->perspective() == Perspective::IS_CLIENT) {
375 config.SetOriginalConnectionIdToSend(
376 session()->connection()->connection_id());
377 config.SetInitialSourceConnectionIdToSend(
378 session()->connection()->connection_id());
379 } else {
380 config.SetInitialSourceConnectionIdToSend(
381 session()->connection()->client_connection_id());
382 }
383
384 TransportParameters params;
385 ASSERT_TRUE(config.FillTransportParameters(¶ms));
386 std::string error_details;
387 QuicErrorCode error = session()->config()->ProcessTransportParameters(
388 params, /*is_resumption=*/false, &error_details);
389 ASSERT_EQ(QUIC_NO_ERROR, error);
390 ASSERT_TRUE(session()->config()->negotiated());
391 session()->OnConfigNegotiated();
392 }
393
FillCryptoParams()394 void MockCryptoClientStream::FillCryptoParams() {
395 DCHECK(session()->version().UsesTls());
396 crypto_negotiated_params_->cipher_suite = TLS1_CK_AES_128_GCM_SHA256 & 0xffff;
397 crypto_negotiated_params_->key_exchange_group = SSL_CURVE_X25519;
398 crypto_negotiated_params_->peer_signature_algorithm =
399 SSL_SIGN_ECDSA_SECP256R1_SHA256;
400 }
401
402 } // namespace net
403