Lots of random cleanups, mostly for native_theme_win.cc:
[chromium-blink-merge.git] / net / quic / quic_crypto_client_stream.cc
blobf3a924b9ef4770b4f6dc9b996ac1155ee2dcd9a8
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_client_stream.h"
7 #include "net/quic/crypto/crypto_protocol.h"
8 #include "net/quic/crypto/crypto_utils.h"
9 #include "net/quic/crypto/null_encrypter.h"
10 #include "net/quic/quic_client_session_base.h"
11 #include "net/quic/quic_protocol.h"
12 #include "net/quic/quic_session.h"
14 namespace net {
16 QuicCryptoClientStream::ChannelIDSourceCallbackImpl::
17 ChannelIDSourceCallbackImpl(QuicCryptoClientStream* stream)
18 : stream_(stream) {}
20 QuicCryptoClientStream::ChannelIDSourceCallbackImpl::
21 ~ChannelIDSourceCallbackImpl() {}
23 void QuicCryptoClientStream::ChannelIDSourceCallbackImpl::Run(
24 scoped_ptr<ChannelIDKey>* channel_id_key) {
25 if (stream_ == NULL) {
26 return;
29 stream_->channel_id_key_.reset(channel_id_key->release());
30 stream_->channel_id_source_callback_ = NULL;
31 stream_->DoHandshakeLoop(NULL);
33 // The ChannelIDSource owns this object and will delete it when this method
34 // returns.
37 void QuicCryptoClientStream::ChannelIDSourceCallbackImpl::Cancel() {
38 stream_ = NULL;
41 QuicCryptoClientStream::ProofVerifierCallbackImpl::ProofVerifierCallbackImpl(
42 QuicCryptoClientStream* stream)
43 : stream_(stream) {}
45 QuicCryptoClientStream::ProofVerifierCallbackImpl::
46 ~ProofVerifierCallbackImpl() {}
48 void QuicCryptoClientStream::ProofVerifierCallbackImpl::Run(
49 bool ok,
50 const string& error_details,
51 scoped_ptr<ProofVerifyDetails>* details) {
52 if (stream_ == NULL) {
53 return;
56 stream_->verify_ok_ = ok;
57 stream_->verify_error_details_ = error_details;
58 stream_->verify_details_.reset(details->release());
59 stream_->proof_verify_callback_ = NULL;
60 stream_->DoHandshakeLoop(NULL);
62 // The ProofVerifier owns this object and will delete it when this method
63 // returns.
66 void QuicCryptoClientStream::ProofVerifierCallbackImpl::Cancel() {
67 stream_ = NULL;
70 QuicCryptoClientStream::QuicCryptoClientStream(
71 const QuicServerId& server_id,
72 QuicClientSessionBase* session,
73 ProofVerifyContext* verify_context,
74 QuicCryptoClientConfig* crypto_config)
75 : QuicCryptoStream(session),
76 next_state_(STATE_IDLE),
77 num_client_hellos_(0),
78 crypto_config_(crypto_config),
79 server_id_(server_id),
80 generation_counter_(0),
81 channel_id_source_callback_(NULL),
82 verify_context_(verify_context),
83 proof_verify_callback_(NULL) {
86 QuicCryptoClientStream::~QuicCryptoClientStream() {
87 if (channel_id_source_callback_) {
88 channel_id_source_callback_->Cancel();
90 if (proof_verify_callback_) {
91 proof_verify_callback_->Cancel();
95 void QuicCryptoClientStream::OnHandshakeMessage(
96 const CryptoHandshakeMessage& message) {
97 QuicCryptoStream::OnHandshakeMessage(message);
99 DoHandshakeLoop(&message);
102 bool QuicCryptoClientStream::CryptoConnect() {
103 next_state_ = STATE_INITIALIZE;
104 DoHandshakeLoop(NULL);
105 return true;
108 int QuicCryptoClientStream::num_sent_client_hellos() const {
109 return num_client_hellos_;
112 bool QuicCryptoClientStream::WasChannelIDSent() const {
113 // TODO(rch): we should replace this with a boolean member so we
114 // can free the memory associated with the key after we're finished with it.
115 return channel_id_key_.get() != NULL;
118 // kMaxClientHellos is the maximum number of times that we'll send a client
119 // hello. The value 3 accounts for:
120 // * One failure due to an incorrect or missing source-address token.
121 // * One failure due the server's certificate chain being unavailible and the
122 // server being unwilling to send it without a valid source-address token.
123 static const int kMaxClientHellos = 3;
125 void QuicCryptoClientStream::DoHandshakeLoop(
126 const CryptoHandshakeMessage* in) {
127 CryptoHandshakeMessage out;
128 QuicErrorCode error;
129 string error_details;
130 QuicCryptoClientConfig::CachedState* cached =
131 crypto_config_->LookupOrCreate(server_id_);
133 if (in != NULL) {
134 DVLOG(1) << "Client: Received " << in->DebugString();
137 for (;;) {
138 const State state = next_state_;
139 next_state_ = STATE_IDLE;
140 switch (state) {
141 case STATE_INITIALIZE: {
142 if (!cached->IsEmpty() && !cached->proof_valid() &&
143 !cached->signature().empty() && server_id_.is_https()) {
144 DCHECK(crypto_config_->proof_verifier());
145 // If the cached state needs to be verified, do it now.
146 next_state_ = STATE_VERIFY_PROOF;
147 } else {
148 next_state_ = STATE_GET_CHANNEL_ID;
150 break;
152 case STATE_SEND_CHLO: {
153 // Send the client hello in plaintext.
154 session()->connection()->SetDefaultEncryptionLevel(ENCRYPTION_NONE);
155 if (num_client_hellos_ > kMaxClientHellos) {
156 CloseConnection(QUIC_CRYPTO_TOO_MANY_REJECTS);
157 return;
159 num_client_hellos_++;
161 if (!cached->IsComplete(session()->connection()->clock()->WallNow())) {
162 crypto_config_->FillInchoateClientHello(
163 server_id_,
164 session()->connection()->supported_versions().front(),
165 cached, &crypto_negotiated_params_, &out);
166 // Pad the inchoate client hello to fill up a packet.
167 const size_t kFramingOverhead = 50; // A rough estimate.
168 const size_t max_packet_size =
169 session()->connection()->max_packet_length();
170 if (max_packet_size <= kFramingOverhead) {
171 DLOG(DFATAL) << "max_packet_length (" << max_packet_size
172 << ") has no room for framing overhead.";
173 CloseConnection(QUIC_INTERNAL_ERROR);
174 return;
176 if (kClientHelloMinimumSize > max_packet_size - kFramingOverhead) {
177 DLOG(DFATAL) << "Client hello won't fit in a single packet.";
178 CloseConnection(QUIC_INTERNAL_ERROR);
179 return;
181 out.set_minimum_size(max_packet_size - kFramingOverhead);
182 next_state_ = STATE_RECV_REJ;
183 DVLOG(1) << "Client: Sending " << out.DebugString();
184 SendHandshakeMessage(out);
185 return;
187 session()->config()->ToHandshakeMessage(&out);
188 error = crypto_config_->FillClientHello(
189 server_id_,
190 session()->connection()->connection_id(),
191 session()->connection()->supported_versions().front(),
192 cached,
193 session()->connection()->clock()->WallNow(),
194 session()->connection()->random_generator(),
195 channel_id_key_.get(),
196 &crypto_negotiated_params_,
197 &out,
198 &error_details);
199 if (error != QUIC_NO_ERROR) {
200 // Flush the cached config so that, if it's bad, the server has a
201 // chance to send us another in the future.
202 cached->InvalidateServerConfig();
203 CloseConnectionWithDetails(error, error_details);
204 return;
206 if (cached->proof_verify_details()) {
207 client_session()->OnProofVerifyDetailsAvailable(
208 *cached->proof_verify_details());
210 next_state_ = STATE_RECV_SHLO;
211 DVLOG(1) << "Client: Sending " << out.DebugString();
212 SendHandshakeMessage(out);
213 // Be prepared to decrypt with the new server write key.
214 session()->connection()->SetAlternativeDecrypter(
215 crypto_negotiated_params_.initial_crypters.decrypter.release(),
216 ENCRYPTION_INITIAL,
217 true /* latch once used */);
218 // Send subsequent packets under encryption on the assumption that the
219 // server will accept the handshake.
220 session()->connection()->SetEncrypter(
221 ENCRYPTION_INITIAL,
222 crypto_negotiated_params_.initial_crypters.encrypter.release());
223 session()->connection()->SetDefaultEncryptionLevel(
224 ENCRYPTION_INITIAL);
225 if (!encryption_established_) {
226 encryption_established_ = true;
227 session()->OnCryptoHandshakeEvent(
228 QuicSession::ENCRYPTION_FIRST_ESTABLISHED);
229 } else {
230 session()->OnCryptoHandshakeEvent(
231 QuicSession::ENCRYPTION_REESTABLISHED);
233 return;
235 case STATE_RECV_REJ:
236 // We sent a dummy CHLO because we didn't have enough information to
237 // perform a handshake, or we sent a full hello that the server
238 // rejected. Here we hope to have a REJ that contains the information
239 // that we need.
240 if (in->tag() != kREJ) {
241 CloseConnectionWithDetails(QUIC_INVALID_CRYPTO_MESSAGE_TYPE,
242 "Expected REJ");
243 return;
245 error = crypto_config_->ProcessRejection(
246 *in, session()->connection()->clock()->WallNow(), cached,
247 &crypto_negotiated_params_, &error_details);
248 if (error != QUIC_NO_ERROR) {
249 CloseConnectionWithDetails(error, error_details);
250 return;
252 if (!cached->proof_valid()) {
253 if (!server_id_.is_https()) {
254 // We don't check the certificates for insecure QUIC connections.
255 SetCachedProofValid(cached);
256 } else if (!cached->signature().empty()) {
257 next_state_ = STATE_VERIFY_PROOF;
258 break;
261 next_state_ = STATE_GET_CHANNEL_ID;
262 break;
263 case STATE_VERIFY_PROOF: {
264 ProofVerifier* verifier = crypto_config_->proof_verifier();
265 DCHECK(verifier);
266 next_state_ = STATE_VERIFY_PROOF_COMPLETE;
267 generation_counter_ = cached->generation_counter();
269 ProofVerifierCallbackImpl* proof_verify_callback =
270 new ProofVerifierCallbackImpl(this);
272 verify_ok_ = false;
274 QuicAsyncStatus status = verifier->VerifyProof(
275 server_id_.host(),
276 cached->server_config(),
277 cached->certs(),
278 cached->signature(),
279 verify_context_.get(),
280 &verify_error_details_,
281 &verify_details_,
282 proof_verify_callback);
284 switch (status) {
285 case QUIC_PENDING:
286 proof_verify_callback_ = proof_verify_callback;
287 DVLOG(1) << "Doing VerifyProof";
288 return;
289 case QUIC_FAILURE:
290 delete proof_verify_callback;
291 break;
292 case QUIC_SUCCESS:
293 delete proof_verify_callback;
294 verify_ok_ = true;
295 break;
297 break;
299 case STATE_VERIFY_PROOF_COMPLETE:
300 if (!verify_ok_) {
301 client_session()->OnProofVerifyDetailsAvailable(*verify_details_);
302 CloseConnectionWithDetails(
303 QUIC_PROOF_INVALID, "Proof invalid: " + verify_error_details_);
304 return;
306 // Check if generation_counter has changed between STATE_VERIFY_PROOF
307 // and STATE_VERIFY_PROOF_COMPLETE state changes.
308 if (generation_counter_ != cached->generation_counter()) {
309 next_state_ = STATE_VERIFY_PROOF;
310 } else {
311 SetCachedProofValid(cached);
312 cached->SetProofVerifyDetails(verify_details_.release());
313 next_state_ = STATE_GET_CHANNEL_ID;
315 break;
316 case STATE_GET_CHANNEL_ID: {
317 next_state_ = STATE_GET_CHANNEL_ID_COMPLETE;
318 channel_id_key_.reset();
319 if (!RequiresChannelID(cached)) {
320 next_state_ = STATE_SEND_CHLO;
321 break;
324 ChannelIDSourceCallbackImpl* channel_id_source_callback =
325 new ChannelIDSourceCallbackImpl(this);
326 QuicAsyncStatus status =
327 crypto_config_->channel_id_source()->GetChannelIDKey(
328 server_id_.host(), &channel_id_key_,
329 channel_id_source_callback);
331 switch (status) {
332 case QUIC_PENDING:
333 channel_id_source_callback_ = channel_id_source_callback;
334 DVLOG(1) << "Looking up channel ID";
335 return;
336 case QUIC_FAILURE:
337 delete channel_id_source_callback;
338 CloseConnectionWithDetails(QUIC_INVALID_CHANNEL_ID_SIGNATURE,
339 "Channel ID lookup failed");
340 return;
341 case QUIC_SUCCESS:
342 delete channel_id_source_callback;
343 break;
345 break;
347 case STATE_GET_CHANNEL_ID_COMPLETE:
348 if (!channel_id_key_.get()) {
349 CloseConnectionWithDetails(QUIC_INVALID_CHANNEL_ID_SIGNATURE,
350 "Channel ID lookup failed");
351 return;
353 next_state_ = STATE_SEND_CHLO;
354 break;
355 case STATE_RECV_SHLO: {
356 // We sent a CHLO that we expected to be accepted and now we're hoping
357 // for a SHLO from the server to confirm that.
358 if (in->tag() == kREJ) {
359 // alternative_decrypter will be NULL if the original alternative
360 // decrypter latched and became the primary decrypter. That happens
361 // if we received a message encrypted with the INITIAL key.
362 if (session()->connection()->alternative_decrypter() == NULL) {
363 // The rejection was sent encrypted!
364 CloseConnectionWithDetails(QUIC_CRYPTO_ENCRYPTION_LEVEL_INCORRECT,
365 "encrypted REJ message");
366 return;
368 next_state_ = STATE_RECV_REJ;
369 break;
371 if (in->tag() != kSHLO) {
372 CloseConnectionWithDetails(QUIC_INVALID_CRYPTO_MESSAGE_TYPE,
373 "Expected SHLO or REJ");
374 return;
376 // alternative_decrypter will be NULL if the original alternative
377 // decrypter latched and became the primary decrypter. That happens
378 // if we received a message encrypted with the INITIAL key.
379 if (session()->connection()->alternative_decrypter() != NULL) {
380 // The server hello was sent without encryption.
381 CloseConnectionWithDetails(QUIC_CRYPTO_ENCRYPTION_LEVEL_INCORRECT,
382 "unencrypted SHLO message");
383 return;
385 error = crypto_config_->ProcessServerHello(
386 *in, session()->connection()->connection_id(),
387 session()->connection()->server_supported_versions(),
388 cached, &crypto_negotiated_params_, &error_details);
390 if (error != QUIC_NO_ERROR) {
391 CloseConnectionWithDetails(
392 error, "Server hello invalid: " + error_details);
393 return;
395 error =
396 session()->config()->ProcessPeerHello(*in, SERVER, &error_details);
397 if (error != QUIC_NO_ERROR) {
398 CloseConnectionWithDetails(
399 error, "Server hello invalid: " + error_details);
400 return;
402 session()->OnConfigNegotiated();
404 CrypterPair* crypters =
405 &crypto_negotiated_params_.forward_secure_crypters;
406 // TODO(agl): we don't currently latch this decrypter because the idea
407 // has been floated that the server shouldn't send packets encrypted
408 // with the FORWARD_SECURE key until it receives a FORWARD_SECURE
409 // packet from the client.
410 session()->connection()->SetAlternativeDecrypter(
411 crypters->decrypter.release(), ENCRYPTION_FORWARD_SECURE,
412 false /* don't latch */);
413 session()->connection()->SetEncrypter(
414 ENCRYPTION_FORWARD_SECURE, crypters->encrypter.release());
415 session()->connection()->SetDefaultEncryptionLevel(
416 ENCRYPTION_FORWARD_SECURE);
418 handshake_confirmed_ = true;
419 session()->OnCryptoHandshakeEvent(QuicSession::HANDSHAKE_CONFIRMED);
420 return;
422 case STATE_IDLE:
423 // This means that the peer sent us a message that we weren't expecting.
424 CloseConnection(QUIC_INVALID_CRYPTO_MESSAGE_TYPE);
425 return;
430 void QuicCryptoClientStream::SetCachedProofValid(
431 QuicCryptoClientConfig::CachedState* cached) {
432 cached->SetProofValid();
433 client_session()->OnProofValid(*cached);
436 bool QuicCryptoClientStream::RequiresChannelID(
437 QuicCryptoClientConfig::CachedState* cached) {
438 if (!server_id_.is_https() ||
439 server_id_.privacy_mode() == PRIVACY_MODE_ENABLED ||
440 !crypto_config_->channel_id_source()) {
441 return false;
443 const CryptoHandshakeMessage* scfg = cached->GetServerConfig();
444 if (!scfg) { // scfg may be null when we send an inchoate CHLO.
445 return false;
447 const QuicTag* their_proof_demands;
448 size_t num_their_proof_demands;
449 if (scfg->GetTaglist(kPDMD, &their_proof_demands,
450 &num_their_proof_demands) != QUIC_NO_ERROR) {
451 return false;
453 for (size_t i = 0; i < num_their_proof_demands; i++) {
454 if (their_proof_demands[i] == kCHID) {
455 return true;
458 return false;
461 QuicClientSessionBase* QuicCryptoClientStream::client_session() {
462 return reinterpret_cast<QuicClientSessionBase*>(session());
465 } // namespace net