Add Wi-FI SSID to captive portal interstitial.
[chromium-blink-merge.git] / net / quic / quic_crypto_server_stream.cc
blob3ec65b0ecfb66bd887258937816be45e8bdbc08e
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/cached_network_parameters.h"
10 #include "net/quic/crypto/crypto_protocol.h"
11 #include "net/quic/crypto/crypto_utils.h"
12 #include "net/quic/crypto/quic_crypto_server_config.h"
13 #include "net/quic/quic_config.h"
14 #include "net/quic/quic_protocol.h"
15 #include "net/quic/quic_session.h"
17 using std::string;
19 namespace net {
21 void ServerHelloNotifier::OnAckNotification(
22 int num_retransmitted_packets,
23 int num_retransmitted_bytes,
24 QuicTime::Delta delta_largest_observed) {
25 server_stream_->OnServerHelloAcked();
28 QuicCryptoServerStream::QuicCryptoServerStream(
29 const QuicCryptoServerConfig& crypto_config,
30 QuicSession* session)
31 : QuicCryptoStream(session),
32 crypto_config_(crypto_config),
33 validate_client_hello_cb_(nullptr),
34 num_handshake_messages_(0),
35 num_server_config_update_messages_sent_(0) {}
37 QuicCryptoServerStream::~QuicCryptoServerStream() {
38 CancelOutstandingCallbacks();
41 void QuicCryptoServerStream::CancelOutstandingCallbacks() {
42 // Detach from the validation callback. Calling this multiple times is safe.
43 if (validate_client_hello_cb_ != nullptr) {
44 validate_client_hello_cb_->Cancel();
48 void QuicCryptoServerStream::OnHandshakeMessage(
49 const CryptoHandshakeMessage& message) {
50 QuicCryptoStream::OnHandshakeMessage(message);
51 ++num_handshake_messages_;
53 // Do not process handshake messages after the handshake is confirmed.
54 if (handshake_confirmed_) {
55 CloseConnection(QUIC_CRYPTO_MESSAGE_AFTER_HANDSHAKE_COMPLETE);
56 return;
59 if (message.tag() != kCHLO) {
60 CloseConnection(QUIC_INVALID_CRYPTO_MESSAGE_TYPE);
61 return;
64 if (validate_client_hello_cb_ != nullptr) {
65 // Already processing some other handshake message. The protocol
66 // does not allow for clients to send multiple handshake messages
67 // before the server has a chance to respond.
68 CloseConnection(QUIC_CRYPTO_MESSAGE_WHILE_VALIDATING_CLIENT_HELLO);
69 return;
72 validate_client_hello_cb_ = new ValidateCallback(this);
73 return crypto_config_.ValidateClientHello(
74 message,
75 session()->connection()->peer_address(),
76 session()->connection()->clock(),
77 validate_client_hello_cb_);
80 void QuicCryptoServerStream::FinishProcessingHandshakeMessage(
81 const CryptoHandshakeMessage& message,
82 const ValidateClientHelloResultCallback::Result& result) {
83 // Clear the callback that got us here.
84 DCHECK(validate_client_hello_cb_ != nullptr);
85 validate_client_hello_cb_ = nullptr;
87 string error_details;
88 CryptoHandshakeMessage reply;
89 QuicErrorCode error = ProcessClientHello(
90 message, result, &reply, &error_details);
92 if (error != QUIC_NO_ERROR) {
93 CloseConnectionWithDetails(error, error_details);
94 return;
97 if (reply.tag() != kSHLO) {
98 SendHandshakeMessage(reply);
99 return;
102 // If we are returning a SHLO then we accepted the handshake.
103 QuicConfig* config = session()->config();
104 OverrideQuicConfigDefaults(config);
105 error = config->ProcessPeerHello(message, CLIENT, &error_details);
106 if (error != QUIC_NO_ERROR) {
107 CloseConnectionWithDetails(error, error_details);
108 return;
110 session()->OnConfigNegotiated();
112 config->ToHandshakeMessage(&reply);
114 // Receiving a full CHLO implies the client is prepared to decrypt with
115 // the new server write key. We can start to encrypt with the new server
116 // write key.
118 // NOTE: the SHLO will be encrypted with the new server write key.
119 session()->connection()->SetEncrypter(
120 ENCRYPTION_INITIAL,
121 crypto_negotiated_params_.initial_crypters.encrypter.release());
122 session()->connection()->SetDefaultEncryptionLevel(ENCRYPTION_INITIAL);
123 // Set the decrypter immediately so that we no longer accept unencrypted
124 // packets.
125 session()->connection()->SetDecrypter(
126 crypto_negotiated_params_.initial_crypters.decrypter.release(),
127 ENCRYPTION_INITIAL);
129 // We want to be notified when the SHLO is ACKed so that we can disable
130 // HANDSHAKE_MODE in the sent packet manager.
131 scoped_refptr<ServerHelloNotifier> server_hello_notifier(
132 new ServerHelloNotifier(this));
133 SendHandshakeMessage(reply, server_hello_notifier.get());
135 session()->connection()->SetEncrypter(
136 ENCRYPTION_FORWARD_SECURE,
137 crypto_negotiated_params_.forward_secure_crypters.encrypter.release());
138 session()->connection()->SetAlternativeDecrypter(
139 crypto_negotiated_params_.forward_secure_crypters.decrypter.release(),
140 ENCRYPTION_FORWARD_SECURE, false /* don't latch */);
142 encryption_established_ = true;
143 handshake_confirmed_ = true;
144 session()->OnCryptoHandshakeEvent(QuicSession::HANDSHAKE_CONFIRMED);
147 void QuicCryptoServerStream::SendServerConfigUpdate(
148 const CachedNetworkParameters* cached_network_params) {
149 if (!handshake_confirmed_) {
150 return;
153 CryptoHandshakeMessage server_config_update_message;
154 if (!crypto_config_.BuildServerConfigUpdateMessage(
155 previous_source_address_tokens_,
156 session()->connection()->self_address(),
157 session()->connection()->peer_address(),
158 session()->connection()->clock(),
159 session()->connection()->random_generator(),
160 crypto_negotiated_params_, cached_network_params,
161 &server_config_update_message)) {
162 DVLOG(1) << "Server: Failed to build server config update (SCUP)!";
163 return;
166 DVLOG(1) << "Server: Sending server config update: "
167 << server_config_update_message.DebugString();
168 const QuicData& data = server_config_update_message.GetSerialized();
169 WriteOrBufferData(string(data.data(), data.length()), false, nullptr);
171 ++num_server_config_update_messages_sent_;
174 void QuicCryptoServerStream::OnServerHelloAcked() {
175 session()->connection()->OnHandshakeComplete();
178 void QuicCryptoServerStream::set_previous_cached_network_params(
179 CachedNetworkParameters cached_network_params) {
180 previous_cached_network_params_.reset(
181 new CachedNetworkParameters(cached_network_params));
184 bool QuicCryptoServerStream::GetBase64SHA256ClientChannelID(
185 string* output) const {
186 if (!encryption_established_ ||
187 crypto_negotiated_params_.channel_id.empty()) {
188 return false;
191 const string& channel_id(crypto_negotiated_params_.channel_id);
192 scoped_ptr<crypto::SecureHash> hash(
193 crypto::SecureHash::Create(crypto::SecureHash::SHA256));
194 hash->Update(channel_id.data(), channel_id.size());
195 uint8 digest[32];
196 hash->Finish(digest, sizeof(digest));
198 base::Base64Encode(string(
199 reinterpret_cast<const char*>(digest), sizeof(digest)), output);
200 // Remove padding.
201 size_t len = output->size();
202 if (len >= 2) {
203 if ((*output)[len - 1] == '=') {
204 len--;
205 if ((*output)[len - 1] == '=') {
206 len--;
208 output->resize(len);
211 return true;
214 QuicErrorCode QuicCryptoServerStream::ProcessClientHello(
215 const CryptoHandshakeMessage& message,
216 const ValidateClientHelloResultCallback::Result& result,
217 CryptoHandshakeMessage* reply,
218 string* error_details) {
219 // Store the bandwidth estimate from the client.
220 if (result.cached_network_params.bandwidth_estimate_bytes_per_second() > 0) {
221 previous_cached_network_params_.reset(
222 new CachedNetworkParameters(result.cached_network_params));
224 previous_source_address_tokens_ = result.info.source_address_tokens;
226 return crypto_config_.ProcessClientHello(
227 result, session()->connection()->connection_id(),
228 session()->connection()->self_address(),
229 session()->connection()->peer_address(),
230 session()->connection()->version(),
231 session()->connection()->supported_versions(),
232 session()->connection()->clock(),
233 session()->connection()->random_generator(), &crypto_negotiated_params_,
234 reply, error_details);
237 void QuicCryptoServerStream::OverrideQuicConfigDefaults(QuicConfig* config) {
240 const CachedNetworkParameters*
241 QuicCryptoServerStream::previous_cached_network_params() const {
242 return previous_cached_network_params_.get();
245 QuicCryptoServerStream::ValidateCallback::ValidateCallback(
246 QuicCryptoServerStream* parent) : parent_(parent) {
249 void QuicCryptoServerStream::ValidateCallback::Cancel() { parent_ = nullptr; }
251 void QuicCryptoServerStream::ValidateCallback::RunImpl(
252 const CryptoHandshakeMessage& client_hello,
253 const Result& result) {
254 if (parent_ != nullptr) {
255 parent_->FinishProcessingHandshakeMessage(client_hello, result);
259 } // namespace net