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/quic/crypto/channel_id.h"
8 #include "net/quic/crypto/crypto_protocol.h"
9 #include "net/quic/crypto/crypto_utils.h"
10 #include "net/quic/crypto/null_encrypter.h"
11 #include "net/quic/crypto/proof_verifier.h"
12 #include "net/quic/quic_client_session_base.h"
13 #include "net/quic/quic_protocol.h"
14 #include "net/quic/quic_session.h"
15
16 namespace net {
17
ProofVerifierCallbackImpl(QuicCryptoClientStream * stream)18 QuicCryptoClientStream::ProofVerifierCallbackImpl::ProofVerifierCallbackImpl(
19 QuicCryptoClientStream* stream)
20 : stream_(stream) {}
21
22 QuicCryptoClientStream::ProofVerifierCallbackImpl::
~ProofVerifierCallbackImpl()23 ~ProofVerifierCallbackImpl() {}
24
Run(bool ok,const string & error_details,scoped_ptr<ProofVerifyDetails> * details)25 void QuicCryptoClientStream::ProofVerifierCallbackImpl::Run(
26 bool ok,
27 const string& error_details,
28 scoped_ptr<ProofVerifyDetails>* details) {
29 if (stream_ == NULL) {
30 return;
31 }
32
33 stream_->verify_ok_ = ok;
34 stream_->verify_error_details_ = error_details;
35 stream_->verify_details_.reset(details->release());
36 stream_->proof_verify_callback_ = NULL;
37 stream_->DoHandshakeLoop(NULL);
38
39 // The ProofVerifier owns this object and will delete it when this method
40 // returns.
41 }
42
Cancel()43 void QuicCryptoClientStream::ProofVerifierCallbackImpl::Cancel() {
44 stream_ = NULL;
45 }
46
QuicCryptoClientStream(const QuicServerId & server_id,QuicClientSessionBase * session,ProofVerifyContext * verify_context,QuicCryptoClientConfig * crypto_config)47 QuicCryptoClientStream::QuicCryptoClientStream(
48 const QuicServerId& server_id,
49 QuicClientSessionBase* session,
50 ProofVerifyContext* verify_context,
51 QuicCryptoClientConfig* crypto_config)
52 : QuicCryptoStream(session),
53 next_state_(STATE_IDLE),
54 num_client_hellos_(0),
55 crypto_config_(crypto_config),
56 server_id_(server_id),
57 generation_counter_(0),
58 proof_verify_callback_(NULL),
59 verify_context_(verify_context) {
60 }
61
~QuicCryptoClientStream()62 QuicCryptoClientStream::~QuicCryptoClientStream() {
63 if (proof_verify_callback_) {
64 proof_verify_callback_->Cancel();
65 }
66 }
67
OnHandshakeMessage(const CryptoHandshakeMessage & message)68 void QuicCryptoClientStream::OnHandshakeMessage(
69 const CryptoHandshakeMessage& message) {
70 QuicCryptoStream::OnHandshakeMessage(message);
71
72 DoHandshakeLoop(&message);
73 }
74
CryptoConnect()75 bool QuicCryptoClientStream::CryptoConnect() {
76 next_state_ = STATE_INITIALIZE;
77 DoHandshakeLoop(NULL);
78 return true;
79 }
80
num_sent_client_hellos() const81 int QuicCryptoClientStream::num_sent_client_hellos() const {
82 return num_client_hellos_;
83 }
84
85 // kMaxClientHellos is the maximum number of times that we'll send a client
86 // hello. The value 3 accounts for:
87 // * One failure due to an incorrect or missing source-address token.
88 // * One failure due the server's certificate chain being unavailible and the
89 // server being unwilling to send it without a valid source-address token.
90 static const int kMaxClientHellos = 3;
91
DoHandshakeLoop(const CryptoHandshakeMessage * in)92 void QuicCryptoClientStream::DoHandshakeLoop(
93 const CryptoHandshakeMessage* in) {
94 CryptoHandshakeMessage out;
95 QuicErrorCode error;
96 string error_details;
97 QuicCryptoClientConfig::CachedState* cached =
98 crypto_config_->LookupOrCreate(server_id_);
99
100 if (in != NULL) {
101 DVLOG(1) << "Client: Received " << in->DebugString();
102 }
103
104 for (;;) {
105 const State state = next_state_;
106 next_state_ = STATE_IDLE;
107 switch (state) {
108 case STATE_INITIALIZE: {
109 if (!cached->IsEmpty() && !cached->signature().empty() &&
110 server_id_.is_https()) {
111 DCHECK(crypto_config_->proof_verifier());
112 // If the cached state needs to be verified, do it now.
113 next_state_ = STATE_VERIFY_PROOF;
114 } else {
115 next_state_ = STATE_SEND_CHLO;
116 }
117 break;
118 }
119 case STATE_SEND_CHLO: {
120 // Send the client hello in plaintext.
121 session()->connection()->SetDefaultEncryptionLevel(ENCRYPTION_NONE);
122 if (num_client_hellos_ > kMaxClientHellos) {
123 CloseConnection(QUIC_CRYPTO_TOO_MANY_REJECTS);
124 return;
125 }
126 num_client_hellos_++;
127
128 if (!cached->IsComplete(session()->connection()->clock()->WallNow())) {
129 crypto_config_->FillInchoateClientHello(
130 server_id_,
131 session()->connection()->supported_versions().front(),
132 cached, &crypto_negotiated_params_, &out);
133 // Pad the inchoate client hello to fill up a packet.
134 const size_t kFramingOverhead = 50; // A rough estimate.
135 const size_t max_packet_size =
136 session()->connection()->max_packet_length();
137 if (max_packet_size <= kFramingOverhead) {
138 DLOG(DFATAL) << "max_packet_length (" << max_packet_size
139 << ") has no room for framing overhead.";
140 CloseConnection(QUIC_INTERNAL_ERROR);
141 return;
142 }
143 if (kClientHelloMinimumSize > max_packet_size - kFramingOverhead) {
144 DLOG(DFATAL) << "Client hello won't fit in a single packet.";
145 CloseConnection(QUIC_INTERNAL_ERROR);
146 return;
147 }
148 out.set_minimum_size(max_packet_size - kFramingOverhead);
149 next_state_ = STATE_RECV_REJ;
150 DVLOG(1) << "Client: Sending " << out.DebugString();
151 SendHandshakeMessage(out);
152 return;
153 }
154 session()->config()->ToHandshakeMessage(&out);
155
156 scoped_ptr<ChannelIDKey> channel_id_key;
157 bool do_channel_id = false;
158 if (crypto_config_->channel_id_source()) {
159 const CryptoHandshakeMessage* scfg = cached->GetServerConfig();
160 DCHECK(scfg);
161 const QuicTag* their_proof_demands;
162 size_t num_their_proof_demands;
163 if (scfg->GetTaglist(kPDMD, &their_proof_demands,
164 &num_their_proof_demands) == QUIC_NO_ERROR) {
165 for (size_t i = 0; i < num_their_proof_demands; i++) {
166 if (their_proof_demands[i] == kCHID) {
167 do_channel_id = true;
168 break;
169 }
170 }
171 }
172 }
173 if (do_channel_id) {
174 QuicAsyncStatus status =
175 crypto_config_->channel_id_source()->GetChannelIDKey(
176 server_id_.host(), &channel_id_key, NULL);
177 if (status != QUIC_SUCCESS) {
178 CloseConnectionWithDetails(QUIC_INVALID_CHANNEL_ID_SIGNATURE,
179 "Channel ID lookup failed");
180 return;
181 }
182 }
183
184 error = crypto_config_->FillClientHello(
185 server_id_,
186 session()->connection()->connection_id(),
187 session()->connection()->supported_versions().front(),
188 cached,
189 session()->connection()->clock()->WallNow(),
190 session()->connection()->random_generator(),
191 channel_id_key.get(),
192 &crypto_negotiated_params_,
193 &out,
194 &error_details);
195 if (error != QUIC_NO_ERROR) {
196 // Flush the cached config so that, if it's bad, the server has a
197 // chance to send us another in the future.
198 cached->InvalidateServerConfig();
199 CloseConnectionWithDetails(error, error_details);
200 return;
201 }
202 if (cached->proof_verify_details()) {
203 client_session()->OnProofVerifyDetailsAvailable(
204 *cached->proof_verify_details());
205 }
206 next_state_ = STATE_RECV_SHLO;
207 DVLOG(1) << "Client: Sending " << out.DebugString();
208 SendHandshakeMessage(out);
209 // Be prepared to decrypt with the new server write key.
210 session()->connection()->SetAlternativeDecrypter(
211 crypto_negotiated_params_.initial_crypters.decrypter.release(),
212 ENCRYPTION_INITIAL,
213 true /* latch once used */);
214 // Send subsequent packets under encryption on the assumption that the
215 // server will accept the handshake.
216 session()->connection()->SetEncrypter(
217 ENCRYPTION_INITIAL,
218 crypto_negotiated_params_.initial_crypters.encrypter.release());
219 session()->connection()->SetDefaultEncryptionLevel(
220 ENCRYPTION_INITIAL);
221 if (!encryption_established_) {
222 encryption_established_ = true;
223 session()->OnCryptoHandshakeEvent(
224 QuicSession::ENCRYPTION_FIRST_ESTABLISHED);
225 } else {
226 session()->OnCryptoHandshakeEvent(
227 QuicSession::ENCRYPTION_REESTABLISHED);
228 }
229 return;
230 }
231 case STATE_RECV_REJ:
232 // We sent a dummy CHLO because we didn't have enough information to
233 // perform a handshake, or we sent a full hello that the server
234 // rejected. Here we hope to have a REJ that contains the information
235 // that we need.
236 if (in->tag() != kREJ) {
237 CloseConnectionWithDetails(QUIC_INVALID_CRYPTO_MESSAGE_TYPE,
238 "Expected REJ");
239 return;
240 }
241 error = crypto_config_->ProcessRejection(
242 *in, session()->connection()->clock()->WallNow(), cached,
243 &crypto_negotiated_params_, &error_details);
244 if (error != QUIC_NO_ERROR) {
245 CloseConnectionWithDetails(error, error_details);
246 return;
247 }
248 if (!cached->proof_valid()) {
249 if (!server_id_.is_https()) {
250 // We don't check the certificates for insecure QUIC connections.
251 SetCachedProofValid(cached);
252 } else if (!cached->signature().empty()) {
253 next_state_ = STATE_VERIFY_PROOF;
254 break;
255 }
256 }
257 next_state_ = STATE_SEND_CHLO;
258 break;
259 case STATE_VERIFY_PROOF: {
260 ProofVerifier* verifier = crypto_config_->proof_verifier();
261 DCHECK(verifier);
262 next_state_ = STATE_VERIFY_PROOF_COMPLETE;
263 generation_counter_ = cached->generation_counter();
264
265 ProofVerifierCallbackImpl* proof_verify_callback =
266 new ProofVerifierCallbackImpl(this);
267
268 verify_ok_ = false;
269
270 QuicAsyncStatus status = verifier->VerifyProof(
271 server_id_.host(),
272 cached->server_config(),
273 cached->certs(),
274 cached->signature(),
275 verify_context_.get(),
276 &verify_error_details_,
277 &verify_details_,
278 proof_verify_callback);
279
280 switch (status) {
281 case QUIC_PENDING:
282 proof_verify_callback_ = proof_verify_callback;
283 DVLOG(1) << "Doing VerifyProof";
284 return;
285 case QUIC_FAILURE:
286 delete proof_verify_callback;
287 break;
288 case QUIC_SUCCESS:
289 delete proof_verify_callback;
290 verify_ok_ = true;
291 break;
292 }
293 break;
294 }
295 case STATE_VERIFY_PROOF_COMPLETE:
296 if (!verify_ok_) {
297 client_session()->OnProofVerifyDetailsAvailable(*verify_details_);
298 CloseConnectionWithDetails(
299 QUIC_PROOF_INVALID, "Proof invalid: " + verify_error_details_);
300 return;
301 }
302 // Check if generation_counter has changed between STATE_VERIFY_PROOF
303 // and STATE_VERIFY_PROOF_COMPLETE state changes.
304 if (generation_counter_ != cached->generation_counter()) {
305 next_state_ = STATE_VERIFY_PROOF;
306 } else {
307 SetCachedProofValid(cached);
308 cached->SetProofVerifyDetails(verify_details_.release());
309 next_state_ = STATE_SEND_CHLO;
310 }
311 break;
312 case STATE_RECV_SHLO: {
313 // We sent a CHLO that we expected to be accepted and now we're hoping
314 // for a SHLO from the server to confirm that.
315 if (in->tag() == kREJ) {
316 // alternative_decrypter will be NULL if the original alternative
317 // decrypter latched and became the primary decrypter. That happens
318 // if we received a message encrypted with the INITIAL key.
319 if (session()->connection()->alternative_decrypter() == NULL) {
320 // The rejection was sent encrypted!
321 CloseConnectionWithDetails(QUIC_CRYPTO_ENCRYPTION_LEVEL_INCORRECT,
322 "encrypted REJ message");
323 return;
324 }
325 next_state_ = STATE_RECV_REJ;
326 break;
327 }
328 if (in->tag() != kSHLO) {
329 CloseConnectionWithDetails(QUIC_INVALID_CRYPTO_MESSAGE_TYPE,
330 "Expected SHLO or REJ");
331 return;
332 }
333 // alternative_decrypter will be NULL if the original alternative
334 // decrypter latched and became the primary decrypter. That happens
335 // if we received a message encrypted with the INITIAL key.
336 if (session()->connection()->alternative_decrypter() != NULL) {
337 // The server hello was sent without encryption.
338 CloseConnectionWithDetails(QUIC_CRYPTO_ENCRYPTION_LEVEL_INCORRECT,
339 "unencrypted SHLO message");
340 return;
341 }
342 error = crypto_config_->ProcessServerHello(
343 *in, session()->connection()->connection_id(),
344 session()->connection()->server_supported_versions(),
345 cached, &crypto_negotiated_params_, &error_details);
346
347 if (error != QUIC_NO_ERROR) {
348 CloseConnectionWithDetails(
349 error, "Server hello invalid: " + error_details);
350 return;
351 }
352 error =
353 session()->config()->ProcessPeerHello(*in, SERVER, &error_details);
354 if (error != QUIC_NO_ERROR) {
355 CloseConnectionWithDetails(
356 error, "Server hello invalid: " + error_details);
357 return;
358 }
359 session()->OnConfigNegotiated();
360
361 CrypterPair* crypters =
362 &crypto_negotiated_params_.forward_secure_crypters;
363 // TODO(agl): we don't currently latch this decrypter because the idea
364 // has been floated that the server shouldn't send packets encrypted
365 // with the FORWARD_SECURE key until it receives a FORWARD_SECURE
366 // packet from the client.
367 session()->connection()->SetAlternativeDecrypter(
368 crypters->decrypter.release(), ENCRYPTION_FORWARD_SECURE,
369 false /* don't latch */);
370 session()->connection()->SetEncrypter(
371 ENCRYPTION_FORWARD_SECURE, crypters->encrypter.release());
372 session()->connection()->SetDefaultEncryptionLevel(
373 ENCRYPTION_FORWARD_SECURE);
374
375 handshake_confirmed_ = true;
376 session()->OnCryptoHandshakeEvent(QuicSession::HANDSHAKE_CONFIRMED);
377 return;
378 }
379 case STATE_IDLE:
380 // This means that the peer sent us a message that we weren't expecting.
381 CloseConnection(QUIC_INVALID_CRYPTO_MESSAGE_TYPE);
382 return;
383 }
384 }
385 }
386
SetCachedProofValid(QuicCryptoClientConfig::CachedState * cached)387 void QuicCryptoClientStream::SetCachedProofValid(
388 QuicCryptoClientConfig::CachedState* cached) {
389 cached->SetProofValid();
390 client_session()->OnProofValid(*cached);
391 }
392
client_session()393 QuicClientSessionBase* QuicCryptoClientStream::client_session() {
394 return reinterpret_cast<QuicClientSessionBase*>(session());
395 }
396
397 } // namespace net
398