Chromium Code Reviews| OLD | NEW |
|---|---|
| 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 "base/lock.h" | 13 #include "base/lock.h" |
| 14 #include "base/metrics/histogram.h" | 14 #include "base/metrics/histogram.h" |
| 15 #include "base/openssl_util.h" | 15 #include "base/openssl_util.h" |
| 16 #include "base/singleton.h" | 16 #include "base/singleton.h" |
| 17 #include "net/base/cert_verifier.h" | 17 #include "net/base/cert_verifier.h" |
| 18 #include "net/base/net_errors.h" | 18 #include "net/base/net_errors.h" |
| 19 #include "net/base/ssl_cert_request_info.h" | |
| 19 #include "net/base/ssl_connection_status_flags.h" | 20 #include "net/base/ssl_connection_status_flags.h" |
| 20 #include "net/base/ssl_info.h" | 21 #include "net/base/ssl_info.h" |
| 21 | 22 |
| 22 namespace net { | 23 namespace net { |
| 23 | 24 |
| 24 namespace { | 25 namespace { |
| 25 | 26 |
| 26 // Enable this to see logging for state machine state transitions. | 27 // Enable this to see logging for state machine state transitions. |
| 27 #if 0 | 28 #if 0 |
| 28 #define GotoState(s) do { DVLOG(2) << (void *)this << " " << __FUNCTION__ << \ | 29 #define GotoState(s) do { DVLOG(2) << (void *)this << " " << __FUNCTION__ << \ |
| (...skipping 137 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 166 base::EnsureOpenSSLInit(); | 167 base::EnsureOpenSSLInit(); |
| 167 ssl_socket_data_index_ = SSL_get_ex_new_index(0, 0, 0, 0, 0); | 168 ssl_socket_data_index_ = SSL_get_ex_new_index(0, 0, 0, 0, 0); |
| 168 DCHECK_NE(ssl_socket_data_index_, -1); | 169 DCHECK_NE(ssl_socket_data_index_, -1); |
| 169 ssl_ctx_.reset(SSL_CTX_new(SSLv23_client_method())); | 170 ssl_ctx_.reset(SSL_CTX_new(SSLv23_client_method())); |
| 170 SSL_CTX_set_cert_verify_callback(ssl_ctx_.get(), NoOpVerifyCallback, NULL); | 171 SSL_CTX_set_cert_verify_callback(ssl_ctx_.get(), NoOpVerifyCallback, NULL); |
| 171 SSL_CTX_set_session_cache_mode(ssl_ctx_.get(), SSL_SESS_CACHE_CLIENT); | 172 SSL_CTX_set_session_cache_mode(ssl_ctx_.get(), SSL_SESS_CACHE_CLIENT); |
| 172 SSL_CTX_sess_set_new_cb(ssl_ctx_.get(), NewSessionCallbackStatic); | 173 SSL_CTX_sess_set_new_cb(ssl_ctx_.get(), NewSessionCallbackStatic); |
| 173 SSL_CTX_sess_set_remove_cb(ssl_ctx_.get(), RemoveSessionCallbackStatic); | 174 SSL_CTX_sess_set_remove_cb(ssl_ctx_.get(), RemoveSessionCallbackStatic); |
| 174 SSL_CTX_set_timeout(ssl_ctx_.get(), kSessionCacheTimeoutSeconds); | 175 SSL_CTX_set_timeout(ssl_ctx_.get(), kSessionCacheTimeoutSeconds); |
| 175 SSL_CTX_sess_set_cache_size(ssl_ctx_.get(), kSessionCacheMaxEntires); | 176 SSL_CTX_sess_set_cache_size(ssl_ctx_.get(), kSessionCacheMaxEntires); |
| 177 SSL_CTX_set_client_cert_cb(ssl_ctx_.get(), ClientCertCallback); | |
| 176 } | 178 } |
| 177 | 179 |
| 178 static int NewSessionCallbackStatic(SSL* ssl, SSL_SESSION* session) { | 180 static int NewSessionCallbackStatic(SSL* ssl, SSL_SESSION* session) { |
| 179 return Get()->NewSessionCallback(ssl, session); | 181 return Get()->NewSessionCallback(ssl, session); |
| 180 } | 182 } |
| 181 | 183 |
| 182 int NewSessionCallback(SSL* ssl, SSL_SESSION* session) { | 184 int NewSessionCallback(SSL* ssl, SSL_SESSION* session) { |
| 183 SSLClientSocketOpenSSL* socket = GetClientSocketFromSSL(ssl); | 185 SSLClientSocketOpenSSL* socket = GetClientSocketFromSSL(ssl); |
| 184 session_cache_.OnSessionAdded(socket->host_and_port(), session); | 186 session_cache_.OnSessionAdded(socket->host_and_port(), session); |
| 185 return 1; // 1 => We took ownership of |session|. | 187 return 1; // 1 => We took ownership of |session|. |
| 186 } | 188 } |
| 187 | 189 |
| 188 static void RemoveSessionCallbackStatic(SSL_CTX* ctx, SSL_SESSION* session) { | 190 static void RemoveSessionCallbackStatic(SSL_CTX* ctx, SSL_SESSION* session) { |
| 189 return Get()->RemoveSessionCallback(ctx, session); | 191 return Get()->RemoveSessionCallback(ctx, session); |
| 190 } | 192 } |
| 191 | 193 |
| 192 void RemoveSessionCallback(SSL_CTX* ctx, SSL_SESSION* session) { | 194 void RemoveSessionCallback(SSL_CTX* ctx, SSL_SESSION* session) { |
| 193 DCHECK(ctx == ssl_ctx()); | 195 DCHECK(ctx == ssl_ctx()); |
| 194 session_cache_.OnSessionRemoved(session); | 196 session_cache_.OnSessionRemoved(session); |
| 195 } | 197 } |
| 196 | 198 |
| 199 static int ClientCertCallback(SSL* ssl, X509** x509, EVP_PKEY** pkey) { | |
| 200 SSLClientSocketOpenSSL* socket = Get()->GetClientSocketFromSSL(ssl); | |
| 201 CHECK(socket); | |
| 202 return socket->ClientCertRequestCallback(ssl, x509, pkey); | |
| 203 } | |
| 204 | |
| 197 // This is the index used with SSL_get_ex_data to retrieve the owner | 205 // This is the index used with SSL_get_ex_data to retrieve the owner |
| 198 // SSLClientSocketOpenSSL object from an SSL instance. | 206 // SSLClientSocketOpenSSL object from an SSL instance. |
| 199 int ssl_socket_data_index_; | 207 int ssl_socket_data_index_; |
| 200 | 208 |
| 201 base::ScopedOpenSSL<SSL_CTX, SSL_CTX_free> ssl_ctx_; | 209 base::ScopedOpenSSL<SSL_CTX, SSL_CTX_free> ssl_ctx_; |
| 202 SSLSessionCache session_cache_; | 210 SSLSessionCache session_cache_; |
| 203 }; | 211 }; |
| 204 | 212 |
| 205 } // namespace | 213 } // namespace |
| 206 | 214 |
| (...skipping 111 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 318 ssl_info->connection_status |= SSL_CONNECTION_NO_RENEGOTIATION_EXTENSION; | 326 ssl_info->connection_status |= SSL_CONNECTION_NO_RENEGOTIATION_EXTENSION; |
| 319 UMA_HISTOGRAM_ENUMERATION("Net.RenegotiationExtensionSupported", | 327 UMA_HISTOGRAM_ENUMERATION("Net.RenegotiationExtensionSupported", |
| 320 (int)peer_supports_renego_ext, 2); | 328 (int)peer_supports_renego_ext, 2); |
| 321 | 329 |
| 322 if (ssl_config_.ssl3_fallback) | 330 if (ssl_config_.ssl3_fallback) |
| 323 ssl_info->connection_status |= SSL_CONNECTION_SSL3_FALLBACK; | 331 ssl_info->connection_status |= SSL_CONNECTION_SSL3_FALLBACK; |
| 324 } | 332 } |
| 325 | 333 |
| 326 void SSLClientSocketOpenSSL::GetSSLCertRequestInfo( | 334 void SSLClientSocketOpenSSL::GetSSLCertRequestInfo( |
| 327 SSLCertRequestInfo* cert_request_info) { | 335 SSLCertRequestInfo* cert_request_info) { |
| 328 NOTREACHED(); | 336 cert_request_info->host_and_port = host_and_port_.ToString(); |
| 337 cert_request_info->client_certs = client_certs_; | |
| 329 } | 338 } |
| 330 | 339 |
| 331 SSLClientSocket::NextProtoStatus SSLClientSocketOpenSSL::GetNextProto( | 340 SSLClientSocket::NextProtoStatus SSLClientSocketOpenSSL::GetNextProto( |
| 332 std::string* proto) { | 341 std::string* proto) { |
| 333 proto->clear(); | 342 proto->clear(); |
| 334 return kNextProtoUnsupported; | 343 return kNextProtoUnsupported; |
| 335 } | 344 } |
| 336 | 345 |
| 337 void SSLClientSocketOpenSSL::DoReadCallback(int rv) { | 346 void SSLClientSocketOpenSSL::DoReadCallback(int rv) { |
| 338 // Since Run may result in Read being called, clear |user_read_callback_| | 347 // Since Run may result in Read being called, clear |user_read_callback_| |
| (...skipping 116 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 455 } while ((rv != ERR_IO_PENDING || network_moved) && | 464 } while ((rv != ERR_IO_PENDING || network_moved) && |
| 456 next_handshake_state_ != STATE_NONE); | 465 next_handshake_state_ != STATE_NONE); |
| 457 return rv; | 466 return rv; |
| 458 } | 467 } |
| 459 | 468 |
| 460 int SSLClientSocketOpenSSL::DoHandshake() { | 469 int SSLClientSocketOpenSSL::DoHandshake() { |
| 461 base::OpenSSLErrStackTracer err_tracer(FROM_HERE); | 470 base::OpenSSLErrStackTracer err_tracer(FROM_HERE); |
| 462 int net_error = net::OK; | 471 int net_error = net::OK; |
| 463 int rv = SSL_do_handshake(ssl_); | 472 int rv = SSL_do_handshake(ssl_); |
| 464 | 473 |
| 465 if (rv == 1) { | 474 if (client_auth_cert_needed_) { |
| 475 net_error = ERR_SSL_CLIENT_AUTH_CERT_NEEDED; | |
| 476 // If the handshake already succeeded (because the server requests but | |
| 477 // doesn't require a client cert), we need to invalidate the SSL session | |
| 478 // so that we won't try to resume the non-client-authenticated session in | |
| 479 // the next handshake. This will cause the server to ask for a client | |
| 480 // cert again. | |
| 481 if (rv == 1) { | |
| 482 // Remove from session cache but don't clear this connection. | |
| 483 SSL_SESSION* session = SSL_get_session(ssl_); | |
| 484 if (session) { | |
| 485 int rv = SSL_CTX_remove_session(SSL_get_SSL_CTX(ssl_), session); | |
| 486 LOG_IF(WARNING, !rv) << "Couldn't invalidate SSL session: " << session; | |
| 487 } | |
| 488 } | |
| 489 } else if (rv == 1) { | |
| 466 if (trying_cached_session_ && logging::DEBUG_MODE) { | 490 if (trying_cached_session_ && logging::DEBUG_MODE) { |
| 467 DVLOG(2) << "Result of session reuse for " << host_and_port_.ToString() | 491 DVLOG(2) << "Result of session reuse for " << host_and_port_.ToString() |
| 468 << " is: " << (SSL_session_reused(ssl_) ? "Success" : "Fail"); | 492 << " is: " << (SSL_session_reused(ssl_) ? "Success" : "Fail"); |
| 469 } | 493 } |
| 470 | |
| 471 // SSL handshake is completed. Let's verify the certificate. | 494 // SSL handshake is completed. Let's verify the certificate. |
| 472 const bool got_cert = !!UpdateServerCert(); | 495 const bool got_cert = !!UpdateServerCert(); |
| 473 DCHECK(got_cert); | 496 DCHECK(got_cert); |
| 474 GotoState(STATE_VERIFY_CERT); | 497 GotoState(STATE_VERIFY_CERT); |
| 475 } else { | 498 } else { |
| 476 int ssl_error = SSL_get_error(ssl_, rv); | 499 int ssl_error = SSL_get_error(ssl_, rv); |
| 477 net_error = MapOpenSSLError(ssl_error); | 500 net_error = MapOpenSSLError(ssl_error); |
| 478 | 501 |
| 479 // If not done, stay in this state | 502 // If not done, stay in this state |
| 480 if (net_error == ERR_IO_PENDING) { | 503 if (net_error == ERR_IO_PENDING) { |
| 481 GotoState(STATE_HANDSHAKE); | 504 GotoState(STATE_HANDSHAKE); |
| 482 } else { | 505 } else { |
| 483 LOG(ERROR) << "handshake failed; returned " << rv | 506 LOG(ERROR) << "handshake failed; returned " << rv |
| 484 << ", SSL error code " << ssl_error | 507 << ", SSL error code " << ssl_error |
| 485 << ", net_error " << net_error; | 508 << ", net_error " << net_error; |
| 486 } | 509 } |
| 487 } | 510 } |
| 488 return net_error; | 511 return net_error; |
| 489 } | 512 } |
| 490 | 513 |
| 514 int SSLClientSocketOpenSSL::ClientCertRequestCallback(SSL* ssl, | |
| 515 X509** x509, | |
| 516 EVP_PKEY** pkey) { | |
| 517 DVLOG(3) << "OpenSSL ClientCertRequestCallback called"; | |
| 518 DCHECK(ssl == ssl_); | |
| 519 DCHECK(*x509 == NULL); | |
| 520 DCHECK(*pkey == NULL); | |
| 521 | |
| 522 if (!ssl_config_.send_client_cert) { | |
| 523 client_auth_cert_needed_ = true; | |
| 524 return -1; // Suspends handshake. | |
| 525 } | |
| 526 | |
| 527 // Second pass: a client certificate should have been selected. | |
| 528 if (ssl_config_.client_cert) { | |
| 529 // TODO(joth): Need a way to acquire the private key for the client cert. | |
| 530 NOTIMPLEMENTED(); | |
|
bulach
2010/12/01 18:01:33
provided the second part is correct, it may be cle
joth
2010/12/02 17:12:01
Done.
| |
| 531 EVP_PKEY* privkey = NULL; | |
| 532 if (privkey) { | |
| 533 // TODO(joth): (copied from NSS) We should wait for server certificate | |
| 534 // verification before sending our credentials. See http://crbug.com/13934 | |
| 535 *x509 = X509Certificate::DupOSCertHandle( | |
| 536 ssl_config_.client_cert->os_cert_handle()); | |
| 537 *pkey = privkey; | |
| 538 return 1; | |
| 539 } | |
| 540 LOG(WARNING) << "Client cert found without private key"; | |
| 541 } | |
| 542 // Send no client certificate. | |
| 543 return 0; | |
| 544 } | |
| 545 | |
| 491 int SSLClientSocketOpenSSL::DoVerifyCert(int result) { | 546 int SSLClientSocketOpenSSL::DoVerifyCert(int result) { |
| 492 DCHECK(server_cert_); | 547 DCHECK(server_cert_); |
| 493 GotoState(STATE_VERIFY_CERT_COMPLETE); | 548 GotoState(STATE_VERIFY_CERT_COMPLETE); |
| 494 int flags = 0; | 549 int flags = 0; |
| 495 | 550 |
| 496 if (ssl_config_.rev_checking_enabled) | 551 if (ssl_config_.rev_checking_enabled) |
| 497 flags |= X509Certificate::VERIFY_REV_CHECKING_ENABLED; | 552 flags |= X509Certificate::VERIFY_REV_CHECKING_ENABLED; |
| 498 if (ssl_config_.verify_ev_cert) | 553 if (ssl_config_.verify_ev_cert) |
| 499 flags |= X509Certificate::VERIFY_EV_CERT; | 554 flags |= X509Certificate::VERIFY_EV_CERT; |
| 500 verifier_.reset(new CertVerifier); | 555 verifier_.reset(new CertVerifier); |
| (...skipping 364 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 865 int rv = SSL_write(ssl_, user_write_buf_->data(), user_write_buf_len_); | 920 int rv = SSL_write(ssl_, user_write_buf_->data(), user_write_buf_len_); |
| 866 | 921 |
| 867 if (rv >= 0) | 922 if (rv >= 0) |
| 868 return rv; | 923 return rv; |
| 869 | 924 |
| 870 int err = SSL_get_error(ssl_, rv); | 925 int err = SSL_get_error(ssl_, rv); |
| 871 return MapOpenSSLError(err); | 926 return MapOpenSSLError(err); |
| 872 } | 927 } |
| 873 | 928 |
| 874 } // namespace net | 929 } // namespace net |
| OLD | NEW |