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/source_address_token.h"
13 #include "net/quic/quic_config.h"
14 #include "net/quic/quic_protocol.h"
15 #include "net/quic/quic_session.h"
19 void ServerHelloNotifier::OnAckNotification(
20 int num_original_packets
,
21 int num_original_bytes
,
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
,
31 : QuicCryptoStream(session
),
32 crypto_config_(crypto_config
),
33 validate_client_hello_cb_(NULL
),
34 num_handshake_messages_(0),
35 num_server_config_update_messages_sent_(0) {
38 QuicCryptoServerStream::~QuicCryptoServerStream() {
39 CancelOutstandingCallbacks();
42 void QuicCryptoServerStream::CancelOutstandingCallbacks() {
43 // Detach from the validation callback. Calling this multiple times is safe.
44 if (validate_client_hello_cb_
!= NULL
) {
45 validate_client_hello_cb_
->Cancel();
49 void QuicCryptoServerStream::OnHandshakeMessage(
50 const CryptoHandshakeMessage
& message
) {
51 QuicCryptoStream::OnHandshakeMessage(message
);
52 ++num_handshake_messages_
;
54 // Do not process handshake messages after the handshake is confirmed.
55 if (handshake_confirmed_
) {
56 CloseConnection(QUIC_CRYPTO_MESSAGE_AFTER_HANDSHAKE_COMPLETE
);
60 if (message
.tag() != kCHLO
) {
61 CloseConnection(QUIC_INVALID_CRYPTO_MESSAGE_TYPE
);
65 if (validate_client_hello_cb_
!= NULL
) {
66 // Already processing some other handshake message. The protocol
67 // does not allow for clients to send multiple handshake messages
68 // before the server has a chance to respond.
69 CloseConnection(QUIC_CRYPTO_MESSAGE_WHILE_VALIDATING_CLIENT_HELLO
);
73 validate_client_hello_cb_
= new ValidateCallback(this);
74 return crypto_config_
.ValidateClientHello(
76 session()->connection()->peer_address(),
77 session()->connection()->clock(),
78 validate_client_hello_cb_
);
81 void QuicCryptoServerStream::FinishProcessingHandshakeMessage(
82 const CryptoHandshakeMessage
& message
,
83 const ValidateClientHelloResultCallback::Result
& result
) {
84 // Clear the callback that got us here.
85 DCHECK(validate_client_hello_cb_
!= NULL
);
86 validate_client_hello_cb_
= NULL
;
89 CryptoHandshakeMessage reply
;
90 QuicErrorCode error
= ProcessClientHello(
91 message
, result
, &reply
, &error_details
);
93 if (error
!= QUIC_NO_ERROR
) {
94 CloseConnectionWithDetails(error
, error_details
);
98 if (reply
.tag() != kSHLO
) {
99 SendHandshakeMessage(reply
);
103 // If we are returning a SHLO then we accepted the handshake.
104 QuicConfig
* config
= session()->config();
105 OverrideQuicConfigDefaults(config
);
106 error
= config
->ProcessPeerHello(message
, CLIENT
, &error_details
);
107 if (error
!= QUIC_NO_ERROR
) {
108 CloseConnectionWithDetails(error
, error_details
);
111 session()->OnConfigNegotiated();
113 config
->ToHandshakeMessage(&reply
);
115 // Receiving a full CHLO implies the client is prepared to decrypt with
116 // the new server write key. We can start to encrypt with the new server
119 // NOTE: the SHLO will be encrypted with the new server write key.
120 session()->connection()->SetEncrypter(
122 crypto_negotiated_params_
.initial_crypters
.encrypter
.release());
123 session()->connection()->SetDefaultEncryptionLevel(
125 // Set the decrypter immediately so that we no longer accept unencrypted
127 session()->connection()->SetDecrypter(
128 crypto_negotiated_params_
.initial_crypters
.decrypter
.release(),
131 // We want to be notified when the SHLO is ACKed so that we can disable
132 // HANDSHAKE_MODE in the sent packet manager.
133 if (session()->connection()->version() <= QUIC_VERSION_21
) {
134 SendHandshakeMessage(reply
);
136 scoped_refptr
<ServerHelloNotifier
> server_hello_notifier(
137 new ServerHelloNotifier(this));
138 SendHandshakeMessage(reply
, server_hello_notifier
.get());
141 session()->connection()->SetEncrypter(
142 ENCRYPTION_FORWARD_SECURE
,
143 crypto_negotiated_params_
.forward_secure_crypters
.encrypter
.release());
144 session()->connection()->SetDefaultEncryptionLevel(
145 ENCRYPTION_FORWARD_SECURE
);
146 session()->connection()->SetAlternativeDecrypter(
147 crypto_negotiated_params_
.forward_secure_crypters
.decrypter
.release(),
148 ENCRYPTION_FORWARD_SECURE
, false /* don't latch */);
150 encryption_established_
= true;
151 handshake_confirmed_
= true;
152 session()->OnCryptoHandshakeEvent(QuicSession::HANDSHAKE_CONFIRMED
);
154 // Now that the handshake is complete, send an updated server config and
155 // source-address token to the client.
156 SendServerConfigUpdate(NULL
);
159 void QuicCryptoServerStream::SendServerConfigUpdate(
160 const CachedNetworkParameters
* cached_network_params
) {
161 if (session()->connection()->version() <= QUIC_VERSION_21
) {
165 CryptoHandshakeMessage server_config_update_message
;
166 if (!crypto_config_
.BuildServerConfigUpdateMessage(
167 session()->connection()->peer_address(),
168 session()->connection()->clock(),
169 session()->connection()->random_generator(),
170 crypto_negotiated_params_
,
171 cached_network_params
,
172 &server_config_update_message
)) {
173 DVLOG(1) << "Server: Failed to build server config update (SCUP)!";
177 DVLOG(1) << "Server: Sending server config update: "
178 << server_config_update_message
.DebugString();
179 const QuicData
& data
= server_config_update_message
.GetSerialized();
180 WriteOrBufferData(string(data
.data(), data
.length()), false, NULL
);
182 ++num_server_config_update_messages_sent_
;
185 void QuicCryptoServerStream::OnServerHelloAcked() {
186 session()->connection()->OnHandshakeComplete();
189 bool QuicCryptoServerStream::GetBase64SHA256ClientChannelID(
190 string
* output
) const {
191 if (!encryption_established_
||
192 crypto_negotiated_params_
.channel_id
.empty()) {
196 const string
& channel_id(crypto_negotiated_params_
.channel_id
);
197 scoped_ptr
<crypto::SecureHash
> hash(
198 crypto::SecureHash::Create(crypto::SecureHash::SHA256
));
199 hash
->Update(channel_id
.data(), channel_id
.size());
201 hash
->Finish(digest
, sizeof(digest
));
203 base::Base64Encode(string(
204 reinterpret_cast<const char*>(digest
), sizeof(digest
)), output
);
206 size_t len
= output
->size();
208 if ((*output
)[len
- 1] == '=') {
210 if ((*output
)[len
- 1] == '=') {
219 QuicErrorCode
QuicCryptoServerStream::ProcessClientHello(
220 const CryptoHandshakeMessage
& message
,
221 const ValidateClientHelloResultCallback::Result
& result
,
222 CryptoHandshakeMessage
* reply
,
223 string
* error_details
) {
224 return crypto_config_
.ProcessClientHello(
226 session()->connection()->connection_id(),
227 session()->connection()->peer_address(),
228 session()->connection()->version(),
229 session()->connection()->supported_versions(),
230 session()->connection()->clock(),
231 session()->connection()->random_generator(),
232 &crypto_negotiated_params_
, reply
, error_details
);
235 void QuicCryptoServerStream::OverrideQuicConfigDefaults(QuicConfig
* config
) {
238 QuicCryptoServerStream::ValidateCallback::ValidateCallback(
239 QuicCryptoServerStream
* parent
) : parent_(parent
) {
242 void QuicCryptoServerStream::ValidateCallback::Cancel() {
246 void QuicCryptoServerStream::ValidateCallback::RunImpl(
247 const CryptoHandshakeMessage
& client_hello
,
248 const Result
& result
) {
249 if (parent_
!= NULL
) {
250 parent_
->FinishProcessingHandshakeMessage(client_hello
, result
);