blob: f345a14720835dbe5449d9573caf4b9bedeb748b [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"
11#include "net/third_party/quiche/src/quic/platform/api/quic_arraysize.h"
QUICHE teama6ef0a62019-03-07 20:34:33 -050012#include "net/third_party/quiche/src/quic/platform/api/quic_text_utils.h"
13
14namespace quic {
15
16class QuicCryptoServerHandshaker::ProcessClientHelloCallback
17 : public ProcessClientHelloResultCallback {
18 public:
19 ProcessClientHelloCallback(
20 QuicCryptoServerHandshaker* parent,
21 const QuicReferenceCountedPointer<
22 ValidateClientHelloResultCallback::Result>& result)
23 : parent_(parent), result_(result) {}
24
25 void Run(
26 QuicErrorCode error,
vasilvvc48c8712019-03-11 13:38:16 -070027 const std::string& error_details,
QUICHE teama6ef0a62019-03-07 20:34:33 -050028 std::unique_ptr<CryptoHandshakeMessage> message,
29 std::unique_ptr<DiversificationNonce> diversification_nonce,
30 std::unique_ptr<ProofSource::Details> proof_source_details) override {
31 if (parent_ == nullptr) {
32 return;
33 }
34
35 parent_->FinishProcessingHandshakeMessageAfterProcessClientHello(
36 *result_, error, error_details, std::move(message),
37 std::move(diversification_nonce), std::move(proof_source_details));
38 }
39
40 void Cancel() { parent_ = nullptr; }
41
42 private:
43 QuicCryptoServerHandshaker* parent_;
44 QuicReferenceCountedPointer<ValidateClientHelloResultCallback::Result>
45 result_;
46};
47
48QuicCryptoServerHandshaker::QuicCryptoServerHandshaker(
49 const QuicCryptoServerConfig* crypto_config,
50 QuicCryptoServerStream* stream,
51 QuicCompressedCertsCache* compressed_certs_cache,
52 QuicSession* session,
53 QuicCryptoServerStream::Helper* helper)
54 : QuicCryptoHandshaker(stream, session),
55 stream_(stream),
56 session_(session),
57 crypto_config_(crypto_config),
58 compressed_certs_cache_(compressed_certs_cache),
59 signed_config_(new QuicSignedServerConfig),
60 helper_(helper),
61 num_handshake_messages_(0),
62 num_handshake_messages_with_server_nonces_(0),
63 send_server_config_update_cb_(nullptr),
64 num_server_config_update_messages_sent_(0),
65 zero_rtt_attempted_(false),
66 chlo_packet_size_(0),
67 validate_client_hello_cb_(nullptr),
68 process_client_hello_cb_(nullptr),
69 encryption_established_(false),
70 handshake_confirmed_(false),
71 crypto_negotiated_params_(new QuicCryptoNegotiatedParameters) {}
72
73QuicCryptoServerHandshaker::~QuicCryptoServerHandshaker() {
74 CancelOutstandingCallbacks();
75}
76
77void QuicCryptoServerHandshaker::CancelOutstandingCallbacks() {
78 // Detach from the validation callback. Calling this multiple times is safe.
79 if (validate_client_hello_cb_ != nullptr) {
80 validate_client_hello_cb_->Cancel();
81 validate_client_hello_cb_ = nullptr;
82 }
83 if (send_server_config_update_cb_ != nullptr) {
84 send_server_config_update_cb_->Cancel();
85 send_server_config_update_cb_ = nullptr;
86 }
87 if (process_client_hello_cb_ != nullptr) {
88 process_client_hello_cb_->Cancel();
89 process_client_hello_cb_ = nullptr;
90 }
91}
92
93void QuicCryptoServerHandshaker::OnHandshakeMessage(
94 const CryptoHandshakeMessage& message) {
95 QuicCryptoHandshaker::OnHandshakeMessage(message);
96 ++num_handshake_messages_;
97 chlo_packet_size_ = session()->connection()->GetCurrentPacket().length();
98
99 // Do not process handshake messages after the handshake is confirmed.
100 if (handshake_confirmed_) {
101 stream_->CloseConnectionWithDetails(
102 QUIC_CRYPTO_MESSAGE_AFTER_HANDSHAKE_COMPLETE,
103 "Unexpected handshake message from client");
104 return;
105 }
106
107 if (message.tag() != kCHLO) {
108 stream_->CloseConnectionWithDetails(QUIC_INVALID_CRYPTO_MESSAGE_TYPE,
109 "Handshake packet not CHLO");
110 return;
111 }
112
113 if (validate_client_hello_cb_ != nullptr ||
114 process_client_hello_cb_ != nullptr) {
115 // Already processing some other handshake message. The protocol
116 // does not allow for clients to send multiple handshake messages
117 // before the server has a chance to respond.
118 stream_->CloseConnectionWithDetails(
119 QUIC_CRYPTO_MESSAGE_WHILE_VALIDATING_CLIENT_HELLO,
120 "Unexpected handshake message while processing CHLO");
121 return;
122 }
123
QUICHE team84910bd2019-03-15 07:03:40 -0700124 chlo_hash_ =
125 CryptoUtils::HashHandshakeMessage(message, Perspective::IS_SERVER);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500126
127 std::unique_ptr<ValidateCallback> cb(new ValidateCallback(this));
128 DCHECK(validate_client_hello_cb_ == nullptr);
129 DCHECK(process_client_hello_cb_ == nullptr);
130 validate_client_hello_cb_ = cb.get();
131 crypto_config_->ValidateClientHello(
132 message, GetClientAddress().host(),
133 session()->connection()->self_address(), transport_version(),
134 session()->connection()->clock(), signed_config_, std::move(cb));
135}
136
137void QuicCryptoServerHandshaker::FinishProcessingHandshakeMessage(
138 QuicReferenceCountedPointer<ValidateClientHelloResultCallback::Result>
139 result,
140 std::unique_ptr<ProofSource::Details> details) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500141 // Clear the callback that got us here.
142 DCHECK(validate_client_hello_cb_ != nullptr);
143 DCHECK(process_client_hello_cb_ == nullptr);
144 validate_client_hello_cb_ = nullptr;
145
QUICHE teama6ef0a62019-03-07 20:34:33 -0500146 std::unique_ptr<ProcessClientHelloCallback> cb(
147 new ProcessClientHelloCallback(this, result));
148 process_client_hello_cb_ = cb.get();
149 ProcessClientHello(result, std::move(details), std::move(cb));
150}
151
152void QuicCryptoServerHandshaker::
153 FinishProcessingHandshakeMessageAfterProcessClientHello(
154 const ValidateClientHelloResultCallback::Result& result,
155 QuicErrorCode error,
vasilvvc48c8712019-03-11 13:38:16 -0700156 const std::string& error_details,
QUICHE teama6ef0a62019-03-07 20:34:33 -0500157 std::unique_ptr<CryptoHandshakeMessage> reply,
158 std::unique_ptr<DiversificationNonce> diversification_nonce,
159 std::unique_ptr<ProofSource::Details> proof_source_details) {
160 // Clear the callback that got us here.
161 DCHECK(process_client_hello_cb_ != nullptr);
162 DCHECK(validate_client_hello_cb_ == nullptr);
163 process_client_hello_cb_ = nullptr;
164
165 const CryptoHandshakeMessage& message = result.client_hello;
166 if (error != QUIC_NO_ERROR) {
167 stream_->CloseConnectionWithDetails(error, error_details);
168 return;
169 }
170
171 if (reply->tag() != kSHLO) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500172 session()->connection()->set_fully_pad_crypto_hadshake_packets(
173 crypto_config_->pad_rej());
174 SendHandshakeMessage(*reply);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500175 return;
176 }
177
178 // If we are returning a SHLO then we accepted the handshake. Now
179 // process the negotiated configuration options as part of the
180 // session config.
181 QuicConfig* config = session()->config();
182 OverrideQuicConfigDefaults(config);
vasilvvc48c8712019-03-11 13:38:16 -0700183 std::string process_error_details;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500184 const QuicErrorCode process_error =
185 config->ProcessPeerHello(message, CLIENT, &process_error_details);
186 if (process_error != QUIC_NO_ERROR) {
187 stream_->CloseConnectionWithDetails(process_error, process_error_details);
188 return;
189 }
190
191 session()->OnConfigNegotiated();
192
fkastenholzd3a1de92019-05-15 07:00:07 -0700193 config->ToHandshakeMessage(reply.get(), session()->transport_version());
QUICHE teama6ef0a62019-03-07 20:34:33 -0500194
195 // Receiving a full CHLO implies the client is prepared to decrypt with
196 // the new server write key. We can start to encrypt with the new server
197 // write key.
198 //
199 // NOTE: the SHLO will be encrypted with the new server write key.
200 session()->connection()->SetEncrypter(
201 ENCRYPTION_ZERO_RTT,
202 std::move(crypto_negotiated_params_->initial_crypters.encrypter));
203 session()->connection()->SetDefaultEncryptionLevel(ENCRYPTION_ZERO_RTT);
204 // Set the decrypter immediately so that we no longer accept unencrypted
205 // packets.
zhongyi546cc452019-04-12 15:27:49 -0700206 if (session()->connection()->version().KnowsWhichDecrypterToUse()) {
207 session()->connection()->InstallDecrypter(
208 ENCRYPTION_ZERO_RTT,
209 std::move(crypto_negotiated_params_->initial_crypters.decrypter));
210 session()->connection()->RemoveDecrypter(ENCRYPTION_INITIAL);
211 } else {
212 session()->connection()->SetDecrypter(
213 ENCRYPTION_ZERO_RTT,
214 std::move(crypto_negotiated_params_->initial_crypters.decrypter));
215 }
QUICHE teama6ef0a62019-03-07 20:34:33 -0500216 session()->connection()->SetDiversificationNonce(*diversification_nonce);
217
218 session()->connection()->set_fully_pad_crypto_hadshake_packets(
219 crypto_config_->pad_shlo());
220 SendHandshakeMessage(*reply);
221
222 session()->connection()->SetEncrypter(
223 ENCRYPTION_FORWARD_SECURE,
224 std::move(crypto_negotiated_params_->forward_secure_crypters.encrypter));
225 session()->connection()->SetDefaultEncryptionLevel(ENCRYPTION_FORWARD_SECURE);
226
zhongyi546cc452019-04-12 15:27:49 -0700227 if (session()->connection()->version().KnowsWhichDecrypterToUse()) {
228 session()->connection()->InstallDecrypter(
229 ENCRYPTION_FORWARD_SECURE,
230 std::move(
231 crypto_negotiated_params_->forward_secure_crypters.decrypter));
232 } else {
233 session()->connection()->SetAlternativeDecrypter(
234 ENCRYPTION_FORWARD_SECURE,
235 std::move(crypto_negotiated_params_->forward_secure_crypters.decrypter),
236 false /* don't latch */);
237 }
QUICHE teama6ef0a62019-03-07 20:34:33 -0500238
239 encryption_established_ = true;
240 handshake_confirmed_ = true;
241 session()->OnCryptoHandshakeEvent(QuicSession::HANDSHAKE_CONFIRMED);
242}
243
244void QuicCryptoServerHandshaker::SendServerConfigUpdate(
245 const CachedNetworkParameters* cached_network_params) {
246 if (!handshake_confirmed_) {
247 return;
248 }
249
250 if (send_server_config_update_cb_ != nullptr) {
251 QUIC_DVLOG(1)
252 << "Skipped server config update since one is already in progress";
253 return;
254 }
255
256 std::unique_ptr<SendServerConfigUpdateCallback> cb(
257 new SendServerConfigUpdateCallback(this));
258 send_server_config_update_cb_ = cb.get();
259
260 crypto_config_->BuildServerConfigUpdateMessage(
261 session()->connection()->transport_version(), chlo_hash_,
262 previous_source_address_tokens_, session()->connection()->self_address(),
263 GetClientAddress().host(), session()->connection()->clock(),
264 session()->connection()->random_generator(), compressed_certs_cache_,
265 *crypto_negotiated_params_, cached_network_params, std::move(cb));
266}
267
268QuicCryptoServerHandshaker::SendServerConfigUpdateCallback::
269 SendServerConfigUpdateCallback(QuicCryptoServerHandshaker* parent)
270 : parent_(parent) {}
271
272void QuicCryptoServerHandshaker::SendServerConfigUpdateCallback::Cancel() {
273 parent_ = nullptr;
274}
275
276// From BuildServerConfigUpdateMessageResultCallback
277void QuicCryptoServerHandshaker::SendServerConfigUpdateCallback::Run(
278 bool ok,
279 const CryptoHandshakeMessage& message) {
280 if (parent_ == nullptr) {
281 return;
282 }
283 parent_->FinishSendServerConfigUpdate(ok, message);
284}
285
286void QuicCryptoServerHandshaker::FinishSendServerConfigUpdate(
287 bool ok,
288 const CryptoHandshakeMessage& message) {
289 // Clear the callback that got us here.
290 DCHECK(send_server_config_update_cb_ != nullptr);
291 send_server_config_update_cb_ = nullptr;
292
293 if (!ok) {
294 QUIC_DVLOG(1) << "Server: Failed to build server config update (SCUP)!";
295 return;
296 }
297
298 QUIC_DVLOG(1) << "Server: Sending server config update: "
299 << message.DebugString();
QUICHE teamea740082019-03-11 17:58:43 -0700300 if (!QuicVersionUsesCryptoFrames(transport_version())) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500301 const QuicData& data = message.GetSerialized();
302 stream_->WriteOrBufferData(QuicStringPiece(data.data(), data.length()),
303 false, nullptr);
304 } else {
305 SendHandshakeMessage(message);
306 }
307
308 ++num_server_config_update_messages_sent_;
309}
310
311uint8_t QuicCryptoServerHandshaker::NumHandshakeMessages() const {
312 return num_handshake_messages_;
313}
314
315uint8_t QuicCryptoServerHandshaker::NumHandshakeMessagesWithServerNonces()
316 const {
317 return num_handshake_messages_with_server_nonces_;
318}
319
320int QuicCryptoServerHandshaker::NumServerConfigUpdateMessagesSent() const {
321 return num_server_config_update_messages_sent_;
322}
323
324const CachedNetworkParameters*
325QuicCryptoServerHandshaker::PreviousCachedNetworkParams() const {
326 return previous_cached_network_params_.get();
327}
328
329bool QuicCryptoServerHandshaker::ZeroRttAttempted() const {
330 return zero_rtt_attempted_;
331}
332
333void QuicCryptoServerHandshaker::SetPreviousCachedNetworkParams(
334 CachedNetworkParameters cached_network_params) {
335 previous_cached_network_params_.reset(
336 new CachedNetworkParameters(cached_network_params));
337}
338
339bool QuicCryptoServerHandshaker::ShouldSendExpectCTHeader() const {
340 return signed_config_->proof.send_expect_ct_header;
341}
342
343bool QuicCryptoServerHandshaker::GetBase64SHA256ClientChannelID(
vasilvvc48c8712019-03-11 13:38:16 -0700344 std::string* output) const {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500345 if (!encryption_established() ||
346 crypto_negotiated_params_->channel_id.empty()) {
347 return false;
348 }
349
vasilvvc48c8712019-03-11 13:38:16 -0700350 const std::string& channel_id(crypto_negotiated_params_->channel_id);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500351 uint8_t digest[SHA256_DIGEST_LENGTH];
352 SHA256(reinterpret_cast<const uint8_t*>(channel_id.data()), channel_id.size(),
353 digest);
354
355 QuicTextUtils::Base64Encode(digest, QUIC_ARRAYSIZE(digest), output);
356 return true;
357}
358
359bool QuicCryptoServerHandshaker::encryption_established() const {
360 return encryption_established_;
361}
362
363bool QuicCryptoServerHandshaker::handshake_confirmed() const {
364 return handshake_confirmed_;
365}
366
367const QuicCryptoNegotiatedParameters&
368QuicCryptoServerHandshaker::crypto_negotiated_params() const {
369 return *crypto_negotiated_params_;
370}
371
372CryptoMessageParser* QuicCryptoServerHandshaker::crypto_message_parser() {
373 return QuicCryptoHandshaker::crypto_message_parser();
374}
375
376void QuicCryptoServerHandshaker::ProcessClientHello(
377 QuicReferenceCountedPointer<ValidateClientHelloResultCallback::Result>
378 result,
379 std::unique_ptr<ProofSource::Details> proof_source_details,
380 std::unique_ptr<ProcessClientHelloResultCallback> done_cb) {
381 const CryptoHandshakeMessage& message = result->client_hello;
vasilvvc48c8712019-03-11 13:38:16 -0700382 std::string error_details;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500383 if (!helper_->CanAcceptClientHello(
384 message, GetClientAddress(), session()->connection()->peer_address(),
385 session()->connection()->self_address(), &error_details)) {
386 done_cb->Run(QUIC_HANDSHAKE_FAILED, error_details, nullptr, nullptr,
387 nullptr);
388 return;
389 }
390 if (!result->info.server_nonce.empty()) {
391 ++num_handshake_messages_with_server_nonces_;
392 }
393
394 if (num_handshake_messages_ == 1) {
395 // Client attempts zero RTT handshake by sending a non-inchoate CHLO.
396 QuicStringPiece public_value;
397 zero_rtt_attempted_ = message.GetStringPiece(kPUBS, &public_value);
398 }
399
400 // Store the bandwidth estimate from the client.
401 if (result->cached_network_params.bandwidth_estimate_bytes_per_second() > 0) {
402 previous_cached_network_params_.reset(
403 new CachedNetworkParameters(result->cached_network_params));
404 }
405 previous_source_address_tokens_ = result->info.source_address_tokens;
406
QUICHE teama6ef0a62019-03-07 20:34:33 -0500407 QuicConnection* connection = session()->connection();
408 const QuicConnectionId server_designated_connection_id =
wub46a1de72019-05-13 08:23:13 -0700409 GenerateConnectionIdForReject(/*use_stateless_rejects=*/false);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500410 crypto_config_->ProcessClientHello(
411 result, /*reject_only=*/false, connection->connection_id(),
412 connection->self_address(), GetClientAddress(), connection->version(),
wub46a1de72019-05-13 08:23:13 -0700413 session()->supported_versions(), /*use_stateless_rejects=*/false,
QUICHE teama6ef0a62019-03-07 20:34:33 -0500414 server_designated_connection_id, connection->clock(),
415 connection->random_generator(), compressed_certs_cache_,
416 crypto_negotiated_params_, signed_config_,
417 QuicCryptoStream::CryptoMessageFramingOverhead(
418 transport_version(), connection->connection_id()),
419 chlo_packet_size_, std::move(done_cb));
420}
421
422void QuicCryptoServerHandshaker::OverrideQuicConfigDefaults(
423 QuicConfig* config) {}
424
425QuicCryptoServerHandshaker::ValidateCallback::ValidateCallback(
426 QuicCryptoServerHandshaker* parent)
427 : parent_(parent) {}
428
429void QuicCryptoServerHandshaker::ValidateCallback::Cancel() {
430 parent_ = nullptr;
431}
432
433void QuicCryptoServerHandshaker::ValidateCallback::Run(
434 QuicReferenceCountedPointer<Result> result,
435 std::unique_ptr<ProofSource::Details> details) {
436 if (parent_ != nullptr) {
437 parent_->FinishProcessingHandshakeMessage(std::move(result),
438 std::move(details));
439 }
440}
441
442QuicConnectionId QuicCryptoServerHandshaker::GenerateConnectionIdForReject(
443 bool use_stateless_rejects) {
444 if (!use_stateless_rejects) {
445 return EmptyQuicConnectionId();
446 }
447 return helper_->GenerateConnectionIdForReject(
448 transport_version(), session()->connection()->connection_id());
449}
450
451const QuicSocketAddress QuicCryptoServerHandshaker::GetClientAddress() {
452 return session()->connection()->peer_address();
453}
454
455} // namespace quic