| OLD | NEW |
| 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 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/memory/singleton.h" | 13 #include "base/memory/singleton.h" |
| 14 #include "base/metrics/histogram.h" | 14 #include "base/metrics/histogram.h" |
| 15 #include "base/openssl_util.h" | |
| 16 #include "base/synchronization/lock.h" | 15 #include "base/synchronization/lock.h" |
| 16 #include "crypto/openssl_util.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/openssl_private_key_store.h" | 19 #include "net/base/openssl_private_key_store.h" |
| 20 #include "net/base/ssl_cert_request_info.h" | 20 #include "net/base/ssl_cert_request_info.h" |
| 21 #include "net/base/ssl_connection_status_flags.h" | 21 #include "net/base/ssl_connection_status_flags.h" |
| 22 #include "net/base/ssl_info.h" | 22 #include "net/base/ssl_info.h" |
| 23 #include "net/socket/ssl_error_params.h" | 23 #include "net/socket/ssl_error_params.h" |
| 24 | 24 |
| 25 namespace net { | 25 namespace net { |
| 26 | 26 |
| (...skipping 138 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 165 default: | 165 default: |
| 166 LOG(WARNING) << "Unmapped error reason: " << ERR_GET_REASON(error_code); | 166 LOG(WARNING) << "Unmapped error reason: " << ERR_GET_REASON(error_code); |
| 167 return ERR_FAILED; | 167 return ERR_FAILED; |
| 168 } | 168 } |
| 169 } | 169 } |
| 170 | 170 |
| 171 // Converts an OpenSSL error code into a net error code, walking the OpenSSL | 171 // Converts an OpenSSL error code into a net error code, walking the OpenSSL |
| 172 // error stack if needed. Note that |tracer| is not currently used in the | 172 // error stack if needed. Note that |tracer| is not currently used in the |
| 173 // implementation, but is passed in anyway as this ensures the caller will clear | 173 // implementation, but is passed in anyway as this ensures the caller will clear |
| 174 // any residual codes left on the error stack. | 174 // any residual codes left on the error stack. |
| 175 int MapOpenSSLError(int err, const base::OpenSSLErrStackTracer& tracer) { | 175 int MapOpenSSLError(int err, const crypto::OpenSSLErrStackTracer& tracer) { |
| 176 switch (err) { | 176 switch (err) { |
| 177 case SSL_ERROR_WANT_READ: | 177 case SSL_ERROR_WANT_READ: |
| 178 case SSL_ERROR_WANT_WRITE: | 178 case SSL_ERROR_WANT_WRITE: |
| 179 return ERR_IO_PENDING; | 179 return ERR_IO_PENDING; |
| 180 case SSL_ERROR_SYSCALL: | 180 case SSL_ERROR_SYSCALL: |
| 181 DVLOG(1) << "OpenSSL SYSCALL error, errno " << errno; | 181 DVLOG(1) << "OpenSSL SYSCALL error, errno " << errno; |
| 182 return ERR_SSL_PROTOCOL_ERROR; | 182 return ERR_SSL_PROTOCOL_ERROR; |
| 183 case SSL_ERROR_SSL: | 183 case SSL_ERROR_SSL: |
| 184 return MapOpenSSLErrorSSL(); | 184 return MapOpenSSLErrorSSL(); |
| 185 default: | 185 default: |
| (...skipping 13 matching lines...) Expand all Loading... |
| 199 // OpenSSL manages a cache of SSL_SESSION, this class provides the application | 199 // OpenSSL manages a cache of SSL_SESSION, this class provides the application |
| 200 // side policy for that cache about session re-use: we retain one session per | 200 // side policy for that cache about session re-use: we retain one session per |
| 201 // unique HostPortPair. | 201 // unique HostPortPair. |
| 202 class SSLSessionCache { | 202 class SSLSessionCache { |
| 203 public: | 203 public: |
| 204 SSLSessionCache() {} | 204 SSLSessionCache() {} |
| 205 | 205 |
| 206 void OnSessionAdded(const HostPortPair& host_and_port, SSL_SESSION* session) { | 206 void OnSessionAdded(const HostPortPair& host_and_port, SSL_SESSION* session) { |
| 207 // Declare the session cleaner-upper before the lock, so any call into | 207 // Declare the session cleaner-upper before the lock, so any call into |
| 208 // OpenSSL to free the session will happen after the lock is released. | 208 // OpenSSL to free the session will happen after the lock is released. |
| 209 base::ScopedOpenSSL<SSL_SESSION, SSL_SESSION_free> session_to_free; | 209 crypto::ScopedOpenSSL<SSL_SESSION, SSL_SESSION_free> session_to_free; |
| 210 base::AutoLock lock(lock_); | 210 base::AutoLock lock(lock_); |
| 211 | 211 |
| 212 DCHECK_EQ(0U, session_map_.count(session)); | 212 DCHECK_EQ(0U, session_map_.count(session)); |
| 213 std::pair<HostPortMap::iterator, bool> res = | 213 std::pair<HostPortMap::iterator, bool> res = |
| 214 host_port_map_.insert(std::make_pair(host_and_port, session)); | 214 host_port_map_.insert(std::make_pair(host_and_port, session)); |
| 215 if (!res.second) { // Already exists: replace old entry. | 215 if (!res.second) { // Already exists: replace old entry. |
| 216 session_to_free.reset(res.first->second); | 216 session_to_free.reset(res.first->second); |
| 217 session_map_.erase(session_to_free.get()); | 217 session_map_.erase(session_to_free.get()); |
| 218 res.first->second = session; | 218 res.first->second = session; |
| 219 } | 219 } |
| 220 DVLOG(2) << "Adding session " << session << " => " | 220 DVLOG(2) << "Adding session " << session << " => " |
| 221 << host_and_port.ToString() << ", new entry = " << res.second; | 221 << host_and_port.ToString() << ", new entry = " << res.second; |
| 222 DCHECK(host_port_map_[host_and_port] == session); | 222 DCHECK(host_port_map_[host_and_port] == session); |
| 223 session_map_[session] = res.first; | 223 session_map_[session] = res.first; |
| 224 DCHECK_EQ(host_port_map_.size(), session_map_.size()); | 224 DCHECK_EQ(host_port_map_.size(), session_map_.size()); |
| 225 DCHECK_LE(host_port_map_.size(), kSessionCacheMaxEntires); | 225 DCHECK_LE(host_port_map_.size(), kSessionCacheMaxEntires); |
| 226 } | 226 } |
| 227 | 227 |
| 228 void OnSessionRemoved(SSL_SESSION* session) { | 228 void OnSessionRemoved(SSL_SESSION* session) { |
| 229 // Declare the session cleaner-upper before the lock, so any call into | 229 // Declare the session cleaner-upper before the lock, so any call into |
| 230 // OpenSSL to free the session will happen after the lock is released. | 230 // OpenSSL to free the session will happen after the lock is released. |
| 231 base::ScopedOpenSSL<SSL_SESSION, SSL_SESSION_free> session_to_free; | 231 crypto::ScopedOpenSSL<SSL_SESSION, SSL_SESSION_free> session_to_free; |
| 232 base::AutoLock lock(lock_); | 232 base::AutoLock lock(lock_); |
| 233 | 233 |
| 234 SessionMap::iterator it = session_map_.find(session); | 234 SessionMap::iterator it = session_map_.find(session); |
| 235 if (it == session_map_.end()) | 235 if (it == session_map_.end()) |
| 236 return; | 236 return; |
| 237 DVLOG(2) << "Remove session " << session << " => " | 237 DVLOG(2) << "Remove session " << session << " => " |
| 238 << it->second->first.ToString(); | 238 << it->second->first.ToString(); |
| 239 DCHECK(it->second->second == session); | 239 DCHECK(it->second->second == session); |
| 240 host_port_map_.erase(it->second); | 240 host_port_map_.erase(it->second); |
| 241 session_map_.erase(it); | 241 session_map_.erase(it); |
| (...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 294 } | 294 } |
| 295 | 295 |
| 296 bool SetClientSocketForSSL(SSL* ssl, SSLClientSocketOpenSSL* socket) { | 296 bool SetClientSocketForSSL(SSL* ssl, SSLClientSocketOpenSSL* socket) { |
| 297 return SSL_set_ex_data(ssl, ssl_socket_data_index_, socket) != 0; | 297 return SSL_set_ex_data(ssl, ssl_socket_data_index_, socket) != 0; |
| 298 } | 298 } |
| 299 | 299 |
| 300 private: | 300 private: |
| 301 friend struct DefaultSingletonTraits<SSLContext>; | 301 friend struct DefaultSingletonTraits<SSLContext>; |
| 302 | 302 |
| 303 SSLContext() { | 303 SSLContext() { |
| 304 base::EnsureOpenSSLInit(); | 304 crypto::EnsureOpenSSLInit(); |
| 305 ssl_socket_data_index_ = SSL_get_ex_new_index(0, 0, 0, 0, 0); | 305 ssl_socket_data_index_ = SSL_get_ex_new_index(0, 0, 0, 0, 0); |
| 306 DCHECK_NE(ssl_socket_data_index_, -1); | 306 DCHECK_NE(ssl_socket_data_index_, -1); |
| 307 ssl_ctx_.reset(SSL_CTX_new(SSLv23_client_method())); | 307 ssl_ctx_.reset(SSL_CTX_new(SSLv23_client_method())); |
| 308 SSL_CTX_set_cert_verify_callback(ssl_ctx_.get(), NoOpVerifyCallback, NULL); | 308 SSL_CTX_set_cert_verify_callback(ssl_ctx_.get(), NoOpVerifyCallback, NULL); |
| 309 SSL_CTX_set_session_cache_mode(ssl_ctx_.get(), SSL_SESS_CACHE_CLIENT); | 309 SSL_CTX_set_session_cache_mode(ssl_ctx_.get(), SSL_SESS_CACHE_CLIENT); |
| 310 SSL_CTX_sess_set_new_cb(ssl_ctx_.get(), NewSessionCallbackStatic); | 310 SSL_CTX_sess_set_new_cb(ssl_ctx_.get(), NewSessionCallbackStatic); |
| 311 SSL_CTX_sess_set_remove_cb(ssl_ctx_.get(), RemoveSessionCallbackStatic); | 311 SSL_CTX_sess_set_remove_cb(ssl_ctx_.get(), RemoveSessionCallbackStatic); |
| 312 SSL_CTX_set_timeout(ssl_ctx_.get(), kSessionCacheTimeoutSeconds); | 312 SSL_CTX_set_timeout(ssl_ctx_.get(), kSessionCacheTimeoutSeconds); |
| 313 SSL_CTX_sess_set_cache_size(ssl_ctx_.get(), kSessionCacheMaxEntires); | 313 SSL_CTX_sess_set_cache_size(ssl_ctx_.get(), kSessionCacheMaxEntires); |
| 314 SSL_CTX_set_client_cert_cb(ssl_ctx_.get(), ClientCertCallback); | 314 SSL_CTX_set_client_cert_cb(ssl_ctx_.get(), ClientCertCallback); |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 351 const unsigned char* in, | 351 const unsigned char* in, |
| 352 unsigned int inlen, void* arg) { | 352 unsigned int inlen, void* arg) { |
| 353 SSLClientSocketOpenSSL* socket = GetInstance()->GetClientSocketFromSSL(ssl); | 353 SSLClientSocketOpenSSL* socket = GetInstance()->GetClientSocketFromSSL(ssl); |
| 354 return socket->SelectNextProtoCallback(out, outlen, in, inlen); | 354 return socket->SelectNextProtoCallback(out, outlen, in, inlen); |
| 355 } | 355 } |
| 356 | 356 |
| 357 // This is the index used with SSL_get_ex_data to retrieve the owner | 357 // This is the index used with SSL_get_ex_data to retrieve the owner |
| 358 // SSLClientSocketOpenSSL object from an SSL instance. | 358 // SSLClientSocketOpenSSL object from an SSL instance. |
| 359 int ssl_socket_data_index_; | 359 int ssl_socket_data_index_; |
| 360 | 360 |
| 361 base::ScopedOpenSSL<SSL_CTX, SSL_CTX_free> ssl_ctx_; | 361 crypto::ScopedOpenSSL<SSL_CTX, SSL_CTX_free> ssl_ctx_; |
| 362 SSLSessionCache session_cache_; | 362 SSLSessionCache session_cache_; |
| 363 }; | 363 }; |
| 364 | 364 |
| 365 // Utility to construct the appropriate set & clear masks for use the OpenSSL | 365 // Utility to construct the appropriate set & clear masks for use the OpenSSL |
| 366 // options and mode configuration functions. (SSL_set_options etc) | 366 // options and mode configuration functions. (SSL_set_options etc) |
| 367 struct SslSetClearMask { | 367 struct SslSetClearMask { |
| 368 SslSetClearMask() : set_mask(0), clear_mask(0) {} | 368 SslSetClearMask() : set_mask(0), clear_mask(0) {} |
| 369 void ConfigureFlag(long flag, bool state) { | 369 void ConfigureFlag(long flag, bool state) { |
| 370 (state ? set_mask : clear_mask) |= flag; | 370 (state ? set_mask : clear_mask) |= flag; |
| 371 // Make sure we haven't got any intersection in the set & clear options. | 371 // Make sure we haven't got any intersection in the set & clear options. |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 408 | 408 |
| 409 SSLClientSocketOpenSSL::~SSLClientSocketOpenSSL() { | 409 SSLClientSocketOpenSSL::~SSLClientSocketOpenSSL() { |
| 410 Disconnect(); | 410 Disconnect(); |
| 411 } | 411 } |
| 412 | 412 |
| 413 bool SSLClientSocketOpenSSL::Init() { | 413 bool SSLClientSocketOpenSSL::Init() { |
| 414 DCHECK(!ssl_); | 414 DCHECK(!ssl_); |
| 415 DCHECK(!transport_bio_); | 415 DCHECK(!transport_bio_); |
| 416 | 416 |
| 417 SSLContext* context = SSLContext::GetInstance(); | 417 SSLContext* context = SSLContext::GetInstance(); |
| 418 base::OpenSSLErrStackTracer err_tracer(FROM_HERE); | 418 crypto::OpenSSLErrStackTracer err_tracer(FROM_HERE); |
| 419 | 419 |
| 420 ssl_ = SSL_new(context->ssl_ctx()); | 420 ssl_ = SSL_new(context->ssl_ctx()); |
| 421 if (!ssl_ || !context->SetClientSocketForSSL(ssl_, this)) | 421 if (!ssl_ || !context->SetClientSocketForSSL(ssl_, this)) |
| 422 return false; | 422 return false; |
| 423 | 423 |
| 424 if (!SSL_set_tlsext_host_name(ssl_, host_and_port_.host().c_str())) | 424 if (!SSL_set_tlsext_host_name(ssl_, host_and_port_.host().c_str())) |
| 425 return false; | 425 return false; |
| 426 | 426 |
| 427 trying_cached_session_ = | 427 trying_cached_session_ = |
| 428 context->session_cache()->SetSSLSession(ssl_, host_and_port_); | 428 context->session_cache()->SetSSLSession(ssl_, host_and_port_); |
| (...skipping 287 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 716 break; | 716 break; |
| 717 | 717 |
| 718 // Do the actual network I/O. | 718 // Do the actual network I/O. |
| 719 network_moved = DoTransportIO(); | 719 network_moved = DoTransportIO(); |
| 720 } while ((rv != ERR_IO_PENDING || network_moved) && | 720 } while ((rv != ERR_IO_PENDING || network_moved) && |
| 721 next_handshake_state_ != STATE_NONE); | 721 next_handshake_state_ != STATE_NONE); |
| 722 return rv; | 722 return rv; |
| 723 } | 723 } |
| 724 | 724 |
| 725 int SSLClientSocketOpenSSL::DoHandshake() { | 725 int SSLClientSocketOpenSSL::DoHandshake() { |
| 726 base::OpenSSLErrStackTracer err_tracer(FROM_HERE); | 726 crypto::OpenSSLErrStackTracer err_tracer(FROM_HERE); |
| 727 int net_error = net::OK; | 727 int net_error = net::OK; |
| 728 int rv = SSL_do_handshake(ssl_); | 728 int rv = SSL_do_handshake(ssl_); |
| 729 | 729 |
| 730 if (client_auth_cert_needed_) { | 730 if (client_auth_cert_needed_) { |
| 731 net_error = ERR_SSL_CLIENT_AUTH_CERT_NEEDED; | 731 net_error = ERR_SSL_CLIENT_AUTH_CERT_NEEDED; |
| 732 // If the handshake already succeeded (because the server requests but | 732 // If the handshake already succeeded (because the server requests but |
| 733 // doesn't require a client cert), we need to invalidate the SSL session | 733 // doesn't require a client cert), we need to invalidate the SSL session |
| 734 // so that we won't try to resume the non-client-authenticated session in | 734 // so that we won't try to resume the non-client-authenticated session in |
| 735 // the next handshake. This will cause the server to ask for a client | 735 // the next handshake. This will cause the server to ask for a client |
| 736 // cert again. | 736 // cert again. |
| (...skipping 111 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 848 completed_handshake_ = true; | 848 completed_handshake_ = true; |
| 849 // Exit DoHandshakeLoop and return the result to the caller to Connect. | 849 // Exit DoHandshakeLoop and return the result to the caller to Connect. |
| 850 DCHECK_EQ(STATE_NONE, next_handshake_state_); | 850 DCHECK_EQ(STATE_NONE, next_handshake_state_); |
| 851 return result; | 851 return result; |
| 852 } | 852 } |
| 853 | 853 |
| 854 X509Certificate* SSLClientSocketOpenSSL::UpdateServerCert() { | 854 X509Certificate* SSLClientSocketOpenSSL::UpdateServerCert() { |
| 855 if (server_cert_) | 855 if (server_cert_) |
| 856 return server_cert_; | 856 return server_cert_; |
| 857 | 857 |
| 858 base::ScopedOpenSSL<X509, X509_free> cert(SSL_get_peer_certificate(ssl_)); | 858 crypto::ScopedOpenSSL<X509, X509_free> cert(SSL_get_peer_certificate(ssl_)); |
| 859 if (!cert.get()) { | 859 if (!cert.get()) { |
| 860 LOG(WARNING) << "SSL_get_peer_certificate returned NULL"; | 860 LOG(WARNING) << "SSL_get_peer_certificate returned NULL"; |
| 861 return NULL; | 861 return NULL; |
| 862 } | 862 } |
| 863 | 863 |
| 864 // Unlike SSL_get_peer_certificate, SSL_get_peer_cert_chain does not | 864 // Unlike SSL_get_peer_certificate, SSL_get_peer_cert_chain does not |
| 865 // increment the reference so sk_X509_free does not need to be called. | 865 // increment the reference so sk_X509_free does not need to be called. |
| 866 STACK_OF(X509)* chain = SSL_get_peer_cert_chain(ssl_); | 866 STACK_OF(X509)* chain = SSL_get_peer_cert_chain(ssl_); |
| 867 X509Certificate::OSCertHandles intermediates; | 867 X509Certificate::OSCertHandles intermediates; |
| 868 if (chain) { | 868 if (chain) { |
| (...skipping 289 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1158 | 1158 |
| 1159 bool SSLClientSocketOpenSSL::SetReceiveBufferSize(int32 size) { | 1159 bool SSLClientSocketOpenSSL::SetReceiveBufferSize(int32 size) { |
| 1160 return transport_->socket()->SetReceiveBufferSize(size); | 1160 return transport_->socket()->SetReceiveBufferSize(size); |
| 1161 } | 1161 } |
| 1162 | 1162 |
| 1163 bool SSLClientSocketOpenSSL::SetSendBufferSize(int32 size) { | 1163 bool SSLClientSocketOpenSSL::SetSendBufferSize(int32 size) { |
| 1164 return transport_->socket()->SetSendBufferSize(size); | 1164 return transport_->socket()->SetSendBufferSize(size); |
| 1165 } | 1165 } |
| 1166 | 1166 |
| 1167 int SSLClientSocketOpenSSL::DoPayloadRead() { | 1167 int SSLClientSocketOpenSSL::DoPayloadRead() { |
| 1168 base::OpenSSLErrStackTracer err_tracer(FROM_HERE); | 1168 crypto::OpenSSLErrStackTracer err_tracer(FROM_HERE); |
| 1169 int rv = SSL_read(ssl_, user_read_buf_->data(), user_read_buf_len_); | 1169 int rv = SSL_read(ssl_, user_read_buf_->data(), user_read_buf_len_); |
| 1170 // We don't need to invalidate the non-client-authenticated SSL session | 1170 // We don't need to invalidate the non-client-authenticated SSL session |
| 1171 // because the server will renegotiate anyway. | 1171 // because the server will renegotiate anyway. |
| 1172 if (client_auth_cert_needed_) | 1172 if (client_auth_cert_needed_) |
| 1173 return ERR_SSL_CLIENT_AUTH_CERT_NEEDED; | 1173 return ERR_SSL_CLIENT_AUTH_CERT_NEEDED; |
| 1174 | 1174 |
| 1175 if (rv >= 0) | 1175 if (rv >= 0) |
| 1176 return rv; | 1176 return rv; |
| 1177 | 1177 |
| 1178 int err = SSL_get_error(ssl_, rv); | 1178 int err = SSL_get_error(ssl_, rv); |
| 1179 return MapOpenSSLError(err, err_tracer); | 1179 return MapOpenSSLError(err, err_tracer); |
| 1180 } | 1180 } |
| 1181 | 1181 |
| 1182 int SSLClientSocketOpenSSL::DoPayloadWrite() { | 1182 int SSLClientSocketOpenSSL::DoPayloadWrite() { |
| 1183 base::OpenSSLErrStackTracer err_tracer(FROM_HERE); | 1183 crypto::OpenSSLErrStackTracer err_tracer(FROM_HERE); |
| 1184 int rv = SSL_write(ssl_, user_write_buf_->data(), user_write_buf_len_); | 1184 int rv = SSL_write(ssl_, user_write_buf_->data(), user_write_buf_len_); |
| 1185 | 1185 |
| 1186 if (rv >= 0) | 1186 if (rv >= 0) |
| 1187 return rv; | 1187 return rv; |
| 1188 | 1188 |
| 1189 int err = SSL_get_error(ssl_, rv); | 1189 int err = SSL_get_error(ssl_, rv); |
| 1190 return MapOpenSSLError(err, err_tracer); | 1190 return MapOpenSSLError(err, err_tracer); |
| 1191 } | 1191 } |
| 1192 | 1192 |
| 1193 } // namespace net | 1193 } // namespace net |
| OLD | NEW |