Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(251)

Side by Side Diff: net/quic/quic_crypto_server_stream.cc

Issue 2193073003: Move shared files in net/quic/ into net/quic/core/ (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: io_thread_unittest.cc Created 4 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « net/quic/quic_crypto_server_stream.h ('k') | net/quic/quic_crypto_server_stream_test.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
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.
4
5 #include "net/quic/quic_crypto_server_stream.h"
6
7 #include <memory>
8
9 #include "base/base64.h"
10 #include "crypto/secure_hash.h"
11 #include "net/quic/crypto/crypto_protocol.h"
12 #include "net/quic/crypto/crypto_utils.h"
13 #include "net/quic/crypto/quic_crypto_server_config.h"
14 #include "net/quic/crypto/quic_random.h"
15 #include "net/quic/proto/cached_network_parameters.pb.h"
16 #include "net/quic/quic_config.h"
17 #include "net/quic/quic_flags.h"
18 #include "net/quic/quic_protocol.h"
19 #include "net/quic/quic_server_session_base.h"
20
21 using base::StringPiece;
22 using std::string;
23
24 namespace net {
25
26 namespace {
27 bool HasFixedTag(const CryptoHandshakeMessage& message) {
28 const QuicTag* received_tags;
29 size_t received_tags_length;
30 QuicErrorCode error =
31 message.GetTaglist(kCOPT, &received_tags, &received_tags_length);
32 if (error == QUIC_NO_ERROR) {
33 DCHECK(received_tags);
34 for (size_t i = 0; i < received_tags_length; ++i) {
35 if (received_tags[i] == kFIXD) {
36 return true;
37 }
38 }
39 }
40 return false;
41 }
42 } // namespace
43
44 void ServerHelloNotifier::OnPacketAcked(int acked_bytes,
45 QuicTime::Delta ack_delay_time) {
46 DCHECK(!FLAGS_quic_no_shlo_listener);
47 // The SHLO is sent in one packet.
48 server_stream_->OnServerHelloAcked();
49 }
50
51 void ServerHelloNotifier::OnPacketRetransmitted(int /*retransmitted_bytes*/) {}
52
53 QuicCryptoServerStreamBase::QuicCryptoServerStreamBase(
54 QuicServerSessionBase* session)
55 : QuicCryptoStream(session) {}
56
57 // TODO(jokulik): Once stateless rejects support is inherent in the version
58 // number, this function will likely go away entirely.
59 // static
60 bool QuicCryptoServerStreamBase::DoesPeerSupportStatelessRejects(
61 const CryptoHandshakeMessage& message) {
62 const QuicTag* received_tags;
63 size_t received_tags_length;
64 QuicErrorCode error =
65 message.GetTaglist(kCOPT, &received_tags, &received_tags_length);
66 if (error != QUIC_NO_ERROR) {
67 return false;
68 }
69 for (size_t i = 0; i < received_tags_length; ++i) {
70 if (received_tags[i] == kSREJ) {
71 return true;
72 }
73 }
74 return false;
75 }
76
77 QuicCryptoServerStream::QuicCryptoServerStream(
78 const QuicCryptoServerConfig* crypto_config,
79 QuicCompressedCertsCache* compressed_certs_cache,
80 bool use_stateless_rejects_if_peer_supported,
81 QuicServerSessionBase* session)
82 : QuicCryptoServerStreamBase(session),
83 crypto_config_(crypto_config),
84 compressed_certs_cache_(compressed_certs_cache),
85 validate_client_hello_cb_(nullptr),
86 num_handshake_messages_(0),
87 num_handshake_messages_with_server_nonces_(0),
88 send_server_config_update_cb_(nullptr),
89 num_server_config_update_messages_sent_(0),
90 use_stateless_rejects_if_peer_supported_(
91 use_stateless_rejects_if_peer_supported),
92 peer_supports_stateless_rejects_(false) {
93 DCHECK_EQ(Perspective::IS_SERVER, session->connection()->perspective());
94 }
95
96 QuicCryptoServerStream::~QuicCryptoServerStream() {
97 CancelOutstandingCallbacks();
98 }
99
100 void QuicCryptoServerStream::CancelOutstandingCallbacks() {
101 // Detach from the validation callback. Calling this multiple times is safe.
102 if (validate_client_hello_cb_ != nullptr) {
103 validate_client_hello_cb_->Cancel();
104 validate_client_hello_cb_ = nullptr;
105 }
106 if (send_server_config_update_cb_ != nullptr) {
107 send_server_config_update_cb_->Cancel();
108 send_server_config_update_cb_ = nullptr;
109 }
110 }
111
112 void QuicCryptoServerStream::OnHandshakeMessage(
113 const CryptoHandshakeMessage& message) {
114 QuicCryptoServerStreamBase::OnHandshakeMessage(message);
115 ++num_handshake_messages_;
116
117 bool require_kfixd = !FLAGS_quic_deprecate_kfixd;
118
119 if (require_kfixd && !HasFixedTag(message)) {
120 CloseConnectionWithDetails(QUIC_CRYPTO_MESSAGE_PARAMETER_NOT_FOUND,
121 "Missing kFIXD");
122 return;
123 }
124
125 // Do not process handshake messages after the handshake is confirmed.
126 if (handshake_confirmed_) {
127 CloseConnectionWithDetails(QUIC_CRYPTO_MESSAGE_AFTER_HANDSHAKE_COMPLETE,
128 "Unexpected handshake message from client");
129 return;
130 }
131
132 if (message.tag() != kCHLO) {
133 CloseConnectionWithDetails(QUIC_INVALID_CRYPTO_MESSAGE_TYPE,
134 "Handshake packet not CHLO");
135 return;
136 }
137
138 if (validate_client_hello_cb_ != nullptr) {
139 // Already processing some other handshake message. The protocol
140 // does not allow for clients to send multiple handshake messages
141 // before the server has a chance to respond.
142 CloseConnectionWithDetails(
143 QUIC_CRYPTO_MESSAGE_WHILE_VALIDATING_CLIENT_HELLO,
144 "Unexpected handshake message while processing CHLO");
145 return;
146 }
147
148 CryptoUtils::HashHandshakeMessage(message, &chlo_hash_);
149
150 validate_client_hello_cb_ = new ValidateCallback(this);
151 crypto_config_->ValidateClientHello(
152 message, session()->connection()->peer_address().address(),
153 session()->connection()->self_address().address(), version(),
154 session()->connection()->clock(), &crypto_proof_,
155 validate_client_hello_cb_);
156 }
157
158 void QuicCryptoServerStream::FinishProcessingHandshakeMessage(
159 const CryptoHandshakeMessage& message,
160 const ValidateClientHelloResultCallback::Result& result,
161 std::unique_ptr<ProofSource::Details> details) {
162 // Clear the callback that got us here.
163 DCHECK(validate_client_hello_cb_ != nullptr);
164 validate_client_hello_cb_ = nullptr;
165
166 if (use_stateless_rejects_if_peer_supported_) {
167 peer_supports_stateless_rejects_ = DoesPeerSupportStatelessRejects(message);
168 }
169
170 CryptoHandshakeMessage reply;
171 DiversificationNonce diversification_nonce;
172 string error_details;
173 QuicErrorCode error =
174 ProcessClientHello(message, result, std::move(details), &reply,
175 &diversification_nonce, &error_details);
176
177 if (error != QUIC_NO_ERROR) {
178 CloseConnectionWithDetails(error, error_details);
179 return;
180 }
181
182 if (reply.tag() != kSHLO) {
183 if (reply.tag() == kSREJ) {
184 DCHECK(use_stateless_rejects_if_peer_supported_);
185 DCHECK(peer_supports_stateless_rejects_);
186 // Before sending the SREJ, cause the connection to save crypto packets
187 // so that they can be added to the time wait list manager and
188 // retransmitted.
189 session()->connection()->EnableSavingCryptoPackets();
190 }
191 SendHandshakeMessage(reply);
192
193 if (reply.tag() == kSREJ) {
194 DCHECK(use_stateless_rejects_if_peer_supported_);
195 DCHECK(peer_supports_stateless_rejects_);
196 DCHECK(!handshake_confirmed());
197 DVLOG(1) << "Closing connection "
198 << session()->connection()->connection_id()
199 << " because of a stateless reject.";
200 session()->connection()->CloseConnection(
201 QUIC_CRYPTO_HANDSHAKE_STATELESS_REJECT, "stateless reject",
202 ConnectionCloseBehavior::SILENT_CLOSE);
203 }
204 return;
205 }
206
207 // If we are returning a SHLO then we accepted the handshake. Now
208 // process the negotiated configuration options as part of the
209 // session config.
210 QuicConfig* config = session()->config();
211 OverrideQuicConfigDefaults(config);
212 error = config->ProcessPeerHello(message, CLIENT, &error_details);
213 if (error != QUIC_NO_ERROR) {
214 CloseConnectionWithDetails(error, error_details);
215 return;
216 }
217
218 session()->OnConfigNegotiated();
219
220 config->ToHandshakeMessage(&reply);
221
222 // Receiving a full CHLO implies the client is prepared to decrypt with
223 // the new server write key. We can start to encrypt with the new server
224 // write key.
225 //
226 // NOTE: the SHLO will be encrypted with the new server write key.
227 session()->connection()->SetEncrypter(
228 ENCRYPTION_INITIAL,
229 crypto_negotiated_params_.initial_crypters.encrypter.release());
230 session()->connection()->SetDefaultEncryptionLevel(ENCRYPTION_INITIAL);
231 // Set the decrypter immediately so that we no longer accept unencrypted
232 // packets.
233 session()->connection()->SetDecrypter(
234 ENCRYPTION_INITIAL,
235 crypto_negotiated_params_.initial_crypters.decrypter.release());
236 if (version() > QUIC_VERSION_32) {
237 session()->connection()->SetDiversificationNonce(diversification_nonce);
238 }
239
240 // We want to be notified when the SHLO is ACKed so that we can disable
241 // HANDSHAKE_MODE in the sent packet manager.
242 scoped_refptr<ServerHelloNotifier> server_hello_notifier(
243 new ServerHelloNotifier(this));
244 SendHandshakeMessage(reply, FLAGS_quic_no_shlo_listener
245 ? nullptr
246 : server_hello_notifier.get());
247
248 session()->connection()->SetEncrypter(
249 ENCRYPTION_FORWARD_SECURE,
250 crypto_negotiated_params_.forward_secure_crypters.encrypter.release());
251 session()->connection()->SetDefaultEncryptionLevel(ENCRYPTION_FORWARD_SECURE);
252
253 session()->connection()->SetAlternativeDecrypter(
254 ENCRYPTION_FORWARD_SECURE,
255 crypto_negotiated_params_.forward_secure_crypters.decrypter.release(),
256 false /* don't latch */);
257
258 encryption_established_ = true;
259 handshake_confirmed_ = true;
260 session()->OnCryptoHandshakeEvent(QuicSession::HANDSHAKE_CONFIRMED);
261 }
262
263 void QuicCryptoServerStream::SendServerConfigUpdate(
264 const CachedNetworkParameters* cached_network_params) {
265 if (!handshake_confirmed_) {
266 return;
267 }
268
269 if (FLAGS_enable_async_get_proof) {
270 if (send_server_config_update_cb_ != nullptr) {
271 DVLOG(1)
272 << "Skipped server config update since one is already in progress";
273 return;
274 }
275
276 std::unique_ptr<SendServerConfigUpdateCallback> cb(
277 new SendServerConfigUpdateCallback(this));
278 send_server_config_update_cb_ = cb.get();
279 crypto_config_->BuildServerConfigUpdateMessage(
280 session()->connection()->version(), chlo_hash_,
281 previous_source_address_tokens_,
282 session()->connection()->self_address().address(),
283 session()->connection()->peer_address().address(),
284 session()->connection()->clock(),
285 session()->connection()->random_generator(), compressed_certs_cache_,
286 crypto_negotiated_params_, cached_network_params, std::move(cb));
287 return;
288 }
289
290 CryptoHandshakeMessage server_config_update_message;
291 if (!crypto_config_->BuildServerConfigUpdateMessage(
292 session()->connection()->version(), chlo_hash_,
293 previous_source_address_tokens_,
294 session()->connection()->self_address().address(),
295 session()->connection()->peer_address().address(),
296 session()->connection()->clock(),
297 session()->connection()->random_generator(), compressed_certs_cache_,
298 crypto_negotiated_params_, cached_network_params,
299 &server_config_update_message)) {
300 DVLOG(1) << "Server: Failed to build server config update (SCUP)!";
301 return;
302 }
303
304 DVLOG(1) << "Server: Sending server config update: "
305 << server_config_update_message.DebugString();
306 const QuicData& data = server_config_update_message.GetSerialized();
307 WriteOrBufferData(StringPiece(data.data(), data.length()), false, nullptr);
308
309 ++num_server_config_update_messages_sent_;
310 }
311
312 QuicCryptoServerStream::SendServerConfigUpdateCallback::
313 SendServerConfigUpdateCallback(QuicCryptoServerStream* parent)
314 : parent_(parent) {}
315
316 void QuicCryptoServerStream::SendServerConfigUpdateCallback::Cancel() {
317 parent_ = nullptr;
318 }
319
320 // From BuildServerConfigUpdateMessageResultCallback
321 void QuicCryptoServerStream::SendServerConfigUpdateCallback::Run(
322 bool ok,
323 const CryptoHandshakeMessage& message) {
324 if (parent_ == nullptr) {
325 return;
326 }
327 parent_->FinishSendServerConfigUpdate(ok, message);
328 }
329
330 void QuicCryptoServerStream::FinishSendServerConfigUpdate(
331 bool ok,
332 const CryptoHandshakeMessage& message) {
333 // Clear the callback that got us here.
334 DCHECK(send_server_config_update_cb_ != nullptr);
335 send_server_config_update_cb_ = nullptr;
336
337 if (!ok) {
338 DVLOG(1) << "Server: Failed to build server config update (SCUP)!";
339 return;
340 }
341
342 DVLOG(1) << "Server: Sending server config update: " << message.DebugString();
343 const QuicData& data = message.GetSerialized();
344 WriteOrBufferData(StringPiece(data.data(), data.length()), false, nullptr);
345
346 ++num_server_config_update_messages_sent_;
347 }
348
349 void QuicCryptoServerStream::OnServerHelloAcked() {
350 session()->connection()->OnHandshakeComplete();
351 }
352
353 uint8_t QuicCryptoServerStream::NumHandshakeMessages() const {
354 return num_handshake_messages_;
355 }
356
357 uint8_t QuicCryptoServerStream::NumHandshakeMessagesWithServerNonces() const {
358 return num_handshake_messages_with_server_nonces_;
359 }
360
361 int QuicCryptoServerStream::NumServerConfigUpdateMessagesSent() const {
362 return num_server_config_update_messages_sent_;
363 }
364
365 const CachedNetworkParameters*
366 QuicCryptoServerStream::PreviousCachedNetworkParams() const {
367 return previous_cached_network_params_.get();
368 }
369
370 bool QuicCryptoServerStream::UseStatelessRejectsIfPeerSupported() const {
371 return use_stateless_rejects_if_peer_supported_;
372 }
373
374 bool QuicCryptoServerStream::PeerSupportsStatelessRejects() const {
375 return peer_supports_stateless_rejects_;
376 }
377
378 void QuicCryptoServerStream::SetPeerSupportsStatelessRejects(
379 bool peer_supports_stateless_rejects) {
380 peer_supports_stateless_rejects_ = peer_supports_stateless_rejects;
381 }
382
383 void QuicCryptoServerStream::SetPreviousCachedNetworkParams(
384 CachedNetworkParameters cached_network_params) {
385 previous_cached_network_params_.reset(
386 new CachedNetworkParameters(cached_network_params));
387 }
388
389 bool QuicCryptoServerStream::GetBase64SHA256ClientChannelID(
390 string* output) const {
391 if (!encryption_established_ ||
392 crypto_negotiated_params_.channel_id.empty()) {
393 return false;
394 }
395
396 const string& channel_id(crypto_negotiated_params_.channel_id);
397 std::unique_ptr<crypto::SecureHash> hash(
398 crypto::SecureHash::Create(crypto::SecureHash::SHA256));
399 hash->Update(channel_id.data(), channel_id.size());
400 uint8_t digest[32];
401 hash->Finish(digest, sizeof(digest));
402
403 base::Base64Encode(
404 string(reinterpret_cast<const char*>(digest), sizeof(digest)), output);
405 // Remove padding.
406 size_t len = output->size();
407 if (len >= 2) {
408 if ((*output)[len - 1] == '=') {
409 len--;
410 if ((*output)[len - 1] == '=') {
411 len--;
412 }
413 output->resize(len);
414 }
415 }
416 return true;
417 }
418
419 QuicErrorCode QuicCryptoServerStream::ProcessClientHello(
420 const CryptoHandshakeMessage& message,
421 const ValidateClientHelloResultCallback::Result& result,
422 std::unique_ptr<ProofSource::Details> proof_source_details,
423 CryptoHandshakeMessage* reply,
424 DiversificationNonce* out_diversification_nonce,
425 string* error_details) {
426 QuicServerSessionBase* session_base =
427 static_cast<QuicServerSessionBase*>(session());
428 if (!session_base->CanAcceptClientHello(message, error_details)) {
429 return QUIC_HANDSHAKE_FAILED;
430 }
431
432 if (!result.info.server_nonce.empty()) {
433 ++num_handshake_messages_with_server_nonces_;
434 }
435 // Store the bandwidth estimate from the client.
436 if (result.cached_network_params.bandwidth_estimate_bytes_per_second() > 0) {
437 previous_cached_network_params_.reset(
438 new CachedNetworkParameters(result.cached_network_params));
439 }
440 previous_source_address_tokens_ = result.info.source_address_tokens;
441
442 const bool use_stateless_rejects_in_crypto_config =
443 use_stateless_rejects_if_peer_supported_ &&
444 peer_supports_stateless_rejects_;
445 QuicConnection* connection = session()->connection();
446 const QuicConnectionId server_designated_connection_id =
447 use_stateless_rejects_in_crypto_config
448 ? GenerateConnectionIdForReject(connection->connection_id())
449 : 0;
450 return crypto_config_->ProcessClientHello(
451 result, /*reject_only=*/false, connection->connection_id(),
452 connection->self_address().address(), connection->peer_address(),
453 version(), connection->supported_versions(),
454 use_stateless_rejects_in_crypto_config, server_designated_connection_id,
455 connection->clock(), connection->random_generator(),
456 compressed_certs_cache_, &crypto_negotiated_params_, &crypto_proof_,
457 reply, out_diversification_nonce, error_details);
458 }
459
460 void QuicCryptoServerStream::OverrideQuicConfigDefaults(QuicConfig* config) {}
461
462 QuicCryptoServerStream::ValidateCallback::ValidateCallback(
463 QuicCryptoServerStream* parent)
464 : parent_(parent) {}
465
466 void QuicCryptoServerStream::ValidateCallback::Cancel() {
467 parent_ = nullptr;
468 }
469
470 void QuicCryptoServerStream::ValidateCallback::RunImpl(
471 const CryptoHandshakeMessage& client_hello,
472 const Result& result,
473 std::unique_ptr<ProofSource::Details> details) {
474 if (parent_ != nullptr) {
475 parent_->FinishProcessingHandshakeMessage(client_hello, result,
476 std::move(details));
477 }
478 }
479
480 QuicConnectionId QuicCryptoServerStream::GenerateConnectionIdForReject(
481 QuicConnectionId connection_id) {
482 // TODO(rch): Remove this method when
483 // reloadable_flag_quic_dispatcher_creates_id2 is removed.
484 QuicServerSessionBase* session_base =
485 static_cast<QuicServerSessionBase*>(session());
486 return session_base->GenerateConnectionIdForReject(connection_id);
487 }
488
489 } // namespace net
OLDNEW
« no previous file with comments | « net/quic/quic_crypto_server_stream.h ('k') | net/quic/quic_crypto_server_stream_test.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698