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

Side by Side Diff: net/socket/ssl_client_socket_openssl.cc

Issue 3571011: implement certificate verification state machine (Closed)
Patch Set: wtc comments Created 10 years, 2 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
« no previous file with comments | « net/socket/ssl_client_socket_openssl.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2010 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 // OpenSSL binding for SSLClientSocket. The class layout and general principle 5 // OpenSSL binding for SSLClientSocket. The class layout and general principle
6 // of operation is derived from SSLClientSocketNSS. 6 // of operation is derived from SSLClientSocketNSS.
7 7
8 #include "net/socket/ssl_client_socket_openssl.h" 8 #include "net/socket/ssl_client_socket_openssl.h"
9 9
10 #include <openssl/ssl.h> 10 #include <openssl/ssl.h>
11 #include <openssl/err.h> 11 #include <openssl/err.h>
12 12
13 #include "net/base/cert_verifier.h"
13 #include "net/base/net_errors.h" 14 #include "net/base/net_errors.h"
14 #include "net/base/ssl_connection_status_flags.h" 15 #include "net/base/ssl_connection_status_flags.h"
15 #include "net/base/ssl_info.h" 16 #include "net/base/ssl_info.h"
16 #include "net/base/test_certificate_data.h" // TODO(joth): Remove!! 17 #include "net/base/test_certificate_data.h" // TODO(joth): Remove!!
17 18
18 namespace net { 19 namespace net {
19 20
20 namespace { 21 namespace {
21 22
22 // Enable this to see logging for state machine state transitions. 23 // Enable this to see logging for state machine state transitions.
(...skipping 16 matching lines...) Expand all
39 ERR_error_string_n(error_num, buf, arraysize(buf)); 40 ERR_error_string_n(error_num, buf, arraysize(buf));
40 DVLOG(1) << "SSL error " << error_num << ": " << buf; 41 DVLOG(1) << "SSL error " << error_num << ": " << buf;
41 } 42 }
42 } 43 }
43 44
44 int MapOpenSSLError(int err) { 45 int MapOpenSSLError(int err) {
45 switch (err) { 46 switch (err) {
46 case SSL_ERROR_WANT_READ: 47 case SSL_ERROR_WANT_READ:
47 case SSL_ERROR_WANT_WRITE: 48 case SSL_ERROR_WANT_WRITE:
48 return ERR_IO_PENDING; 49 return ERR_IO_PENDING;
50 case SSL_ERROR_SYSCALL:
51 DVLOG(1) << "OpenSSL SYSVCALL error, errno " << errno;
wtc 2010/10/04 23:13:53 Typo: SYSVCALL => SYSCALL Should this really be m
52 MaybeLogSSLError();
53 return ERR_SSL_PROTOCOL_ERROR;
49 default: 54 default:
50 // TODO(joth): Implement full mapping. 55 // TODO(joth): Implement full mapping.
51 LOG(WARNING) << "Unknown OpenSSL error " << err; 56 LOG(WARNING) << "Unknown OpenSSL error " << err;
52 MaybeLogSSLError(); 57 MaybeLogSSLError();
53 return ERR_SSL_PROTOCOL_ERROR; 58 return ERR_SSL_PROTOCOL_ERROR;
54 } 59 }
55 } 60 }
56 61
57 // Registered with |g_ctx| as global verify callback handler; we unpack the 62 // Registered with |g_ctx| as global verify callback handler; we unpack the
58 // SSLClientSocketOpenSSL instance associated with this callback and delegate 63 // SSLClientSocketOpenSSL instance associated with this callback and delegate
(...skipping 20 matching lines...) Expand all
79 : ALLOW_THIS_IN_INITIALIZER_LIST(buffer_send_callback_( 84 : ALLOW_THIS_IN_INITIALIZER_LIST(buffer_send_callback_(
80 this, &SSLClientSocketOpenSSL::BufferSendComplete)), 85 this, &SSLClientSocketOpenSSL::BufferSendComplete)),
81 ALLOW_THIS_IN_INITIALIZER_LIST(buffer_recv_callback_( 86 ALLOW_THIS_IN_INITIALIZER_LIST(buffer_recv_callback_(
82 this, &SSLClientSocketOpenSSL::BufferRecvComplete)), 87 this, &SSLClientSocketOpenSSL::BufferRecvComplete)),
83 transport_send_busy_(false), 88 transport_send_busy_(false),
84 transport_recv_busy_(false), 89 transport_recv_busy_(false),
85 user_connect_callback_(NULL), 90 user_connect_callback_(NULL),
86 user_read_callback_(NULL), 91 user_read_callback_(NULL),
87 user_write_callback_(NULL), 92 user_write_callback_(NULL),
88 client_auth_cert_needed_(false), 93 client_auth_cert_needed_(false),
94 ALLOW_THIS_IN_INITIALIZER_LIST(handshake_io_callback_(
95 this, &SSLClientSocketOpenSSL::OnHandshakeIOComplete)),
89 ssl_(NULL), 96 ssl_(NULL),
90 transport_bio_(NULL), 97 transport_bio_(NULL),
91 transport_(transport_socket), 98 transport_(transport_socket),
92 hostname_(hostname), 99 hostname_(hostname),
93 ssl_config_(ssl_config), 100 ssl_config_(ssl_config),
94 completed_handshake_(false), 101 completed_handshake_(false),
95 net_log_(transport_socket->socket()->NetLog()) { 102 net_log_(transport_socket->socket()->NetLog()) {
96 } 103 }
97 104
98 SSLClientSocketOpenSSL::~SSLClientSocketOpenSSL() { 105 SSLClientSocketOpenSSL::~SSLClientSocketOpenSSL() {
(...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after
158 165
159 SSL_set_bio(ssl_, ssl_bio, ssl_bio); 166 SSL_set_bio(ssl_, ssl_bio, ssl_bio);
160 167
161 return true; 168 return true;
162 } 169 }
163 170
164 int SSLClientSocketOpenSSL::SSLVerifyCallback(int preverify_ok, 171 int SSLClientSocketOpenSSL::SSLVerifyCallback(int preverify_ok,
165 SSL* ssl, 172 SSL* ssl,
166 X509_STORE_CTX* x509_ctx) { 173 X509_STORE_CTX* x509_ctx) {
167 DCHECK_EQ(ssl_, ssl); 174 DCHECK_EQ(ssl_, ssl);
168 if (!preverify_ok) { 175 int depth = X509_STORE_CTX_get_error_depth(x509_ctx);
169 int depth = X509_STORE_CTX_get_error_depth(x509_ctx); 176 DVLOG(preverify_ok ? 3 : 1) << "SSLVerifyCallback " << preverify_ok
170 DVLOG(2) << "SSLVerifyCallback " << preverify_ok << " depth " << depth; 177 << " depth " << depth;
171 MaybeLogSSLError(); 178 MaybeLogSSLError();
172 }
173 return preverify_ok; 179 return preverify_ok;
174 } 180 }
175 181
176 // SSLClientSocket methods 182 // SSLClientSocket methods
177 183
178 void SSLClientSocketOpenSSL::GetSSLInfo(SSLInfo* ssl_info) { 184 void SSLClientSocketOpenSSL::GetSSLInfo(SSLInfo* ssl_info) {
185 ssl_info->Reset();
186 if (!server_cert_)
187 return;
188
179 // Chrome DCHECKs that https pages provide a valid cert. For now (whilst in 189 // Chrome DCHECKs that https pages provide a valid cert. For now (whilst in
180 // early dev) we just create a spoof cert. 190 // early dev) we just create a spoof cert.
181 // TODO(joth): implement X509Certificate for OpenSSL and remove this hack. 191 // TODO(joth): implement X509Certificate for OpenSSL and remove this hack.
182 LOG(WARNING) << "Filling in certificate with bogus content"; 192 LOG(WARNING) << "Filling in certificate with bogus content";
183 ssl_info->Reset(); 193 ssl_info->cert = server_cert_;
184 ssl_info->cert = X509Certificate::CreateFromBytes( 194 ssl_info->cert_status = server_cert_verify_result_.cert_status;
185 reinterpret_cast<const char*>(google_der), sizeof(google_der));
186 DCHECK(ssl_info->cert);
187 ssl_info->cert_status = 0;
188 ssl_info->security_bits = 56; 195 ssl_info->security_bits = 56;
189 ssl_info->connection_status = 196 ssl_info->connection_status =
190 ((TLS1_CK_RSA_EXPORT1024_WITH_DES_CBC_SHA) & 197 ((TLS1_CK_RSA_EXPORT1024_WITH_DES_CBC_SHA) &
191 SSL_CONNECTION_CIPHERSUITE_MASK) << SSL_CONNECTION_CIPHERSUITE_SHIFT; 198 SSL_CONNECTION_CIPHERSUITE_MASK) << SSL_CONNECTION_CIPHERSUITE_SHIFT;
192
193 // Silence compiler about unused vars.
194 (void)google_der;
195 (void)webkit_der;
196 (void)thawte_der;
197 (void)paypal_null_der;
198 } 199 }
199 200
200 void SSLClientSocketOpenSSL::GetSSLCertRequestInfo( 201 void SSLClientSocketOpenSSL::GetSSLCertRequestInfo(
201 SSLCertRequestInfo* cert_request_info) { 202 SSLCertRequestInfo* cert_request_info) {
202 NOTREACHED(); 203 NOTREACHED();
203 } 204 }
204 205
205 SSLClientSocket::NextProtoStatus SSLClientSocketOpenSSL::GetNextProto( 206 SSLClientSocket::NextProtoStatus SSLClientSocketOpenSSL::GetNextProto(
206 std::string* proto) { 207 std::string* proto) {
207 proto->clear(); 208 proto->clear();
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after
252 if (rv == ERR_IO_PENDING) { 253 if (rv == ERR_IO_PENDING) {
253 user_connect_callback_ = callback; 254 user_connect_callback_ = callback;
254 } else { 255 } else {
255 net_log_.EndEvent(NetLog::TYPE_SSL_CONNECT, NULL); 256 net_log_.EndEvent(NetLog::TYPE_SSL_CONNECT, NULL);
256 } 257 }
257 258
258 return rv > OK ? OK : rv; 259 return rv > OK ? OK : rv;
259 } 260 }
260 261
261 void SSLClientSocketOpenSSL::Disconnect() { 262 void SSLClientSocketOpenSSL::Disconnect() {
263 if (ssl_) {
264 SSL_free(ssl_);
265 ssl_ = NULL;
266 }
267 if (transport_bio_) {
268 BIO_free_all(transport_bio_);
269 transport_bio_ = NULL;
270 }
271
272 // Shut down anything that may call us back (through buffer_send_callback_,
273 // buffer_recv_callback, or handshake_io_callback_).
274 verifier_.reset();
275 transport_->socket()->Disconnect();
276
262 // Null all callbacks, delete all buffers. 277 // Null all callbacks, delete all buffers.
263 transport_send_busy_ = false; 278 transport_send_busy_ = false;
264 send_buffer_ = NULL; 279 send_buffer_ = NULL;
265 transport_recv_busy_ = false; 280 transport_recv_busy_ = false;
266 recv_buffer_ = NULL; 281 recv_buffer_ = NULL;
267 282
268 user_connect_callback_ = NULL; 283 user_connect_callback_ = NULL;
269 user_read_callback_ = NULL; 284 user_read_callback_ = NULL;
270 user_write_callback_ = NULL; 285 user_write_callback_ = NULL;
271 user_read_buf_ = NULL; 286 user_read_buf_ = NULL;
272 user_read_buf_len_ = 0; 287 user_read_buf_len_ = 0;
273 user_write_buf_ = NULL; 288 user_write_buf_ = NULL;
274 user_write_buf_len_ = 0; 289 user_write_buf_len_ = 0;
275 290
276 client_certs_.clear(); 291 client_certs_.clear();
277 client_auth_cert_needed_ = false; 292 client_auth_cert_needed_ = false;
278 293
279 if (ssl_) { 294 server_cert_verify_result_.Reset();
280 SSL_free(ssl_);
281 ssl_ = NULL;
282 }
283 if (transport_bio_) {
284 BIO_free(transport_bio_);
285 transport_bio_ = NULL;
286 }
287
288 completed_handshake_ = false; 295 completed_handshake_ = false;
289 transport_->socket()->Disconnect();
290 } 296 }
291 297
292 int SSLClientSocketOpenSSL::DoHandshakeLoop(int last_io_result) { 298 int SSLClientSocketOpenSSL::DoHandshakeLoop(int last_io_result) {
293 bool network_moved; 299 bool network_moved;
294 int rv = last_io_result; 300 int rv = last_io_result;
295 do { 301 do {
296 // Default to STATE_NONE for next state. 302 // Default to STATE_NONE for next state.
297 // (This is a quirk carried over from the windows 303 // (This is a quirk carried over from the windows
298 // implementation. It makes reading the logs a bit harder.) 304 // implementation. It makes reading the logs a bit harder.)
299 // State handlers can and often do call GotoState just 305 // State handlers can and often do call GotoState just
300 // to stay in the current state. 306 // to stay in the current state.
301 State state = next_handshake_state_; 307 State state = next_handshake_state_;
302 GotoState(STATE_NONE); 308 GotoState(STATE_NONE);
303 switch (state) { 309 switch (state) {
304 case STATE_NONE: 310 case STATE_NONE:
305 // we're just pumping data between the buffer and the network 311 // we're just pumping data between the buffer and the network
306 break; 312 break;
307 case STATE_HANDSHAKE: 313 case STATE_HANDSHAKE:
308 rv = DoHandshake(); 314 rv = DoHandshake();
309 break; 315 break;
310 #if 0 // TODO(joth): Implement cert verification.
311 case STATE_VERIFY_CERT: 316 case STATE_VERIFY_CERT:
312 DCHECK(rv == OK); 317 DCHECK(rv == OK);
313 rv = DoVerifyCert(rv); 318 rv = DoVerifyCert(rv);
314 break; 319 break;
315 case STATE_VERIFY_CERT_COMPLETE: 320 case STATE_VERIFY_CERT_COMPLETE:
316 rv = DoVerifyCertComplete(rv); 321 rv = DoVerifyCertComplete(rv);
317 break; 322 break;
318 #endif
319 default: 323 default:
320 rv = ERR_UNEXPECTED; 324 rv = ERR_UNEXPECTED;
321 NOTREACHED() << "unexpected state" << state; 325 NOTREACHED() << "unexpected state" << state;
322 break; 326 break;
323 } 327 }
324 328
325 // To avoid getting an ERR_IO_PENDING here after handshake complete. 329 // To avoid getting an ERR_IO_PENDING here after handshake complete.
326 if (next_handshake_state_ == STATE_NONE) 330 if (next_handshake_state_ == STATE_NONE)
327 break; 331 break;
328 332
329 // Do the actual network I/O. 333 // Do the actual network I/O.
330 network_moved = DoTransportIO(); 334 network_moved = DoTransportIO();
331 } while ((rv != ERR_IO_PENDING || network_moved) && 335 } while ((rv != ERR_IO_PENDING || network_moved) &&
332 next_handshake_state_ != STATE_NONE); 336 next_handshake_state_ != STATE_NONE);
333 return rv; 337 return rv;
334 } 338 }
335 339
336 int SSLClientSocketOpenSSL::DoHandshake() { 340 int SSLClientSocketOpenSSL::DoHandshake() {
337 int net_error = net::OK; 341 int net_error = net::OK;
338 int rv = SSL_do_handshake(ssl_); 342 int rv = SSL_do_handshake(ssl_);
339 343
340 if (rv == 1) { 344 if (rv == 1) {
341 // SSL handshake is completed. Let's verify the certificate. 345 // SSL handshake is completed. Let's verify the certificate.
342 // For now we are done, certificates not implemented yet. 346 if (UpdateServerCert() == NULL) {
343 // TODO(joth): Implement certificates 347 net_error = ERR_SSL_PROTOCOL_ERROR;
344 GotoState(STATE_NONE); 348 } else {
345 completed_handshake_ = true; 349 GotoState(STATE_VERIFY_CERT);
350
351 // TODO(joth): Remove this check when X509Certificate::Verify is
352 // implemented for OpenSSL
353 long verify_result = SSL_get_verify_result(ssl_);
354 LOG_IF(WARNING, verify_result != X509_V_OK)
355 << "Built in verify failed: " << verify_result;
356 }
346 } else { 357 } else {
347 int ssl_error = SSL_get_error(ssl_, rv); 358 int ssl_error = SSL_get_error(ssl_, rv);
359 net_error = MapOpenSSLError(ssl_error);
348 360
349 // If not done, stay in this state 361 // If not done, stay in this state
350 GotoState(STATE_HANDSHAKE); 362 if (net_error == ERR_IO_PENDING) {
351 net_error = MapOpenSSLError(ssl_error); 363 GotoState(STATE_HANDSHAKE);
364 } else {
365 LOG(ERROR) << "handshake failed; returned " << rv
366 << ", SSL error code " << ssl_error
367 << ", net_error " << net_error;
368 MaybeLogSSLError();
369 }
370 }
371 return net_error;
372 }
373
374 int SSLClientSocketOpenSSL::DoVerifyCert(int result) {
375 DCHECK(server_cert_);
376 GotoState(STATE_VERIFY_CERT_COMPLETE);
377 int flags = 0;
378
379 if (ssl_config_.rev_checking_enabled)
380 flags |= X509Certificate::VERIFY_REV_CHECKING_ENABLED;
381 if (ssl_config_.verify_ev_cert)
382 flags |= X509Certificate::VERIFY_EV_CERT;
383 verifier_.reset(new CertVerifier);
384 return verifier_->Verify(server_cert_, hostname_, flags,
385 &server_cert_verify_result_,
386 &handshake_io_callback_);
387 }
388
389 int SSLClientSocketOpenSSL::DoVerifyCertComplete(int result) {
390 verifier_.reset();
391
392 if (result == OK) {
393 // TODO(joth): Work out if we need to remember the intermediate CA certs
394 // when the server sends them to us, and do so here.
352 } 395 }
353 396
354 return net_error; 397 // If we have been explicitly told to accept this certificate, override the
398 // result of verifier_.Verify.
399 // Eventually, we should cache the cert verification results so that we don't
400 // need to call verifier_.Verify repeatedly. But for now we need to do this.
401 // Alternatively, we could use the cert's status that we stored along with
402 // the cert in the allowed_bad_certs vector.
403 if (IsCertificateError(result) &&
404 ssl_config_.IsAllowedBadCert(server_cert_)) {
405 LOG(INFO) << "accepting bad SSL certificate, as user told us to";
406 result = OK;
407 }
408
409 completed_handshake_ = true;
410 // The NSS version has a comment that we may not need this call because it is
411 // now harmless to have a session with a bad cert.
412 // This may or may not apply here, but let's invalidate it anyway.
413 InvalidateSessionIfBadCertificate();
414 // Exit DoHandshakeLoop and return the result to the caller to Connect.
415 DCHECK_EQ(STATE_NONE, next_handshake_state_);
416 return result;
417 }
418
419 void SSLClientSocketOpenSSL::InvalidateSessionIfBadCertificate() {
420 if (UpdateServerCert() != NULL &&
421 ssl_config_.IsAllowedBadCert(server_cert_)) {
422 // Remove from session cache but don't clear this connection.
423 // TODO(joth): This should be a no-op until we enable session caching,
424 // see SSL_CTX_set_session_cache_mode(SSL_SESS_CACHE_CLIENT).
425 SSL_SESSION* session = SSL_get_session(ssl_);
426 LOG_IF(ERROR, session) << "Connection has a session?? " << session;
427 int rv = SSL_CTX_remove_session(g_ctx, session);
428 LOG_IF(ERROR, rv) << "Session was cached?? " << rv;
429 }
430 }
431
432 X509Certificate* SSLClientSocketOpenSSL::UpdateServerCert() {
433 if (server_cert_)
434 return server_cert_;
435
436 X509* cert = SSL_get_peer_certificate(ssl_);
437 if (cert == NULL) {
438 LOG(WARNING) << "SSL_get_peer_certificate returned NULL";
439 return NULL;
440 }
441
442 // TODO(joth): Get |server_cert_| from |cert|.
443 server_cert_ = X509Certificate::CreateFromBytes(
444 reinterpret_cast<const char*>(google_der), sizeof(google_der));
445 X509_free(cert);
446 DCHECK(server_cert_);
447 // Silence compiler about unused vars.
448 (void)google_der; (void)webkit_der; (void)thawte_der; (void)paypal_null_der;
449
450 return server_cert_;
355 } 451 }
356 452
357 bool SSLClientSocketOpenSSL::DoTransportIO() { 453 bool SSLClientSocketOpenSSL::DoTransportIO() {
358 bool network_moved = false; 454 bool network_moved = false;
359 int nsent = BufferSend(); 455 int nsent = BufferSend();
360 int nreceived = BufferRecv(); 456 int nreceived = BufferRecv();
361 network_moved = (nsent > 0 || nreceived >= 0); 457 network_moved = (nsent > 0 || nreceived >= 0);
362 return network_moved; 458 return network_moved;
363 } 459 }
364 460
(...skipping 280 matching lines...) Expand 10 before | Expand all | Expand 10 after
645 int rv = SSL_write(ssl_, user_write_buf_->data(), user_write_buf_len_); 741 int rv = SSL_write(ssl_, user_write_buf_->data(), user_write_buf_len_);
646 742
647 if (rv >= 0) 743 if (rv >= 0)
648 return rv; 744 return rv;
649 745
650 int err = SSL_get_error(ssl_, rv); 746 int err = SSL_get_error(ssl_, rv);
651 return MapOpenSSLError(err); 747 return MapOpenSSLError(err);
652 } 748 }
653 749
654 } // namespace net 750 } // namespace net
OLDNEW
« no previous file with comments | « net/socket/ssl_client_socket_openssl.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698