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.
4
5 #include "net/quic/quic_crypto_server_stream.h"
6
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"
16
17 namespace net {
18
OnAckNotification(int num_original_packets,int num_original_bytes,int num_retransmitted_packets,int num_retransmitted_bytes,QuicTime::Delta delta_largest_observed)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();
26 }
27
QuicCryptoServerStream(const QuicCryptoServerConfig & crypto_config,QuicSession * session)28 QuicCryptoServerStream::QuicCryptoServerStream(
29 const QuicCryptoServerConfig& crypto_config,
30 QuicSession* session)
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) {
36 }
37
~QuicCryptoServerStream()38 QuicCryptoServerStream::~QuicCryptoServerStream() {
39 CancelOutstandingCallbacks();
40 }
41
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();
46 }
47 }
48
OnHandshakeMessage(const CryptoHandshakeMessage & message)49 void QuicCryptoServerStream::OnHandshakeMessage(
50 const CryptoHandshakeMessage& message) {
51 QuicCryptoStream::OnHandshakeMessage(message);
52 ++num_handshake_messages_;
53
54 // Do not process handshake messages after the handshake is confirmed.
55 if (handshake_confirmed_) {
56 CloseConnection(QUIC_CRYPTO_MESSAGE_AFTER_HANDSHAKE_COMPLETE);
57 return;
58 }
59
60 if (message.tag() != kCHLO) {
61 CloseConnection(QUIC_INVALID_CRYPTO_MESSAGE_TYPE);
62 return;
63 }
64
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);
70 return;
71 }
72
73 validate_client_hello_cb_ = new ValidateCallback(this);
74 return crypto_config_.ValidateClientHello(
75 message,
76 session()->connection()->peer_address(),
77 session()->connection()->clock(),
78 validate_client_hello_cb_);
79 }
80
FinishProcessingHandshakeMessage(const CryptoHandshakeMessage & message,const ValidateClientHelloResultCallback::Result & result)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;
87
88 string error_details;
89 CryptoHandshakeMessage reply;
90 QuicErrorCode error = ProcessClientHello(
91 message, result, &reply, &error_details);
92
93 if (error != QUIC_NO_ERROR) {
94 CloseConnectionWithDetails(error, error_details);
95 return;
96 }
97
98 if (reply.tag() != kSHLO) {
99 SendHandshakeMessage(reply);
100 return;
101 }
102
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);
109 return;
110 }
111 session()->OnConfigNegotiated();
112
113 config->ToHandshakeMessage(&reply);
114
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
117 // write key.
118 //
119 // NOTE: the SHLO will be encrypted with the new server write key.
120 session()->connection()->SetEncrypter(
121 ENCRYPTION_INITIAL,
122 crypto_negotiated_params_.initial_crypters.encrypter.release());
123 session()->connection()->SetDefaultEncryptionLevel(
124 ENCRYPTION_INITIAL);
125 // Set the decrypter immediately so that we no longer accept unencrypted
126 // packets.
127 session()->connection()->SetDecrypter(
128 crypto_negotiated_params_.initial_crypters.decrypter.release(),
129 ENCRYPTION_INITIAL);
130
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);
135 } else {
136 scoped_refptr<ServerHelloNotifier> server_hello_notifier(
137 new ServerHelloNotifier(this));
138 SendHandshakeMessage(reply, server_hello_notifier.get());
139 }
140
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 */);
149
150 encryption_established_ = true;
151 handshake_confirmed_ = true;
152 session()->OnCryptoHandshakeEvent(QuicSession::HANDSHAKE_CONFIRMED);
153
154 // Now that the handshake is complete, send an updated server config and
155 // source-address token to the client.
156 SendServerConfigUpdate(NULL);
157 }
158
SendServerConfigUpdate(const CachedNetworkParameters * cached_network_params)159 void QuicCryptoServerStream::SendServerConfigUpdate(
160 const CachedNetworkParameters* cached_network_params) {
161 if (session()->connection()->version() <= QUIC_VERSION_21 ||
162 !handshake_confirmed_) {
163 return;
164 }
165
166 CryptoHandshakeMessage server_config_update_message;
167 if (!crypto_config_.BuildServerConfigUpdateMessage(
168 session()->connection()->peer_address(),
169 session()->connection()->clock(),
170 session()->connection()->random_generator(),
171 crypto_negotiated_params_,
172 cached_network_params,
173 &server_config_update_message)) {
174 DVLOG(1) << "Server: Failed to build server config update (SCUP)!";
175 return;
176 }
177
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, NULL);
182
183 ++num_server_config_update_messages_sent_;
184 }
185
OnServerHelloAcked()186 void QuicCryptoServerStream::OnServerHelloAcked() {
187 session()->connection()->OnHandshakeComplete();
188 }
189
GetBase64SHA256ClientChannelID(string * output) const190 bool QuicCryptoServerStream::GetBase64SHA256ClientChannelID(
191 string* output) const {
192 if (!encryption_established_ ||
193 crypto_negotiated_params_.channel_id.empty()) {
194 return false;
195 }
196
197 const string& channel_id(crypto_negotiated_params_.channel_id);
198 scoped_ptr<crypto::SecureHash> hash(
199 crypto::SecureHash::Create(crypto::SecureHash::SHA256));
200 hash->Update(channel_id.data(), channel_id.size());
201 uint8 digest[32];
202 hash->Finish(digest, sizeof(digest));
203
204 base::Base64Encode(string(
205 reinterpret_cast<const char*>(digest), sizeof(digest)), output);
206 // Remove padding.
207 size_t len = output->size();
208 if (len >= 2) {
209 if ((*output)[len - 1] == '=') {
210 len--;
211 if ((*output)[len - 1] == '=') {
212 len--;
213 }
214 output->resize(len);
215 }
216 }
217 return true;
218 }
219
ProcessClientHello(const CryptoHandshakeMessage & message,const ValidateClientHelloResultCallback::Result & result,CryptoHandshakeMessage * reply,string * error_details)220 QuicErrorCode QuicCryptoServerStream::ProcessClientHello(
221 const CryptoHandshakeMessage& message,
222 const ValidateClientHelloResultCallback::Result& result,
223 CryptoHandshakeMessage* reply,
224 string* error_details) {
225 return crypto_config_.ProcessClientHello(
226 result,
227 session()->connection()->connection_id(),
228 session()->connection()->peer_address(),
229 session()->connection()->version(),
230 session()->connection()->supported_versions(),
231 session()->connection()->clock(),
232 session()->connection()->random_generator(),
233 &crypto_negotiated_params_, reply, error_details);
234 }
235
OverrideQuicConfigDefaults(QuicConfig * config)236 void QuicCryptoServerStream::OverrideQuicConfigDefaults(QuicConfig* config) {
237 }
238
ValidateCallback(QuicCryptoServerStream * parent)239 QuicCryptoServerStream::ValidateCallback::ValidateCallback(
240 QuicCryptoServerStream* parent) : parent_(parent) {
241 }
242
Cancel()243 void QuicCryptoServerStream::ValidateCallback::Cancel() {
244 parent_ = NULL;
245 }
246
RunImpl(const CryptoHandshakeMessage & client_hello,const Result & result)247 void QuicCryptoServerStream::ValidateCallback::RunImpl(
248 const CryptoHandshakeMessage& client_hello,
249 const Result& result) {
250 if (parent_ != NULL) {
251 parent_->FinishProcessingHandshakeMessage(client_hello, result);
252 }
253 }
254
255 } // namespace net
256