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

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

Issue 8857002: net: split the SSL session cache between incognito and normal. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: ... Created 9 years 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 | Annotate | Revision Log
OLDNEW
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>
(...skipping 182 matching lines...) Expand 10 before | Expand all | Expand 10 after
193 193
194 // We do certificate verification after handshake, so we disable the default 194 // We do certificate verification after handshake, so we disable the default
195 // by registering a no-op verify function. 195 // by registering a no-op verify function.
196 int NoOpVerifyCallback(X509_STORE_CTX*, void *) { 196 int NoOpVerifyCallback(X509_STORE_CTX*, void *) {
197 DVLOG(3) << "skipping cert verify"; 197 DVLOG(3) << "skipping cert verify";
198 return 1; 198 return 1;
199 } 199 }
200 200
201 // OpenSSL manages a cache of SSL_SESSION, this class provides the application 201 // OpenSSL manages a cache of SSL_SESSION, this class provides the application
202 // side policy for that cache about session re-use: we retain one session per 202 // side policy for that cache about session re-use: we retain one session per
203 // unique HostPortPair. 203 // unique HostPortPair, per shard.
204 class SSLSessionCache { 204 class SSLSessionCache {
205 public: 205 public:
206 SSLSessionCache() {} 206 SSLSessionCache() {}
207 207
208 void OnSessionAdded(const HostPortPair& host_and_port, SSL_SESSION* session) { 208 void OnSessionAdded(const HostPortPair& host_and_port,
209 const std::string& shard,
210 SSL_SESSION* session) {
209 // Declare the session cleaner-upper before the lock, so any call into 211 // Declare the session cleaner-upper before the lock, so any call into
210 // OpenSSL to free the session will happen after the lock is released. 212 // OpenSSL to free the session will happen after the lock is released.
211 crypto::ScopedOpenSSL<SSL_SESSION, SSL_SESSION_free> session_to_free; 213 crypto::ScopedOpenSSL<SSL_SESSION, SSL_SESSION_free> session_to_free;
212 base::AutoLock lock(lock_); 214 base::AutoLock lock(lock_);
213 215
214 DCHECK_EQ(0U, session_map_.count(session)); 216 DCHECK_EQ(0U, session_map_.count(session));
217 const std::string cache_key = GetCacheKey(host_and_port, shard);
218
215 std::pair<HostPortMap::iterator, bool> res = 219 std::pair<HostPortMap::iterator, bool> res =
216 host_port_map_.insert(std::make_pair(host_and_port, session)); 220 host_port_map_.insert(std::make_pair(cache_key, session));
217 if (!res.second) { // Already exists: replace old entry. 221 if (!res.second) { // Already exists: replace old entry.
218 session_to_free.reset(res.first->second); 222 session_to_free.reset(res.first->second);
219 session_map_.erase(session_to_free.get()); 223 session_map_.erase(session_to_free.get());
220 res.first->second = session; 224 res.first->second = session;
221 } 225 }
222 DVLOG(2) << "Adding session " << session << " => " 226 DVLOG(2) << "Adding session " << session << " => "
223 << host_and_port.ToString() << ", new entry = " << res.second; 227 << cache_key << ", new entry = " << res.second;
224 DCHECK(host_port_map_[host_and_port] == session); 228 DCHECK(host_port_map_[cache_key] == session);
225 session_map_[session] = res.first; 229 session_map_[session] = res.first;
226 DCHECK_EQ(host_port_map_.size(), session_map_.size()); 230 DCHECK_EQ(host_port_map_.size(), session_map_.size());
227 DCHECK_LE(host_port_map_.size(), kSessionCacheMaxEntires); 231 DCHECK_LE(host_port_map_.size(), kSessionCacheMaxEntires);
228 } 232 }
229 233
230 void OnSessionRemoved(SSL_SESSION* session) { 234 void OnSessionRemoved(SSL_SESSION* session) {
231 // Declare the session cleaner-upper before the lock, so any call into 235 // Declare the session cleaner-upper before the lock, so any call into
232 // OpenSSL to free the session will happen after the lock is released. 236 // OpenSSL to free the session will happen after the lock is released.
233 crypto::ScopedOpenSSL<SSL_SESSION, SSL_SESSION_free> session_to_free; 237 crypto::ScopedOpenSSL<SSL_SESSION, SSL_SESSION_free> session_to_free;
234 base::AutoLock lock(lock_); 238 base::AutoLock lock(lock_);
235 239
236 SessionMap::iterator it = session_map_.find(session); 240 SessionMap::iterator it = session_map_.find(session);
237 if (it == session_map_.end()) 241 if (it == session_map_.end())
238 return; 242 return;
239 DVLOG(2) << "Remove session " << session << " => " 243 DVLOG(2) << "Remove session " << session << " => " << it->second->first;
240 << it->second->first.ToString();
241 DCHECK(it->second->second == session); 244 DCHECK(it->second->second == session);
242 host_port_map_.erase(it->second); 245 host_port_map_.erase(it->second);
243 session_map_.erase(it); 246 session_map_.erase(it);
244 session_to_free.reset(session); 247 session_to_free.reset(session);
245 DCHECK_EQ(host_port_map_.size(), session_map_.size()); 248 DCHECK_EQ(host_port_map_.size(), session_map_.size());
246 } 249 }
247 250
248 // Looks up the host:port in the cache, and if a session is found it is added 251 // Looks up the host:port in the cache, and if a session is found it is added
249 // to |ssl|, returning true on success. 252 // to |ssl|, returning true on success.
250 bool SetSSLSession(SSL* ssl, const HostPortPair& host_and_port) { 253 bool SetSSLSession(SSL* ssl, const HostPortPair& host_and_port,
254 const std::string& shard) {
251 base::AutoLock lock(lock_); 255 base::AutoLock lock(lock_);
252 HostPortMap::iterator it = host_port_map_.find(host_and_port); 256 const std::string cache_key = GetCacheKey(host_and_port, shard);
257 HostPortMap::iterator it = host_port_map_.find(cache_key);
253 if (it == host_port_map_.end()) 258 if (it == host_port_map_.end())
254 return false; 259 return false;
255 DVLOG(2) << "Lookup session: " << it->second << " => " 260 DVLOG(2) << "Lookup session: " << it->second << " => " << cache_key;
256 << host_and_port.ToString();
257 SSL_SESSION* session = it->second; 261 SSL_SESSION* session = it->second;
258 DCHECK(session); 262 DCHECK(session);
259 DCHECK(session_map_[session] == it); 263 DCHECK(session_map_[session] == it);
260 // Ideally we'd release |lock_| before calling into OpenSSL here, however 264 // Ideally we'd release |lock_| before calling into OpenSSL here, however
261 // that opens a small risk |session| will go out of scope before it is used. 265 // that opens a small risk |session| will go out of scope before it is used.
262 // Alternatively we would take a temporary local refcount on |session|, 266 // Alternatively we would take a temporary local refcount on |session|,
263 // except OpenSSL does not provide a public API for adding a ref (c.f. 267 // except OpenSSL does not provide a public API for adding a ref (c.f.
264 // SSL_SESSION_free which decrements the ref). 268 // SSL_SESSION_free which decrements the ref).
265 return SSL_set_session(ssl, session) == 1; 269 return SSL_set_session(ssl, session) == 1;
266 } 270 }
267 271
272 // Flush removes all entries from the cache. This is called when a client
273 // certificate is added.
274 void Flush() {
275 for (HostPortMap::iterator i = host_port_map_.begin();
276 i != host_port_map_.end(); i++) {
277 SSL_SESSION_free(i->second);
278 }
279 host_port_map_.clear();
280 session_map_.clear();
281 }
282
268 private: 283 private:
284 static std::string GetCacheKey(const HostPortPair& host_and_port,
285 const std::string& shard) {
286 return host_and_port.ToString() + "/" + shard;
287 }
288
269 // A pair of maps to allow bi-directional lookups between host:port and an 289 // A pair of maps to allow bi-directional lookups between host:port and an
270 // associated session. 290 // associated session.
271 // TODO(joth): When client certificates are implemented we should key the 291 typedef std::map<std::string, SSL_SESSION*> HostPortMap;
272 // cache on the client certificate used in addition to the host-port pair.
273 typedef std::map<HostPortPair, SSL_SESSION*> HostPortMap;
274 typedef std::map<SSL_SESSION*, HostPortMap::iterator> SessionMap; 292 typedef std::map<SSL_SESSION*, HostPortMap::iterator> SessionMap;
275 HostPortMap host_port_map_; 293 HostPortMap host_port_map_;
276 SessionMap session_map_; 294 SessionMap session_map_;
277 295
278 // Protects access to both the above maps. 296 // Protects access to both the above maps.
279 base::Lock lock_; 297 base::Lock lock_;
280 298
281 DISALLOW_COPY_AND_ASSIGN(SSLSessionCache); 299 DISALLOW_COPY_AND_ASSIGN(SSLSessionCache);
282 }; 300 };
283 301
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after
322 NULL); 340 NULL);
323 #endif 341 #endif
324 } 342 }
325 343
326 static int NewSessionCallbackStatic(SSL* ssl, SSL_SESSION* session) { 344 static int NewSessionCallbackStatic(SSL* ssl, SSL_SESSION* session) {
327 return GetInstance()->NewSessionCallback(ssl, session); 345 return GetInstance()->NewSessionCallback(ssl, session);
328 } 346 }
329 347
330 int NewSessionCallback(SSL* ssl, SSL_SESSION* session) { 348 int NewSessionCallback(SSL* ssl, SSL_SESSION* session) {
331 SSLClientSocketOpenSSL* socket = GetClientSocketFromSSL(ssl); 349 SSLClientSocketOpenSSL* socket = GetClientSocketFromSSL(ssl);
332 session_cache_.OnSessionAdded(socket->host_and_port(), session); 350 session_cache_.OnSessionAdded(socket->host_and_port(),
351 socket->ssl_session_cache_shard(),
352 session);
333 return 1; // 1 => We took ownership of |session|. 353 return 1; // 1 => We took ownership of |session|.
334 } 354 }
335 355
336 static void RemoveSessionCallbackStatic(SSL_CTX* ctx, SSL_SESSION* session) { 356 static void RemoveSessionCallbackStatic(SSL_CTX* ctx, SSL_SESSION* session) {
337 return GetInstance()->RemoveSessionCallback(ctx, session); 357 return GetInstance()->RemoveSessionCallback(ctx, session);
338 } 358 }
339 359
340 void RemoveSessionCallback(SSL_CTX* ctx, SSL_SESSION* session) { 360 void RemoveSessionCallback(SSL_CTX* ctx, SSL_SESSION* session) {
341 DCHECK(ctx == ssl_ctx()); 361 DCHECK(ctx == ssl_ctx());
342 session_cache_.OnSessionRemoved(session); 362 session_cache_.OnSessionRemoved(session);
(...skipping 10 matching lines...) Expand all
353 const unsigned char* in, 373 const unsigned char* in,
354 unsigned int inlen, void* arg) { 374 unsigned int inlen, void* arg) {
355 SSLClientSocketOpenSSL* socket = GetInstance()->GetClientSocketFromSSL(ssl); 375 SSLClientSocketOpenSSL* socket = GetInstance()->GetClientSocketFromSSL(ssl);
356 return socket->SelectNextProtoCallback(out, outlen, in, inlen); 376 return socket->SelectNextProtoCallback(out, outlen, in, inlen);
357 } 377 }
358 378
359 // This is the index used with SSL_get_ex_data to retrieve the owner 379 // This is the index used with SSL_get_ex_data to retrieve the owner
360 // SSLClientSocketOpenSSL object from an SSL instance. 380 // SSLClientSocketOpenSSL object from an SSL instance.
361 int ssl_socket_data_index_; 381 int ssl_socket_data_index_;
362 382
383 // session_cache_ must appear before |ssl_ctx_| because the destruction of
384 // |ssl_ctx_| may trigger callbacks into |session_cache_|. Therefore,
385 // |session_cache_| must be destructed after |ssl_ctx_|.
386 SSLSessionCache session_cache_;
363 crypto::ScopedOpenSSL<SSL_CTX, SSL_CTX_free> ssl_ctx_; 387 crypto::ScopedOpenSSL<SSL_CTX, SSL_CTX_free> ssl_ctx_;
364 SSLSessionCache session_cache_;
365 }; 388 };
366 389
367 // Utility to construct the appropriate set & clear masks for use the OpenSSL 390 // Utility to construct the appropriate set & clear masks for use the OpenSSL
368 // options and mode configuration functions. (SSL_set_options etc) 391 // options and mode configuration functions. (SSL_set_options etc)
369 struct SslSetClearMask { 392 struct SslSetClearMask {
370 SslSetClearMask() : set_mask(0), clear_mask(0) {} 393 SslSetClearMask() : set_mask(0), clear_mask(0) {}
371 void ConfigureFlag(long flag, bool state) { 394 void ConfigureFlag(long flag, bool state) {
372 (state ? set_mask : clear_mask) |= flag; 395 (state ? set_mask : clear_mask) |= flag;
373 // Make sure we haven't got any intersection in the set & clear options. 396 // Make sure we haven't got any intersection in the set & clear options.
374 DCHECK_EQ(0, set_mask & clear_mask) << flag << ":" << state; 397 DCHECK_EQ(0, set_mask & clear_mask) << flag << ":" << state;
375 } 398 }
376 long set_mask; 399 long set_mask;
377 long clear_mask; 400 long clear_mask;
378 }; 401 };
379 402
380 } // namespace 403 } // namespace
381 404
405 // static
406 void SSLClientSocket::ClearSessionCache() {
407 SSLContext* context = SSLContext::GetInstance();
408 context->session_cache()->Flush();
409 }
410
382 SSLClientSocketOpenSSL::SSLClientSocketOpenSSL( 411 SSLClientSocketOpenSSL::SSLClientSocketOpenSSL(
383 ClientSocketHandle* transport_socket, 412 ClientSocketHandle* transport_socket,
384 const HostPortPair& host_and_port, 413 const HostPortPair& host_and_port,
385 const SSLConfig& ssl_config, 414 const SSLConfig& ssl_config,
386 const SSLClientSocketContext& context) 415 const SSLClientSocketContext& context)
387 : transport_send_busy_(false), 416 : transport_send_busy_(false),
388 transport_recv_busy_(false), 417 transport_recv_busy_(false),
389 completed_handshake_(false), 418 completed_handshake_(false),
390 client_auth_cert_needed_(false), 419 client_auth_cert_needed_(false),
391 cert_verifier_(context.cert_verifier), 420 cert_verifier_(context.cert_verifier),
392 ssl_(NULL), 421 ssl_(NULL),
393 transport_bio_(NULL), 422 transport_bio_(NULL),
394 transport_(transport_socket), 423 transport_(transport_socket),
395 host_and_port_(host_and_port), 424 host_and_port_(host_and_port),
396 ssl_config_(ssl_config), 425 ssl_config_(ssl_config),
426 ssl_session_cache_shard_(context.ssl_session_cache_shard),
397 trying_cached_session_(false), 427 trying_cached_session_(false),
398 npn_status_(kNextProtoUnsupported), 428 npn_status_(kNextProtoUnsupported),
399 net_log_(transport_socket->socket()->NetLog()) { 429 net_log_(transport_socket->socket()->NetLog()) {
400 } 430 }
401 431
402 SSLClientSocketOpenSSL::~SSLClientSocketOpenSSL() { 432 SSLClientSocketOpenSSL::~SSLClientSocketOpenSSL() {
403 Disconnect(); 433 Disconnect();
404 } 434 }
405 435
406 bool SSLClientSocketOpenSSL::Init() { 436 bool SSLClientSocketOpenSSL::Init() {
407 DCHECK(!ssl_); 437 DCHECK(!ssl_);
408 DCHECK(!transport_bio_); 438 DCHECK(!transport_bio_);
409 439
410 SSLContext* context = SSLContext::GetInstance(); 440 SSLContext* context = SSLContext::GetInstance();
411 crypto::OpenSSLErrStackTracer err_tracer(FROM_HERE); 441 crypto::OpenSSLErrStackTracer err_tracer(FROM_HERE);
412 442
413 ssl_ = SSL_new(context->ssl_ctx()); 443 ssl_ = SSL_new(context->ssl_ctx());
414 if (!ssl_ || !context->SetClientSocketForSSL(ssl_, this)) 444 if (!ssl_ || !context->SetClientSocketForSSL(ssl_, this))
415 return false; 445 return false;
416 446
417 if (!SSL_set_tlsext_host_name(ssl_, host_and_port_.host().c_str())) 447 if (!SSL_set_tlsext_host_name(ssl_, host_and_port_.host().c_str()))
418 return false; 448 return false;
419 449
420 trying_cached_session_ = 450 trying_cached_session_ =
421 context->session_cache()->SetSSLSession(ssl_, host_and_port_); 451 context->session_cache()->SetSSLSession(ssl_, host_and_port_,
452 ssl_session_cache_shard_);
422 453
423 BIO* ssl_bio = NULL; 454 BIO* ssl_bio = NULL;
424 // 0 => use default buffer sizes. 455 // 0 => use default buffer sizes.
425 if (!BIO_new_bio_pair(&ssl_bio, 0, &transport_bio_, 0)) 456 if (!BIO_new_bio_pair(&ssl_bio, 0, &transport_bio_, 0))
426 return false; 457 return false;
427 DCHECK(ssl_bio); 458 DCHECK(ssl_bio);
428 DCHECK(transport_bio_); 459 DCHECK(transport_bio_);
429 460
430 SSL_set_bio(ssl_, ssl_bio, ssl_bio); 461 SSL_set_bio(ssl_, ssl_bio, ssl_bio);
431 462
(...skipping 212 matching lines...) Expand 10 before | Expand all | Expand 10 after
644 user_connect_callback_ = callback; 675 user_connect_callback_ = callback;
645 } else { 676 } else {
646 net_log_.EndEventWithNetErrorCode(NetLog::TYPE_SSL_CONNECT, rv); 677 net_log_.EndEventWithNetErrorCode(NetLog::TYPE_SSL_CONNECT, rv);
647 } 678 }
648 679
649 return rv > OK ? OK : rv; 680 return rv > OK ? OK : rv;
650 } 681 }
651 682
652 void SSLClientSocketOpenSSL::Disconnect() { 683 void SSLClientSocketOpenSSL::Disconnect() {
653 if (ssl_) { 684 if (ssl_) {
685 // Calling SSL_shutdown prevents the session from being marked as
686 // unresumable.
687 SSL_shutdown(ssl_);
654 SSL_free(ssl_); 688 SSL_free(ssl_);
655 ssl_ = NULL; 689 ssl_ = NULL;
656 } 690 }
657 if (transport_bio_) { 691 if (transport_bio_) {
658 BIO_free_all(transport_bio_); 692 BIO_free_all(transport_bio_);
659 transport_bio_ = NULL; 693 transport_bio_ = NULL;
660 } 694 }
661 695
662 // Shut down anything that may call us back. 696 // Shut down anything that may call us back.
663 verifier_.reset(); 697 verifier_.reset();
(...skipping 581 matching lines...) Expand 10 before | Expand all | Expand 10 after
1245 net_log_.AddByteTransferEvent(NetLog::TYPE_SSL_SOCKET_BYTES_SENT, rv, 1279 net_log_.AddByteTransferEvent(NetLog::TYPE_SSL_SOCKET_BYTES_SENT, rv,
1246 user_write_buf_->data()); 1280 user_write_buf_->data());
1247 return rv; 1281 return rv;
1248 } 1282 }
1249 1283
1250 int err = SSL_get_error(ssl_, rv); 1284 int err = SSL_get_error(ssl_, rv);
1251 return MapOpenSSLError(err, err_tracer); 1285 return MapOpenSSLError(err, err_tracer);
1252 } 1286 }
1253 1287
1254 } // namespace net 1288 } // namespace net
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698