blob: 94293f4878ff7ae163906f1653a9e9bebc1c4598 [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_handshaker.h"
6
7#include <memory>
vasilvv872e7a32019-03-12 16:42:44 -07008#include <string>
QUICHE teama6ef0a62019-03-07 20:34:33 -05009
10#include "third_party/boringssl/src/include/openssl/sha.h"
bnc4e9283d2019-12-17 07:08:57 -080011#include "net/third_party/quiche/src/common/platform/api/quiche_arraysize.h"
dmcardlecf0bfcf2019-12-13 08:08:21 -080012#include "net/third_party/quiche/src/common/platform/api/quiche_string_piece.h"
13#include "net/third_party/quiche/src/common/platform/api/quiche_text_utils.h"
QUICHE teama6ef0a62019-03-07 20:34:33 -050014
15namespace quic {
16
17class QuicCryptoServerHandshaker::ProcessClientHelloCallback
18 : public ProcessClientHelloResultCallback {
19 public:
20 ProcessClientHelloCallback(
21 QuicCryptoServerHandshaker* parent,
22 const QuicReferenceCountedPointer<
23 ValidateClientHelloResultCallback::Result>& result)
24 : parent_(parent), result_(result) {}
25
26 void Run(
27 QuicErrorCode error,
vasilvvc48c8712019-03-11 13:38:16 -070028 const std::string& error_details,
QUICHE teama6ef0a62019-03-07 20:34:33 -050029 std::unique_ptr<CryptoHandshakeMessage> message,
30 std::unique_ptr<DiversificationNonce> diversification_nonce,
31 std::unique_ptr<ProofSource::Details> proof_source_details) override {
32 if (parent_ == nullptr) {
33 return;
34 }
35
36 parent_->FinishProcessingHandshakeMessageAfterProcessClientHello(
37 *result_, error, error_details, std::move(message),
38 std::move(diversification_nonce), std::move(proof_source_details));
39 }
40
41 void Cancel() { parent_ = nullptr; }
42
43 private:
44 QuicCryptoServerHandshaker* parent_;
45 QuicReferenceCountedPointer<ValidateClientHelloResultCallback::Result>
46 result_;
47};
48
49QuicCryptoServerHandshaker::QuicCryptoServerHandshaker(
50 const QuicCryptoServerConfig* crypto_config,
51 QuicCryptoServerStream* stream,
52 QuicCompressedCertsCache* compressed_certs_cache,
53 QuicSession* session,
54 QuicCryptoServerStream::Helper* helper)
55 : QuicCryptoHandshaker(stream, session),
56 stream_(stream),
57 session_(session),
fayangd58736d2019-11-27 13:35:31 -080058 delegate_(session),
QUICHE teama6ef0a62019-03-07 20:34:33 -050059 crypto_config_(crypto_config),
60 compressed_certs_cache_(compressed_certs_cache),
61 signed_config_(new QuicSignedServerConfig),
62 helper_(helper),
63 num_handshake_messages_(0),
64 num_handshake_messages_with_server_nonces_(0),
65 send_server_config_update_cb_(nullptr),
66 num_server_config_update_messages_sent_(0),
67 zero_rtt_attempted_(false),
68 chlo_packet_size_(0),
69 validate_client_hello_cb_(nullptr),
70 process_client_hello_cb_(nullptr),
71 encryption_established_(false),
72 handshake_confirmed_(false),
73 crypto_negotiated_params_(new QuicCryptoNegotiatedParameters) {}
74
75QuicCryptoServerHandshaker::~QuicCryptoServerHandshaker() {
76 CancelOutstandingCallbacks();
77}
78
79void QuicCryptoServerHandshaker::CancelOutstandingCallbacks() {
80 // Detach from the validation callback. Calling this multiple times is safe.
81 if (validate_client_hello_cb_ != nullptr) {
82 validate_client_hello_cb_->Cancel();
83 validate_client_hello_cb_ = nullptr;
84 }
85 if (send_server_config_update_cb_ != nullptr) {
86 send_server_config_update_cb_->Cancel();
87 send_server_config_update_cb_ = nullptr;
88 }
89 if (process_client_hello_cb_ != nullptr) {
90 process_client_hello_cb_->Cancel();
91 process_client_hello_cb_ = nullptr;
92 }
93}
94
95void QuicCryptoServerHandshaker::OnHandshakeMessage(
96 const CryptoHandshakeMessage& message) {
97 QuicCryptoHandshaker::OnHandshakeMessage(message);
98 ++num_handshake_messages_;
99 chlo_packet_size_ = session()->connection()->GetCurrentPacket().length();
100
101 // Do not process handshake messages after the handshake is confirmed.
102 if (handshake_confirmed_) {
103 stream_->CloseConnectionWithDetails(
104 QUIC_CRYPTO_MESSAGE_AFTER_HANDSHAKE_COMPLETE,
105 "Unexpected handshake message from client");
106 return;
107 }
108
109 if (message.tag() != kCHLO) {
110 stream_->CloseConnectionWithDetails(QUIC_INVALID_CRYPTO_MESSAGE_TYPE,
111 "Handshake packet not CHLO");
112 return;
113 }
114
115 if (validate_client_hello_cb_ != nullptr ||
116 process_client_hello_cb_ != nullptr) {
117 // Already processing some other handshake message. The protocol
118 // does not allow for clients to send multiple handshake messages
119 // before the server has a chance to respond.
120 stream_->CloseConnectionWithDetails(
121 QUIC_CRYPTO_MESSAGE_WHILE_VALIDATING_CLIENT_HELLO,
122 "Unexpected handshake message while processing CHLO");
123 return;
124 }
125
QUICHE team84910bd2019-03-15 07:03:40 -0700126 chlo_hash_ =
127 CryptoUtils::HashHandshakeMessage(message, Perspective::IS_SERVER);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500128
129 std::unique_ptr<ValidateCallback> cb(new ValidateCallback(this));
130 DCHECK(validate_client_hello_cb_ == nullptr);
131 DCHECK(process_client_hello_cb_ == nullptr);
132 validate_client_hello_cb_ = cb.get();
133 crypto_config_->ValidateClientHello(
134 message, GetClientAddress().host(),
135 session()->connection()->self_address(), transport_version(),
136 session()->connection()->clock(), signed_config_, std::move(cb));
137}
138
139void QuicCryptoServerHandshaker::FinishProcessingHandshakeMessage(
140 QuicReferenceCountedPointer<ValidateClientHelloResultCallback::Result>
141 result,
142 std::unique_ptr<ProofSource::Details> details) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500143 // Clear the callback that got us here.
144 DCHECK(validate_client_hello_cb_ != nullptr);
145 DCHECK(process_client_hello_cb_ == nullptr);
146 validate_client_hello_cb_ = nullptr;
147
QUICHE teama6ef0a62019-03-07 20:34:33 -0500148 std::unique_ptr<ProcessClientHelloCallback> cb(
149 new ProcessClientHelloCallback(this, result));
150 process_client_hello_cb_ = cb.get();
151 ProcessClientHello(result, std::move(details), std::move(cb));
152}
153
154void QuicCryptoServerHandshaker::
155 FinishProcessingHandshakeMessageAfterProcessClientHello(
156 const ValidateClientHelloResultCallback::Result& result,
157 QuicErrorCode error,
vasilvvc48c8712019-03-11 13:38:16 -0700158 const std::string& error_details,
QUICHE teama6ef0a62019-03-07 20:34:33 -0500159 std::unique_ptr<CryptoHandshakeMessage> reply,
160 std::unique_ptr<DiversificationNonce> diversification_nonce,
dschinazi17d42422019-06-18 16:35:07 -0700161 std::unique_ptr<ProofSource::Details> /*proof_source_details*/) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500162 // Clear the callback that got us here.
163 DCHECK(process_client_hello_cb_ != nullptr);
164 DCHECK(validate_client_hello_cb_ == nullptr);
165 process_client_hello_cb_ = nullptr;
166
167 const CryptoHandshakeMessage& message = result.client_hello;
168 if (error != QUIC_NO_ERROR) {
169 stream_->CloseConnectionWithDetails(error, error_details);
170 return;
171 }
172
173 if (reply->tag() != kSHLO) {
nharper3907ac22019-09-25 15:32:28 -0700174 session()->connection()->set_fully_pad_crypto_handshake_packets(
QUICHE teama6ef0a62019-03-07 20:34:33 -0500175 crypto_config_->pad_rej());
176 SendHandshakeMessage(*reply);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500177 return;
178 }
179
180 // If we are returning a SHLO then we accepted the handshake. Now
181 // process the negotiated configuration options as part of the
182 // session config.
183 QuicConfig* config = session()->config();
184 OverrideQuicConfigDefaults(config);
vasilvvc48c8712019-03-11 13:38:16 -0700185 std::string process_error_details;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500186 const QuicErrorCode process_error =
187 config->ProcessPeerHello(message, CLIENT, &process_error_details);
188 if (process_error != QUIC_NO_ERROR) {
189 stream_->CloseConnectionWithDetails(process_error, process_error_details);
190 return;
191 }
192
193 session()->OnConfigNegotiated();
194
fkastenholzd3a1de92019-05-15 07:00:07 -0700195 config->ToHandshakeMessage(reply.get(), session()->transport_version());
QUICHE teama6ef0a62019-03-07 20:34:33 -0500196
197 // Receiving a full CHLO implies the client is prepared to decrypt with
198 // the new server write key. We can start to encrypt with the new server
199 // write key.
200 //
201 // NOTE: the SHLO will be encrypted with the new server write key.
fayangd58736d2019-11-27 13:35:31 -0800202 if (session()->use_handshake_delegate()) {
203 delegate_->OnNewKeysAvailable(
zhongyi546cc452019-04-12 15:27:49 -0700204 ENCRYPTION_ZERO_RTT,
fayangd58736d2019-11-27 13:35:31 -0800205 std::move(crypto_negotiated_params_->initial_crypters.decrypter),
206 /*set_alternative_decrypter=*/false,
207 /*latch_once_used=*/false,
208 std::move(crypto_negotiated_params_->initial_crypters.encrypter));
209 delegate_->SetDefaultEncryptionLevel(ENCRYPTION_ZERO_RTT);
210 delegate_->DiscardOldDecryptionKey(ENCRYPTION_INITIAL);
zhongyi546cc452019-04-12 15:27:49 -0700211 } else {
fayangd58736d2019-11-27 13:35:31 -0800212 session()->connection()->SetEncrypter(
zhongyi546cc452019-04-12 15:27:49 -0700213 ENCRYPTION_ZERO_RTT,
fayangd58736d2019-11-27 13:35:31 -0800214 std::move(crypto_negotiated_params_->initial_crypters.encrypter));
215 session()->connection()->SetDefaultEncryptionLevel(ENCRYPTION_ZERO_RTT);
216 // Set the decrypter immediately so that we no longer accept unencrypted
217 // packets.
218 if (session()->connection()->version().KnowsWhichDecrypterToUse()) {
219 session()->connection()->InstallDecrypter(
220 ENCRYPTION_ZERO_RTT,
221 std::move(crypto_negotiated_params_->initial_crypters.decrypter));
222 session()->connection()->RemoveDecrypter(ENCRYPTION_INITIAL);
223 } else {
224 session()->connection()->SetDecrypter(
225 ENCRYPTION_ZERO_RTT,
226 std::move(crypto_negotiated_params_->initial_crypters.decrypter));
227 }
zhongyi546cc452019-04-12 15:27:49 -0700228 }
QUICHE teama6ef0a62019-03-07 20:34:33 -0500229 session()->connection()->SetDiversificationNonce(*diversification_nonce);
230
nharper3907ac22019-09-25 15:32:28 -0700231 session()->connection()->set_fully_pad_crypto_handshake_packets(
QUICHE teama6ef0a62019-03-07 20:34:33 -0500232 crypto_config_->pad_shlo());
233 SendHandshakeMessage(*reply);
fayangd58736d2019-11-27 13:35:31 -0800234 if (session()->use_handshake_delegate()) {
235 delegate_->OnNewKeysAvailable(
236 ENCRYPTION_FORWARD_SECURE,
237 std::move(crypto_negotiated_params_->forward_secure_crypters.decrypter),
238 /*set_alternative_decrypter=*/true,
239 /*latch_once_used=*/false,
240 std::move(
241 crypto_negotiated_params_->forward_secure_crypters.encrypter));
242 encryption_established_ = true;
243 handshake_confirmed_ = true;
244 delegate_->SetDefaultEncryptionLevel(ENCRYPTION_FORWARD_SECURE);
245 delegate_->DiscardOldEncryptionKey(ENCRYPTION_INITIAL);
246 return;
247 }
QUICHE teama6ef0a62019-03-07 20:34:33 -0500248
249 session()->connection()->SetEncrypter(
250 ENCRYPTION_FORWARD_SECURE,
251 std::move(crypto_negotiated_params_->forward_secure_crypters.encrypter));
252 session()->connection()->SetDefaultEncryptionLevel(ENCRYPTION_FORWARD_SECURE);
253
zhongyi546cc452019-04-12 15:27:49 -0700254 if (session()->connection()->version().KnowsWhichDecrypterToUse()) {
255 session()->connection()->InstallDecrypter(
256 ENCRYPTION_FORWARD_SECURE,
257 std::move(
258 crypto_negotiated_params_->forward_secure_crypters.decrypter));
259 } else {
260 session()->connection()->SetAlternativeDecrypter(
261 ENCRYPTION_FORWARD_SECURE,
262 std::move(crypto_negotiated_params_->forward_secure_crypters.decrypter),
263 false /* don't latch */);
264 }
QUICHE teama6ef0a62019-03-07 20:34:33 -0500265
266 encryption_established_ = true;
267 handshake_confirmed_ = true;
268 session()->OnCryptoHandshakeEvent(QuicSession::HANDSHAKE_CONFIRMED);
269}
270
271void QuicCryptoServerHandshaker::SendServerConfigUpdate(
272 const CachedNetworkParameters* cached_network_params) {
273 if (!handshake_confirmed_) {
274 return;
275 }
276
277 if (send_server_config_update_cb_ != nullptr) {
278 QUIC_DVLOG(1)
279 << "Skipped server config update since one is already in progress";
280 return;
281 }
282
283 std::unique_ptr<SendServerConfigUpdateCallback> cb(
284 new SendServerConfigUpdateCallback(this));
285 send_server_config_update_cb_ = cb.get();
286
287 crypto_config_->BuildServerConfigUpdateMessage(
renjietangd1d00852019-09-06 10:43:12 -0700288 session()->transport_version(), chlo_hash_,
QUICHE teama6ef0a62019-03-07 20:34:33 -0500289 previous_source_address_tokens_, session()->connection()->self_address(),
290 GetClientAddress().host(), session()->connection()->clock(),
291 session()->connection()->random_generator(), compressed_certs_cache_,
292 *crypto_negotiated_params_, cached_network_params, std::move(cb));
293}
294
295QuicCryptoServerHandshaker::SendServerConfigUpdateCallback::
296 SendServerConfigUpdateCallback(QuicCryptoServerHandshaker* parent)
297 : parent_(parent) {}
298
299void QuicCryptoServerHandshaker::SendServerConfigUpdateCallback::Cancel() {
300 parent_ = nullptr;
301}
302
303// From BuildServerConfigUpdateMessageResultCallback
304void QuicCryptoServerHandshaker::SendServerConfigUpdateCallback::Run(
305 bool ok,
306 const CryptoHandshakeMessage& message) {
307 if (parent_ == nullptr) {
308 return;
309 }
310 parent_->FinishSendServerConfigUpdate(ok, message);
311}
312
313void QuicCryptoServerHandshaker::FinishSendServerConfigUpdate(
314 bool ok,
315 const CryptoHandshakeMessage& message) {
316 // Clear the callback that got us here.
317 DCHECK(send_server_config_update_cb_ != nullptr);
318 send_server_config_update_cb_ = nullptr;
319
320 if (!ok) {
321 QUIC_DVLOG(1) << "Server: Failed to build server config update (SCUP)!";
322 return;
323 }
324
325 QUIC_DVLOG(1) << "Server: Sending server config update: "
326 << message.DebugString();
QUICHE teamea740082019-03-11 17:58:43 -0700327 if (!QuicVersionUsesCryptoFrames(transport_version())) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500328 const QuicData& data = message.GetSerialized();
dmcardlecf0bfcf2019-12-13 08:08:21 -0800329 stream_->WriteOrBufferData(
330 quiche::QuicheStringPiece(data.data(), data.length()), false, nullptr);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500331 } else {
332 SendHandshakeMessage(message);
333 }
334
335 ++num_server_config_update_messages_sent_;
336}
337
338uint8_t QuicCryptoServerHandshaker::NumHandshakeMessages() const {
339 return num_handshake_messages_;
340}
341
342uint8_t QuicCryptoServerHandshaker::NumHandshakeMessagesWithServerNonces()
343 const {
344 return num_handshake_messages_with_server_nonces_;
345}
346
347int QuicCryptoServerHandshaker::NumServerConfigUpdateMessagesSent() const {
348 return num_server_config_update_messages_sent_;
349}
350
351const CachedNetworkParameters*
352QuicCryptoServerHandshaker::PreviousCachedNetworkParams() const {
353 return previous_cached_network_params_.get();
354}
355
356bool QuicCryptoServerHandshaker::ZeroRttAttempted() const {
357 return zero_rtt_attempted_;
358}
359
360void QuicCryptoServerHandshaker::SetPreviousCachedNetworkParams(
361 CachedNetworkParameters cached_network_params) {
362 previous_cached_network_params_.reset(
363 new CachedNetworkParameters(cached_network_params));
364}
365
fayangd58736d2019-11-27 13:35:31 -0800366void QuicCryptoServerHandshaker::OnPacketDecrypted(EncryptionLevel level) {
367 if (level == ENCRYPTION_FORWARD_SECURE) {
368 delegate_->NeuterHandshakeData();
369 }
370}
371
QUICHE teama6ef0a62019-03-07 20:34:33 -0500372bool QuicCryptoServerHandshaker::ShouldSendExpectCTHeader() const {
373 return signed_config_->proof.send_expect_ct_header;
374}
375
376bool QuicCryptoServerHandshaker::GetBase64SHA256ClientChannelID(
vasilvvc48c8712019-03-11 13:38:16 -0700377 std::string* output) const {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500378 if (!encryption_established() ||
379 crypto_negotiated_params_->channel_id.empty()) {
380 return false;
381 }
382
vasilvvc48c8712019-03-11 13:38:16 -0700383 const std::string& channel_id(crypto_negotiated_params_->channel_id);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500384 uint8_t digest[SHA256_DIGEST_LENGTH];
385 SHA256(reinterpret_cast<const uint8_t*>(channel_id.data()), channel_id.size(),
386 digest);
387
bnc4e9283d2019-12-17 07:08:57 -0800388 quiche::QuicheTextUtils::Base64Encode(digest, QUICHE_ARRAYSIZE(digest),
389 output);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500390 return true;
391}
392
393bool QuicCryptoServerHandshaker::encryption_established() const {
394 return encryption_established_;
395}
396
397bool QuicCryptoServerHandshaker::handshake_confirmed() const {
398 return handshake_confirmed_;
399}
400
401const QuicCryptoNegotiatedParameters&
402QuicCryptoServerHandshaker::crypto_negotiated_params() const {
403 return *crypto_negotiated_params_;
404}
405
406CryptoMessageParser* QuicCryptoServerHandshaker::crypto_message_parser() {
407 return QuicCryptoHandshaker::crypto_message_parser();
408}
409
nharper486a8a92019-08-28 16:25:10 -0700410size_t QuicCryptoServerHandshaker::BufferSizeLimitForLevel(
411 EncryptionLevel level) const {
412 return QuicCryptoHandshaker::BufferSizeLimitForLevel(level);
413}
414
QUICHE teama6ef0a62019-03-07 20:34:33 -0500415void QuicCryptoServerHandshaker::ProcessClientHello(
416 QuicReferenceCountedPointer<ValidateClientHelloResultCallback::Result>
417 result,
dschinazi17d42422019-06-18 16:35:07 -0700418 std::unique_ptr<ProofSource::Details> /*proof_source_details*/,
QUICHE teama6ef0a62019-03-07 20:34:33 -0500419 std::unique_ptr<ProcessClientHelloResultCallback> done_cb) {
420 const CryptoHandshakeMessage& message = result->client_hello;
vasilvvc48c8712019-03-11 13:38:16 -0700421 std::string error_details;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500422 if (!helper_->CanAcceptClientHello(
423 message, GetClientAddress(), session()->connection()->peer_address(),
424 session()->connection()->self_address(), &error_details)) {
425 done_cb->Run(QUIC_HANDSHAKE_FAILED, error_details, nullptr, nullptr,
426 nullptr);
427 return;
428 }
429 if (!result->info.server_nonce.empty()) {
430 ++num_handshake_messages_with_server_nonces_;
431 }
432
433 if (num_handshake_messages_ == 1) {
434 // Client attempts zero RTT handshake by sending a non-inchoate CHLO.
dmcardlecf0bfcf2019-12-13 08:08:21 -0800435 quiche::QuicheStringPiece public_value;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500436 zero_rtt_attempted_ = message.GetStringPiece(kPUBS, &public_value);
437 }
438
439 // Store the bandwidth estimate from the client.
440 if (result->cached_network_params.bandwidth_estimate_bytes_per_second() > 0) {
441 previous_cached_network_params_.reset(
442 new CachedNetworkParameters(result->cached_network_params));
443 }
444 previous_source_address_tokens_ = result->info.source_address_tokens;
445
QUICHE teama6ef0a62019-03-07 20:34:33 -0500446 QuicConnection* connection = session()->connection();
QUICHE teama6ef0a62019-03-07 20:34:33 -0500447 crypto_config_->ProcessClientHello(
448 result, /*reject_only=*/false, connection->connection_id(),
449 connection->self_address(), GetClientAddress(), connection->version(),
wubecf9bd82019-06-05 04:57:02 -0700450 session()->supported_versions(), connection->clock(),
QUICHE teama6ef0a62019-03-07 20:34:33 -0500451 connection->random_generator(), compressed_certs_cache_,
452 crypto_negotiated_params_, signed_config_,
453 QuicCryptoStream::CryptoMessageFramingOverhead(
454 transport_version(), connection->connection_id()),
455 chlo_packet_size_, std::move(done_cb));
456}
457
458void QuicCryptoServerHandshaker::OverrideQuicConfigDefaults(
dschinazi17d42422019-06-18 16:35:07 -0700459 QuicConfig* /*config*/) {}
QUICHE teama6ef0a62019-03-07 20:34:33 -0500460
461QuicCryptoServerHandshaker::ValidateCallback::ValidateCallback(
462 QuicCryptoServerHandshaker* parent)
463 : parent_(parent) {}
464
465void QuicCryptoServerHandshaker::ValidateCallback::Cancel() {
466 parent_ = nullptr;
467}
468
469void QuicCryptoServerHandshaker::ValidateCallback::Run(
470 QuicReferenceCountedPointer<Result> result,
471 std::unique_ptr<ProofSource::Details> details) {
472 if (parent_ != nullptr) {
473 parent_->FinishProcessingHandshakeMessage(std::move(result),
474 std::move(details));
475 }
476}
477
QUICHE teama6ef0a62019-03-07 20:34:33 -0500478const QuicSocketAddress QuicCryptoServerHandshaker::GetClientAddress() {
479 return session()->connection()->peer_address();
480}
481
482} // namespace quic