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(
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_
) {
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)!";
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()) {
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());
209 hash
->Finish(digest
, sizeof(digest
));
211 base::Base64Encode(string(
212 reinterpret_cast<const char*>(digest
), sizeof(digest
)), output
);
214 size_t len
= output
->size();
216 if ((*output
)[len
- 1] == '=') {
218 if ((*output
)[len
- 1] == '=') {
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())
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.
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
) {
298 for (size_t i
= 0; i
< received_tags_length
; ++i
) {
299 if (received_tags
[i
] == kSREJ
) {