[Android WebView] Fix webview perf bot switchover to use org.chromium.webview_shell...
[chromium-blink-merge.git] / net / quic / quic_crypto_server_stream.cc
blob5c7f5a80e03ec5aa076d26bec5524f463e98a878
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 crypto_negotiated_params_.initial_crypters.decrypter.release(),
139 ENCRYPTION_INITIAL);
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 crypto_negotiated_params_.forward_secure_crypters.decrypter.release(),
152 ENCRYPTION_FORWARD_SECURE, false /* don't latch */);
154 encryption_established_ = true;
155 handshake_confirmed_ = true;
156 session()->OnCryptoHandshakeEvent(QuicSession::HANDSHAKE_CONFIRMED);
159 void QuicCryptoServerStream::SendServerConfigUpdate(
160 const CachedNetworkParameters* cached_network_params) {
161 if (!handshake_confirmed_) {
162 return;
165 CryptoHandshakeMessage server_config_update_message;
166 if (!crypto_config_->BuildServerConfigUpdateMessage(
167 previous_source_address_tokens_,
168 session()->connection()->self_address().address(),
169 session()->connection()->peer_address().address(),
170 session()->connection()->clock(),
171 session()->connection()->random_generator(),
172 crypto_negotiated_params_, cached_network_params,
173 &server_config_update_message)) {
174 DVLOG(1) << "Server: Failed to build server config update (SCUP)!";
175 return;
178 DVLOG(1) << "Server: Sending server config update: "
179 << server_config_update_message.DebugString();
180 const QuicData& data = server_config_update_message.GetSerialized();
181 WriteOrBufferData(string(data.data(), data.length()), false, nullptr);
183 ++num_server_config_update_messages_sent_;
186 void QuicCryptoServerStream::OnServerHelloAcked() {
187 session()->connection()->OnHandshakeComplete();
190 void QuicCryptoServerStream::set_previous_cached_network_params(
191 CachedNetworkParameters cached_network_params) {
192 previous_cached_network_params_.reset(
193 new CachedNetworkParameters(cached_network_params));
196 bool QuicCryptoServerStream::GetBase64SHA256ClientChannelID(
197 string* output) const {
198 if (!encryption_established_ ||
199 crypto_negotiated_params_.channel_id.empty()) {
200 return false;
203 const string& channel_id(crypto_negotiated_params_.channel_id);
204 scoped_ptr<crypto::SecureHash> hash(
205 crypto::SecureHash::Create(crypto::SecureHash::SHA256));
206 hash->Update(channel_id.data(), channel_id.size());
207 uint8 digest[32];
208 hash->Finish(digest, sizeof(digest));
210 base::Base64Encode(string(
211 reinterpret_cast<const char*>(digest), sizeof(digest)), output);
212 // Remove padding.
213 size_t len = output->size();
214 if (len >= 2) {
215 if ((*output)[len - 1] == '=') {
216 len--;
217 if ((*output)[len - 1] == '=') {
218 len--;
220 output->resize(len);
223 return true;
226 QuicErrorCode QuicCryptoServerStream::ProcessClientHello(
227 const CryptoHandshakeMessage& message,
228 const ValidateClientHelloResultCallback::Result& result,
229 CryptoHandshakeMessage* reply,
230 string* error_details) {
231 if (!result.info.server_nonce.empty()) {
232 ++num_handshake_messages_with_server_nonces_;
234 // Store the bandwidth estimate from the client.
235 if (result.cached_network_params.bandwidth_estimate_bytes_per_second() > 0) {
236 previous_cached_network_params_.reset(
237 new CachedNetworkParameters(result.cached_network_params));
239 previous_source_address_tokens_ = result.info.source_address_tokens;
241 const bool use_stateless_rejects_in_crypto_config =
242 FLAGS_enable_quic_stateless_reject_support &&
243 use_stateless_rejects_if_peer_supported_ &&
244 peer_supports_stateless_rejects_;
245 QuicConnection* connection = session()->connection();
246 const QuicConnectionId server_designated_connection_id =
247 use_stateless_rejects_in_crypto_config
248 ? GenerateConnectionIdForReject(connection->connection_id())
249 : 0;
250 return crypto_config_->ProcessClientHello(
251 result, connection->connection_id(), connection->self_address().address(),
252 connection->peer_address(), version(), connection->supported_versions(),
253 use_stateless_rejects_in_crypto_config, server_designated_connection_id,
254 connection->clock(), connection->random_generator(),
255 &crypto_negotiated_params_, reply, error_details);
258 void QuicCryptoServerStream::OverrideQuicConfigDefaults(QuicConfig* config) {
261 const CachedNetworkParameters*
262 QuicCryptoServerStream::previous_cached_network_params() const {
263 return previous_cached_network_params_.get();
266 QuicCryptoServerStream::ValidateCallback::ValidateCallback(
267 QuicCryptoServerStream* parent) : parent_(parent) {
270 void QuicCryptoServerStream::ValidateCallback::Cancel() { parent_ = nullptr; }
272 void QuicCryptoServerStream::ValidateCallback::RunImpl(
273 const CryptoHandshakeMessage& client_hello,
274 const Result& result) {
275 if (parent_ != nullptr) {
276 parent_->FinishProcessingHandshakeMessage(client_hello, result);
280 QuicConnectionId QuicCryptoServerStream::GenerateConnectionIdForReject(
281 QuicConnectionId connection_id) {
282 return session()->connection()->random_generator()->RandUint64();
285 // TODO(jokulik): Once stateless rejects support is inherent in the version
286 // number, this function will likely go away entirely.
287 // static
288 bool QuicCryptoServerStream::DoesPeerSupportStatelessRejects(
289 const CryptoHandshakeMessage& message) {
290 const QuicTag* received_tags;
291 size_t received_tags_length;
292 QuicErrorCode error =
293 message.GetTaglist(kCOPT, &received_tags, &received_tags_length);
294 if (error != QUIC_NO_ERROR) {
295 return false;
297 for (size_t i = 0; i < received_tags_length; ++i) {
298 if (received_tags[i] == kSREJ) {
299 return true;
302 return false;
305 } // namespace net