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"
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
,
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
);
66 if (message
.tag() != kCHLO
) {
67 CloseConnection(QUIC_INVALID_CRYPTO_MESSAGE_TYPE
);
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
);
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
;
99 ProcessClientHello(message
, result
, &reply
, &error_details
);
101 if (error
!= QUIC_NO_ERROR
) {
102 CloseConnectionWithDetails(error
, error_details
);
106 if (reply
.tag() != kSHLO
) {
107 SendHandshakeMessage(reply
);
111 // If we are returning a SHLO then we accepted the handshake. Now
112 // process the negotiated configuration options as part of the
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
);
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
130 // NOTE: the SHLO will be encrypted with the new server write key.
131 session()->connection()->SetEncrypter(
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
137 session()->connection()->SetDecrypter(
138 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 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_
) {
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)!";
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()) {
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());
208 hash
->Finish(digest
, sizeof(digest
));
210 base::Base64Encode(string(
211 reinterpret_cast<const char*>(digest
), sizeof(digest
)), output
);
213 size_t len
= output
->size();
215 if ((*output
)[len
- 1] == '=') {
217 if ((*output
)[len
- 1] == '=') {
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())
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.
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
) {
297 for (size_t i
= 0; i
< received_tags_length
; ++i
) {
298 if (received_tags
[i
] == kSREJ
) {