• 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 "net/quic/crypto/channel_id.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/crypto/proof_verifier.h"
12 #include "net/quic/quic_client_session_base.h"
13 #include "net/quic/quic_protocol.h"
14 #include "net/quic/quic_session.h"
15 
16 namespace net {
17 
ProofVerifierCallbackImpl(QuicCryptoClientStream * stream)18 QuicCryptoClientStream::ProofVerifierCallbackImpl::ProofVerifierCallbackImpl(
19     QuicCryptoClientStream* stream)
20     : stream_(stream) {}
21 
22 QuicCryptoClientStream::ProofVerifierCallbackImpl::
~ProofVerifierCallbackImpl()23 ~ProofVerifierCallbackImpl() {}
24 
Run(bool ok,const string & error_details,scoped_ptr<ProofVerifyDetails> * details)25 void QuicCryptoClientStream::ProofVerifierCallbackImpl::Run(
26     bool ok,
27     const string& error_details,
28     scoped_ptr<ProofVerifyDetails>* details) {
29   if (stream_ == NULL) {
30     return;
31   }
32 
33   stream_->verify_ok_ = ok;
34   stream_->verify_error_details_ = error_details;
35   stream_->verify_details_.reset(details->release());
36   stream_->proof_verify_callback_ = NULL;
37   stream_->DoHandshakeLoop(NULL);
38 
39   // The ProofVerifier owns this object and will delete it when this method
40   // returns.
41 }
42 
Cancel()43 void QuicCryptoClientStream::ProofVerifierCallbackImpl::Cancel() {
44   stream_ = NULL;
45 }
46 
QuicCryptoClientStream(const QuicServerId & server_id,QuicClientSessionBase * session,ProofVerifyContext * verify_context,QuicCryptoClientConfig * crypto_config)47 QuicCryptoClientStream::QuicCryptoClientStream(
48     const QuicServerId& server_id,
49     QuicClientSessionBase* session,
50     ProofVerifyContext* verify_context,
51     QuicCryptoClientConfig* crypto_config)
52     : QuicCryptoStream(session),
53       next_state_(STATE_IDLE),
54       num_client_hellos_(0),
55       crypto_config_(crypto_config),
56       server_id_(server_id),
57       generation_counter_(0),
58       proof_verify_callback_(NULL),
59       verify_context_(verify_context) {
60 }
61 
~QuicCryptoClientStream()62 QuicCryptoClientStream::~QuicCryptoClientStream() {
63   if (proof_verify_callback_) {
64     proof_verify_callback_->Cancel();
65   }
66 }
67 
OnHandshakeMessage(const CryptoHandshakeMessage & message)68 void QuicCryptoClientStream::OnHandshakeMessage(
69     const CryptoHandshakeMessage& message) {
70   QuicCryptoStream::OnHandshakeMessage(message);
71 
72   DoHandshakeLoop(&message);
73 }
74 
CryptoConnect()75 bool QuicCryptoClientStream::CryptoConnect() {
76   next_state_ = STATE_INITIALIZE;
77   DoHandshakeLoop(NULL);
78   return true;
79 }
80 
num_sent_client_hellos() const81 int QuicCryptoClientStream::num_sent_client_hellos() const {
82   return num_client_hellos_;
83 }
84 
85 // kMaxClientHellos is the maximum number of times that we'll send a client
86 // hello. The value 3 accounts for:
87 //   * One failure due to an incorrect or missing source-address token.
88 //   * One failure due the server's certificate chain being unavailible and the
89 //     server being unwilling to send it without a valid source-address token.
90 static const int kMaxClientHellos = 3;
91 
DoHandshakeLoop(const CryptoHandshakeMessage * in)92 void QuicCryptoClientStream::DoHandshakeLoop(
93     const CryptoHandshakeMessage* in) {
94   CryptoHandshakeMessage out;
95   QuicErrorCode error;
96   string error_details;
97   QuicCryptoClientConfig::CachedState* cached =
98       crypto_config_->LookupOrCreate(server_id_);
99 
100   if (in != NULL) {
101     DVLOG(1) << "Client: Received " << in->DebugString();
102   }
103 
104   for (;;) {
105     const State state = next_state_;
106     next_state_ = STATE_IDLE;
107     switch (state) {
108       case STATE_INITIALIZE: {
109         if (!cached->IsEmpty() && !cached->signature().empty() &&
110             server_id_.is_https()) {
111           DCHECK(crypto_config_->proof_verifier());
112           // If the cached state needs to be verified, do it now.
113           next_state_ = STATE_VERIFY_PROOF;
114         } else {
115           next_state_ = STATE_SEND_CHLO;
116         }
117         break;
118       }
119       case STATE_SEND_CHLO: {
120         // Send the client hello in plaintext.
121         session()->connection()->SetDefaultEncryptionLevel(ENCRYPTION_NONE);
122         if (num_client_hellos_ > kMaxClientHellos) {
123           CloseConnection(QUIC_CRYPTO_TOO_MANY_REJECTS);
124           return;
125         }
126         num_client_hellos_++;
127 
128         if (!cached->IsComplete(session()->connection()->clock()->WallNow())) {
129           crypto_config_->FillInchoateClientHello(
130               server_id_,
131               session()->connection()->supported_versions().front(),
132               cached, &crypto_negotiated_params_, &out);
133           // Pad the inchoate client hello to fill up a packet.
134           const size_t kFramingOverhead = 50;  // A rough estimate.
135           const size_t max_packet_size =
136               session()->connection()->max_packet_length();
137           if (max_packet_size <= kFramingOverhead) {
138             DLOG(DFATAL) << "max_packet_length (" << max_packet_size
139                          << ") has no room for framing overhead.";
140             CloseConnection(QUIC_INTERNAL_ERROR);
141             return;
142           }
143           if (kClientHelloMinimumSize > max_packet_size - kFramingOverhead) {
144             DLOG(DFATAL) << "Client hello won't fit in a single packet.";
145             CloseConnection(QUIC_INTERNAL_ERROR);
146             return;
147           }
148           out.set_minimum_size(max_packet_size - kFramingOverhead);
149           next_state_ = STATE_RECV_REJ;
150           DVLOG(1) << "Client: Sending " << out.DebugString();
151           SendHandshakeMessage(out);
152           return;
153         }
154         session()->config()->ToHandshakeMessage(&out);
155 
156         scoped_ptr<ChannelIDKey> channel_id_key;
157         bool do_channel_id = false;
158         if (crypto_config_->channel_id_source()) {
159           const CryptoHandshakeMessage* scfg = cached->GetServerConfig();
160           DCHECK(scfg);
161           const QuicTag* their_proof_demands;
162           size_t num_their_proof_demands;
163           if (scfg->GetTaglist(kPDMD, &their_proof_demands,
164                                &num_their_proof_demands) == QUIC_NO_ERROR) {
165             for (size_t i = 0; i < num_their_proof_demands; i++) {
166               if (their_proof_demands[i] == kCHID) {
167                 do_channel_id = true;
168                 break;
169               }
170             }
171           }
172         }
173         if (do_channel_id) {
174           QuicAsyncStatus status =
175               crypto_config_->channel_id_source()->GetChannelIDKey(
176                   server_id_.host(), &channel_id_key, NULL);
177           if (status != QUIC_SUCCESS) {
178             CloseConnectionWithDetails(QUIC_INVALID_CHANNEL_ID_SIGNATURE,
179                                        "Channel ID lookup failed");
180             return;
181           }
182         }
183 
184         error = crypto_config_->FillClientHello(
185             server_id_,
186             session()->connection()->connection_id(),
187             session()->connection()->supported_versions().front(),
188             cached,
189             session()->connection()->clock()->WallNow(),
190             session()->connection()->random_generator(),
191             channel_id_key.get(),
192             &crypto_negotiated_params_,
193             &out,
194             &error_details);
195         if (error != QUIC_NO_ERROR) {
196           // Flush the cached config so that, if it's bad, the server has a
197           // chance to send us another in the future.
198           cached->InvalidateServerConfig();
199           CloseConnectionWithDetails(error, error_details);
200           return;
201         }
202         if (cached->proof_verify_details()) {
203           client_session()->OnProofVerifyDetailsAvailable(
204               *cached->proof_verify_details());
205         }
206         next_state_ = STATE_RECV_SHLO;
207         DVLOG(1) << "Client: Sending " << out.DebugString();
208         SendHandshakeMessage(out);
209         // Be prepared to decrypt with the new server write key.
210         session()->connection()->SetAlternativeDecrypter(
211             crypto_negotiated_params_.initial_crypters.decrypter.release(),
212             ENCRYPTION_INITIAL,
213             true /* latch once used */);
214         // Send subsequent packets under encryption on the assumption that the
215         // server will accept the handshake.
216         session()->connection()->SetEncrypter(
217             ENCRYPTION_INITIAL,
218             crypto_negotiated_params_.initial_crypters.encrypter.release());
219         session()->connection()->SetDefaultEncryptionLevel(
220             ENCRYPTION_INITIAL);
221         if (!encryption_established_) {
222           encryption_established_ = true;
223           session()->OnCryptoHandshakeEvent(
224               QuicSession::ENCRYPTION_FIRST_ESTABLISHED);
225         } else {
226           session()->OnCryptoHandshakeEvent(
227               QuicSession::ENCRYPTION_REESTABLISHED);
228         }
229         return;
230       }
231       case STATE_RECV_REJ:
232         // We sent a dummy CHLO because we didn't have enough information to
233         // perform a handshake, or we sent a full hello that the server
234         // rejected. Here we hope to have a REJ that contains the information
235         // that we need.
236         if (in->tag() != kREJ) {
237           CloseConnectionWithDetails(QUIC_INVALID_CRYPTO_MESSAGE_TYPE,
238                                      "Expected REJ");
239           return;
240         }
241         error = crypto_config_->ProcessRejection(
242             *in, session()->connection()->clock()->WallNow(), cached,
243             &crypto_negotiated_params_, &error_details);
244         if (error != QUIC_NO_ERROR) {
245           CloseConnectionWithDetails(error, error_details);
246           return;
247         }
248         if (!cached->proof_valid()) {
249           if (!server_id_.is_https()) {
250             // We don't check the certificates for insecure QUIC connections.
251             SetCachedProofValid(cached);
252           } else if (!cached->signature().empty()) {
253             next_state_ = STATE_VERIFY_PROOF;
254             break;
255           }
256         }
257         next_state_ = STATE_SEND_CHLO;
258         break;
259       case STATE_VERIFY_PROOF: {
260         ProofVerifier* verifier = crypto_config_->proof_verifier();
261         DCHECK(verifier);
262         next_state_ = STATE_VERIFY_PROOF_COMPLETE;
263         generation_counter_ = cached->generation_counter();
264 
265         ProofVerifierCallbackImpl* proof_verify_callback =
266             new ProofVerifierCallbackImpl(this);
267 
268         verify_ok_ = false;
269 
270         QuicAsyncStatus status = verifier->VerifyProof(
271             server_id_.host(),
272             cached->server_config(),
273             cached->certs(),
274             cached->signature(),
275             verify_context_.get(),
276             &verify_error_details_,
277             &verify_details_,
278             proof_verify_callback);
279 
280         switch (status) {
281           case QUIC_PENDING:
282             proof_verify_callback_ = proof_verify_callback;
283             DVLOG(1) << "Doing VerifyProof";
284             return;
285           case QUIC_FAILURE:
286             delete proof_verify_callback;
287             break;
288           case QUIC_SUCCESS:
289             delete proof_verify_callback;
290             verify_ok_ = true;
291             break;
292         }
293         break;
294       }
295       case STATE_VERIFY_PROOF_COMPLETE:
296         if (!verify_ok_) {
297           client_session()->OnProofVerifyDetailsAvailable(*verify_details_);
298           CloseConnectionWithDetails(
299               QUIC_PROOF_INVALID, "Proof invalid: " + verify_error_details_);
300           return;
301         }
302         // Check if generation_counter has changed between STATE_VERIFY_PROOF
303         // and STATE_VERIFY_PROOF_COMPLETE state changes.
304         if (generation_counter_ != cached->generation_counter()) {
305           next_state_ = STATE_VERIFY_PROOF;
306         } else {
307           SetCachedProofValid(cached);
308           cached->SetProofVerifyDetails(verify_details_.release());
309           next_state_ = STATE_SEND_CHLO;
310         }
311         break;
312       case STATE_RECV_SHLO: {
313         // We sent a CHLO that we expected to be accepted and now we're hoping
314         // for a SHLO from the server to confirm that.
315         if (in->tag() == kREJ) {
316           // alternative_decrypter will be NULL if the original alternative
317           // decrypter latched and became the primary decrypter. That happens
318           // if we received a message encrypted with the INITIAL key.
319           if (session()->connection()->alternative_decrypter() == NULL) {
320             // The rejection was sent encrypted!
321             CloseConnectionWithDetails(QUIC_CRYPTO_ENCRYPTION_LEVEL_INCORRECT,
322                                        "encrypted REJ message");
323             return;
324           }
325           next_state_ = STATE_RECV_REJ;
326           break;
327         }
328         if (in->tag() != kSHLO) {
329           CloseConnectionWithDetails(QUIC_INVALID_CRYPTO_MESSAGE_TYPE,
330                                      "Expected SHLO or REJ");
331           return;
332         }
333         // alternative_decrypter will be NULL if the original alternative
334         // decrypter latched and became the primary decrypter. That happens
335         // if we received a message encrypted with the INITIAL key.
336         if (session()->connection()->alternative_decrypter() != NULL) {
337           // The server hello was sent without encryption.
338           CloseConnectionWithDetails(QUIC_CRYPTO_ENCRYPTION_LEVEL_INCORRECT,
339                                      "unencrypted SHLO message");
340           return;
341         }
342         error = crypto_config_->ProcessServerHello(
343             *in, session()->connection()->connection_id(),
344             session()->connection()->server_supported_versions(),
345             cached, &crypto_negotiated_params_, &error_details);
346 
347         if (error != QUIC_NO_ERROR) {
348           CloseConnectionWithDetails(
349               error, "Server hello invalid: " + error_details);
350           return;
351         }
352         error =
353             session()->config()->ProcessPeerHello(*in, SERVER, &error_details);
354         if (error != QUIC_NO_ERROR) {
355           CloseConnectionWithDetails(
356               error, "Server hello invalid: " + error_details);
357           return;
358         }
359         session()->OnConfigNegotiated();
360 
361         CrypterPair* crypters =
362             &crypto_negotiated_params_.forward_secure_crypters;
363         // TODO(agl): we don't currently latch this decrypter because the idea
364         // has been floated that the server shouldn't send packets encrypted
365         // with the FORWARD_SECURE key until it receives a FORWARD_SECURE
366         // packet from the client.
367         session()->connection()->SetAlternativeDecrypter(
368             crypters->decrypter.release(), ENCRYPTION_FORWARD_SECURE,
369             false /* don't latch */);
370         session()->connection()->SetEncrypter(
371             ENCRYPTION_FORWARD_SECURE, crypters->encrypter.release());
372         session()->connection()->SetDefaultEncryptionLevel(
373             ENCRYPTION_FORWARD_SECURE);
374 
375         handshake_confirmed_ = true;
376         session()->OnCryptoHandshakeEvent(QuicSession::HANDSHAKE_CONFIRMED);
377         return;
378       }
379       case STATE_IDLE:
380         // This means that the peer sent us a message that we weren't expecting.
381         CloseConnection(QUIC_INVALID_CRYPTO_MESSAGE_TYPE);
382         return;
383     }
384   }
385 }
386 
SetCachedProofValid(QuicCryptoClientConfig::CachedState * cached)387 void QuicCryptoClientStream::SetCachedProofValid(
388     QuicCryptoClientConfig::CachedState* cached) {
389   cached->SetProofValid();
390   client_session()->OnProofValid(*cached);
391 }
392 
client_session()393 QuicClientSessionBase* QuicCryptoClientStream::client_session() {
394   return reinterpret_cast<QuicClientSessionBase*>(session());
395 }
396 
397 }  // namespace net
398