OLD | NEW |
---|---|
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "net/quic/quic_crypto_client_stream.h" | 5 #include "net/quic/quic_crypto_client_stream.h" |
6 | 6 |
7 #include "net/base/completion_callback.h" | |
8 #include "net/base/net_errors.h" | |
7 #include "net/quic/crypto/crypto_protocol.h" | 9 #include "net/quic/crypto/crypto_protocol.h" |
8 #include "net/quic/crypto/crypto_utils.h" | 10 #include "net/quic/crypto/crypto_utils.h" |
9 #include "net/quic/crypto/null_encrypter.h" | 11 #include "net/quic/crypto/null_encrypter.h" |
10 #include "net/quic/crypto/proof_verifier.h" | 12 #include "net/quic/crypto/proof_verifier.h" |
11 #include "net/quic/quic_protocol.h" | 13 #include "net/quic/quic_protocol.h" |
12 #include "net/quic/quic_session.h" | 14 #include "net/quic/quic_session.h" |
13 | 15 |
14 namespace net { | 16 namespace net { |
15 | 17 |
16 QuicCryptoClientStream::QuicCryptoClientStream( | 18 QuicCryptoClientStream::QuicCryptoClientStream( |
17 const string& server_hostname, | 19 const string& server_hostname, |
18 QuicSession* session, | 20 QuicSession* session, |
19 QuicCryptoClientConfig* crypto_config) | 21 QuicCryptoClientConfig* crypto_config) |
20 : QuicCryptoStream(session), | 22 : QuicCryptoStream(session), |
23 weak_factory_(this), | |
21 next_state_(STATE_IDLE), | 24 next_state_(STATE_IDLE), |
22 num_client_hellos_(0), | 25 num_client_hellos_(0), |
23 crypto_config_(crypto_config), | 26 crypto_config_(crypto_config), |
24 server_hostname_(server_hostname) { | 27 server_hostname_(server_hostname), |
28 generation_counter_(0) { | |
25 } | 29 } |
26 | 30 |
27 QuicCryptoClientStream::~QuicCryptoClientStream() { | 31 QuicCryptoClientStream::~QuicCryptoClientStream() { |
28 } | 32 } |
29 | 33 |
30 void QuicCryptoClientStream::OnHandshakeMessage( | 34 void QuicCryptoClientStream::OnHandshakeMessage( |
31 const CryptoHandshakeMessage& message) { | 35 const CryptoHandshakeMessage& message) { |
32 DoHandshakeLoop(&message); | 36 DoHandshakeLoop(&message, OK); |
33 } | 37 } |
34 | 38 |
35 bool QuicCryptoClientStream::CryptoConnect() { | 39 bool QuicCryptoClientStream::CryptoConnect() { |
36 next_state_ = STATE_SEND_CHLO; | 40 next_state_ = STATE_SEND_CHLO; |
37 DoHandshakeLoop(NULL); | 41 DoHandshakeLoop(NULL, OK); |
38 return true; | 42 return true; |
39 } | 43 } |
40 | 44 |
41 int QuicCryptoClientStream::num_sent_client_hellos() const { | 45 int QuicCryptoClientStream::num_sent_client_hellos() const { |
42 return num_client_hellos_; | 46 return num_client_hellos_; |
43 } | 47 } |
44 | 48 |
45 // kMaxClientHellos is the maximum number of times that we'll send a client | 49 // kMaxClientHellos is the maximum number of times that we'll send a client |
46 // hello. The value 3 accounts for: | 50 // hello. The value 3 accounts for: |
47 // * One failure due to an incorrect or missing source-address token. | 51 // * One failure due to an incorrect or missing source-address token. |
48 // * One failure due the server's certificate chain being unavailible and the | 52 // * One failure due the server's certificate chain being unavailible and the |
49 // server being unwilling to send it without a valid source-address token. | 53 // server being unwilling to send it without a valid source-address token. |
50 static const int kMaxClientHellos = 3; | 54 static const int kMaxClientHellos = 3; |
51 | 55 |
52 void QuicCryptoClientStream::DoHandshakeLoop( | 56 void QuicCryptoClientStream::DoHandshakeLoop( |
53 const CryptoHandshakeMessage* in) { | 57 const CryptoHandshakeMessage* in, |
58 int result) { | |
54 CryptoHandshakeMessage out; | 59 CryptoHandshakeMessage out; |
55 QuicErrorCode error; | 60 QuicErrorCode error; |
56 string error_details; | 61 string error_details; |
57 QuicCryptoClientConfig::CachedState* cached = | 62 QuicCryptoClientConfig::CachedState* cached = |
58 crypto_config_->LookupOrCreate(server_hostname_); | 63 crypto_config_->LookupOrCreate(server_hostname_); |
59 | 64 |
60 if (in != NULL) { | 65 if (in != NULL) { |
61 DVLOG(1) << "Client received: " << in->DebugString(); | 66 DVLOG(1) << "Client received: " << in->DebugString(); |
62 } | 67 } |
63 | 68 |
64 for (;;) { | 69 for (;;) { |
65 const State state = next_state_; | 70 const State state = next_state_; |
66 next_state_ = STATE_IDLE; | 71 next_state_ = STATE_IDLE; |
67 switch (state) { | 72 switch (state) { |
68 case STATE_SEND_CHLO: { | 73 case STATE_SEND_CHLO: { |
wtc
2013/07/03 00:20:26
Nit: we may want to DCHECK that |in| is NULL and |
ramant (doing other things)
2013/07/03 05:46:34
Added the DCHECK for |result| is |OK|. IMO, |in| n
wtc
2013/07/03 18:50:23
Ah, I see. Yes, there are three ways to enter the
| |
74 // Send the subsequent client hello in plaintext. | |
75 session()->connection()->SetDefaultEncryptionLevel(ENCRYPTION_NONE); | |
wtc
2013/07/03 00:20:26
"subsequent" probably should be removed from this
ramant (doing other things)
2013/07/03 05:46:34
Done.
| |
69 if (num_client_hellos_ > kMaxClientHellos) { | 76 if (num_client_hellos_ > kMaxClientHellos) { |
70 CloseConnection(QUIC_CRYPTO_TOO_MANY_REJECTS); | 77 CloseConnection(QUIC_CRYPTO_TOO_MANY_REJECTS); |
71 return; | 78 return; |
72 } | 79 } |
73 num_client_hellos_++; | 80 num_client_hellos_++; |
74 | 81 |
75 if (!cached->IsComplete(session()->connection()->clock()->WallNow())) { | 82 if (!cached->IsComplete(session()->connection()->clock()->WallNow())) { |
76 crypto_config_->FillInchoateClientHello( | 83 crypto_config_->FillInchoateClientHello( |
77 server_hostname_, cached, &crypto_negotiated_params_, &out); | 84 server_hostname_, cached, &crypto_negotiated_params_, &out); |
78 next_state_ = STATE_RECV_REJ; | 85 next_state_ = STATE_RECV_REJ; |
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
115 encryption_established_ = true; | 122 encryption_established_ = true; |
116 session()->OnCryptoHandshakeEvent( | 123 session()->OnCryptoHandshakeEvent( |
117 QuicSession::ENCRYPTION_FIRST_ESTABLISHED); | 124 QuicSession::ENCRYPTION_FIRST_ESTABLISHED); |
118 } else { | 125 } else { |
119 session()->OnCryptoHandshakeEvent( | 126 session()->OnCryptoHandshakeEvent( |
120 QuicSession::ENCRYPTION_REESTABLISHED); | 127 QuicSession::ENCRYPTION_REESTABLISHED); |
121 } | 128 } |
122 return; | 129 return; |
123 } | 130 } |
124 case STATE_RECV_REJ: | 131 case STATE_RECV_REJ: |
132 DCHECK_EQ(OK, result); | |
125 // We sent a dummy CHLO because we didn't have enough information to | 133 // We sent a dummy CHLO because we didn't have enough information to |
126 // perform a handshake, or we sent a full hello that the server | 134 // perform a handshake, or we sent a full hello that the server |
127 // rejected. Here we hope to have a REJ that contains the information | 135 // rejected. Here we hope to have a REJ that contains the information |
128 // that we need. | 136 // that we need. |
129 if (in->tag() != kREJ) { | 137 if (in->tag() != kREJ) { |
130 CloseConnectionWithDetails(QUIC_INVALID_CRYPTO_MESSAGE_TYPE, | 138 CloseConnectionWithDetails(QUIC_INVALID_CRYPTO_MESSAGE_TYPE, |
131 "Expected REJ"); | 139 "Expected REJ"); |
132 return; | 140 return; |
133 } | 141 } |
134 error = crypto_config_->ProcessRejection( | 142 error = crypto_config_->ProcessRejection( |
135 cached, *in, session()->connection()->clock()->WallNow(), | 143 cached, *in, session()->connection()->clock()->WallNow(), |
136 &crypto_negotiated_params_, &error_details); | 144 &crypto_negotiated_params_, &error_details); |
137 if (error != QUIC_NO_ERROR) { | 145 if (error != QUIC_NO_ERROR) { |
138 CloseConnectionWithDetails(error, error_details); | 146 CloseConnectionWithDetails(error, error_details); |
139 return; | 147 return; |
140 } | 148 } |
141 if (!cached->proof_valid()) { | 149 if (!cached->proof_valid()) { |
142 const ProofVerifier* verifier = crypto_config_->proof_verifier(); | 150 ProofVerifier* verifier = session()->proof_verifier(); |
143 if (!verifier) { | 151 if (!verifier) { |
144 // If no verifier is set then we don't check the certificates. | 152 // If no verifier is set then we don't check the certificates. |
145 cached->SetProofValid(); | 153 cached->SetProofValid(); |
146 } else if (!cached->signature().empty()) { | 154 } else if (!cached->signature().empty()) { |
147 // TODO(rtenneti): In Chromium, we will need to make VerifyProof() | 155 next_state_ = STATE_VERIFY_PROOF; |
148 // asynchronous. | 156 continue; |
wtc
2013/07/03 00:20:26
Nit: it is equivalent, but I think it looks nicer
ramant (doing other things)
2013/07/03 05:46:34
Done.
| |
149 if (!verifier->VerifyProof(server_hostname_, | |
150 cached->server_config(), | |
151 cached->certs(), | |
152 cached->signature(), | |
153 &error_details)) { | |
154 CloseConnectionWithDetails(QUIC_PROOF_INVALID, | |
155 "Proof invalid: " + error_details); | |
156 return; | |
157 } | |
158 cached->SetProofValid(); | |
159 } | 157 } |
160 } | 158 } |
161 // Send the subsequent client hello in plaintext. | |
162 session()->connection()->SetDefaultEncryptionLevel( | |
163 ENCRYPTION_NONE); | |
164 next_state_ = STATE_SEND_CHLO; | 159 next_state_ = STATE_SEND_CHLO; |
165 break; | 160 break; |
161 case STATE_VERIFY_PROOF: { | |
162 ProofVerifier* verifier = session()->proof_verifier(); | |
163 DCHECK(verifier); | |
164 next_state_ = STATE_VERIFY_PROOF_COMPLETED; | |
165 generation_counter_ = cached->generation_counter(); | |
166 result = verifier->VerifyProof( | |
167 server_hostname_, | |
168 cached->server_config(), | |
169 cached->certs(), | |
170 cached->signature(), | |
171 &error_details_, | |
172 base::Bind(&QuicCryptoClientStream::OnVerifyProofComplete, | |
173 weak_factory_.GetWeakPtr())); | |
174 if (result == ERR_IO_PENDING) { | |
175 DVLOG(1) << "Doing VerifyProof"; | |
176 return; | |
177 } | |
178 break; | |
179 } | |
180 case STATE_VERIFY_PROOF_COMPLETED: { | |
181 if (result != OK) { | |
182 CloseConnectionWithDetails( | |
183 QUIC_PROOF_INVALID, "Proof invalid: " + error_details_); | |
184 return; | |
185 } | |
186 ProofVerifier* verifier = session()->proof_verifier(); | |
187 DCHECK(verifier); | |
wtc
2013/07/03 00:20:26
Delete these two lines. |verifier| is unused. You
ramant (doing other things)
2013/07/03 05:46:34
Done.
| |
188 // Check if generation_counter has changed between STATE_VERIFY_PROOF | |
189 // and STATE_VERIFY_PROOF_COMPLETED state changes. | |
190 if (generation_counter_ != cached->generation_counter()) { | |
191 next_state_ = STATE_VERIFY_PROOF; | |
192 continue; | |
wtc
2013/07/03 00:20:26
Nit: similarly, I suggest using "break" instead of
ramant (doing other things)
2013/07/03 05:46:34
Done.
| |
193 } | |
194 cached->SetProofValid(); | |
195 next_state_ = STATE_SEND_CHLO; | |
196 break; | |
197 } | |
166 case STATE_RECV_SHLO: { | 198 case STATE_RECV_SHLO: { |
167 // We sent a CHLO that we expected to be accepted and now we're hoping | 199 // We sent a CHLO that we expected to be accepted and now we're hoping |
168 // for a SHLO from the server to confirm that. | 200 // for a SHLO from the server to confirm that. |
169 if (in->tag() == kREJ) { | 201 if (in->tag() == kREJ) { |
170 // alternative_decrypter will be NULL if the original alternative | 202 // alternative_decrypter will be NULL if the original alternative |
171 // decrypter latched and became the primary decrypter. That happens | 203 // decrypter latched and became the primary decrypter. That happens |
172 // if we received a message encrypted with the INITIAL key. | 204 // if we received a message encrypted with the INITIAL key. |
173 if (session()->connection()->alternative_decrypter() == NULL) { | 205 if (session()->connection()->alternative_decrypter() == NULL) { |
174 // The rejection was sent encrypted! | 206 // The rejection was sent encrypted! |
175 CloseConnectionWithDetails(QUIC_CRYPTO_ENCRYPTION_LEVEL_INCORRECT, | 207 CloseConnectionWithDetails(QUIC_CRYPTO_ENCRYPTION_LEVEL_INCORRECT, |
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
225 return; | 257 return; |
226 } | 258 } |
227 case STATE_IDLE: | 259 case STATE_IDLE: |
228 // This means that the peer sent us a message that we weren't expecting. | 260 // This means that the peer sent us a message that we weren't expecting. |
229 CloseConnection(QUIC_INVALID_CRYPTO_MESSAGE_TYPE); | 261 CloseConnection(QUIC_INVALID_CRYPTO_MESSAGE_TYPE); |
230 return; | 262 return; |
231 } | 263 } |
232 } | 264 } |
233 } | 265 } |
234 | 266 |
267 void QuicCryptoClientStream::OnVerifyProofComplete(int result) { | |
268 DCHECK_EQ(STATE_VERIFY_PROOF_COMPLETED, next_state_); | |
269 DVLOG(1) << "VerifyProof completed: " << result; | |
270 DoHandshakeLoop(NULL, result); | |
271 } | |
272 | |
235 } // namespace net | 273 } // namespace net |
OLD | NEW |