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