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(
174 session()->connection()->supported_versions().front(),
175 cached
, &crypto_negotiated_params_
, &out
);
176 // Pad the inchoate client hello to fill up a packet.
177 const size_t kFramingOverhead
= 50; // A rough estimate.
178 const size_t max_packet_size
=
179 session()->connection()->options()->max_packet_length
;
180 if (max_packet_size
<= kFramingOverhead
) {
181 DLOG(DFATAL
) << "max_packet_length (" << max_packet_size
182 << ") has no room for framing overhead.";
183 CloseConnection(QUIC_INTERNAL_ERROR
);
186 if (kClientHelloMinimumSize
> max_packet_size
- kFramingOverhead
) {
187 DLOG(DFATAL
) << "Client hello won't fit in a single packet.";
188 CloseConnection(QUIC_INTERNAL_ERROR
);
191 out
.set_minimum_size(max_packet_size
- kFramingOverhead
);
192 next_state_
= STATE_RECV_REJ
;
193 DVLOG(1) << "Client: Sending " << out
.DebugString();
194 SendHandshakeMessage(out
);
197 session()->config()->ToHandshakeMessage(&out
);
198 error
= crypto_config_
->FillClientHello(
200 session()->connection()->guid(),
201 session()->connection()->supported_versions().front(),
203 session()->connection()->clock()->WallNow(),
204 session()->connection()->random_generator(),
205 &crypto_negotiated_params_
,
208 if (error
!= QUIC_NO_ERROR
) {
209 // Flush the cached config so that, if it's bad, the server has a
210 // chance to send us another in the future.
211 cached
->InvalidateServerConfig();
212 CloseConnectionWithDetails(error
, error_details
);
215 if (cached
->proof_verify_details()) {
216 CopyCertVerifyResult(cached
->proof_verify_details(),
217 &cert_verify_result_
);
219 cert_verify_result_
.reset();
221 next_state_
= STATE_RECV_SHLO
;
222 DVLOG(1) << "Client: Sending " << out
.DebugString();
223 SendHandshakeMessage(out
);
224 // Be prepared to decrypt with the new server write key.
225 session()->connection()->SetAlternativeDecrypter(
226 crypto_negotiated_params_
.initial_crypters
.decrypter
.release(),
227 true /* latch once used */);
228 // Send subsequent packets under encryption on the assumption that the
229 // server will accept the handshake.
230 session()->connection()->SetEncrypter(
232 crypto_negotiated_params_
.initial_crypters
.encrypter
.release());
233 session()->connection()->SetDefaultEncryptionLevel(
235 if (!encryption_established_
) {
236 encryption_established_
= true;
237 session()->OnCryptoHandshakeEvent(
238 QuicSession::ENCRYPTION_FIRST_ESTABLISHED
);
240 session()->OnCryptoHandshakeEvent(
241 QuicSession::ENCRYPTION_REESTABLISHED
);
246 // We sent a dummy CHLO because we didn't have enough information to
247 // perform a handshake, or we sent a full hello that the server
248 // rejected. Here we hope to have a REJ that contains the information
250 if (in
->tag() != kREJ
) {
251 CloseConnectionWithDetails(QUIC_INVALID_CRYPTO_MESSAGE_TYPE
,
255 error
= crypto_config_
->ProcessRejection(
256 *in
, session()->connection()->clock()->WallNow(), cached
,
257 &crypto_negotiated_params_
, &error_details
);
258 if (error
!= QUIC_NO_ERROR
) {
259 CloseConnectionWithDetails(error
, error_details
);
262 if (!cached
->proof_valid()) {
263 ProofVerifier
* verifier
= crypto_config_
->proof_verifier();
265 // If no verifier is set then we don't check the certificates.
266 cached
->SetProofValid();
267 } else if (!cached
->signature().empty()) {
268 next_state_
= STATE_VERIFY_PROOF
;
272 next_state_
= STATE_SEND_CHLO
;
274 case STATE_VERIFY_PROOF
: {
275 ProofVerifier
* verifier
= crypto_config_
->proof_verifier();
277 next_state_
= STATE_VERIFY_PROOF_COMPLETE
;
278 generation_counter_
= cached
->generation_counter();
280 ProofVerifierCallbackImpl
* proof_verify_callback
=
281 new ProofVerifierCallbackImpl(this);
285 ProofVerifier::Status status
= verifier
->VerifyProof(
287 cached
->server_config(),
290 &verify_error_details_
,
292 proof_verify_callback
);
295 case ProofVerifier::PENDING
:
296 proof_verify_callback_
= proof_verify_callback
;
297 DVLOG(1) << "Doing VerifyProof";
299 case ProofVerifier::FAILURE
:
301 case ProofVerifier::SUCCESS
:
307 case STATE_VERIFY_PROOF_COMPLETE
:
309 CopyCertVerifyResult(verify_details_
.get(), &cert_verify_result_
);
310 CloseConnectionWithDetails(
311 QUIC_PROOF_INVALID
, "Proof invalid: " + verify_error_details_
);
314 // Check if generation_counter has changed between STATE_VERIFY_PROOF
315 // and STATE_VERIFY_PROOF_COMPLETE state changes.
316 if (generation_counter_
!= cached
->generation_counter()) {
317 next_state_
= STATE_VERIFY_PROOF
;
319 cached
->SetProofValid();
320 cached
->SetProofVerifyDetails(verify_details_
.release());
321 next_state_
= STATE_SEND_CHLO
;
324 case STATE_RECV_SHLO
: {
325 // We sent a CHLO that we expected to be accepted and now we're hoping
326 // for a SHLO from the server to confirm that.
327 if (in
->tag() == kREJ
) {
328 // alternative_decrypter will be NULL if the original alternative
329 // decrypter latched and became the primary decrypter. That happens
330 // if we received a message encrypted with the INITIAL key.
331 if (session()->connection()->alternative_decrypter() == NULL
) {
332 // The rejection was sent encrypted!
333 CloseConnectionWithDetails(QUIC_CRYPTO_ENCRYPTION_LEVEL_INCORRECT
,
334 "encrypted REJ message");
337 next_state_
= STATE_RECV_REJ
;
340 if (in
->tag() != kSHLO
) {
341 CloseConnectionWithDetails(QUIC_INVALID_CRYPTO_MESSAGE_TYPE
,
342 "Expected SHLO or REJ");
345 // alternative_decrypter will be NULL if the original alternative
346 // decrypter latched and became the primary decrypter. That happens
347 // if we received a message encrypted with the INITIAL key.
348 if (session()->connection()->alternative_decrypter() != NULL
) {
349 // The server hello was sent without encryption.
350 CloseConnectionWithDetails(QUIC_CRYPTO_ENCRYPTION_LEVEL_INCORRECT
,
351 "unencrypted SHLO message");
354 error
= crypto_config_
->ProcessServerHello(
355 *in
, session()->connection()->guid(),
356 session()->connection()->server_supported_versions(),
357 cached
, &crypto_negotiated_params_
, &error_details
);
359 if (error
!= QUIC_NO_ERROR
) {
360 CloseConnectionWithDetails(
361 error
, "Server hello invalid: " + error_details
);
364 error
= session()->config()->ProcessServerHello(*in
, &error_details
);
365 if (error
!= QUIC_NO_ERROR
) {
366 CloseConnectionWithDetails(
367 error
, "Server hello invalid: " + error_details
);
370 session()->OnConfigNegotiated();
372 CrypterPair
* crypters
=
373 &crypto_negotiated_params_
.forward_secure_crypters
;
374 // TODO(agl): we don't currently latch this decrypter because the idea
375 // has been floated that the server shouldn't send packets encrypted
376 // with the FORWARD_SECURE key until it receives a FORWARD_SECURE
377 // packet from the client.
378 session()->connection()->SetAlternativeDecrypter(
379 crypters
->decrypter
.release(), false /* don't latch */);
380 session()->connection()->SetEncrypter(
381 ENCRYPTION_FORWARD_SECURE
, crypters
->encrypter
.release());
382 session()->connection()->SetDefaultEncryptionLevel(
383 ENCRYPTION_FORWARD_SECURE
);
385 handshake_confirmed_
= true;
386 session()->OnCryptoHandshakeEvent(QuicSession::HANDSHAKE_CONFIRMED
);
390 // This means that the peer sent us a message that we weren't expecting.
391 CloseConnection(QUIC_INVALID_CRYPTO_MESSAGE_TYPE
);