Chromium Code Reviews| OLD | NEW |
|---|---|
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 |
| OLD | NEW |