Switch global error menu icon to vectorized MD asset
[chromium-blink-merge.git] / net / quic / quic_crypto_server_stream.cc
blobdd22a8e450d4a2bc0e17fd5e7753353719684aa8
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.
5 #include "net/quic/quic_crypto_server_stream.h"
7 #include "base/base64.h"
8 #include "crypto/secure_hash.h"
9 #include "net/quic/crypto/crypto_protocol.h"
10 #include "net/quic/crypto/crypto_utils.h"
11 #include "net/quic/crypto/quic_crypto_server_config.h"
12 #include "net/quic/crypto/quic_random.h"
13 #include "net/quic/proto/cached_network_parameters.pb.h"
14 #include "net/quic/quic_config.h"
15 #include "net/quic/quic_flags.h"
16 #include "net/quic/quic_protocol.h"
17 #include "net/quic/quic_session.h"
19 using std::string;
21 namespace net {
23 void ServerHelloNotifier::OnAckNotification(
24 int num_retransmitted_packets,
25 int num_retransmitted_bytes,
26 QuicTime::Delta delta_largest_observed) {
27 server_stream_->OnServerHelloAcked();
30 QuicCryptoServerStream::QuicCryptoServerStream(
31 const QuicCryptoServerConfig* crypto_config,
32 QuicSession* session)
33 : QuicCryptoStream(session),
34 crypto_config_(crypto_config),
35 validate_client_hello_cb_(nullptr),
36 num_handshake_messages_(0),
37 num_handshake_messages_with_server_nonces_(0),
38 num_server_config_update_messages_sent_(0),
39 use_stateless_rejects_if_peer_supported_(false),
40 peer_supports_stateless_rejects_(false) {
41 DCHECK_EQ(Perspective::IS_SERVER, session->connection()->perspective());
44 QuicCryptoServerStream::~QuicCryptoServerStream() {
45 CancelOutstandingCallbacks();
48 void QuicCryptoServerStream::CancelOutstandingCallbacks() {
49 // Detach from the validation callback. Calling this multiple times is safe.
50 if (validate_client_hello_cb_ != nullptr) {
51 validate_client_hello_cb_->Cancel();
55 void QuicCryptoServerStream::OnHandshakeMessage(
56 const CryptoHandshakeMessage& message) {
57 QuicCryptoStream::OnHandshakeMessage(message);
58 ++num_handshake_messages_;
60 // Do not process handshake messages after the handshake is confirmed.
61 if (handshake_confirmed_) {
62 CloseConnection(QUIC_CRYPTO_MESSAGE_AFTER_HANDSHAKE_COMPLETE);
63 return;
66 if (message.tag() != kCHLO) {
67 CloseConnection(QUIC_INVALID_CRYPTO_MESSAGE_TYPE);
68 return;
71 if (validate_client_hello_cb_ != nullptr) {
72 // Already processing some other handshake message. The protocol
73 // does not allow for clients to send multiple handshake messages
74 // before the server has a chance to respond.
75 CloseConnection(QUIC_CRYPTO_MESSAGE_WHILE_VALIDATING_CLIENT_HELLO);
76 return;
79 validate_client_hello_cb_ = new ValidateCallback(this);
80 return crypto_config_->ValidateClientHello(
81 message, session()->connection()->peer_address().address(),
82 session()->connection()->clock(), validate_client_hello_cb_);
85 void QuicCryptoServerStream::FinishProcessingHandshakeMessage(
86 const CryptoHandshakeMessage& message,
87 const ValidateClientHelloResultCallback::Result& result) {
88 // Clear the callback that got us here.
89 DCHECK(validate_client_hello_cb_ != nullptr);
90 validate_client_hello_cb_ = nullptr;
92 if (FLAGS_enable_quic_stateless_reject_support) {
93 peer_supports_stateless_rejects_ = DoesPeerSupportStatelessRejects(message);
96 CryptoHandshakeMessage reply;
97 string error_details;
98 QuicErrorCode error =
99 ProcessClientHello(message, result, &reply, &error_details);
101 if (error != QUIC_NO_ERROR) {
102 CloseConnectionWithDetails(error, error_details);
103 return;
106 if (reply.tag() != kSHLO) {
107 SendHandshakeMessage(reply);
108 return;
111 // If we are returning a SHLO then we accepted the handshake. Now
112 // process the negotiated configuration options as part of the
113 // session config.
114 QuicConfig* config = session()->config();
115 OverrideQuicConfigDefaults(config);
116 error = config->ProcessPeerHello(message, CLIENT, &error_details);
117 if (error != QUIC_NO_ERROR) {
118 CloseConnectionWithDetails(error, error_details);
119 return;
122 session()->OnConfigNegotiated();
124 config->ToHandshakeMessage(&reply);
126 // Receiving a full CHLO implies the client is prepared to decrypt with
127 // the new server write key. We can start to encrypt with the new server
128 // write key.
130 // NOTE: the SHLO will be encrypted with the new server write key.
131 session()->connection()->SetEncrypter(
132 ENCRYPTION_INITIAL,
133 crypto_negotiated_params_.initial_crypters.encrypter.release());
134 session()->connection()->SetDefaultEncryptionLevel(ENCRYPTION_INITIAL);
135 // Set the decrypter immediately so that we no longer accept unencrypted
136 // packets.
137 session()->connection()->SetDecrypter(
138 ENCRYPTION_INITIAL,
139 crypto_negotiated_params_.initial_crypters.decrypter.release());
141 // We want to be notified when the SHLO is ACKed so that we can disable
142 // HANDSHAKE_MODE in the sent packet manager.
143 scoped_refptr<ServerHelloNotifier> server_hello_notifier(
144 new ServerHelloNotifier(this));
145 SendHandshakeMessage(reply, server_hello_notifier.get());
147 session()->connection()->SetEncrypter(
148 ENCRYPTION_FORWARD_SECURE,
149 crypto_negotiated_params_.forward_secure_crypters.encrypter.release());
150 session()->connection()->SetAlternativeDecrypter(
151 ENCRYPTION_FORWARD_SECURE,
152 crypto_negotiated_params_.forward_secure_crypters.decrypter.release(),
153 false /* don't latch */);
155 encryption_established_ = true;
156 handshake_confirmed_ = true;
157 session()->OnCryptoHandshakeEvent(QuicSession::HANDSHAKE_CONFIRMED);
160 void QuicCryptoServerStream::SendServerConfigUpdate(
161 const CachedNetworkParameters* cached_network_params) {
162 if (!handshake_confirmed_) {
163 return;
166 CryptoHandshakeMessage server_config_update_message;
167 if (!crypto_config_->BuildServerConfigUpdateMessage(
168 previous_source_address_tokens_,
169 session()->connection()->self_address().address(),
170 session()->connection()->peer_address().address(),
171 session()->connection()->clock(),
172 session()->connection()->random_generator(),
173 crypto_negotiated_params_, cached_network_params,
174 &server_config_update_message)) {
175 DVLOG(1) << "Server: Failed to build server config update (SCUP)!";
176 return;
179 DVLOG(1) << "Server: Sending server config update: "
180 << server_config_update_message.DebugString();
181 const QuicData& data = server_config_update_message.GetSerialized();
182 WriteOrBufferData(string(data.data(), data.length()), false, nullptr);
184 ++num_server_config_update_messages_sent_;
187 void QuicCryptoServerStream::OnServerHelloAcked() {
188 session()->connection()->OnHandshakeComplete();
191 void QuicCryptoServerStream::set_previous_cached_network_params(
192 CachedNetworkParameters cached_network_params) {
193 previous_cached_network_params_.reset(
194 new CachedNetworkParameters(cached_network_params));
197 bool QuicCryptoServerStream::GetBase64SHA256ClientChannelID(
198 string* output) const {
199 if (!encryption_established_ ||
200 crypto_negotiated_params_.channel_id.empty()) {
201 return false;
204 const string& channel_id(crypto_negotiated_params_.channel_id);
205 scoped_ptr<crypto::SecureHash> hash(
206 crypto::SecureHash::Create(crypto::SecureHash::SHA256));
207 hash->Update(channel_id.data(), channel_id.size());
208 uint8 digest[32];
209 hash->Finish(digest, sizeof(digest));
211 base::Base64Encode(string(
212 reinterpret_cast<const char*>(digest), sizeof(digest)), output);
213 // Remove padding.
214 size_t len = output->size();
215 if (len >= 2) {
216 if ((*output)[len - 1] == '=') {
217 len--;
218 if ((*output)[len - 1] == '=') {
219 len--;
221 output->resize(len);
224 return true;
227 QuicErrorCode QuicCryptoServerStream::ProcessClientHello(
228 const CryptoHandshakeMessage& message,
229 const ValidateClientHelloResultCallback::Result& result,
230 CryptoHandshakeMessage* reply,
231 string* error_details) {
232 if (!result.info.server_nonce.empty()) {
233 ++num_handshake_messages_with_server_nonces_;
235 // Store the bandwidth estimate from the client.
236 if (result.cached_network_params.bandwidth_estimate_bytes_per_second() > 0) {
237 previous_cached_network_params_.reset(
238 new CachedNetworkParameters(result.cached_network_params));
240 previous_source_address_tokens_ = result.info.source_address_tokens;
242 const bool use_stateless_rejects_in_crypto_config =
243 FLAGS_enable_quic_stateless_reject_support &&
244 use_stateless_rejects_if_peer_supported_ &&
245 peer_supports_stateless_rejects_;
246 QuicConnection* connection = session()->connection();
247 const QuicConnectionId server_designated_connection_id =
248 use_stateless_rejects_in_crypto_config
249 ? GenerateConnectionIdForReject(connection->connection_id())
250 : 0;
251 return crypto_config_->ProcessClientHello(
252 result, connection->connection_id(), connection->self_address().address(),
253 connection->peer_address(), version(), connection->supported_versions(),
254 use_stateless_rejects_in_crypto_config, server_designated_connection_id,
255 connection->clock(), connection->random_generator(),
256 &crypto_negotiated_params_, reply, error_details);
259 void QuicCryptoServerStream::OverrideQuicConfigDefaults(QuicConfig* config) {
262 const CachedNetworkParameters*
263 QuicCryptoServerStream::previous_cached_network_params() const {
264 return previous_cached_network_params_.get();
267 QuicCryptoServerStream::ValidateCallback::ValidateCallback(
268 QuicCryptoServerStream* parent) : parent_(parent) {
271 void QuicCryptoServerStream::ValidateCallback::Cancel() { parent_ = nullptr; }
273 void QuicCryptoServerStream::ValidateCallback::RunImpl(
274 const CryptoHandshakeMessage& client_hello,
275 const Result& result) {
276 if (parent_ != nullptr) {
277 parent_->FinishProcessingHandshakeMessage(client_hello, result);
281 QuicConnectionId QuicCryptoServerStream::GenerateConnectionIdForReject(
282 QuicConnectionId connection_id) {
283 return session()->connection()->random_generator()->RandUint64();
286 // TODO(jokulik): Once stateless rejects support is inherent in the version
287 // number, this function will likely go away entirely.
288 // static
289 bool QuicCryptoServerStream::DoesPeerSupportStatelessRejects(
290 const CryptoHandshakeMessage& message) {
291 const QuicTag* received_tags;
292 size_t received_tags_length;
293 QuicErrorCode error =
294 message.GetTaglist(kCOPT, &received_tags, &received_tags_length);
295 if (error != QUIC_NO_ERROR) {
296 return false;
298 for (size_t i = 0; i < received_tags_length; ++i) {
299 if (received_tags[i] == kSREJ) {
300 return true;
303 return false;
306 } // namespace net