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