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/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/quic_client_session_base.h"
11 #include "net/quic/quic_protocol.h"
12 #include "net/quic/quic_session.h"
16 QuicCryptoClientStream::ChannelIDSourceCallbackImpl::
17 ChannelIDSourceCallbackImpl(QuicCryptoClientStream
* stream
)
20 QuicCryptoClientStream::ChannelIDSourceCallbackImpl::
21 ~ChannelIDSourceCallbackImpl() {}
23 void QuicCryptoClientStream::ChannelIDSourceCallbackImpl::Run(
24 scoped_ptr
<ChannelIDKey
>* channel_id_key
) {
25 if (stream_
== NULL
) {
29 stream_
->channel_id_key_
.reset(channel_id_key
->release());
30 stream_
->channel_id_source_callback_
= NULL
;
31 stream_
->DoHandshakeLoop(NULL
);
33 // The ChannelIDSource owns this object and will delete it when this method
37 void QuicCryptoClientStream::ChannelIDSourceCallbackImpl::Cancel() {
41 QuicCryptoClientStream::ProofVerifierCallbackImpl::ProofVerifierCallbackImpl(
42 QuicCryptoClientStream
* stream
)
45 QuicCryptoClientStream::ProofVerifierCallbackImpl::
46 ~ProofVerifierCallbackImpl() {}
48 void QuicCryptoClientStream::ProofVerifierCallbackImpl::Run(
50 const string
& error_details
,
51 scoped_ptr
<ProofVerifyDetails
>* details
) {
52 if (stream_
== NULL
) {
56 stream_
->verify_ok_
= ok
;
57 stream_
->verify_error_details_
= error_details
;
58 stream_
->verify_details_
.reset(details
->release());
59 stream_
->proof_verify_callback_
= NULL
;
60 stream_
->DoHandshakeLoop(NULL
);
62 // The ProofVerifier owns this object and will delete it when this method
66 void QuicCryptoClientStream::ProofVerifierCallbackImpl::Cancel() {
70 QuicCryptoClientStream::QuicCryptoClientStream(
71 const QuicServerId
& server_id
,
72 QuicClientSessionBase
* session
,
73 ProofVerifyContext
* verify_context
,
74 QuicCryptoClientConfig
* crypto_config
)
75 : QuicCryptoStream(session
),
76 next_state_(STATE_IDLE
),
77 num_client_hellos_(0),
78 crypto_config_(crypto_config
),
79 server_id_(server_id
),
80 generation_counter_(0),
81 channel_id_source_callback_(NULL
),
82 verify_context_(verify_context
),
83 proof_verify_callback_(NULL
) {
86 QuicCryptoClientStream::~QuicCryptoClientStream() {
87 if (channel_id_source_callback_
) {
88 channel_id_source_callback_
->Cancel();
90 if (proof_verify_callback_
) {
91 proof_verify_callback_
->Cancel();
95 void QuicCryptoClientStream::OnHandshakeMessage(
96 const CryptoHandshakeMessage
& message
) {
97 QuicCryptoStream::OnHandshakeMessage(message
);
99 DoHandshakeLoop(&message
);
102 bool QuicCryptoClientStream::CryptoConnect() {
103 next_state_
= STATE_INITIALIZE
;
104 DoHandshakeLoop(NULL
);
108 int QuicCryptoClientStream::num_sent_client_hellos() const {
109 return num_client_hellos_
;
112 bool QuicCryptoClientStream::WasChannelIDSent() const {
113 // TODO(rch): we should replace this with a boolean member so we
114 // can free the memory associated with the key after we're finished with it.
115 return channel_id_key_
.get() != NULL
;
118 // kMaxClientHellos is the maximum number of times that we'll send a client
119 // hello. The value 3 accounts for:
120 // * One failure due to an incorrect or missing source-address token.
121 // * One failure due the server's certificate chain being unavailible and the
122 // server being unwilling to send it without a valid source-address token.
123 static const int kMaxClientHellos
= 3;
125 void QuicCryptoClientStream::DoHandshakeLoop(
126 const CryptoHandshakeMessage
* in
) {
127 CryptoHandshakeMessage out
;
129 string error_details
;
130 QuicCryptoClientConfig::CachedState
* cached
=
131 crypto_config_
->LookupOrCreate(server_id_
);
134 DVLOG(1) << "Client: Received " << in
->DebugString();
138 const State state
= next_state_
;
139 next_state_
= STATE_IDLE
;
141 case STATE_INITIALIZE
: {
142 if (!cached
->IsEmpty() && !cached
->proof_valid() &&
143 !cached
->signature().empty() && server_id_
.is_https()) {
144 DCHECK(crypto_config_
->proof_verifier());
145 // If the cached state needs to be verified, do it now.
146 next_state_
= STATE_VERIFY_PROOF
;
148 next_state_
= STATE_GET_CHANNEL_ID
;
152 case STATE_SEND_CHLO
: {
153 // Send the client hello in plaintext.
154 session()->connection()->SetDefaultEncryptionLevel(ENCRYPTION_NONE
);
155 if (num_client_hellos_
> kMaxClientHellos
) {
156 CloseConnection(QUIC_CRYPTO_TOO_MANY_REJECTS
);
159 num_client_hellos_
++;
161 if (!cached
->IsComplete(session()->connection()->clock()->WallNow())) {
162 crypto_config_
->FillInchoateClientHello(
164 session()->connection()->supported_versions().front(),
165 cached
, &crypto_negotiated_params_
, &out
);
166 // Pad the inchoate client hello to fill up a packet.
167 const size_t kFramingOverhead
= 50; // A rough estimate.
168 const size_t max_packet_size
=
169 session()->connection()->max_packet_length();
170 if (max_packet_size
<= kFramingOverhead
) {
171 DLOG(DFATAL
) << "max_packet_length (" << max_packet_size
172 << ") has no room for framing overhead.";
173 CloseConnection(QUIC_INTERNAL_ERROR
);
176 if (kClientHelloMinimumSize
> max_packet_size
- kFramingOverhead
) {
177 DLOG(DFATAL
) << "Client hello won't fit in a single packet.";
178 CloseConnection(QUIC_INTERNAL_ERROR
);
181 out
.set_minimum_size(max_packet_size
- kFramingOverhead
);
182 next_state_
= STATE_RECV_REJ
;
183 DVLOG(1) << "Client: Sending " << out
.DebugString();
184 SendHandshakeMessage(out
);
187 session()->config()->ToHandshakeMessage(&out
);
188 error
= crypto_config_
->FillClientHello(
190 session()->connection()->connection_id(),
191 session()->connection()->supported_versions().front(),
193 session()->connection()->clock()->WallNow(),
194 session()->connection()->random_generator(),
195 channel_id_key_
.get(),
196 &crypto_negotiated_params_
,
199 if (error
!= QUIC_NO_ERROR
) {
200 // Flush the cached config so that, if it's bad, the server has a
201 // chance to send us another in the future.
202 cached
->InvalidateServerConfig();
203 CloseConnectionWithDetails(error
, error_details
);
206 if (cached
->proof_verify_details()) {
207 client_session()->OnProofVerifyDetailsAvailable(
208 *cached
->proof_verify_details());
210 next_state_
= STATE_RECV_SHLO
;
211 DVLOG(1) << "Client: Sending " << out
.DebugString();
212 SendHandshakeMessage(out
);
213 // Be prepared to decrypt with the new server write key.
214 session()->connection()->SetAlternativeDecrypter(
215 crypto_negotiated_params_
.initial_crypters
.decrypter
.release(),
217 true /* latch once used */);
218 // Send subsequent packets under encryption on the assumption that the
219 // server will accept the handshake.
220 session()->connection()->SetEncrypter(
222 crypto_negotiated_params_
.initial_crypters
.encrypter
.release());
223 session()->connection()->SetDefaultEncryptionLevel(
225 if (!encryption_established_
) {
226 encryption_established_
= true;
227 session()->OnCryptoHandshakeEvent(
228 QuicSession::ENCRYPTION_FIRST_ESTABLISHED
);
230 session()->OnCryptoHandshakeEvent(
231 QuicSession::ENCRYPTION_REESTABLISHED
);
236 // We sent a dummy CHLO because we didn't have enough information to
237 // perform a handshake, or we sent a full hello that the server
238 // rejected. Here we hope to have a REJ that contains the information
240 if (in
->tag() != kREJ
) {
241 CloseConnectionWithDetails(QUIC_INVALID_CRYPTO_MESSAGE_TYPE
,
245 error
= crypto_config_
->ProcessRejection(
246 *in
, session()->connection()->clock()->WallNow(), cached
,
247 &crypto_negotiated_params_
, &error_details
);
248 if (error
!= QUIC_NO_ERROR
) {
249 CloseConnectionWithDetails(error
, error_details
);
252 if (!cached
->proof_valid()) {
253 if (!server_id_
.is_https()) {
254 // We don't check the certificates for insecure QUIC connections.
255 SetCachedProofValid(cached
);
256 } else if (!cached
->signature().empty()) {
257 next_state_
= STATE_VERIFY_PROOF
;
261 next_state_
= STATE_GET_CHANNEL_ID
;
263 case STATE_VERIFY_PROOF
: {
264 ProofVerifier
* verifier
= crypto_config_
->proof_verifier();
266 next_state_
= STATE_VERIFY_PROOF_COMPLETE
;
267 generation_counter_
= cached
->generation_counter();
269 ProofVerifierCallbackImpl
* proof_verify_callback
=
270 new ProofVerifierCallbackImpl(this);
274 QuicAsyncStatus status
= verifier
->VerifyProof(
276 cached
->server_config(),
279 verify_context_
.get(),
280 &verify_error_details_
,
282 proof_verify_callback
);
286 proof_verify_callback_
= proof_verify_callback
;
287 DVLOG(1) << "Doing VerifyProof";
290 delete proof_verify_callback
;
293 delete proof_verify_callback
;
299 case STATE_VERIFY_PROOF_COMPLETE
:
301 client_session()->OnProofVerifyDetailsAvailable(*verify_details_
);
302 CloseConnectionWithDetails(
303 QUIC_PROOF_INVALID
, "Proof invalid: " + verify_error_details_
);
306 // Check if generation_counter has changed between STATE_VERIFY_PROOF
307 // and STATE_VERIFY_PROOF_COMPLETE state changes.
308 if (generation_counter_
!= cached
->generation_counter()) {
309 next_state_
= STATE_VERIFY_PROOF
;
311 SetCachedProofValid(cached
);
312 cached
->SetProofVerifyDetails(verify_details_
.release());
313 next_state_
= STATE_GET_CHANNEL_ID
;
316 case STATE_GET_CHANNEL_ID
: {
317 next_state_
= STATE_GET_CHANNEL_ID_COMPLETE
;
318 channel_id_key_
.reset();
319 if (!RequiresChannelID(cached
)) {
320 next_state_
= STATE_SEND_CHLO
;
324 ChannelIDSourceCallbackImpl
* channel_id_source_callback
=
325 new ChannelIDSourceCallbackImpl(this);
326 QuicAsyncStatus status
=
327 crypto_config_
->channel_id_source()->GetChannelIDKey(
328 server_id_
.host(), &channel_id_key_
,
329 channel_id_source_callback
);
333 channel_id_source_callback_
= channel_id_source_callback
;
334 DVLOG(1) << "Looking up channel ID";
337 delete channel_id_source_callback
;
338 CloseConnectionWithDetails(QUIC_INVALID_CHANNEL_ID_SIGNATURE
,
339 "Channel ID lookup failed");
342 delete channel_id_source_callback
;
347 case STATE_GET_CHANNEL_ID_COMPLETE
:
348 if (!channel_id_key_
.get()) {
349 CloseConnectionWithDetails(QUIC_INVALID_CHANNEL_ID_SIGNATURE
,
350 "Channel ID lookup failed");
353 next_state_
= STATE_SEND_CHLO
;
355 case STATE_RECV_SHLO
: {
356 // We sent a CHLO that we expected to be accepted and now we're hoping
357 // for a SHLO from the server to confirm that.
358 if (in
->tag() == kREJ
) {
359 // alternative_decrypter will be NULL if the original alternative
360 // decrypter latched and became the primary decrypter. That happens
361 // if we received a message encrypted with the INITIAL key.
362 if (session()->connection()->alternative_decrypter() == NULL
) {
363 // The rejection was sent encrypted!
364 CloseConnectionWithDetails(QUIC_CRYPTO_ENCRYPTION_LEVEL_INCORRECT
,
365 "encrypted REJ message");
368 next_state_
= STATE_RECV_REJ
;
371 if (in
->tag() != kSHLO
) {
372 CloseConnectionWithDetails(QUIC_INVALID_CRYPTO_MESSAGE_TYPE
,
373 "Expected SHLO or REJ");
376 // alternative_decrypter will be NULL if the original alternative
377 // decrypter latched and became the primary decrypter. That happens
378 // if we received a message encrypted with the INITIAL key.
379 if (session()->connection()->alternative_decrypter() != NULL
) {
380 // The server hello was sent without encryption.
381 CloseConnectionWithDetails(QUIC_CRYPTO_ENCRYPTION_LEVEL_INCORRECT
,
382 "unencrypted SHLO message");
385 error
= crypto_config_
->ProcessServerHello(
386 *in
, session()->connection()->connection_id(),
387 session()->connection()->server_supported_versions(),
388 cached
, &crypto_negotiated_params_
, &error_details
);
390 if (error
!= QUIC_NO_ERROR
) {
391 CloseConnectionWithDetails(
392 error
, "Server hello invalid: " + error_details
);
396 session()->config()->ProcessPeerHello(*in
, SERVER
, &error_details
);
397 if (error
!= QUIC_NO_ERROR
) {
398 CloseConnectionWithDetails(
399 error
, "Server hello invalid: " + error_details
);
402 session()->OnConfigNegotiated();
404 CrypterPair
* crypters
=
405 &crypto_negotiated_params_
.forward_secure_crypters
;
406 // TODO(agl): we don't currently latch this decrypter because the idea
407 // has been floated that the server shouldn't send packets encrypted
408 // with the FORWARD_SECURE key until it receives a FORWARD_SECURE
409 // packet from the client.
410 session()->connection()->SetAlternativeDecrypter(
411 crypters
->decrypter
.release(), ENCRYPTION_FORWARD_SECURE
,
412 false /* don't latch */);
413 session()->connection()->SetEncrypter(
414 ENCRYPTION_FORWARD_SECURE
, crypters
->encrypter
.release());
415 session()->connection()->SetDefaultEncryptionLevel(
416 ENCRYPTION_FORWARD_SECURE
);
418 handshake_confirmed_
= true;
419 session()->OnCryptoHandshakeEvent(QuicSession::HANDSHAKE_CONFIRMED
);
423 // This means that the peer sent us a message that we weren't expecting.
424 CloseConnection(QUIC_INVALID_CRYPTO_MESSAGE_TYPE
);
430 void QuicCryptoClientStream::SetCachedProofValid(
431 QuicCryptoClientConfig::CachedState
* cached
) {
432 cached
->SetProofValid();
433 client_session()->OnProofValid(*cached
);
436 bool QuicCryptoClientStream::RequiresChannelID(
437 QuicCryptoClientConfig::CachedState
* cached
) {
438 if (!server_id_
.is_https() ||
439 server_id_
.privacy_mode() == PRIVACY_MODE_ENABLED
||
440 !crypto_config_
->channel_id_source()) {
443 const CryptoHandshakeMessage
* scfg
= cached
->GetServerConfig();
444 if (!scfg
) { // scfg may be null when we send an inchoate CHLO.
447 const QuicTag
* their_proof_demands
;
448 size_t num_their_proof_demands
;
449 if (scfg
->GetTaglist(kPDMD
, &their_proof_demands
,
450 &num_their_proof_demands
) != QUIC_NO_ERROR
) {
453 for (size_t i
= 0; i
< num_their_proof_demands
; i
++) {
454 if (their_proof_demands
[i
] == kCHID
) {
461 QuicClientSessionBase
* QuicCryptoClientStream::client_session() {
462 return reinterpret_cast<QuicClientSessionBase
*>(session());