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 QuicAsyncStatus rv = QUIC_SUCCESS; |
| 182 do { |
| 183 CHECK_NE(STATE_NONE, next_state_); |
185 const State state = next_state_; | 184 const State state = next_state_; |
186 next_state_ = STATE_IDLE; | 185 next_state_ = STATE_IDLE; |
| 186 rv = QUIC_SUCCESS; |
187 switch (state) { | 187 switch (state) { |
188 case STATE_INITIALIZE: { | 188 case STATE_INITIALIZE: |
189 if (!cached->IsEmpty() && !cached->signature().empty() && | 189 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; | 190 break; |
202 } | 191 case STATE_SEND_CHLO: |
203 case STATE_SEND_CHLO: { | 192 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; | 193 return; |
284 } | |
285 case STATE_RECV_REJ: | 194 case STATE_RECV_REJ: |
286 // We sent a dummy CHLO because we didn't have enough information to | 195 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; | 196 break; |
318 case STATE_VERIFY_PROOF: { | 197 case STATE_VERIFY_PROOF: |
319 if (QUIC_PENDING == DoVerifyProof(cached)) { | 198 rv = DoVerifyProof(cached); |
320 return; | |
321 } | |
322 break; | 199 break; |
323 } | |
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 rv = DoGetChannelID(cached); |
331 channel_id_key_.reset(); | |
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 } | |
358 break; | 205 break; |
359 } | |
360 case STATE_GET_CHANNEL_ID_COMPLETE: | 206 case STATE_GET_CHANNEL_ID_COMPLETE: |
361 if (!channel_id_key_.get()) { | 207 DoGetChannelIDComplete(); |
362 CloseConnectionWithDetails(QUIC_INVALID_CHANNEL_ID_SIGNATURE, | |
363 "Channel ID lookup failed"); | |
364 return; | |
365 } | |
366 next_state_ = STATE_SEND_CHLO; | |
367 break; | 208 break; |
368 case STATE_RECV_SHLO: { | 209 case STATE_RECV_SHLO: |
369 // We sent a CHLO that we expected to be accepted and now we're hoping | 210 DoReceiveSHLO(in, cached); |
370 // for a SHLO from the server to confirm that. | 211 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: | 212 case STATE_IDLE: |
437 // This means that the peer sent us a message that we weren't expecting. | 213 // This means that the peer sent us a message that we weren't expecting. |
438 CloseConnection(QUIC_INVALID_CRYPTO_MESSAGE_TYPE); | 214 CloseConnection(QUIC_INVALID_CRYPTO_MESSAGE_TYPE); |
439 return; | 215 return; |
440 case STATE_INITIALIZE_SCUP: | 216 case STATE_INITIALIZE_SCUP: |
441 DoInitializeServerConfigUpdate(cached); | 217 DoInitializeServerConfigUpdate(cached); |
442 break; | 218 break; |
443 case STATE_VERIFY_PROOF_DONE: | 219 case STATE_NONE: |
| 220 NOTREACHED(); |
444 return; // We are done. | 221 return; // We are done. |
445 } | 222 } |
| 223 } while (rv != QUIC_PENDING && next_state_ != STATE_NONE); |
| 224 } |
| 225 |
| 226 void QuicCryptoClientStream::DoInitialize( |
| 227 QuicCryptoClientConfig::CachedState* cached) { |
| 228 if (!cached->IsEmpty() && !cached->signature().empty() && |
| 229 server_id_.is_https()) { |
| 230 // Note that we verify the proof even if the cached proof is valid. |
| 231 // This allows us to respond to CA trust changes or certificate |
| 232 // expiration because it may have been a while since we last verified |
| 233 // the proof. |
| 234 DCHECK(crypto_config_->proof_verifier()); |
| 235 // If the cached state needs to be verified, do it now. |
| 236 next_state_ = STATE_VERIFY_PROOF; |
| 237 } else { |
| 238 next_state_ = STATE_GET_CHANNEL_ID; |
446 } | 239 } |
447 } | 240 } |
448 | 241 |
449 void QuicCryptoClientStream::DoInitializeServerConfigUpdate( | 242 void QuicCryptoClientStream::DoSendCHLO( |
| 243 const CryptoHandshakeMessage* in, |
450 QuicCryptoClientConfig::CachedState* cached) { | 244 QuicCryptoClientConfig::CachedState* cached) { |
451 bool update_ignored = false; | 245 // Send the client hello in plaintext. |
452 if (!server_id_.is_https()) { | 246 session()->connection()->SetDefaultEncryptionLevel(ENCRYPTION_NONE); |
453 // We don't check the certificates for insecure QUIC connections. | 247 if (num_client_hellos_ > kMaxClientHellos) { |
454 SetCachedProofValid(cached); | 248 CloseConnection(QUIC_CRYPTO_TOO_MANY_REJECTS); |
455 next_state_ = STATE_VERIFY_PROOF_DONE; | 249 return; |
456 } else if (!cached->IsEmpty() && !cached->signature().empty()) { | 250 } |
457 // Note that we verify the proof even if the cached proof is valid. | 251 num_client_hellos_++; |
458 DCHECK(crypto_config_->proof_verifier()); | 252 |
459 next_state_ = STATE_VERIFY_PROOF; | 253 CryptoHandshakeMessage out; |
| 254 if (!cached->IsComplete(session()->connection()->clock()->WallNow())) { |
| 255 crypto_config_->FillInchoateClientHello( |
| 256 server_id_, |
| 257 session()->connection()->supported_versions().front(), |
| 258 cached, &crypto_negotiated_params_, &out); |
| 259 // Pad the inchoate client hello to fill up a packet. |
| 260 const size_t kFramingOverhead = 50; // A rough estimate. |
| 261 const size_t max_packet_size = |
| 262 session()->connection()->max_packet_length(); |
| 263 if (max_packet_size <= kFramingOverhead) { |
| 264 DLOG(DFATAL) << "max_packet_length (" << max_packet_size |
| 265 << ") has no room for framing overhead."; |
| 266 CloseConnection(QUIC_INTERNAL_ERROR); |
| 267 return; |
| 268 } |
| 269 if (kClientHelloMinimumSize > max_packet_size - kFramingOverhead) { |
| 270 DLOG(DFATAL) << "Client hello won't fit in a single packet."; |
| 271 CloseConnection(QUIC_INTERNAL_ERROR); |
| 272 return; |
| 273 } |
| 274 out.set_minimum_size(max_packet_size - kFramingOverhead); |
| 275 next_state_ = STATE_RECV_REJ; |
| 276 SendHandshakeMessage(out); |
| 277 return; |
| 278 } |
| 279 |
| 280 session()->config()->ToHandshakeMessage(&out); |
| 281 string error_details; |
| 282 QuicErrorCode error = crypto_config_->FillClientHello( |
| 283 server_id_, |
| 284 session()->connection()->connection_id(), |
| 285 session()->connection()->supported_versions().front(), |
| 286 cached, |
| 287 session()->connection()->clock()->WallNow(), |
| 288 session()->connection()->random_generator(), |
| 289 channel_id_key_.get(), |
| 290 &crypto_negotiated_params_, |
| 291 &out, |
| 292 &error_details); |
| 293 if (error != QUIC_NO_ERROR) { |
| 294 // Flush the cached config so that, if it's bad, the server has a |
| 295 // chance to send us another in the future. |
| 296 cached->InvalidateServerConfig(); |
| 297 CloseConnectionWithDetails(error, error_details); |
| 298 return; |
| 299 } |
| 300 channel_id_sent_ = (channel_id_key_.get() != NULL); |
| 301 if (cached->proof_verify_details()) { |
| 302 client_session()->OnProofVerifyDetailsAvailable( |
| 303 *cached->proof_verify_details()); |
| 304 } |
| 305 next_state_ = STATE_RECV_SHLO; |
| 306 SendHandshakeMessage(out); |
| 307 // Be prepared to decrypt with the new server write key. |
| 308 session()->connection()->SetAlternativeDecrypter( |
| 309 crypto_negotiated_params_.initial_crypters.decrypter.release(), |
| 310 ENCRYPTION_INITIAL, |
| 311 true /* latch once used */); |
| 312 // Send subsequent packets under encryption on the assumption that the |
| 313 // server will accept the handshake. |
| 314 session()->connection()->SetEncrypter( |
| 315 ENCRYPTION_INITIAL, |
| 316 crypto_negotiated_params_.initial_crypters.encrypter.release()); |
| 317 session()->connection()->SetDefaultEncryptionLevel( |
| 318 ENCRYPTION_INITIAL); |
| 319 if (!encryption_established_) { |
| 320 encryption_established_ = true; |
| 321 session()->OnCryptoHandshakeEvent( |
| 322 QuicSession::ENCRYPTION_FIRST_ESTABLISHED); |
460 } else { | 323 } else { |
461 update_ignored = true; | 324 session()->OnCryptoHandshakeEvent( |
462 next_state_ = STATE_VERIFY_PROOF_DONE; | 325 QuicSession::ENCRYPTION_REESTABLISHED); |
463 } | 326 } |
464 UMA_HISTOGRAM_BOOLEAN("Net.QuicNumServerConfig.UpdateMessagesIgnored", | 327 } |
465 update_ignored); | 328 |
| 329 void QuicCryptoClientStream::DoReceiveREJ( |
| 330 const CryptoHandshakeMessage* in, |
| 331 QuicCryptoClientConfig::CachedState* cached) { |
| 332 // We sent a dummy CHLO because we didn't have enough information to |
| 333 // perform a handshake, or we sent a full hello that the server |
| 334 // rejected. Here we hope to have a REJ that contains the information |
| 335 // that we need. |
| 336 if (in->tag() != kREJ) { |
| 337 next_state_ = STATE_NONE; |
| 338 CloseConnectionWithDetails(QUIC_INVALID_CRYPTO_MESSAGE_TYPE, |
| 339 "Expected REJ"); |
| 340 return; |
| 341 } |
| 342 string error_details; |
| 343 QuicErrorCode error = crypto_config_->ProcessRejection( |
| 344 *in, session()->connection()->clock()->WallNow(), cached, |
| 345 server_id_.is_https(), &crypto_negotiated_params_, &error_details); |
| 346 if (error != QUIC_NO_ERROR) { |
| 347 next_state_ = STATE_NONE; |
| 348 CloseConnectionWithDetails(error, error_details); |
| 349 return; |
| 350 } |
| 351 if (!cached->proof_valid()) { |
| 352 if (!server_id_.is_https()) { |
| 353 // We don't check the certificates for insecure QUIC connections. |
| 354 SetCachedProofValid(cached); |
| 355 } else if (!cached->signature().empty()) { |
| 356 // Note that we only verify the proof if the cached proof is not |
| 357 // valid. If the cached proof is valid here, someone else must have |
| 358 // just added the server config to the cache and verified the proof, |
| 359 // so we can assume no CA trust changes or certificate expiration |
| 360 // has happened since then. |
| 361 next_state_ = STATE_VERIFY_PROOF; |
| 362 return; |
| 363 } |
| 364 } |
| 365 next_state_ = STATE_GET_CHANNEL_ID; |
466 } | 366 } |
467 | 367 |
468 QuicAsyncStatus QuicCryptoClientStream::DoVerifyProof( | 368 QuicAsyncStatus QuicCryptoClientStream::DoVerifyProof( |
469 QuicCryptoClientConfig::CachedState* cached) { | 369 QuicCryptoClientConfig::CachedState* cached) { |
470 ProofVerifier* verifier = crypto_config_->proof_verifier(); | 370 ProofVerifier* verifier = crypto_config_->proof_verifier(); |
471 DCHECK(verifier); | 371 DCHECK(verifier); |
472 next_state_ = STATE_VERIFY_PROOF_COMPLETE; | 372 next_state_ = STATE_VERIFY_PROOF_COMPLETE; |
473 generation_counter_ = cached->generation_counter(); | 373 generation_counter_ = cached->generation_counter(); |
474 | 374 |
475 ProofVerifierCallbackImpl* proof_verify_callback = | 375 ProofVerifierCallbackImpl* proof_verify_callback = |
(...skipping 20 matching lines...) Expand all Loading... |
496 delete proof_verify_callback; | 396 delete proof_verify_callback; |
497 break; | 397 break; |
498 case QUIC_SUCCESS: | 398 case QUIC_SUCCESS: |
499 delete proof_verify_callback; | 399 delete proof_verify_callback; |
500 verify_ok_ = true; | 400 verify_ok_ = true; |
501 break; | 401 break; |
502 } | 402 } |
503 return status; | 403 return status; |
504 } | 404 } |
505 | 405 |
506 QuicErrorCode QuicCryptoClientStream::DoVerifyProofComplete( | 406 void QuicCryptoClientStream::DoVerifyProofComplete( |
507 QuicCryptoClientConfig::CachedState* cached) { | 407 QuicCryptoClientConfig::CachedState* cached) { |
508 if (!verify_ok_) { | 408 if (!verify_ok_) { |
| 409 next_state_ = STATE_NONE; |
509 client_session()->OnProofVerifyDetailsAvailable(*verify_details_); | 410 client_session()->OnProofVerifyDetailsAvailable(*verify_details_); |
510 UMA_HISTOGRAM_BOOLEAN("Net.QuicVerifyProofFailed.HandshakeConfirmed", | 411 UMA_HISTOGRAM_BOOLEAN("Net.QuicVerifyProofFailed.HandshakeConfirmed", |
511 handshake_confirmed()); | 412 handshake_confirmed()); |
512 CloseConnectionWithDetails( | 413 CloseConnectionWithDetails( |
513 QUIC_PROOF_INVALID, "Proof invalid: " + verify_error_details_); | 414 QUIC_PROOF_INVALID, "Proof invalid: " + verify_error_details_); |
514 return QUIC_PROOF_INVALID; | 415 return; |
515 } | 416 } |
516 | 417 |
517 // Check if generation_counter has changed between STATE_VERIFY_PROOF and | 418 // Check if generation_counter has changed between STATE_VERIFY_PROOF and |
518 // STATE_VERIFY_PROOF_COMPLETE state changes. | 419 // STATE_VERIFY_PROOF_COMPLETE state changes. |
519 if (generation_counter_ != cached->generation_counter()) { | 420 if (generation_counter_ != cached->generation_counter()) { |
520 next_state_ = STATE_VERIFY_PROOF; | 421 next_state_ = STATE_VERIFY_PROOF; |
521 } else { | 422 } else { |
522 SetCachedProofValid(cached); | 423 SetCachedProofValid(cached); |
523 cached->SetProofVerifyDetails(verify_details_.release()); | 424 cached->SetProofVerifyDetails(verify_details_.release()); |
524 if (!handshake_confirmed()) { | 425 if (!handshake_confirmed()) { |
525 next_state_ = STATE_GET_CHANNEL_ID; | 426 next_state_ = STATE_GET_CHANNEL_ID; |
526 } else { | 427 } else { |
527 next_state_ = STATE_VERIFY_PROOF_DONE; | 428 next_state_ = STATE_NONE; |
528 } | 429 } |
529 } | 430 } |
530 return QUIC_NO_ERROR; | 431 } |
| 432 |
| 433 QuicAsyncStatus QuicCryptoClientStream::DoGetChannelID( |
| 434 QuicCryptoClientConfig::CachedState* cached) { |
| 435 next_state_ = STATE_GET_CHANNEL_ID_COMPLETE; |
| 436 channel_id_key_.reset(); |
| 437 if (!RequiresChannelID(cached)) { |
| 438 next_state_ = STATE_SEND_CHLO; |
| 439 return QUIC_SUCCESS; |
| 440 } |
| 441 |
| 442 ChannelIDSourceCallbackImpl* channel_id_source_callback = |
| 443 new ChannelIDSourceCallbackImpl(this); |
| 444 QuicAsyncStatus status = |
| 445 crypto_config_->channel_id_source()->GetChannelIDKey( |
| 446 server_id_.host(), &channel_id_key_, |
| 447 channel_id_source_callback); |
| 448 |
| 449 switch (status) { |
| 450 case QUIC_PENDING: |
| 451 channel_id_source_callback_ = channel_id_source_callback; |
| 452 DVLOG(1) << "Looking up channel ID"; |
| 453 break; |
| 454 case QUIC_FAILURE: |
| 455 next_state_ = STATE_NONE; |
| 456 delete channel_id_source_callback; |
| 457 CloseConnectionWithDetails(QUIC_INVALID_CHANNEL_ID_SIGNATURE, |
| 458 "Channel ID lookup failed"); |
| 459 break; |
| 460 case QUIC_SUCCESS: |
| 461 delete channel_id_source_callback; |
| 462 break; |
| 463 } |
| 464 return status; |
| 465 } |
| 466 |
| 467 void QuicCryptoClientStream::DoGetChannelIDComplete() { |
| 468 if (!channel_id_key_.get()) { |
| 469 next_state_ = STATE_NONE; |
| 470 CloseConnectionWithDetails(QUIC_INVALID_CHANNEL_ID_SIGNATURE, |
| 471 "Channel ID lookup failed"); |
| 472 return; |
| 473 } |
| 474 next_state_ = STATE_SEND_CHLO; |
| 475 } |
| 476 |
| 477 void QuicCryptoClientStream::DoReceiveSHLO( |
| 478 const CryptoHandshakeMessage* in, |
| 479 QuicCryptoClientConfig::CachedState* cached) { |
| 480 next_state_ = STATE_NONE; |
| 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 // The rejection was sent encrypted! |
| 489 CloseConnectionWithDetails(QUIC_CRYPTO_ENCRYPTION_LEVEL_INCORRECT, |
| 490 "encrypted REJ message"); |
| 491 return; |
| 492 } |
| 493 next_state_ = STATE_RECV_REJ; |
| 494 return; |
| 495 } |
| 496 |
| 497 if (in->tag() != kSHLO) { |
| 498 CloseConnectionWithDetails(QUIC_INVALID_CRYPTO_MESSAGE_TYPE, |
| 499 "Expected SHLO or REJ"); |
| 500 return; |
| 501 } |
| 502 |
| 503 // alternative_decrypter will be NULL if the original alternative |
| 504 // decrypter latched and became the primary decrypter. That happens |
| 505 // if we received a message encrypted with the INITIAL key. |
| 506 if (session()->connection()->alternative_decrypter() != NULL) { |
| 507 // The server hello was sent without encryption. |
| 508 CloseConnectionWithDetails(QUIC_CRYPTO_ENCRYPTION_LEVEL_INCORRECT, |
| 509 "unencrypted SHLO message"); |
| 510 return; |
| 511 } |
| 512 |
| 513 string error_details; |
| 514 QuicErrorCode error = crypto_config_->ProcessServerHello( |
| 515 *in, session()->connection()->connection_id(), |
| 516 session()->connection()->server_supported_versions(), |
| 517 cached, &crypto_negotiated_params_, &error_details); |
| 518 |
| 519 if (error != QUIC_NO_ERROR) { |
| 520 CloseConnectionWithDetails(error, "Server hello invalid: " + error_details); |
| 521 return; |
| 522 } |
| 523 error = session()->config()->ProcessPeerHello(*in, SERVER, &error_details); |
| 524 if (error != QUIC_NO_ERROR) { |
| 525 CloseConnectionWithDetails(error, "Server hello invalid: " + error_details); |
| 526 return; |
| 527 } |
| 528 session()->OnConfigNegotiated(); |
| 529 |
| 530 CrypterPair* crypters = &crypto_negotiated_params_.forward_secure_crypters; |
| 531 // TODO(agl): we don't currently latch this decrypter because the idea |
| 532 // has been floated that the server shouldn't send packets encrypted |
| 533 // with the FORWARD_SECURE key until it receives a FORWARD_SECURE |
| 534 // packet from the client. |
| 535 session()->connection()->SetAlternativeDecrypter( |
| 536 crypters->decrypter.release(), ENCRYPTION_FORWARD_SECURE, |
| 537 false /* don't latch */); |
| 538 session()->connection()->SetEncrypter( |
| 539 ENCRYPTION_FORWARD_SECURE, crypters->encrypter.release()); |
| 540 session()->connection()->SetDefaultEncryptionLevel( |
| 541 ENCRYPTION_FORWARD_SECURE); |
| 542 |
| 543 handshake_confirmed_ = true; |
| 544 session()->OnCryptoHandshakeEvent(QuicSession::HANDSHAKE_CONFIRMED); |
| 545 session()->connection()->OnHandshakeComplete(); |
| 546 } |
| 547 |
| 548 void QuicCryptoClientStream::DoInitializeServerConfigUpdate( |
| 549 QuicCryptoClientConfig::CachedState* cached) { |
| 550 bool update_ignored = false; |
| 551 if (!server_id_.is_https()) { |
| 552 // We don't check the certificates for insecure QUIC connections. |
| 553 SetCachedProofValid(cached); |
| 554 next_state_ = STATE_NONE; |
| 555 } else if (!cached->IsEmpty() && !cached->signature().empty()) { |
| 556 // Note that we verify the proof even if the cached proof is valid. |
| 557 DCHECK(crypto_config_->proof_verifier()); |
| 558 next_state_ = STATE_VERIFY_PROOF; |
| 559 } else { |
| 560 update_ignored = true; |
| 561 next_state_ = STATE_NONE; |
| 562 } |
| 563 UMA_HISTOGRAM_COUNTS("Net.QuicNumServerConfig.UpdateMessagesIgnored", |
| 564 update_ignored); |
531 } | 565 } |
532 | 566 |
533 void QuicCryptoClientStream::SetCachedProofValid( | 567 void QuicCryptoClientStream::SetCachedProofValid( |
534 QuicCryptoClientConfig::CachedState* cached) { | 568 QuicCryptoClientConfig::CachedState* cached) { |
535 cached->SetProofValid(); | 569 cached->SetProofValid(); |
536 client_session()->OnProofValid(*cached); | 570 client_session()->OnProofValid(*cached); |
537 } | 571 } |
538 | 572 |
539 bool QuicCryptoClientStream::RequiresChannelID( | 573 bool QuicCryptoClientStream::RequiresChannelID( |
540 QuicCryptoClientConfig::CachedState* cached) { | 574 QuicCryptoClientConfig::CachedState* cached) { |
(...skipping 18 matching lines...) Expand all Loading... |
559 } | 593 } |
560 } | 594 } |
561 return false; | 595 return false; |
562 } | 596 } |
563 | 597 |
564 QuicClientSessionBase* QuicCryptoClientStream::client_session() { | 598 QuicClientSessionBase* QuicCryptoClientStream::client_session() { |
565 return reinterpret_cast<QuicClientSessionBase*>(session()); | 599 return reinterpret_cast<QuicClientSessionBase*>(session()); |
566 } | 600 } |
567 | 601 |
568 } // namespace net | 602 } // namespace net |
OLD | NEW |