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 |