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"
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
);
37 QuicCryptoClientStream::ProofVerifierCallbackImpl::ProofVerifierCallbackImpl(
38 QuicCryptoClientStream
* stream
)
41 QuicCryptoClientStream::ProofVerifierCallbackImpl::
42 ~ProofVerifierCallbackImpl() {}
44 void QuicCryptoClientStream::ProofVerifierCallbackImpl::Run(
46 const string
& error_details
,
47 scoped_ptr
<ProofVerifyDetails
>* details
) {
48 if (stream_
== NULL
) {
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
62 void QuicCryptoClientStream::ProofVerifierCallbackImpl::Cancel() {
67 QuicCryptoClientStream::QuicCryptoClientStream(
68 const string
& server_hostname
,
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
);
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
) {
107 if (!cert_verify_result_
) {
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
;
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
;
150 string error_details
;
151 QuicCryptoClientConfig::CachedState
* cached
=
152 crypto_config_
->LookupOrCreate(server_hostname_
);
155 DVLOG(1) << "Client: Received " << in
->DebugString();
159 const State state
= next_state_
;
160 next_state_
= STATE_IDLE
;
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
);
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
);
179 session()->config()->ToHandshakeMessage(&out
);
180 error
= crypto_config_
->FillClientHello(
182 session()->connection()->guid(),
184 session()->connection()->clock()->WallNow(),
185 session()->connection()->random_generator(),
186 &crypto_negotiated_params_
,
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
);
196 if (cached
->proof_verify_details()) {
197 CopyCertVerifyResult(cached
->proof_verify_details(),
198 &cert_verify_result_
);
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(
213 crypto_negotiated_params_
.initial_crypters
.encrypter
.release());
214 session()->connection()->SetDefaultEncryptionLevel(
216 if (!encryption_established_
) {
217 encryption_established_
= true;
218 session()->OnCryptoHandshakeEvent(
219 QuicSession::ENCRYPTION_FIRST_ESTABLISHED
);
221 session()->OnCryptoHandshakeEvent(
222 QuicSession::ENCRYPTION_REESTABLISHED
);
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
231 if (in
->tag() != kREJ
) {
232 CloseConnectionWithDetails(QUIC_INVALID_CRYPTO_MESSAGE_TYPE
,
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
);
243 if (!cached
->proof_valid()) {
244 ProofVerifier
* verifier
= crypto_config_
->proof_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
;
253 next_state_
= STATE_SEND_CHLO
;
255 case STATE_VERIFY_PROOF
: {
256 ProofVerifier
* verifier
= crypto_config_
->proof_verifier();
258 next_state_
= STATE_VERIFY_PROOF_COMPLETE
;
259 generation_counter_
= cached
->generation_counter();
261 ProofVerifierCallbackImpl
* proof_verify_callback
=
262 new ProofVerifierCallbackImpl(this);
266 ProofVerifier::Status status
= verifier
->VerifyProof(
268 cached
->server_config(),
271 &verify_error_details_
,
273 proof_verify_callback
);
276 case ProofVerifier::PENDING
:
277 proof_verify_callback_
= proof_verify_callback
;
278 DVLOG(1) << "Doing VerifyProof";
280 case ProofVerifier::FAILURE
:
282 case ProofVerifier::SUCCESS
:
288 case STATE_VERIFY_PROOF_COMPLETE
:
290 CopyCertVerifyResult(verify_details_
.get(), &cert_verify_result_
);
291 CloseConnectionWithDetails(
292 QUIC_PROOF_INVALID
, "Proof invalid: " + verify_error_details_
);
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
;
300 cached
->SetProofValid();
301 cached
->SetProofVerifyDetails(verify_details_
.release());
302 next_state_
= STATE_SEND_CHLO
;
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");
318 next_state_
= STATE_RECV_REJ
;
321 if (in
->tag() != kSHLO
) {
322 CloseConnectionWithDetails(QUIC_INVALID_CRYPTO_MESSAGE_TYPE
,
323 "Expected SHLO or REJ");
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");
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
);
343 error
= session()->config()->ProcessServerHello(*in
, &error_details
);
344 if (error
!= QUIC_NO_ERROR
) {
345 CloseConnectionWithDetails(
346 error
, "Server hello invalid: " + error_details
);
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
);
367 // This means that the peer sent us a message that we weren't expecting.
368 CloseConnection(QUIC_INVALID_CRYPTO_MESSAGE_TYPE
);