Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(691)

Side by Side Diff: net/quic/quic_crypto_client_stream.cc

Issue 17385010: OpenSSL/NSS implementation of ProofVerfifier. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: added quic_ in front of all QUIC specific .crt file names and added them to net/ssl/certificates Created 7 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
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
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
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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698