• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.
4 
5 #include "net/quic/quic_crypto_client_stream.h"
6 
7 #include "base/metrics/histogram.h"
8 #include "net/quic/crypto/crypto_protocol.h"
9 #include "net/quic/crypto/crypto_utils.h"
10 #include "net/quic/crypto/null_encrypter.h"
11 #include "net/quic/quic_client_session_base.h"
12 #include "net/quic/quic_protocol.h"
13 #include "net/quic/quic_session.h"
14 
15 namespace net {
16 
17 QuicCryptoClientStream::ChannelIDSourceCallbackImpl::
ChannelIDSourceCallbackImpl(QuicCryptoClientStream * stream)18 ChannelIDSourceCallbackImpl(QuicCryptoClientStream* stream)
19     : stream_(stream) {}
20 
21 QuicCryptoClientStream::ChannelIDSourceCallbackImpl::
~ChannelIDSourceCallbackImpl()22 ~ChannelIDSourceCallbackImpl() {}
23 
Run(scoped_ptr<ChannelIDKey> * channel_id_key)24 void QuicCryptoClientStream::ChannelIDSourceCallbackImpl::Run(
25     scoped_ptr<ChannelIDKey>* channel_id_key) {
26   if (stream_ == NULL) {
27     return;
28   }
29 
30   stream_->channel_id_key_.reset(channel_id_key->release());
31   stream_->channel_id_source_callback_run_ = true;
32   stream_->channel_id_source_callback_ = NULL;
33   stream_->DoHandshakeLoop(NULL);
34 
35   // The ChannelIDSource owns this object and will delete it when this method
36   // returns.
37 }
38 
Cancel()39 void QuicCryptoClientStream::ChannelIDSourceCallbackImpl::Cancel() {
40   stream_ = NULL;
41 }
42 
ProofVerifierCallbackImpl(QuicCryptoClientStream * stream)43 QuicCryptoClientStream::ProofVerifierCallbackImpl::ProofVerifierCallbackImpl(
44     QuicCryptoClientStream* stream)
45     : stream_(stream) {}
46 
47 QuicCryptoClientStream::ProofVerifierCallbackImpl::
~ProofVerifierCallbackImpl()48 ~ProofVerifierCallbackImpl() {}
49 
Run(bool ok,const string & error_details,scoped_ptr<ProofVerifyDetails> * details)50 void QuicCryptoClientStream::ProofVerifierCallbackImpl::Run(
51     bool ok,
52     const string& error_details,
53     scoped_ptr<ProofVerifyDetails>* details) {
54   if (stream_ == NULL) {
55     return;
56   }
57 
58   stream_->verify_ok_ = ok;
59   stream_->verify_error_details_ = error_details;
60   stream_->verify_details_.reset(details->release());
61   stream_->proof_verify_callback_ = NULL;
62   stream_->DoHandshakeLoop(NULL);
63 
64   // The ProofVerifier owns this object and will delete it when this method
65   // returns.
66 }
67 
Cancel()68 void QuicCryptoClientStream::ProofVerifierCallbackImpl::Cancel() {
69   stream_ = NULL;
70 }
71 
QuicCryptoClientStream(const QuicServerId & server_id,QuicClientSessionBase * session,ProofVerifyContext * verify_context,QuicCryptoClientConfig * crypto_config)72 QuicCryptoClientStream::QuicCryptoClientStream(
73     const QuicServerId& server_id,
74     QuicClientSessionBase* session,
75     ProofVerifyContext* verify_context,
76     QuicCryptoClientConfig* crypto_config)
77     : QuicCryptoStream(session),
78       next_state_(STATE_IDLE),
79       num_client_hellos_(0),
80       crypto_config_(crypto_config),
81       server_id_(server_id),
82       generation_counter_(0),
83       channel_id_sent_(false),
84       channel_id_source_callback_run_(false),
85       channel_id_source_callback_(NULL),
86       verify_context_(verify_context),
87       proof_verify_callback_(NULL) {
88 }
89 
~QuicCryptoClientStream()90 QuicCryptoClientStream::~QuicCryptoClientStream() {
91   if (channel_id_source_callback_) {
92     channel_id_source_callback_->Cancel();
93   }
94   if (proof_verify_callback_) {
95     proof_verify_callback_->Cancel();
96   }
97 }
98 
OnHandshakeMessage(const CryptoHandshakeMessage & message)99 void QuicCryptoClientStream::OnHandshakeMessage(
100     const CryptoHandshakeMessage& message) {
101   QuicCryptoStream::OnHandshakeMessage(message);
102 
103   if (message.tag() == kSCUP) {
104     if (!handshake_confirmed()) {
105       CloseConnection(QUIC_CRYPTO_UPDATE_BEFORE_HANDSHAKE_COMPLETE);
106       return;
107     }
108 
109     // |message| is an update from the server, so we treat it differently from a
110     // handshake message.
111     HandleServerConfigUpdateMessage(message);
112     return;
113   }
114 
115   // Do not process handshake messages after the handshake is confirmed.
116   if (handshake_confirmed()) {
117     CloseConnection(QUIC_CRYPTO_MESSAGE_AFTER_HANDSHAKE_COMPLETE);
118     return;
119   }
120 
121   DoHandshakeLoop(&message);
122 }
123 
CryptoConnect()124 bool QuicCryptoClientStream::CryptoConnect() {
125   next_state_ = STATE_INITIALIZE;
126   DoHandshakeLoop(NULL);
127   return true;
128 }
129 
num_sent_client_hellos() const130 int QuicCryptoClientStream::num_sent_client_hellos() const {
131   return num_client_hellos_;
132 }
133 
WasChannelIDSent() const134 bool QuicCryptoClientStream::WasChannelIDSent() const {
135   return channel_id_sent_;
136 }
137 
WasChannelIDSourceCallbackRun() const138 bool QuicCryptoClientStream::WasChannelIDSourceCallbackRun() const {
139   return channel_id_source_callback_run_;
140 }
141 
HandleServerConfigUpdateMessage(const CryptoHandshakeMessage & server_config_update)142 void QuicCryptoClientStream::HandleServerConfigUpdateMessage(
143     const CryptoHandshakeMessage& server_config_update) {
144   DCHECK(server_config_update.tag() == kSCUP);
145   string error_details;
146   QuicCryptoClientConfig::CachedState* cached =
147       crypto_config_->LookupOrCreate(server_id_);
148   QuicErrorCode error = crypto_config_->ProcessServerConfigUpdate(
149       server_config_update,
150       session()->connection()->clock()->WallNow(),
151       cached,
152       &crypto_negotiated_params_,
153       &error_details);
154 
155   if (error != QUIC_NO_ERROR) {
156     CloseConnectionWithDetails(
157         error, "Server config update invalid: " + error_details);
158     return;
159   }
160 
161   DCHECK(handshake_confirmed());
162   if (proof_verify_callback_) {
163     proof_verify_callback_->Cancel();
164   }
165   next_state_ = STATE_INITIALIZE_SCUP;
166   DoHandshakeLoop(NULL);
167 }
168 
169 // kMaxClientHellos is the maximum number of times that we'll send a client
170 // hello. The value 3 accounts for:
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
173 //     server being unwilling to send it without a valid source-address token.
174 static const int kMaxClientHellos = 3;
175 
DoHandshakeLoop(const CryptoHandshakeMessage * in)176 void QuicCryptoClientStream::DoHandshakeLoop(
177     const CryptoHandshakeMessage* in) {
178   CryptoHandshakeMessage out;
179   QuicErrorCode error;
180   string error_details;
181   QuicCryptoClientConfig::CachedState* cached =
182       crypto_config_->LookupOrCreate(server_id_);
183 
184   for (;;) {
185     const State state = next_state_;
186     next_state_ = STATE_IDLE;
187     switch (state) {
188       case STATE_INITIALIZE: {
189         if (!cached->IsEmpty() && !cached->signature().empty() &&
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;
202       }
203       case STATE_SEND_CHLO: {
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;
284       }
285       case STATE_RECV_REJ:
286         // We sent a dummy CHLO because we didn't have enough information to
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;
318       case STATE_VERIFY_PROOF: {
319         if (QUIC_PENDING == DoVerifyProof(cached)) {
320           return;
321         }
322         break;
323       }
324       case STATE_VERIFY_PROOF_COMPLETE:
325         if (QUIC_PROOF_INVALID == DoVerifyProofComplete(cached)) {
326           return;
327         }
328         break;
329       case STATE_GET_CHANNEL_ID: {
330         next_state_ = STATE_GET_CHANNEL_ID_COMPLETE;
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;
359       }
360       case STATE_GET_CHANNEL_ID_COMPLETE:
361         if (!channel_id_key_.get()) {
362           CloseConnectionWithDetails(QUIC_INVALID_CHANNEL_ID_SIGNATURE,
363                                      "Channel ID lookup failed");
364           return;
365         }
366         next_state_ = STATE_SEND_CHLO;
367         break;
368       case STATE_RECV_SHLO: {
369         // We sent a CHLO that we expected to be accepted and now we're hoping
370         // for a SHLO from the server to confirm that.
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:
437         // This means that the peer sent us a message that we weren't expecting.
438         CloseConnection(QUIC_INVALID_CRYPTO_MESSAGE_TYPE);
439         return;
440       case STATE_INITIALIZE_SCUP:
441         DoInitializeServerConfigUpdate(cached);
442         break;
443       case STATE_VERIFY_PROOF_DONE:
444         return;  // We are done.
445     }
446   }
447 }
448 
DoInitializeServerConfigUpdate(QuicCryptoClientConfig::CachedState * cached)449 void QuicCryptoClientStream::DoInitializeServerConfigUpdate(
450     QuicCryptoClientConfig::CachedState* cached) {
451   bool update_ignored = false;
452   if (!server_id_.is_https()) {
453     // We don't check the certificates for insecure QUIC connections.
454     SetCachedProofValid(cached);
455     next_state_ = STATE_VERIFY_PROOF_DONE;
456   } else if (!cached->IsEmpty() && !cached->signature().empty()) {
457     // Note that we verify the proof even if the cached proof is valid.
458     DCHECK(crypto_config_->proof_verifier());
459     next_state_ = STATE_VERIFY_PROOF;
460   } else {
461     update_ignored = true;
462     next_state_ = STATE_VERIFY_PROOF_DONE;
463   }
464   UMA_HISTOGRAM_BOOLEAN("Net.QuicNumServerConfig.UpdateMessagesIgnored",
465                         update_ignored);
466 }
467 
DoVerifyProof(QuicCryptoClientConfig::CachedState * cached)468 QuicAsyncStatus QuicCryptoClientStream::DoVerifyProof(
469     QuicCryptoClientConfig::CachedState* cached) {
470   ProofVerifier* verifier = crypto_config_->proof_verifier();
471   DCHECK(verifier);
472   next_state_ = STATE_VERIFY_PROOF_COMPLETE;
473   generation_counter_ = cached->generation_counter();
474 
475   ProofVerifierCallbackImpl* proof_verify_callback =
476       new ProofVerifierCallbackImpl(this);
477 
478   verify_ok_ = false;
479 
480   QuicAsyncStatus status = verifier->VerifyProof(
481       server_id_.host(),
482       cached->server_config(),
483       cached->certs(),
484       cached->signature(),
485       verify_context_.get(),
486       &verify_error_details_,
487       &verify_details_,
488       proof_verify_callback);
489 
490   switch (status) {
491     case QUIC_PENDING:
492       proof_verify_callback_ = proof_verify_callback;
493       DVLOG(1) << "Doing VerifyProof";
494       break;
495     case QUIC_FAILURE:
496       delete proof_verify_callback;
497       break;
498     case QUIC_SUCCESS:
499       delete proof_verify_callback;
500       verify_ok_ = true;
501       break;
502   }
503   return status;
504 }
505 
DoVerifyProofComplete(QuicCryptoClientConfig::CachedState * cached)506 QuicErrorCode QuicCryptoClientStream::DoVerifyProofComplete(
507     QuicCryptoClientConfig::CachedState* cached) {
508   if (!verify_ok_) {
509     client_session()->OnProofVerifyDetailsAvailable(*verify_details_);
510     UMA_HISTOGRAM_BOOLEAN("Net.QuicVerifyProofFailed.HandshakeConfirmed",
511                           handshake_confirmed());
512     CloseConnectionWithDetails(
513         QUIC_PROOF_INVALID, "Proof invalid: " + verify_error_details_);
514     return QUIC_PROOF_INVALID;
515   }
516 
517   // Check if generation_counter has changed between STATE_VERIFY_PROOF and
518   // STATE_VERIFY_PROOF_COMPLETE state changes.
519   if (generation_counter_ != cached->generation_counter()) {
520     next_state_ = STATE_VERIFY_PROOF;
521   } else {
522     SetCachedProofValid(cached);
523     cached->SetProofVerifyDetails(verify_details_.release());
524     if (!handshake_confirmed()) {
525       next_state_ = STATE_GET_CHANNEL_ID;
526     } else {
527       next_state_ = STATE_VERIFY_PROOF_DONE;
528     }
529   }
530   return QUIC_NO_ERROR;
531 }
532 
SetCachedProofValid(QuicCryptoClientConfig::CachedState * cached)533 void QuicCryptoClientStream::SetCachedProofValid(
534     QuicCryptoClientConfig::CachedState* cached) {
535   cached->SetProofValid();
536   client_session()->OnProofValid(*cached);
537 }
538 
RequiresChannelID(QuicCryptoClientConfig::CachedState * cached)539 bool QuicCryptoClientStream::RequiresChannelID(
540     QuicCryptoClientConfig::CachedState* cached) {
541   if (!server_id_.is_https() ||
542       server_id_.privacy_mode() == PRIVACY_MODE_ENABLED ||
543       !crypto_config_->channel_id_source()) {
544     return false;
545   }
546   const CryptoHandshakeMessage* scfg = cached->GetServerConfig();
547   if (!scfg) {  // scfg may be null when we send an inchoate CHLO.
548     return false;
549   }
550   const QuicTag* their_proof_demands;
551   size_t num_their_proof_demands;
552   if (scfg->GetTaglist(kPDMD, &their_proof_demands,
553                        &num_their_proof_demands) != QUIC_NO_ERROR) {
554     return false;
555   }
556   for (size_t i = 0; i < num_their_proof_demands; i++) {
557     if (their_proof_demands[i] == kCHID) {
558       return true;
559     }
560   }
561   return false;
562 }
563 
client_session()564 QuicClientSessionBase* QuicCryptoClientStream::client_session() {
565   return reinterpret_cast<QuicClientSessionBase*>(session());
566 }
567 
568 }  // namespace net
569