| 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" | |
| 14 #include "base/metrics/histogram.h" | 13 #include "base/metrics/histogram.h" |
| 15 #include "base/openssl_util.h" | 14 #include "base/openssl_util.h" |
| 16 #include "base/singleton.h" | 15 #include "base/singleton.h" |
| 16 #include "base/synchronization/lock.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 173 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 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 base::ScopedOpenSSL<SSL_SESSION, SSL_SESSION_free> session_to_free; |
| 210 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 base::ScopedOpenSSL<SSL_SESSION, SSL_SESSION_free> session_to_free; |
| 232 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); |
| 242 session_to_free.reset(session); | 242 session_to_free.reset(session); |
| 243 DCHECK_EQ(host_port_map_.size(), session_map_.size()); | 243 DCHECK_EQ(host_port_map_.size(), session_map_.size()); |
| 244 } | 244 } |
| 245 | 245 |
| 246 // Looks up the host:port in the cache, and if a session is found it is added | 246 // Looks up the host:port in the cache, and if a session is found it is added |
| 247 // to |ssl|, returning true on success. | 247 // to |ssl|, returning true on success. |
| 248 bool SetSSLSession(SSL* ssl, const HostPortPair& host_and_port) { | 248 bool SetSSLSession(SSL* ssl, const HostPortPair& host_and_port) { |
| 249 AutoLock lock(lock_); | 249 base::AutoLock lock(lock_); |
| 250 HostPortMap::iterator it = host_port_map_.find(host_and_port); | 250 HostPortMap::iterator it = host_port_map_.find(host_and_port); |
| 251 if (it == host_port_map_.end()) | 251 if (it == host_port_map_.end()) |
| 252 return false; | 252 return false; |
| 253 DVLOG(2) << "Lookup session: " << it->second << " => " | 253 DVLOG(2) << "Lookup session: " << it->second << " => " |
| 254 << host_and_port.ToString(); | 254 << host_and_port.ToString(); |
| 255 SSL_SESSION* session = it->second; | 255 SSL_SESSION* session = it->second; |
| 256 DCHECK(session); | 256 DCHECK(session); |
| 257 DCHECK(session_map_[session] == it); | 257 DCHECK(session_map_[session] == it); |
| 258 // Ideally we'd release |lock_| before calling into OpenSSL here, however | 258 // Ideally we'd release |lock_| before calling into OpenSSL here, however |
| 259 // that opens a small risk |session| will go out of scope before it is used. | 259 // that opens a small risk |session| will go out of scope before it is used. |
| 260 // Alternatively we would take a temporary local refcount on |session|, | 260 // Alternatively we would take a temporary local refcount on |session|, |
| 261 // except OpenSSL does not provide a public API for adding a ref (c.f. | 261 // except OpenSSL does not provide a public API for adding a ref (c.f. |
| 262 // SSL_SESSION_free which decrements the ref). | 262 // SSL_SESSION_free which decrements the ref). |
| 263 return SSL_set_session(ssl, session) == 1; | 263 return SSL_set_session(ssl, session) == 1; |
| 264 } | 264 } |
| 265 | 265 |
| 266 private: | 266 private: |
| 267 // A pair of maps to allow bi-directional lookups between host:port and an | 267 // A pair of maps to allow bi-directional lookups between host:port and an |
| 268 // associated session. | 268 // associated session. |
| 269 // TODO(joth): When client certificates are implemented we should key the | 269 // TODO(joth): When client certificates are implemented we should key the |
| 270 // cache on the client certificate used in addition to the host-port pair. | 270 // cache on the client certificate used in addition to the host-port pair. |
| 271 typedef std::map<HostPortPair, SSL_SESSION*> HostPortMap; | 271 typedef std::map<HostPortPair, SSL_SESSION*> HostPortMap; |
| 272 typedef std::map<SSL_SESSION*, HostPortMap::iterator> SessionMap; | 272 typedef std::map<SSL_SESSION*, HostPortMap::iterator> SessionMap; |
| 273 HostPortMap host_port_map_; | 273 HostPortMap host_port_map_; |
| 274 SessionMap session_map_; | 274 SessionMap session_map_; |
| 275 | 275 |
| 276 // Protects access to both the above maps. | 276 // Protects access to both the above maps. |
| 277 Lock lock_; | 277 base::Lock lock_; |
| 278 | 278 |
| 279 DISALLOW_COPY_AND_ASSIGN(SSLSessionCache); | 279 DISALLOW_COPY_AND_ASSIGN(SSLSessionCache); |
| 280 }; | 280 }; |
| 281 | 281 |
| 282 class SSLContext { | 282 class SSLContext { |
| 283 public: | 283 public: |
| 284 static SSLContext* GetInstance() { return Singleton<SSLContext>::get(); } | 284 static SSLContext* GetInstance() { return Singleton<SSLContext>::get(); } |
| 285 SSL_CTX* ssl_ctx() { return ssl_ctx_.get(); } | 285 SSL_CTX* ssl_ctx() { return ssl_ctx_.get(); } |
| 286 SSLSessionCache* session_cache() { return &session_cache_; } | 286 SSLSessionCache* session_cache() { return &session_cache_; } |
| 287 | 287 |
| (...skipping 895 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1183 int rv = SSL_write(ssl_, user_write_buf_->data(), user_write_buf_len_); | 1183 int rv = SSL_write(ssl_, user_write_buf_->data(), user_write_buf_len_); |
| 1184 | 1184 |
| 1185 if (rv >= 0) | 1185 if (rv >= 0) |
| 1186 return rv; | 1186 return rv; |
| 1187 | 1187 |
| 1188 int err = SSL_get_error(ssl_, rv); | 1188 int err = SSL_get_error(ssl_, rv); |
| 1189 return MapOpenSSLError(err, err_tracer); | 1189 return MapOpenSSLError(err, err_tracer); |
| 1190 } | 1190 } |
| 1191 | 1191 |
| 1192 } // namespace net | 1192 } // namespace net |
| OLD | NEW |