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

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.
joth 2011/12/09 23:28:37 per unique HostPortPair per shard.
agl 2011/12/12 22:18:20 Done.
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 << " => "
240 << it->second->first.ToString(); 244 << it->second->first;
joth 2011/12/09 23:28:37 nit: no need to line break
agl 2011/12/12 22:18:20 Done.
241 DCHECK(it->second->second == session); 245 DCHECK(it->second->second == session);
242 host_port_map_.erase(it->second); 246 host_port_map_.erase(it->second);
243 session_map_.erase(it); 247 session_map_.erase(it);
244 session_to_free.reset(session); 248 session_to_free.reset(session);
245 DCHECK_EQ(host_port_map_.size(), session_map_.size()); 249 DCHECK_EQ(host_port_map_.size(), session_map_.size());
246 } 250 }
247 251
248 // Looks up the host:port in the cache, and if a session is found it is added 252 // Looks up the host:port in the cache, and if a session is found it is added
249 // to |ssl|, returning true on success. 253 // to |ssl|, returning true on success.
250 bool SetSSLSession(SSL* ssl, const HostPortPair& host_and_port) { 254 bool SetSSLSession(SSL* ssl, const HostPortPair& host_and_port,
255 const std::string& shard) {
251 base::AutoLock lock(lock_); 256 base::AutoLock lock(lock_);
252 HostPortMap::iterator it = host_port_map_.find(host_and_port); 257 const std::string cache_key = GetCacheKey(host_and_port, shard);
258 HostPortMap::iterator it = host_port_map_.find(cache_key);
253 if (it == host_port_map_.end()) 259 if (it == host_port_map_.end())
254 return false; 260 return false;
255 DVLOG(2) << "Lookup session: " << it->second << " => " 261 DVLOG(2) << "Lookup session: " << it->second << " => "
256 << host_and_port.ToString(); 262 << cache_key;
joth 2011/12/09 23:28:37 nit: no need for line break
agl 2011/12/12 22:18:20 Done.
257 SSL_SESSION* session = it->second; 263 SSL_SESSION* session = it->second;
258 DCHECK(session); 264 DCHECK(session);
259 DCHECK(session_map_[session] == it); 265 DCHECK(session_map_[session] == it);
260 // Ideally we'd release |lock_| before calling into OpenSSL here, however 266 // 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. 267 // 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|, 268 // 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. 269 // except OpenSSL does not provide a public API for adding a ref (c.f.
264 // SSL_SESSION_free which decrements the ref). 270 // SSL_SESSION_free which decrements the ref).
265 return SSL_set_session(ssl, session) == 1; 271 return SSL_set_session(ssl, session) == 1;
266 } 272 }
267 273
274 // Flush removes all entries from the cache. This is called when a client
275 // certificate is added.
276 void Flush() {
277 for (HostPortMap::iterator i = host_port_map_.begin();
278 i != host_port_map_.end(); i++) {
279 SSL_SESSION_free(i->second);
280 }
281 host_port_map_.clear();
282 session_map_.clear();
283 }
284
268 private: 285 private:
286 static std::string GetCacheKey(const HostPortPair& host_and_port,
287 const std::string& shard) {
288 return host_and_port.ToString() + "/" + shard;
289 }
290
269 // A pair of maps to allow bi-directional lookups between host:port and an 291 // A pair of maps to allow bi-directional lookups between host:port and an
270 // associated session. 292 // associated session.
271 // TODO(joth): When client certificates are implemented we should key the 293 typedef std::map<std::string, SSL_SESSION*> HostPortMap;
272 // cache on the client certificate used in addition to the host-port pair.
joth 2011/12/09 23:28:37 thanks for handling this one too. if I've followed
agl 2011/12/12 22:18:20 Right. And when we add a new client-cert, we flush
273 typedef std::map<HostPortPair, SSL_SESSION*> HostPortMap;
274 typedef std::map<SSL_SESSION*, HostPortMap::iterator> SessionMap; 294 typedef std::map<SSL_SESSION*, HostPortMap::iterator> SessionMap;
275 HostPortMap host_port_map_; 295 HostPortMap host_port_map_;
276 SessionMap session_map_; 296 SessionMap session_map_;
277 297
278 // Protects access to both the above maps. 298 // Protects access to both the above maps.
279 base::Lock lock_; 299 base::Lock lock_;
280 300
281 DISALLOW_COPY_AND_ASSIGN(SSLSessionCache); 301 DISALLOW_COPY_AND_ASSIGN(SSLSessionCache);
282 }; 302 };
283 303
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after
322 NULL); 342 NULL);
323 #endif 343 #endif
324 } 344 }
325 345
326 static int NewSessionCallbackStatic(SSL* ssl, SSL_SESSION* session) { 346 static int NewSessionCallbackStatic(SSL* ssl, SSL_SESSION* session) {
327 return GetInstance()->NewSessionCallback(ssl, session); 347 return GetInstance()->NewSessionCallback(ssl, session);
328 } 348 }
329 349
330 int NewSessionCallback(SSL* ssl, SSL_SESSION* session) { 350 int NewSessionCallback(SSL* ssl, SSL_SESSION* session) {
331 SSLClientSocketOpenSSL* socket = GetClientSocketFromSSL(ssl); 351 SSLClientSocketOpenSSL* socket = GetClientSocketFromSSL(ssl);
332 session_cache_.OnSessionAdded(socket->host_and_port(), session); 352 session_cache_.OnSessionAdded(socket->host_and_port(),
353 socket->session_cache_shard(),
354 session);
333 return 1; // 1 => We took ownership of |session|. 355 return 1; // 1 => We took ownership of |session|.
334 } 356 }
335 357
336 static void RemoveSessionCallbackStatic(SSL_CTX* ctx, SSL_SESSION* session) { 358 static void RemoveSessionCallbackStatic(SSL_CTX* ctx, SSL_SESSION* session) {
337 return GetInstance()->RemoveSessionCallback(ctx, session); 359 return GetInstance()->RemoveSessionCallback(ctx, session);
338 } 360 }
339 361
340 void RemoveSessionCallback(SSL_CTX* ctx, SSL_SESSION* session) { 362 void RemoveSessionCallback(SSL_CTX* ctx, SSL_SESSION* session) {
341 DCHECK(ctx == ssl_ctx()); 363 DCHECK(ctx == ssl_ctx());
342 session_cache_.OnSessionRemoved(session); 364 session_cache_.OnSessionRemoved(session);
(...skipping 10 matching lines...) Expand all
353 const unsigned char* in, 375 const unsigned char* in,
354 unsigned int inlen, void* arg) { 376 unsigned int inlen, void* arg) {
355 SSLClientSocketOpenSSL* socket = GetInstance()->GetClientSocketFromSSL(ssl); 377 SSLClientSocketOpenSSL* socket = GetInstance()->GetClientSocketFromSSL(ssl);
356 return socket->SelectNextProtoCallback(out, outlen, in, inlen); 378 return socket->SelectNextProtoCallback(out, outlen, in, inlen);
357 } 379 }
358 380
359 // This is the index used with SSL_get_ex_data to retrieve the owner 381 // This is the index used with SSL_get_ex_data to retrieve the owner
360 // SSLClientSocketOpenSSL object from an SSL instance. 382 // SSLClientSocketOpenSSL object from an SSL instance.
361 int ssl_socket_data_index_; 383 int ssl_socket_data_index_;
362 384
385 // session_cache_ must appear before |ssl_ctx_| because the destruction of
386 // |ssl_ctx_| may trigger callbacks into |session_cache_|. Therefore,
387 // |session_cache_| must be destructed after |ssl_ctx_|.
388 SSLSessionCache session_cache_;
363 crypto::ScopedOpenSSL<SSL_CTX, SSL_CTX_free> ssl_ctx_; 389 crypto::ScopedOpenSSL<SSL_CTX, SSL_CTX_free> ssl_ctx_;
364 SSLSessionCache session_cache_;
365 }; 390 };
366 391
367 // Utility to construct the appropriate set & clear masks for use the OpenSSL 392 // Utility to construct the appropriate set & clear masks for use the OpenSSL
368 // options and mode configuration functions. (SSL_set_options etc) 393 // options and mode configuration functions. (SSL_set_options etc)
369 struct SslSetClearMask { 394 struct SslSetClearMask {
370 SslSetClearMask() : set_mask(0), clear_mask(0) {} 395 SslSetClearMask() : set_mask(0), clear_mask(0) {}
371 void ConfigureFlag(long flag, bool state) { 396 void ConfigureFlag(long flag, bool state) {
372 (state ? set_mask : clear_mask) |= flag; 397 (state ? set_mask : clear_mask) |= flag;
373 // Make sure we haven't got any intersection in the set & clear options. 398 // Make sure we haven't got any intersection in the set & clear options.
374 DCHECK_EQ(0, set_mask & clear_mask) << flag << ":" << state; 399 DCHECK_EQ(0, set_mask & clear_mask) << flag << ":" << state;
375 } 400 }
376 long set_mask; 401 long set_mask;
377 long clear_mask; 402 long clear_mask;
378 }; 403 };
379 404
380 } // namespace 405 } // namespace
381 406
407 // static
408 void SSLClientSocket::ClearSessionCache() {
409 SSLContext* context = SSLContext::GetInstance();
410 context->session_cache()->Flush();
411 }
412
382 SSLClientSocketOpenSSL::SSLClientSocketOpenSSL( 413 SSLClientSocketOpenSSL::SSLClientSocketOpenSSL(
383 ClientSocketHandle* transport_socket, 414 ClientSocketHandle* transport_socket,
384 const HostPortPair& host_and_port, 415 const HostPortPair& host_and_port,
385 const SSLConfig& ssl_config, 416 const SSLConfig& ssl_config,
386 const SSLClientSocketContext& context) 417 const SSLClientSocketContext& context)
387 : ALLOW_THIS_IN_INITIALIZER_LIST(buffer_send_callback_( 418 : ALLOW_THIS_IN_INITIALIZER_LIST(buffer_send_callback_(
388 this, &SSLClientSocketOpenSSL::BufferSendComplete)), 419 this, &SSLClientSocketOpenSSL::BufferSendComplete)),
389 ALLOW_THIS_IN_INITIALIZER_LIST(buffer_recv_callback_( 420 ALLOW_THIS_IN_INITIALIZER_LIST(buffer_recv_callback_(
390 this, &SSLClientSocketOpenSSL::BufferRecvComplete)), 421 this, &SSLClientSocketOpenSSL::BufferRecvComplete)),
391 transport_send_busy_(false), 422 transport_send_busy_(false),
392 transport_recv_busy_(false), 423 transport_recv_busy_(false),
393 old_user_connect_callback_(NULL), 424 old_user_connect_callback_(NULL),
394 old_user_read_callback_(NULL), 425 old_user_read_callback_(NULL),
395 user_write_callback_(NULL), 426 user_write_callback_(NULL),
396 completed_handshake_(false), 427 completed_handshake_(false),
397 client_auth_cert_needed_(false), 428 client_auth_cert_needed_(false),
398 cert_verifier_(context.cert_verifier), 429 cert_verifier_(context.cert_verifier),
399 ssl_(NULL), 430 ssl_(NULL),
400 transport_bio_(NULL), 431 transport_bio_(NULL),
401 transport_(transport_socket), 432 transport_(transport_socket),
402 host_and_port_(host_and_port), 433 host_and_port_(host_and_port),
403 ssl_config_(ssl_config), 434 ssl_config_(ssl_config),
435 session_cache_shard_(context.session_cache_shard),
404 trying_cached_session_(false), 436 trying_cached_session_(false),
405 npn_status_(kNextProtoUnsupported), 437 npn_status_(kNextProtoUnsupported),
406 net_log_(transport_socket->socket()->NetLog()) { 438 net_log_(transport_socket->socket()->NetLog()) {
407 } 439 }
408 440
409 SSLClientSocketOpenSSL::~SSLClientSocketOpenSSL() { 441 SSLClientSocketOpenSSL::~SSLClientSocketOpenSSL() {
410 Disconnect(); 442 Disconnect();
411 } 443 }
412 444
413 bool SSLClientSocketOpenSSL::Init() { 445 bool SSLClientSocketOpenSSL::Init() {
414 DCHECK(!ssl_); 446 DCHECK(!ssl_);
415 DCHECK(!transport_bio_); 447 DCHECK(!transport_bio_);
416 448
417 SSLContext* context = SSLContext::GetInstance(); 449 SSLContext* context = SSLContext::GetInstance();
418 crypto::OpenSSLErrStackTracer err_tracer(FROM_HERE); 450 crypto::OpenSSLErrStackTracer err_tracer(FROM_HERE);
419 451
420 ssl_ = SSL_new(context->ssl_ctx()); 452 ssl_ = SSL_new(context->ssl_ctx());
421 if (!ssl_ || !context->SetClientSocketForSSL(ssl_, this)) 453 if (!ssl_ || !context->SetClientSocketForSSL(ssl_, this))
422 return false; 454 return false;
423 455
424 if (!SSL_set_tlsext_host_name(ssl_, host_and_port_.host().c_str())) 456 if (!SSL_set_tlsext_host_name(ssl_, host_and_port_.host().c_str()))
425 return false; 457 return false;
426 458
427 trying_cached_session_ = 459 trying_cached_session_ =
428 context->session_cache()->SetSSLSession(ssl_, host_and_port_); 460 context->session_cache()->SetSSLSession(ssl_, host_and_port_,
461 session_cache_shard_);
429 462
430 BIO* ssl_bio = NULL; 463 BIO* ssl_bio = NULL;
431 // 0 => use default buffer sizes. 464 // 0 => use default buffer sizes.
432 if (!BIO_new_bio_pair(&ssl_bio, 0, &transport_bio_, 0)) 465 if (!BIO_new_bio_pair(&ssl_bio, 0, &transport_bio_, 0))
433 return false; 466 return false;
434 DCHECK(ssl_bio); 467 DCHECK(ssl_bio);
435 DCHECK(transport_bio_); 468 DCHECK(transport_bio_);
436 469
437 SSL_set_bio(ssl_, ssl_bio, ssl_bio); 470 SSL_set_bio(ssl_, ssl_bio, ssl_bio);
438 471
(...skipping 244 matching lines...) Expand 10 before | Expand all | Expand 10 after
683 user_connect_callback_ = callback; 716 user_connect_callback_ = callback;
684 } else { 717 } else {
685 net_log_.EndEventWithNetErrorCode(NetLog::TYPE_SSL_CONNECT, rv); 718 net_log_.EndEventWithNetErrorCode(NetLog::TYPE_SSL_CONNECT, rv);
686 } 719 }
687 720
688 return rv > OK ? OK : rv; 721 return rv > OK ? OK : rv;
689 } 722 }
690 723
691 void SSLClientSocketOpenSSL::Disconnect() { 724 void SSLClientSocketOpenSSL::Disconnect() {
692 if (ssl_) { 725 if (ssl_) {
726 // Calling SSL_shutdown prevents the session from being marked as
727 // unresumable.
728 SSL_shutdown(ssl_);
693 SSL_free(ssl_); 729 SSL_free(ssl_);
694 ssl_ = NULL; 730 ssl_ = NULL;
695 } 731 }
696 if (transport_bio_) { 732 if (transport_bio_) {
697 BIO_free_all(transport_bio_); 733 BIO_free_all(transport_bio_);
698 transport_bio_ = NULL; 734 transport_bio_ = NULL;
699 } 735 }
700 736
701 // Shut down anything that may call us back. 737 // Shut down anything that may call us back.
702 verifier_.reset(); 738 verifier_.reset();
(...skipping 600 matching lines...) Expand 10 before | Expand all | Expand 10 after
1303 net_log_.AddByteTransferEvent(NetLog::TYPE_SSL_SOCKET_BYTES_SENT, rv, 1339 net_log_.AddByteTransferEvent(NetLog::TYPE_SSL_SOCKET_BYTES_SENT, rv,
1304 user_write_buf_->data()); 1340 user_write_buf_->data());
1305 return rv; 1341 return rv;
1306 } 1342 }
1307 1343
1308 int err = SSL_get_error(ssl_, rv); 1344 int err = SSL_get_error(ssl_, rv);
1309 return MapOpenSSLError(err, err_tracer); 1345 return MapOpenSSLError(err, err_tracer);
1310 } 1346 }
1311 1347
1312 } // namespace net 1348 } // namespace net
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698