Adding yfriedman@ as owner for the enhanced_bookmarks component.
[chromium-blink-merge.git] / net / quic / quic_crypto_client_stream.cc
blob40e4d45901c531d6fd711e3d1067a3b4cda7d953
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_run_ = true;
31 stream_->channel_id_source_callback_ = NULL;
32 stream_->DoHandshakeLoop(NULL);
34 // The ChannelIDSource owns this object and will delete it when this method
35 // returns.
38 void QuicCryptoClientStream::ChannelIDSourceCallbackImpl::Cancel() {
39 stream_ = NULL;
42 QuicCryptoClientStream::ProofVerifierCallbackImpl::ProofVerifierCallbackImpl(
43 QuicCryptoClientStream* stream)
44 : stream_(stream) {}
46 QuicCryptoClientStream::ProofVerifierCallbackImpl::
47 ~ProofVerifierCallbackImpl() {}
49 void QuicCryptoClientStream::ProofVerifierCallbackImpl::Run(
50 bool ok,
51 const string& error_details,
52 scoped_ptr<ProofVerifyDetails>* details) {
53 if (stream_ == NULL) {
54 return;
57 stream_->verify_ok_ = ok;
58 stream_->verify_error_details_ = error_details;
59 stream_->verify_details_.reset(details->release());
60 stream_->proof_verify_callback_ = NULL;
61 stream_->DoHandshakeLoop(NULL);
63 // The ProofVerifier owns this object and will delete it when this method
64 // returns.
67 void QuicCryptoClientStream::ProofVerifierCallbackImpl::Cancel() {
68 stream_ = NULL;
71 QuicCryptoClientStream::QuicCryptoClientStream(
72 const QuicServerId& server_id,
73 QuicClientSessionBase* session,
74 ProofVerifyContext* verify_context,
75 QuicCryptoClientConfig* crypto_config)
76 : QuicCryptoStream(session),
77 next_state_(STATE_IDLE),
78 num_client_hellos_(0),
79 crypto_config_(crypto_config),
80 server_id_(server_id),
81 generation_counter_(0),
82 channel_id_sent_(false),
83 channel_id_source_callback_run_(false),
84 channel_id_source_callback_(NULL),
85 verify_context_(verify_context),
86 proof_verify_callback_(NULL) {
89 QuicCryptoClientStream::~QuicCryptoClientStream() {
90 if (channel_id_source_callback_) {
91 channel_id_source_callback_->Cancel();
93 if (proof_verify_callback_) {
94 proof_verify_callback_->Cancel();
98 void QuicCryptoClientStream::OnHandshakeMessage(
99 const CryptoHandshakeMessage& message) {
100 QuicCryptoStream::OnHandshakeMessage(message);
102 if (message.tag() == kSCUP) {
103 if (!handshake_confirmed()) {
104 CloseConnection(QUIC_CRYPTO_UPDATE_BEFORE_HANDSHAKE_COMPLETE);
105 return;
108 // |message| is an update from the server, so we treat it differently from a
109 // handshake message.
110 HandleServerConfigUpdateMessage(message);
111 return;
114 // Do not process handshake messages after the handshake is confirmed.
115 if (handshake_confirmed()) {
116 CloseConnection(QUIC_CRYPTO_MESSAGE_AFTER_HANDSHAKE_COMPLETE);
117 return;
120 DoHandshakeLoop(&message);
123 bool QuicCryptoClientStream::CryptoConnect() {
124 next_state_ = STATE_INITIALIZE;
125 DoHandshakeLoop(NULL);
126 return true;
129 int QuicCryptoClientStream::num_sent_client_hellos() const {
130 return num_client_hellos_;
133 bool QuicCryptoClientStream::WasChannelIDSent() const {
134 return channel_id_sent_;
137 bool QuicCryptoClientStream::WasChannelIDSourceCallbackRun() const {
138 return channel_id_source_callback_run_;
141 void QuicCryptoClientStream::HandleServerConfigUpdateMessage(
142 const CryptoHandshakeMessage& server_config_update) {
143 DCHECK(server_config_update.tag() == kSCUP);
144 string error_details;
145 QuicCryptoClientConfig::CachedState* cached =
146 crypto_config_->LookupOrCreate(server_id_);
147 QuicErrorCode error = crypto_config_->ProcessServerConfigUpdate(
148 server_config_update,
149 session()->connection()->clock()->WallNow(),
150 cached,
151 &crypto_negotiated_params_,
152 &error_details);
154 if (error != QUIC_NO_ERROR) {
155 CloseConnectionWithDetails(
156 error, "Server config update invalid: " + error_details);
157 return;
161 // kMaxClientHellos is the maximum number of times that we'll send a client
162 // hello. The value 3 accounts for:
163 // * One failure due to an incorrect or missing source-address token.
164 // * One failure due the server's certificate chain being unavailible and the
165 // server being unwilling to send it without a valid source-address token.
166 static const int kMaxClientHellos = 3;
168 void QuicCryptoClientStream::DoHandshakeLoop(
169 const CryptoHandshakeMessage* in) {
170 CryptoHandshakeMessage out;
171 QuicErrorCode error;
172 string error_details;
173 QuicCryptoClientConfig::CachedState* cached =
174 crypto_config_->LookupOrCreate(server_id_);
176 for (;;) {
177 const State state = next_state_;
178 next_state_ = STATE_IDLE;
179 switch (state) {
180 case STATE_INITIALIZE: {
181 if (!cached->IsEmpty() && !cached->signature().empty() &&
182 server_id_.is_https()) {
183 // Note that we verify the proof even if the cached proof is valid.
184 // This allows us to respond to CA trust changes or certificate
185 // expiration because it may have been a while since we last verified
186 // the proof.
187 DCHECK(crypto_config_->proof_verifier());
188 // If the cached state needs to be verified, do it now.
189 next_state_ = STATE_VERIFY_PROOF;
190 } else {
191 next_state_ = STATE_GET_CHANNEL_ID;
193 break;
195 case STATE_SEND_CHLO: {
196 // Send the client hello in plaintext.
197 session()->connection()->SetDefaultEncryptionLevel(ENCRYPTION_NONE);
198 if (num_client_hellos_ > kMaxClientHellos) {
199 CloseConnection(QUIC_CRYPTO_TOO_MANY_REJECTS);
200 return;
202 num_client_hellos_++;
204 if (!cached->IsComplete(session()->connection()->clock()->WallNow())) {
205 crypto_config_->FillInchoateClientHello(
206 server_id_,
207 session()->connection()->supported_versions().front(),
208 cached, &crypto_negotiated_params_, &out);
209 // Pad the inchoate client hello to fill up a packet.
210 const size_t kFramingOverhead = 50; // A rough estimate.
211 const size_t max_packet_size =
212 session()->connection()->max_packet_length();
213 if (max_packet_size <= kFramingOverhead) {
214 DLOG(DFATAL) << "max_packet_length (" << max_packet_size
215 << ") has no room for framing overhead.";
216 CloseConnection(QUIC_INTERNAL_ERROR);
217 return;
219 if (kClientHelloMinimumSize > max_packet_size - kFramingOverhead) {
220 DLOG(DFATAL) << "Client hello won't fit in a single packet.";
221 CloseConnection(QUIC_INTERNAL_ERROR);
222 return;
224 out.set_minimum_size(max_packet_size - kFramingOverhead);
225 next_state_ = STATE_RECV_REJ;
226 SendHandshakeMessage(out);
227 return;
229 session()->config()->ToHandshakeMessage(&out);
230 error = crypto_config_->FillClientHello(
231 server_id_,
232 session()->connection()->connection_id(),
233 session()->connection()->supported_versions().front(),
234 cached,
235 session()->connection()->clock()->WallNow(),
236 session()->connection()->random_generator(),
237 channel_id_key_.get(),
238 &crypto_negotiated_params_,
239 &out,
240 &error_details);
241 if (error != QUIC_NO_ERROR) {
242 // Flush the cached config so that, if it's bad, the server has a
243 // chance to send us another in the future.
244 cached->InvalidateServerConfig();
245 CloseConnectionWithDetails(error, error_details);
246 return;
248 channel_id_sent_ = (channel_id_key_.get() != NULL);
249 if (cached->proof_verify_details()) {
250 client_session()->OnProofVerifyDetailsAvailable(
251 *cached->proof_verify_details());
253 next_state_ = STATE_RECV_SHLO;
254 SendHandshakeMessage(out);
255 // Be prepared to decrypt with the new server write key.
256 session()->connection()->SetAlternativeDecrypter(
257 crypto_negotiated_params_.initial_crypters.decrypter.release(),
258 ENCRYPTION_INITIAL,
259 true /* latch once used */);
260 // Send subsequent packets under encryption on the assumption that the
261 // server will accept the handshake.
262 session()->connection()->SetEncrypter(
263 ENCRYPTION_INITIAL,
264 crypto_negotiated_params_.initial_crypters.encrypter.release());
265 session()->connection()->SetDefaultEncryptionLevel(
266 ENCRYPTION_INITIAL);
267 if (!encryption_established_) {
268 encryption_established_ = true;
269 session()->OnCryptoHandshakeEvent(
270 QuicSession::ENCRYPTION_FIRST_ESTABLISHED);
271 } else {
272 session()->OnCryptoHandshakeEvent(
273 QuicSession::ENCRYPTION_REESTABLISHED);
275 return;
277 case STATE_RECV_REJ:
278 // We sent a dummy CHLO because we didn't have enough information to
279 // perform a handshake, or we sent a full hello that the server
280 // rejected. Here we hope to have a REJ that contains the information
281 // that we need.
282 if (in->tag() != kREJ) {
283 CloseConnectionWithDetails(QUIC_INVALID_CRYPTO_MESSAGE_TYPE,
284 "Expected REJ");
285 return;
287 error = crypto_config_->ProcessRejection(
288 *in, session()->connection()->clock()->WallNow(), cached,
289 server_id_.is_https(), &crypto_negotiated_params_, &error_details);
290 if (error != QUIC_NO_ERROR) {
291 CloseConnectionWithDetails(error, error_details);
292 return;
294 if (!cached->proof_valid()) {
295 if (!server_id_.is_https()) {
296 // We don't check the certificates for insecure QUIC connections.
297 SetCachedProofValid(cached);
298 } else if (!cached->signature().empty()) {
299 // Note that we only verify the proof if the cached proof is not
300 // valid. If the cached proof is valid here, someone else must have
301 // just added the server config to the cache and verified the proof,
302 // so we can assume no CA trust changes or certificate expiration
303 // has happened since then.
304 next_state_ = STATE_VERIFY_PROOF;
305 break;
308 next_state_ = STATE_GET_CHANNEL_ID;
309 break;
310 case STATE_VERIFY_PROOF: {
311 ProofVerifier* verifier = crypto_config_->proof_verifier();
312 DCHECK(verifier);
313 next_state_ = STATE_VERIFY_PROOF_COMPLETE;
314 generation_counter_ = cached->generation_counter();
316 ProofVerifierCallbackImpl* proof_verify_callback =
317 new ProofVerifierCallbackImpl(this);
319 verify_ok_ = false;
321 QuicAsyncStatus status = verifier->VerifyProof(
322 server_id_.host(),
323 cached->server_config(),
324 cached->certs(),
325 cached->signature(),
326 verify_context_.get(),
327 &verify_error_details_,
328 &verify_details_,
329 proof_verify_callback);
331 switch (status) {
332 case QUIC_PENDING:
333 proof_verify_callback_ = proof_verify_callback;
334 DVLOG(1) << "Doing VerifyProof";
335 return;
336 case QUIC_FAILURE:
337 delete proof_verify_callback;
338 break;
339 case QUIC_SUCCESS:
340 delete proof_verify_callback;
341 verify_ok_ = true;
342 break;
344 break;
346 case STATE_VERIFY_PROOF_COMPLETE:
347 if (!verify_ok_) {
348 client_session()->OnProofVerifyDetailsAvailable(*verify_details_);
349 CloseConnectionWithDetails(
350 QUIC_PROOF_INVALID, "Proof invalid: " + verify_error_details_);
351 return;
353 // Check if generation_counter has changed between STATE_VERIFY_PROOF
354 // and STATE_VERIFY_PROOF_COMPLETE state changes.
355 if (generation_counter_ != cached->generation_counter()) {
356 next_state_ = STATE_VERIFY_PROOF;
357 } else {
358 SetCachedProofValid(cached);
359 cached->SetProofVerifyDetails(verify_details_.release());
360 next_state_ = STATE_GET_CHANNEL_ID;
362 break;
363 case STATE_GET_CHANNEL_ID: {
364 next_state_ = STATE_GET_CHANNEL_ID_COMPLETE;
365 channel_id_key_.reset();
366 if (!RequiresChannelID(cached)) {
367 next_state_ = STATE_SEND_CHLO;
368 break;
371 ChannelIDSourceCallbackImpl* channel_id_source_callback =
372 new ChannelIDSourceCallbackImpl(this);
373 QuicAsyncStatus status =
374 crypto_config_->channel_id_source()->GetChannelIDKey(
375 server_id_.host(), &channel_id_key_,
376 channel_id_source_callback);
378 switch (status) {
379 case QUIC_PENDING:
380 channel_id_source_callback_ = channel_id_source_callback;
381 DVLOG(1) << "Looking up channel ID";
382 return;
383 case QUIC_FAILURE:
384 delete channel_id_source_callback;
385 CloseConnectionWithDetails(QUIC_INVALID_CHANNEL_ID_SIGNATURE,
386 "Channel ID lookup failed");
387 return;
388 case QUIC_SUCCESS:
389 delete channel_id_source_callback;
390 break;
392 break;
394 case STATE_GET_CHANNEL_ID_COMPLETE:
395 if (!channel_id_key_.get()) {
396 CloseConnectionWithDetails(QUIC_INVALID_CHANNEL_ID_SIGNATURE,
397 "Channel ID lookup failed");
398 return;
400 next_state_ = STATE_SEND_CHLO;
401 break;
402 case STATE_RECV_SHLO: {
403 // We sent a CHLO that we expected to be accepted and now we're hoping
404 // for a SHLO from the server to confirm that.
405 if (in->tag() == kREJ) {
406 // alternative_decrypter will be NULL if the original alternative
407 // decrypter latched and became the primary decrypter. That happens
408 // if we received a message encrypted with the INITIAL key.
409 if (session()->connection()->alternative_decrypter() == NULL) {
410 // The rejection was sent encrypted!
411 CloseConnectionWithDetails(QUIC_CRYPTO_ENCRYPTION_LEVEL_INCORRECT,
412 "encrypted REJ message");
413 return;
415 next_state_ = STATE_RECV_REJ;
416 break;
418 if (in->tag() != kSHLO) {
419 CloseConnectionWithDetails(QUIC_INVALID_CRYPTO_MESSAGE_TYPE,
420 "Expected SHLO or REJ");
421 return;
423 // alternative_decrypter will be NULL if the original alternative
424 // decrypter latched and became the primary decrypter. That happens
425 // if we received a message encrypted with the INITIAL key.
426 if (session()->connection()->alternative_decrypter() != NULL) {
427 // The server hello was sent without encryption.
428 CloseConnectionWithDetails(QUIC_CRYPTO_ENCRYPTION_LEVEL_INCORRECT,
429 "unencrypted SHLO message");
430 return;
432 error = crypto_config_->ProcessServerHello(
433 *in, session()->connection()->connection_id(),
434 session()->connection()->server_supported_versions(),
435 cached, &crypto_negotiated_params_, &error_details);
437 if (error != QUIC_NO_ERROR) {
438 CloseConnectionWithDetails(
439 error, "Server hello invalid: " + error_details);
440 return;
442 error =
443 session()->config()->ProcessPeerHello(*in, SERVER, &error_details);
444 if (error != QUIC_NO_ERROR) {
445 CloseConnectionWithDetails(
446 error, "Server hello invalid: " + error_details);
447 return;
449 session()->OnConfigNegotiated();
451 CrypterPair* crypters =
452 &crypto_negotiated_params_.forward_secure_crypters;
453 // TODO(agl): we don't currently latch this decrypter because the idea
454 // has been floated that the server shouldn't send packets encrypted
455 // with the FORWARD_SECURE key until it receives a FORWARD_SECURE
456 // packet from the client.
457 session()->connection()->SetAlternativeDecrypter(
458 crypters->decrypter.release(), ENCRYPTION_FORWARD_SECURE,
459 false /* don't latch */);
460 session()->connection()->SetEncrypter(
461 ENCRYPTION_FORWARD_SECURE, crypters->encrypter.release());
462 session()->connection()->SetDefaultEncryptionLevel(
463 ENCRYPTION_FORWARD_SECURE);
465 handshake_confirmed_ = true;
466 session()->OnCryptoHandshakeEvent(QuicSession::HANDSHAKE_CONFIRMED);
467 session()->connection()->OnHandshakeComplete();
468 return;
470 case STATE_IDLE:
471 // This means that the peer sent us a message that we weren't expecting.
472 CloseConnection(QUIC_INVALID_CRYPTO_MESSAGE_TYPE);
473 return;
478 void QuicCryptoClientStream::SetCachedProofValid(
479 QuicCryptoClientConfig::CachedState* cached) {
480 cached->SetProofValid();
481 client_session()->OnProofValid(*cached);
484 bool QuicCryptoClientStream::RequiresChannelID(
485 QuicCryptoClientConfig::CachedState* cached) {
486 if (!server_id_.is_https() ||
487 server_id_.privacy_mode() == PRIVACY_MODE_ENABLED ||
488 !crypto_config_->channel_id_source()) {
489 return false;
491 const CryptoHandshakeMessage* scfg = cached->GetServerConfig();
492 if (!scfg) { // scfg may be null when we send an inchoate CHLO.
493 return false;
495 const QuicTag* their_proof_demands;
496 size_t num_their_proof_demands;
497 if (scfg->GetTaglist(kPDMD, &their_proof_demands,
498 &num_their_proof_demands) != QUIC_NO_ERROR) {
499 return false;
501 for (size_t i = 0; i < num_their_proof_demands; i++) {
502 if (their_proof_demands[i] == kCHID) {
503 return true;
506 return false;
509 QuicClientSessionBase* QuicCryptoClientStream::client_session() {
510 return reinterpret_cast<QuicClientSessionBase*>(session());
513 } // namespace net