Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(157)

Side by Side Diff: net/quic/quic_crypto_client_stream.cc

Issue 588443002: QUIC - minor reorg of QuicCryptoClientStream::DoHandshakeLoop. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 6 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "net/quic/quic_crypto_client_stream.h" 5 #include "net/quic/quic_crypto_client_stream.h"
6 6
7 #include "base/metrics/histogram.h" 7 #include "base/metrics/histogram.h"
8 #include "net/quic/crypto/crypto_protocol.h" 8 #include "net/quic/crypto/crypto_protocol.h"
9 #include "net/quic/crypto/crypto_utils.h" 9 #include "net/quic/crypto/crypto_utils.h"
10 #include "net/quic/crypto/null_encrypter.h" 10 #include "net/quic/crypto/null_encrypter.h"
(...skipping 157 matching lines...) Expand 10 before | Expand all | Expand 10 after
168 168
169 // kMaxClientHellos is the maximum number of times that we'll send a client 169 // kMaxClientHellos is the maximum number of times that we'll send a client
170 // hello. The value 3 accounts for: 170 // hello. The value 3 accounts for:
171 // * One failure due to an incorrect or missing source-address token. 171 // * One failure due to an incorrect or missing source-address token.
172 // * One failure due the server's certificate chain being unavailible and the 172 // * One failure due the server's certificate chain being unavailible and the
173 // server being unwilling to send it without a valid source-address token. 173 // server being unwilling to send it without a valid source-address token.
174 static const int kMaxClientHellos = 3; 174 static const int kMaxClientHellos = 3;
175 175
176 void QuicCryptoClientStream::DoHandshakeLoop( 176 void QuicCryptoClientStream::DoHandshakeLoop(
177 const CryptoHandshakeMessage* in) { 177 const CryptoHandshakeMessage* in) {
178 CryptoHandshakeMessage out;
179 QuicErrorCode error;
180 string error_details;
181 QuicCryptoClientConfig::CachedState* cached = 178 QuicCryptoClientConfig::CachedState* cached =
182 crypto_config_->LookupOrCreate(server_id_); 179 crypto_config_->LookupOrCreate(server_id_);
183 180
184 for (;;) { 181 for (;;) {
185 const State state = next_state_; 182 const State state = next_state_;
186 next_state_ = STATE_IDLE; 183 next_state_ = STATE_IDLE;
187 switch (state) { 184 switch (state) {
188 case STATE_INITIALIZE: { 185 case STATE_INITIALIZE:
189 if (!cached->IsEmpty() && !cached->signature().empty() && 186 DoInitialize(cached);
190 server_id_.is_https()) {
191 // Note that we verify the proof even if the cached proof is valid.
192 // This allows us to respond to CA trust changes or certificate
193 // expiration because it may have been a while since we last verified
194 // the proof.
195 DCHECK(crypto_config_->proof_verifier());
196 // If the cached state needs to be verified, do it now.
197 next_state_ = STATE_VERIFY_PROOF;
198 } else {
199 next_state_ = STATE_GET_CHANNEL_ID;
200 }
201 break; 187 break;
202 } 188 case STATE_SEND_CHLO:
203 case STATE_SEND_CHLO: { 189 DoSendCHLO(in, cached);
204 // Send the client hello in plaintext.
205 session()->connection()->SetDefaultEncryptionLevel(ENCRYPTION_NONE);
206 if (num_client_hellos_ > kMaxClientHellos) {
207 CloseConnection(QUIC_CRYPTO_TOO_MANY_REJECTS);
208 return;
209 }
210 num_client_hellos_++;
211
212 if (!cached->IsComplete(session()->connection()->clock()->WallNow())) {
213 crypto_config_->FillInchoateClientHello(
214 server_id_,
215 session()->connection()->supported_versions().front(),
216 cached, &crypto_negotiated_params_, &out);
217 // Pad the inchoate client hello to fill up a packet.
218 const size_t kFramingOverhead = 50; // A rough estimate.
219 const size_t max_packet_size =
220 session()->connection()->max_packet_length();
221 if (max_packet_size <= kFramingOverhead) {
222 DLOG(DFATAL) << "max_packet_length (" << max_packet_size
223 << ") has no room for framing overhead.";
224 CloseConnection(QUIC_INTERNAL_ERROR);
225 return;
226 }
227 if (kClientHelloMinimumSize > max_packet_size - kFramingOverhead) {
228 DLOG(DFATAL) << "Client hello won't fit in a single packet.";
229 CloseConnection(QUIC_INTERNAL_ERROR);
230 return;
231 }
232 out.set_minimum_size(max_packet_size - kFramingOverhead);
233 next_state_ = STATE_RECV_REJ;
234 SendHandshakeMessage(out);
235 return;
236 }
237 session()->config()->ToHandshakeMessage(&out);
238 error = crypto_config_->FillClientHello(
239 server_id_,
240 session()->connection()->connection_id(),
241 session()->connection()->supported_versions().front(),
242 cached,
243 session()->connection()->clock()->WallNow(),
244 session()->connection()->random_generator(),
245 channel_id_key_.get(),
246 &crypto_negotiated_params_,
247 &out,
248 &error_details);
249 if (error != QUIC_NO_ERROR) {
250 // Flush the cached config so that, if it's bad, the server has a
251 // chance to send us another in the future.
252 cached->InvalidateServerConfig();
253 CloseConnectionWithDetails(error, error_details);
254 return;
255 }
256 channel_id_sent_ = (channel_id_key_.get() != NULL);
257 if (cached->proof_verify_details()) {
258 client_session()->OnProofVerifyDetailsAvailable(
259 *cached->proof_verify_details());
260 }
261 next_state_ = STATE_RECV_SHLO;
262 SendHandshakeMessage(out);
263 // Be prepared to decrypt with the new server write key.
264 session()->connection()->SetAlternativeDecrypter(
265 crypto_negotiated_params_.initial_crypters.decrypter.release(),
266 ENCRYPTION_INITIAL,
267 true /* latch once used */);
268 // Send subsequent packets under encryption on the assumption that the
269 // server will accept the handshake.
270 session()->connection()->SetEncrypter(
271 ENCRYPTION_INITIAL,
272 crypto_negotiated_params_.initial_crypters.encrypter.release());
273 session()->connection()->SetDefaultEncryptionLevel(
274 ENCRYPTION_INITIAL);
275 if (!encryption_established_) {
276 encryption_established_ = true;
277 session()->OnCryptoHandshakeEvent(
278 QuicSession::ENCRYPTION_FIRST_ESTABLISHED);
279 } else {
280 session()->OnCryptoHandshakeEvent(
281 QuicSession::ENCRYPTION_REESTABLISHED);
282 }
283 return; 190 return;
284 }
285 case STATE_RECV_REJ: 191 case STATE_RECV_REJ:
286 // We sent a dummy CHLO because we didn't have enough information to 192 DoReceiveREJ(in, cached);
287 // perform a handshake, or we sent a full hello that the server
288 // rejected. Here we hope to have a REJ that contains the information
289 // that we need.
290 if (in->tag() != kREJ) {
291 CloseConnectionWithDetails(QUIC_INVALID_CRYPTO_MESSAGE_TYPE,
292 "Expected REJ");
293 return;
294 }
295 error = crypto_config_->ProcessRejection(
296 *in, session()->connection()->clock()->WallNow(), cached,
297 server_id_.is_https(), &crypto_negotiated_params_, &error_details);
298 if (error != QUIC_NO_ERROR) {
299 CloseConnectionWithDetails(error, error_details);
300 return;
301 }
302 if (!cached->proof_valid()) {
303 if (!server_id_.is_https()) {
304 // We don't check the certificates for insecure QUIC connections.
305 SetCachedProofValid(cached);
306 } else if (!cached->signature().empty()) {
307 // Note that we only verify the proof if the cached proof is not
308 // valid. If the cached proof is valid here, someone else must have
309 // just added the server config to the cache and verified the proof,
310 // so we can assume no CA trust changes or certificate expiration
311 // has happened since then.
312 next_state_ = STATE_VERIFY_PROOF;
313 break;
314 }
315 }
316 next_state_ = STATE_GET_CHANNEL_ID;
317 break; 193 break;
318 case STATE_VERIFY_PROOF: { 194 case STATE_VERIFY_PROOF: {
319 if (QUIC_PENDING == DoVerifyProof(cached)) { 195 if (QUIC_PENDING == DoVerifyProof(cached)) {
320 return; 196 return;
321 } 197 }
322 break; 198 break;
323 } 199 }
324 case STATE_VERIFY_PROOF_COMPLETE: 200 case STATE_VERIFY_PROOF_COMPLETE:
325 if (QUIC_PROOF_INVALID == DoVerifyProofComplete(cached)) { 201 DoVerifyProofComplete(cached);
326 return;
327 }
328 break; 202 break;
329 case STATE_GET_CHANNEL_ID: { 203 case STATE_GET_CHANNEL_ID: {
330 next_state_ = STATE_GET_CHANNEL_ID_COMPLETE; 204 if (QUIC_SUCCESS != DoGetChannelID(cached)) {
agl 2014/09/19 17:26:52 In other cases you have changed returns into next_
ramant (doing other things) 2014/09/19 21:25:25 In DoGetChannelID and DoVerifyProof we shouldn't m
331 channel_id_key_.reset(); 205 return;
332 if (!RequiresChannelID(cached)) {
333 next_state_ = STATE_SEND_CHLO;
334 break;
335 }
336
337 ChannelIDSourceCallbackImpl* channel_id_source_callback =
338 new ChannelIDSourceCallbackImpl(this);
339 QuicAsyncStatus status =
340 crypto_config_->channel_id_source()->GetChannelIDKey(
341 server_id_.host(), &channel_id_key_,
342 channel_id_source_callback);
343
344 switch (status) {
345 case QUIC_PENDING:
346 channel_id_source_callback_ = channel_id_source_callback;
347 DVLOG(1) << "Looking up channel ID";
348 return;
349 case QUIC_FAILURE:
350 delete channel_id_source_callback;
351 CloseConnectionWithDetails(QUIC_INVALID_CHANNEL_ID_SIGNATURE,
352 "Channel ID lookup failed");
353 return;
354 case QUIC_SUCCESS:
355 delete channel_id_source_callback;
356 break;
357 } 206 }
358 break; 207 break;
359 } 208 }
360 case STATE_GET_CHANNEL_ID_COMPLETE: 209 case STATE_GET_CHANNEL_ID_COMPLETE:
361 if (!channel_id_key_.get()) { 210 DoGetChannelIDComplete();
362 CloseConnectionWithDetails(QUIC_INVALID_CHANNEL_ID_SIGNATURE,
363 "Channel ID lookup failed");
364 return;
365 }
366 next_state_ = STATE_SEND_CHLO;
367 break; 211 break;
368 case STATE_RECV_SHLO: { 212 case STATE_RECV_SHLO:
369 // We sent a CHLO that we expected to be accepted and now we're hoping 213 DoReceiveSHLO(in, cached);
370 // for a SHLO from the server to confirm that. 214 break;
371 if (in->tag() == kREJ) {
372 // alternative_decrypter will be NULL if the original alternative
373 // decrypter latched and became the primary decrypter. That happens
374 // if we received a message encrypted with the INITIAL key.
375 if (session()->connection()->alternative_decrypter() == NULL) {
376 // The rejection was sent encrypted!
377 CloseConnectionWithDetails(QUIC_CRYPTO_ENCRYPTION_LEVEL_INCORRECT,
378 "encrypted REJ message");
379 return;
380 }
381 next_state_ = STATE_RECV_REJ;
382 break;
383 }
384 if (in->tag() != kSHLO) {
385 CloseConnectionWithDetails(QUIC_INVALID_CRYPTO_MESSAGE_TYPE,
386 "Expected SHLO or REJ");
387 return;
388 }
389 // alternative_decrypter will be NULL if the original alternative
390 // decrypter latched and became the primary decrypter. That happens
391 // if we received a message encrypted with the INITIAL key.
392 if (session()->connection()->alternative_decrypter() != NULL) {
393 // The server hello was sent without encryption.
394 CloseConnectionWithDetails(QUIC_CRYPTO_ENCRYPTION_LEVEL_INCORRECT,
395 "unencrypted SHLO message");
396 return;
397 }
398 error = crypto_config_->ProcessServerHello(
399 *in, session()->connection()->connection_id(),
400 session()->connection()->server_supported_versions(),
401 cached, &crypto_negotiated_params_, &error_details);
402
403 if (error != QUIC_NO_ERROR) {
404 CloseConnectionWithDetails(
405 error, "Server hello invalid: " + error_details);
406 return;
407 }
408 error =
409 session()->config()->ProcessPeerHello(*in, SERVER, &error_details);
410 if (error != QUIC_NO_ERROR) {
411 CloseConnectionWithDetails(
412 error, "Server hello invalid: " + error_details);
413 return;
414 }
415 session()->OnConfigNegotiated();
416
417 CrypterPair* crypters =
418 &crypto_negotiated_params_.forward_secure_crypters;
419 // TODO(agl): we don't currently latch this decrypter because the idea
420 // has been floated that the server shouldn't send packets encrypted
421 // with the FORWARD_SECURE key until it receives a FORWARD_SECURE
422 // packet from the client.
423 session()->connection()->SetAlternativeDecrypter(
424 crypters->decrypter.release(), ENCRYPTION_FORWARD_SECURE,
425 false /* don't latch */);
426 session()->connection()->SetEncrypter(
427 ENCRYPTION_FORWARD_SECURE, crypters->encrypter.release());
428 session()->connection()->SetDefaultEncryptionLevel(
429 ENCRYPTION_FORWARD_SECURE);
430
431 handshake_confirmed_ = true;
432 session()->OnCryptoHandshakeEvent(QuicSession::HANDSHAKE_CONFIRMED);
433 session()->connection()->OnHandshakeComplete();
434 return;
435 }
436 case STATE_IDLE: 215 case STATE_IDLE:
437 // This means that the peer sent us a message that we weren't expecting. 216 // This means that the peer sent us a message that we weren't expecting.
438 CloseConnection(QUIC_INVALID_CRYPTO_MESSAGE_TYPE); 217 CloseConnection(QUIC_INVALID_CRYPTO_MESSAGE_TYPE);
439 return; 218 return;
440 case STATE_INITIALIZE_SCUP: 219 case STATE_INITIALIZE_SCUP:
441 DoInitializeServerConfigUpdate(cached); 220 DoInitializeServerConfigUpdate(cached);
442 break; 221 break;
443 case STATE_VERIFY_PROOF_DONE: 222 case STATE_DONE:
444 return; // We are done. 223 return; // We are done.
445 } 224 }
446 } 225 }
447 } 226 }
448 227
449 void QuicCryptoClientStream::DoInitializeServerConfigUpdate( 228 void QuicCryptoClientStream::DoInitialize(
450 QuicCryptoClientConfig::CachedState* cached) { 229 QuicCryptoClientConfig::CachedState* cached) {
451 if (!server_id_.is_https()) { 230 if (!cached->IsEmpty() && !cached->signature().empty() &&
452 // We don't check the certificates for insecure QUIC connections. 231 server_id_.is_https()) {
453 SetCachedProofValid(cached); 232 // Note that we verify the proof even if the cached proof is valid.
454 next_state_ = STATE_VERIFY_PROOF_DONE; 233 // This allows us to respond to CA trust changes or certificate
234 // expiration because it may have been a while since we last verified
235 // the proof.
236 DCHECK(crypto_config_->proof_verifier());
237 // If the cached state needs to be verified, do it now.
238 next_state_ = STATE_VERIFY_PROOF;
239 } else {
240 next_state_ = STATE_GET_CHANNEL_ID;
241 }
242 }
243
244 void QuicCryptoClientStream::DoSendCHLO(
245 const CryptoHandshakeMessage* in,
246 QuicCryptoClientConfig::CachedState* cached) {
247 // Send the client hello in plaintext.
248 session()->connection()->SetDefaultEncryptionLevel(ENCRYPTION_NONE);
249 if (num_client_hellos_ > kMaxClientHellos) {
250 CloseConnection(QUIC_CRYPTO_TOO_MANY_REJECTS);
455 return; 251 return;
456 } 252 }
457 if (!cached->IsEmpty() && !cached->signature().empty()) { 253 num_client_hellos_++;
458 // Note that we verify the proof even if the cached proof is valid. 254
459 DCHECK(crypto_config_->proof_verifier()); 255 CryptoHandshakeMessage out;
460 next_state_ = STATE_VERIFY_PROOF; 256 if (!cached->IsComplete(session()->connection()->clock()->WallNow())) {
257 crypto_config_->FillInchoateClientHello(
258 server_id_,
259 session()->connection()->supported_versions().front(),
260 cached, &crypto_negotiated_params_, &out);
261 // Pad the inchoate client hello to fill up a packet.
262 const size_t kFramingOverhead = 50; // A rough estimate.
263 const size_t max_packet_size =
264 session()->connection()->max_packet_length();
265 if (max_packet_size <= kFramingOverhead) {
266 DLOG(DFATAL) << "max_packet_length (" << max_packet_size
267 << ") has no room for framing overhead.";
268 CloseConnection(QUIC_INTERNAL_ERROR);
269 return;
270 }
271 if (kClientHelloMinimumSize > max_packet_size - kFramingOverhead) {
272 DLOG(DFATAL) << "Client hello won't fit in a single packet.";
273 CloseConnection(QUIC_INTERNAL_ERROR);
274 return;
275 }
276 out.set_minimum_size(max_packet_size - kFramingOverhead);
277 next_state_ = STATE_RECV_REJ;
278 SendHandshakeMessage(out);
279 return;
461 } 280 }
281
282 session()->config()->ToHandshakeMessage(&out);
283 string error_details;
284 QuicErrorCode error = crypto_config_->FillClientHello(
285 server_id_,
286 session()->connection()->connection_id(),
287 session()->connection()->supported_versions().front(),
288 cached,
289 session()->connection()->clock()->WallNow(),
290 session()->connection()->random_generator(),
291 channel_id_key_.get(),
292 &crypto_negotiated_params_,
293 &out,
294 &error_details);
295 if (error != QUIC_NO_ERROR) {
296 // Flush the cached config so that, if it's bad, the server has a
297 // chance to send us another in the future.
298 cached->InvalidateServerConfig();
299 CloseConnectionWithDetails(error, error_details);
300 return;
301 }
302 channel_id_sent_ = (channel_id_key_.get() != NULL);
303 if (cached->proof_verify_details()) {
304 client_session()->OnProofVerifyDetailsAvailable(
305 *cached->proof_verify_details());
306 }
307 next_state_ = STATE_RECV_SHLO;
308 SendHandshakeMessage(out);
309 // Be prepared to decrypt with the new server write key.
310 session()->connection()->SetAlternativeDecrypter(
311 crypto_negotiated_params_.initial_crypters.decrypter.release(),
312 ENCRYPTION_INITIAL,
313 true /* latch once used */);
314 // Send subsequent packets under encryption on the assumption that the
315 // server will accept the handshake.
316 session()->connection()->SetEncrypter(
317 ENCRYPTION_INITIAL,
318 crypto_negotiated_params_.initial_crypters.encrypter.release());
319 session()->connection()->SetDefaultEncryptionLevel(
320 ENCRYPTION_INITIAL);
321 if (!encryption_established_) {
322 encryption_established_ = true;
323 session()->OnCryptoHandshakeEvent(
324 QuicSession::ENCRYPTION_FIRST_ESTABLISHED);
325 } else {
326 session()->OnCryptoHandshakeEvent(
327 QuicSession::ENCRYPTION_REESTABLISHED);
328 }
329 }
330
331 void QuicCryptoClientStream::DoReceiveREJ(
332 const CryptoHandshakeMessage* in,
333 QuicCryptoClientConfig::CachedState* cached) {
334 // We sent a dummy CHLO because we didn't have enough information to
335 // perform a handshake, or we sent a full hello that the server
336 // rejected. Here we hope to have a REJ that contains the information
337 // that we need.
338 if (in->tag() != kREJ) {
339 next_state_ = STATE_DONE;
340 CloseConnectionWithDetails(QUIC_INVALID_CRYPTO_MESSAGE_TYPE,
341 "Expected REJ");
342 return;
343 }
344 string error_details;
345 QuicErrorCode error = crypto_config_->ProcessRejection(
346 *in, session()->connection()->clock()->WallNow(), cached,
347 server_id_.is_https(), &crypto_negotiated_params_, &error_details);
348 if (error != QUIC_NO_ERROR) {
349 next_state_ = STATE_DONE;
350 CloseConnectionWithDetails(error, error_details);
351 return;
352 }
353 if (!cached->proof_valid()) {
354 if (!server_id_.is_https()) {
355 // We don't check the certificates for insecure QUIC connections.
356 SetCachedProofValid(cached);
357 } else if (!cached->signature().empty()) {
358 // Note that we only verify the proof if the cached proof is not
359 // valid. If the cached proof is valid here, someone else must have
360 // just added the server config to the cache and verified the proof,
361 // so we can assume no CA trust changes or certificate expiration
362 // has happened since then.
363 next_state_ = STATE_VERIFY_PROOF;
364 return;
365 }
366 }
367 next_state_ = STATE_GET_CHANNEL_ID;
462 } 368 }
463 369
464 QuicAsyncStatus QuicCryptoClientStream::DoVerifyProof( 370 QuicAsyncStatus QuicCryptoClientStream::DoVerifyProof(
465 QuicCryptoClientConfig::CachedState* cached) { 371 QuicCryptoClientConfig::CachedState* cached) {
466 ProofVerifier* verifier = crypto_config_->proof_verifier(); 372 ProofVerifier* verifier = crypto_config_->proof_verifier();
467 DCHECK(verifier); 373 DCHECK(verifier);
468 next_state_ = STATE_VERIFY_PROOF_COMPLETE; 374 next_state_ = STATE_VERIFY_PROOF_COMPLETE;
469 generation_counter_ = cached->generation_counter(); 375 generation_counter_ = cached->generation_counter();
470 376
471 ProofVerifierCallbackImpl* proof_verify_callback = 377 ProofVerifierCallbackImpl* proof_verify_callback =
(...skipping 20 matching lines...) Expand all
492 delete proof_verify_callback; 398 delete proof_verify_callback;
493 break; 399 break;
494 case QUIC_SUCCESS: 400 case QUIC_SUCCESS:
495 delete proof_verify_callback; 401 delete proof_verify_callback;
496 verify_ok_ = true; 402 verify_ok_ = true;
497 break; 403 break;
498 } 404 }
499 return status; 405 return status;
500 } 406 }
501 407
502 QuicErrorCode QuicCryptoClientStream::DoVerifyProofComplete( 408 void QuicCryptoClientStream::DoVerifyProofComplete(
503 QuicCryptoClientConfig::CachedState* cached) { 409 QuicCryptoClientConfig::CachedState* cached) {
504 if (!verify_ok_) { 410 if (!verify_ok_) {
411 next_state_ = STATE_DONE;
505 client_session()->OnProofVerifyDetailsAvailable(*verify_details_); 412 client_session()->OnProofVerifyDetailsAvailable(*verify_details_);
506 UMA_HISTOGRAM_BOOLEAN("Net.QuicVerifyProofFailed.HandshakeConfirmed", 413 UMA_HISTOGRAM_BOOLEAN("Net.QuicVerifyProofFailed.HandshakeConfirmed",
507 handshake_confirmed()); 414 handshake_confirmed());
508 CloseConnectionWithDetails( 415 CloseConnectionWithDetails(
509 QUIC_PROOF_INVALID, "Proof invalid: " + verify_error_details_); 416 QUIC_PROOF_INVALID, "Proof invalid: " + verify_error_details_);
510 return QUIC_PROOF_INVALID; 417 return;
511 } 418 }
512 419
513 // Check if generation_counter has changed between STATE_VERIFY_PROOF and 420 // Check if generation_counter has changed between STATE_VERIFY_PROOF and
514 // STATE_VERIFY_PROOF_COMPLETE state changes. 421 // STATE_VERIFY_PROOF_COMPLETE state changes.
515 if (generation_counter_ != cached->generation_counter()) { 422 if (generation_counter_ != cached->generation_counter()) {
516 next_state_ = STATE_VERIFY_PROOF; 423 next_state_ = STATE_VERIFY_PROOF;
517 } else { 424 } else {
518 SetCachedProofValid(cached); 425 SetCachedProofValid(cached);
519 cached->SetProofVerifyDetails(verify_details_.release()); 426 cached->SetProofVerifyDetails(verify_details_.release());
520 if (!handshake_confirmed()) { 427 if (!handshake_confirmed()) {
521 next_state_ = STATE_GET_CHANNEL_ID; 428 next_state_ = STATE_GET_CHANNEL_ID;
522 } else { 429 } else {
523 next_state_ = STATE_VERIFY_PROOF_DONE; 430 next_state_ = STATE_DONE;
524 } 431 }
525 } 432 }
526 return QUIC_NO_ERROR; 433 }
434
435 QuicAsyncStatus QuicCryptoClientStream::DoGetChannelID(
436 QuicCryptoClientConfig::CachedState* cached) {
437 next_state_ = STATE_GET_CHANNEL_ID_COMPLETE;
438 channel_id_key_.reset();
439 if (!RequiresChannelID(cached)) {
440 next_state_ = STATE_SEND_CHLO;
441 return QUIC_SUCCESS;
442 }
443
444 ChannelIDSourceCallbackImpl* channel_id_source_callback =
445 new ChannelIDSourceCallbackImpl(this);
446 QuicAsyncStatus status =
447 crypto_config_->channel_id_source()->GetChannelIDKey(
448 server_id_.host(), &channel_id_key_,
449 channel_id_source_callback);
450
451 switch (status) {
452 case QUIC_PENDING:
453 channel_id_source_callback_ = channel_id_source_callback;
454 DVLOG(1) << "Looking up channel ID";
455 break;
456 case QUIC_FAILURE:
457 delete channel_id_source_callback;
458 CloseConnectionWithDetails(QUIC_INVALID_CHANNEL_ID_SIGNATURE,
459 "Channel ID lookup failed");
460 break;
461 case QUIC_SUCCESS:
462 delete channel_id_source_callback;
463 break;
464 }
465 return status;
466 }
467
468 void QuicCryptoClientStream::DoGetChannelIDComplete() {
469 if (!channel_id_key_.get()) {
470 next_state_ = STATE_DONE;
471 CloseConnectionWithDetails(QUIC_INVALID_CHANNEL_ID_SIGNATURE,
472 "Channel ID lookup failed");
473 } else {
474 next_state_ = STATE_SEND_CHLO;
475 }
476 }
477
478 void QuicCryptoClientStream::DoReceiveSHLO(
479 const CryptoHandshakeMessage* in,
480 QuicCryptoClientConfig::CachedState* cached) {
481 // We sent a CHLO that we expected to be accepted and now we're hoping
482 // for a SHLO from the server to confirm that.
483 if (in->tag() == kREJ) {
484 // alternative_decrypter will be NULL if the original alternative
485 // decrypter latched and became the primary decrypter. That happens
486 // if we received a message encrypted with the INITIAL key.
487 if (session()->connection()->alternative_decrypter() == NULL) {
488 next_state_ = STATE_DONE;
489 // The rejection was sent encrypted!
490 CloseConnectionWithDetails(QUIC_CRYPTO_ENCRYPTION_LEVEL_INCORRECT,
491 "encrypted REJ message");
492 return;
493 }
494 next_state_ = STATE_RECV_REJ;
495 return;
496 }
497
498 next_state_ = STATE_DONE;
499 if (in->tag() != kSHLO) {
500 CloseConnectionWithDetails(QUIC_INVALID_CRYPTO_MESSAGE_TYPE,
501 "Expected SHLO or REJ");
502 return;
503 }
504
505 // alternative_decrypter will be NULL if the original alternative
506 // decrypter latched and became the primary decrypter. That happens
507 // if we received a message encrypted with the INITIAL key.
508 if (session()->connection()->alternative_decrypter() != NULL) {
509 // The server hello was sent without encryption.
510 CloseConnectionWithDetails(QUIC_CRYPTO_ENCRYPTION_LEVEL_INCORRECT,
511 "unencrypted SHLO message");
512 return;
513 }
514
515 string error_details;
516 QuicErrorCode error = crypto_config_->ProcessServerHello(
517 *in, session()->connection()->connection_id(),
518 session()->connection()->server_supported_versions(),
519 cached, &crypto_negotiated_params_, &error_details);
520
521 if (error != QUIC_NO_ERROR) {
522 CloseConnectionWithDetails(error, "Server hello invalid: " + error_details);
523 return;
524 }
525 error = session()->config()->ProcessPeerHello(*in, SERVER, &error_details);
526 if (error != QUIC_NO_ERROR) {
527 CloseConnectionWithDetails(error, "Server hello invalid: " + error_details);
528 return;
529 }
530 session()->OnConfigNegotiated();
531
532 CrypterPair* crypters = &crypto_negotiated_params_.forward_secure_crypters;
533 // TODO(agl): we don't currently latch this decrypter because the idea
534 // has been floated that the server shouldn't send packets encrypted
535 // with the FORWARD_SECURE key until it receives a FORWARD_SECURE
536 // packet from the client.
537 session()->connection()->SetAlternativeDecrypter(
538 crypters->decrypter.release(), ENCRYPTION_FORWARD_SECURE,
539 false /* don't latch */);
540 session()->connection()->SetEncrypter(
541 ENCRYPTION_FORWARD_SECURE, crypters->encrypter.release());
542 session()->connection()->SetDefaultEncryptionLevel(
543 ENCRYPTION_FORWARD_SECURE);
544
545 handshake_confirmed_ = true;
546 session()->OnCryptoHandshakeEvent(QuicSession::HANDSHAKE_CONFIRMED);
547 session()->connection()->OnHandshakeComplete();
548 }
549
550 void QuicCryptoClientStream::DoInitializeServerConfigUpdate(
551 QuicCryptoClientConfig::CachedState* cached) {
552 if (!server_id_.is_https()) {
553 // We don't check the certificates for insecure QUIC connections.
554 SetCachedProofValid(cached);
555 next_state_ = STATE_DONE;
556 return;
557 }
558 if (!cached->IsEmpty() && !cached->signature().empty()) {
559 // Note that we verify the proof even if the cached proof is valid.
560 DCHECK(crypto_config_->proof_verifier());
561 next_state_ = STATE_VERIFY_PROOF;
562 return;
563 }
564 UMA_HISTOGRAM_COUNTS("Net.QuicNumServerConfigUpdateMessagesIgnored", 1);
565 next_state_ = STATE_DONE;
527 } 566 }
528 567
529 void QuicCryptoClientStream::SetCachedProofValid( 568 void QuicCryptoClientStream::SetCachedProofValid(
530 QuicCryptoClientConfig::CachedState* cached) { 569 QuicCryptoClientConfig::CachedState* cached) {
531 cached->SetProofValid(); 570 cached->SetProofValid();
532 client_session()->OnProofValid(*cached); 571 client_session()->OnProofValid(*cached);
533 } 572 }
534 573
535 bool QuicCryptoClientStream::RequiresChannelID( 574 bool QuicCryptoClientStream::RequiresChannelID(
536 QuicCryptoClientConfig::CachedState* cached) { 575 QuicCryptoClientConfig::CachedState* cached) {
(...skipping 18 matching lines...) Expand all
555 } 594 }
556 } 595 }
557 return false; 596 return false;
558 } 597 }
559 598
560 QuicClientSessionBase* QuicCryptoClientStream::client_session() { 599 QuicClientSessionBase* QuicCryptoClientStream::client_session() {
561 return reinterpret_cast<QuicClientSessionBase*>(session()); 600 return reinterpret_cast<QuicClientSessionBase*>(session());
562 } 601 }
563 602
564 } // namespace net 603 } // namespace net
OLDNEW
« net/quic/quic_crypto_client_stream.h ('K') | « net/quic/quic_crypto_client_stream.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698