Revert "Removed the experimental flag for Chromecast support and the corresponding...
[chromium-blink-merge.git] / net / quic / quic_crypto_client_stream.cc
blobb0f81174b7110845c2a5dbf79dc36e61150d827d
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/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"
19 namespace net {
21 namespace {
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);
35 } // namespace
37 QuicCryptoClientStream::ProofVerifierCallbackImpl::ProofVerifierCallbackImpl(
38 QuicCryptoClientStream* stream)
39 : stream_(stream) {}
41 QuicCryptoClientStream::ProofVerifierCallbackImpl::
42 ~ProofVerifierCallbackImpl() {}
44 void QuicCryptoClientStream::ProofVerifierCallbackImpl::Run(
45 bool ok,
46 const string& error_details,
47 scoped_ptr<ProofVerifyDetails>* details) {
48 if (stream_ == NULL) {
49 return;
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);
58 // The ProofVerifier owns this object and will delete it when this method
59 // returns.
62 void QuicCryptoClientStream::ProofVerifierCallbackImpl::Cancel() {
63 stream_ = NULL;
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) {
80 QuicCryptoClientStream::~QuicCryptoClientStream() {
81 if (proof_verify_callback_) {
82 proof_verify_callback_->Cancel();
86 void QuicCryptoClientStream::OnHandshakeMessage(
87 const CryptoHandshakeMessage& message) {
88 QuicCryptoStream::OnHandshakeMessage(message);
90 DoHandshakeLoop(&message);
93 bool QuicCryptoClientStream::CryptoConnect() {
94 next_state_ = STATE_SEND_CHLO;
95 DoHandshakeLoop(NULL);
96 return true;
99 int QuicCryptoClientStream::num_sent_client_hellos() const {
100 return num_client_hellos_;
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;
111 ssl_info->cert_status = cert_verify_result_->cert_status;
112 ssl_info->cert = cert_verify_result_->verified_cert;
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;
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;
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;
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;
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_);
154 if (in != NULL) {
155 DVLOG(1) << "Client: Received " << in->DebugString();
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;
169 num_client_hellos_++;
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;
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;
196 if (cached->proof_verify_details()) {
197 CopyCertVerifyResult(cached->proof_verify_details(),
198 &cert_verify_result_);
199 } else {
200 cert_verify_result_.reset();
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);
224 return;
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;
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;
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;
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();
261 ProofVerifierCallbackImpl* proof_verify_callback =
262 new ProofVerifierCallbackImpl(this);
264 verify_ok_ = false;
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);
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;
286 break;
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;
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;
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;
318 next_state_ = STATE_RECV_REJ;
319 break;
321 if (in->tag() != kSHLO) {
322 CloseConnectionWithDetails(QUIC_INVALID_CRYPTO_MESSAGE_TYPE,
323 "Expected SHLO or REJ");
324 return;
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;
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;
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;
349 CrypterPair* crypters =
350 &crypto_negotiated_params_.forward_secure_crypters;
351 // TODO(agl): we don't currently latch this decrypter because the idea
352 // has been floated that the server shouldn't send packets encrypted
353 // with the FORWARD_SECURE key until it receives a FORWARD_SECURE
354 // packet from the client.
355 session()->connection()->SetAlternativeDecrypter(
356 crypters->decrypter.release(), false /* don't latch */);
357 session()->connection()->SetEncrypter(
358 ENCRYPTION_FORWARD_SECURE, crypters->encrypter.release());
359 session()->connection()->SetDefaultEncryptionLevel(
360 ENCRYPTION_FORWARD_SECURE);
362 handshake_confirmed_ = true;
363 session()->OnCryptoHandshakeEvent(QuicSession::HANDSHAKE_CONFIRMED);
364 return;
366 case STATE_IDLE:
367 // This means that the peer sent us a message that we weren't expecting.
368 CloseConnection(QUIC_INVALID_CRYPTO_MESSAGE_TYPE);
369 return;
374 } // namespace net