OLD | NEW |
1 // Copyright 2013 The Chromium Authors. All rights reserved. | 1 // Copyright 2013 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 #include "net/socket/ssl_session_cache_openssl.h" | 5 #include "net/socket/ssl_session_cache_openssl.h" |
6 | 6 |
7 #include <list> | 7 #include <list> |
8 #include <map> | 8 #include <map> |
9 | 9 |
10 #include <openssl/rand.h> | 10 #include <openssl/rand.h> |
11 #include <openssl/ssl.h> | 11 #include <openssl/ssl.h> |
12 | 12 |
13 #include "base/containers/hash_tables.h" | 13 #include "base/containers/hash_tables.h" |
14 #include "base/lazy_instance.h" | 14 #include "base/lazy_instance.h" |
15 #include "base/logging.h" | 15 #include "base/logging.h" |
16 #include "base/profiler/scoped_tracker.h" | |
17 #include "base/synchronization/lock.h" | 16 #include "base/synchronization/lock.h" |
18 | 17 |
19 namespace net { | 18 namespace net { |
20 | 19 |
21 namespace { | 20 namespace { |
22 | 21 |
23 // A helper class to lazily create a new EX_DATA index to map SSL_CTX handles | 22 // A helper class to lazily create a new EX_DATA index to map SSL_CTX handles |
24 // to their corresponding SSLSessionCacheOpenSSLImpl object. | 23 // to their corresponding SSLSessionCacheOpenSSLImpl object. |
25 class SSLContextExIndex { | 24 class SSLContextExIndex { |
26 public: | 25 public: |
(...skipping 123 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
150 | 149 |
151 class SSLSessionCacheOpenSSLImpl { | 150 class SSLSessionCacheOpenSSLImpl { |
152 public: | 151 public: |
153 // Construct new instance. This registers various hooks into the SSL_CTX | 152 // Construct new instance. This registers various hooks into the SSL_CTX |
154 // context |ctx|. OpenSSL will call back during SSL connection | 153 // context |ctx|. OpenSSL will call back during SSL connection |
155 // operations. |key_func| is used to map a SSL handle to a unique cache | 154 // operations. |key_func| is used to map a SSL handle to a unique cache |
156 // string, according to the client's preferences. | 155 // string, according to the client's preferences. |
157 SSLSessionCacheOpenSSLImpl(SSL_CTX* ctx, | 156 SSLSessionCacheOpenSSLImpl(SSL_CTX* ctx, |
158 const SSLSessionCacheOpenSSL::Config& config) | 157 const SSLSessionCacheOpenSSL::Config& config) |
159 : ctx_(ctx), config_(config), expiration_check_(0) { | 158 : ctx_(ctx), config_(config), expiration_check_(0) { |
160 // TODO(vadimt): Remove ScopedTracker below once crbug.com/424386 is fixed. | |
161 tracked_objects::ScopedTracker tracking_profile( | |
162 FROM_HERE_WITH_EXPLICIT_FUNCTION( | |
163 "424386 SSLSessionCacheOpenSSLImpl::SSLSessionCacheOpenSSLImpl")); | |
164 | |
165 DCHECK(ctx); | 159 DCHECK(ctx); |
166 | 160 |
167 // NO_INTERNAL_STORE disables OpenSSL's builtin cache, and | 161 // NO_INTERNAL_STORE disables OpenSSL's builtin cache, and |
168 // NO_AUTO_CLEAR disables the call to SSL_CTX_flush_sessions | 162 // NO_AUTO_CLEAR disables the call to SSL_CTX_flush_sessions |
169 // every 256 connections (this number is hard-coded in the library | 163 // every 256 connections (this number is hard-coded in the library |
170 // and can't be changed). | 164 // and can't be changed). |
171 SSL_CTX_set_session_cache_mode(ctx_, | 165 SSL_CTX_set_session_cache_mode(ctx_, |
172 SSL_SESS_CACHE_CLIENT | | 166 SSL_SESS_CACHE_CLIENT | |
173 SSL_SESS_CACHE_NO_INTERNAL_STORE | | 167 SSL_SESS_CACHE_NO_INTERNAL_STORE | |
174 SSL_SESS_CACHE_NO_AUTO_CLEAR); | 168 SSL_SESS_CACHE_NO_AUTO_CLEAR); |
(...skipping 20 matching lines...) Expand all Loading... |
195 | 189 |
196 // Retrieve the cache key from |ssl| and look for a corresponding | 190 // Retrieve the cache key from |ssl| and look for a corresponding |
197 // cached session ID. If one is found, call SSL_set_session() to associate | 191 // cached session ID. If one is found, call SSL_set_session() to associate |
198 // it with the |ssl| connection. | 192 // it with the |ssl| connection. |
199 // | 193 // |
200 // Will also check for expired sessions every |expiration_check_count| | 194 // Will also check for expired sessions every |expiration_check_count| |
201 // calls. | 195 // calls. |
202 // | 196 // |
203 // Return true if a cached session ID was found, false otherwise. | 197 // Return true if a cached session ID was found, false otherwise. |
204 bool SetSSLSession(SSL* ssl) { | 198 bool SetSSLSession(SSL* ssl) { |
205 // TODO(vadimt): Remove ScopedTracker below once crbug.com/424386 is fixed. | |
206 tracked_objects::ScopedTracker tracking_profile( | |
207 FROM_HERE_WITH_EXPLICIT_FUNCTION( | |
208 "424386 SSLSessionCacheOpenSSLImpl::SetSSLSession")); | |
209 | |
210 std::string cache_key = config_.key_func(ssl); | 199 std::string cache_key = config_.key_func(ssl); |
211 if (cache_key.empty()) | 200 if (cache_key.empty()) |
212 return false; | 201 return false; |
213 | 202 |
214 return SetSSLSessionWithKey(ssl, cache_key); | 203 return SetSSLSessionWithKey(ssl, cache_key); |
215 } | 204 } |
216 | 205 |
217 // Variant of SetSSLSession to be used when the client already has computed | 206 // Variant of SetSSLSession to be used when the client already has computed |
218 // the cache key. Avoid a call to the configuration's |key_func| function. | 207 // the cache key. Avoid a call to the configuration's |key_func| function. |
219 bool SetSSLSessionWithKey(SSL* ssl, const std::string& cache_key) { | 208 bool SetSSLSessionWithKey(SSL* ssl, const std::string& cache_key) { |
220 // TODO(vadimt): Remove ScopedTracker below once crbug.com/424386 is fixed. | |
221 tracked_objects::ScopedTracker tracking_profile( | |
222 FROM_HERE_WITH_EXPLICIT_FUNCTION( | |
223 "424386 SSLSessionCacheOpenSSLImpl::SetSSLSessionWithKey")); | |
224 | |
225 base::AutoLock locked(lock_); | 209 base::AutoLock locked(lock_); |
226 | 210 |
227 DCHECK_EQ(config_.key_func(ssl), cache_key); | 211 DCHECK_EQ(config_.key_func(ssl), cache_key); |
228 | 212 |
229 if (++expiration_check_ >= config_.expiration_check_count) { | 213 if (++expiration_check_ >= config_.expiration_check_count) { |
230 expiration_check_ = 0; | 214 expiration_check_ = 0; |
231 FlushExpiredSessionsLocked(); | 215 FlushExpiredSessionsLocked(); |
232 } | 216 } |
233 | 217 |
234 KeyIndex::iterator it = key_index_.find(cache_key); | 218 KeyIndex::iterator it = key_index_.find(cache_key); |
(...skipping 12 matching lines...) Expand all Loading... |
247 | 231 |
248 // Move to front of MRU list. | 232 // Move to front of MRU list. |
249 ordering_.push_front(session); | 233 ordering_.push_front(session); |
250 ordering_.erase(it->second); | 234 ordering_.erase(it->second); |
251 it->second = ordering_.begin(); | 235 it->second = ordering_.begin(); |
252 | 236 |
253 return SSL_set_session(ssl, session) == 1; | 237 return SSL_set_session(ssl, session) == 1; |
254 } | 238 } |
255 | 239 |
256 void MarkSSLSessionAsGood(SSL* ssl) { | 240 void MarkSSLSessionAsGood(SSL* ssl) { |
257 // TODO(vadimt): Remove ScopedTracker below once crbug.com/424386 is fixed. | |
258 tracked_objects::ScopedTracker tracking_profile( | |
259 FROM_HERE_WITH_EXPLICIT_FUNCTION( | |
260 "424386 SSLSessionCacheOpenSSLImpl::MarkSSLSessionAsGood")); | |
261 | |
262 SSL_SESSION* session = SSL_get_session(ssl); | 241 SSL_SESSION* session = SSL_get_session(ssl); |
263 if (!session) | 242 if (!session) |
264 return; | 243 return; |
265 | 244 |
266 // Mark the session as good, allowing it to be used for future connections. | 245 // Mark the session as good, allowing it to be used for future connections. |
267 SSL_SESSION_set_ex_data( | 246 SSL_SESSION_set_ex_data( |
268 session, GetSSLSessionExIndex(), reinterpret_cast<void*>(1)); | 247 session, GetSSLSessionExIndex(), reinterpret_cast<void*>(1)); |
269 } | 248 } |
270 | 249 |
271 // Flush all entries from the cache. | 250 // Flush all entries from the cache. |
272 void Flush() { | 251 void Flush() { |
273 // TODO(vadimt): Remove ScopedTracker below once crbug.com/424386 is fixed. | |
274 tracked_objects::ScopedTracker tracking_profile( | |
275 FROM_HERE_WITH_EXPLICIT_FUNCTION( | |
276 "424386 SSLSessionCacheOpenSSLImpl::Flush")); | |
277 | |
278 base::AutoLock lock(lock_); | 252 base::AutoLock lock(lock_); |
279 id_index_.clear(); | 253 id_index_.clear(); |
280 key_index_.clear(); | 254 key_index_.clear(); |
281 while (!ordering_.empty()) { | 255 while (!ordering_.empty()) { |
282 SSL_SESSION* session = ordering_.front(); | 256 SSL_SESSION* session = ordering_.front(); |
283 ordering_.pop_front(); | 257 ordering_.pop_front(); |
284 SSL_SESSION_free(session); | 258 SSL_SESSION_free(session); |
285 } | 259 } |
286 } | 260 } |
287 | 261 |
(...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
362 DCHECK(result); | 336 DCHECK(result); |
363 return reinterpret_cast<SSLSessionCacheOpenSSLImpl*>(result); | 337 return reinterpret_cast<SSLSessionCacheOpenSSLImpl*>(result); |
364 } | 338 } |
365 | 339 |
366 // Called by OpenSSL when a new |session| was created and added to a given | 340 // Called by OpenSSL when a new |session| was created and added to a given |
367 // |ssl| connection. Note that the session's reference count was already | 341 // |ssl| connection. Note that the session's reference count was already |
368 // incremented before the function is entered. The function must return 1 | 342 // incremented before the function is entered. The function must return 1 |
369 // to indicate that it took ownership of the session, i.e. that the caller | 343 // to indicate that it took ownership of the session, i.e. that the caller |
370 // should not decrement its reference count after completion. | 344 // should not decrement its reference count after completion. |
371 static int NewSessionCallbackStatic(SSL* ssl, SSL_SESSION* session) { | 345 static int NewSessionCallbackStatic(SSL* ssl, SSL_SESSION* session) { |
372 // TODO(vadimt): Remove ScopedTracker below once crbug.com/424386 is fixed. | |
373 tracked_objects::ScopedTracker tracking_profile( | |
374 FROM_HERE_WITH_EXPLICIT_FUNCTION( | |
375 "424386 SSLSessionCacheOpenSSLImpl::NewSessionCallbackStatic")); | |
376 | |
377 GetCache(ssl->ctx)->OnSessionAdded(ssl, session); | 346 GetCache(ssl->ctx)->OnSessionAdded(ssl, session); |
378 return 1; | 347 return 1; |
379 } | 348 } |
380 | 349 |
381 // Called by OpenSSL to indicate that a session must be removed from the | 350 // Called by OpenSSL to indicate that a session must be removed from the |
382 // cache. This happens when SSL_CTX is destroyed. | 351 // cache. This happens when SSL_CTX is destroyed. |
383 static void RemoveSessionCallbackStatic(SSL_CTX* ctx, SSL_SESSION* session) { | 352 static void RemoveSessionCallbackStatic(SSL_CTX* ctx, SSL_SESSION* session) { |
384 // TODO(vadimt): Remove ScopedTracker below once crbug.com/424386 is fixed. | |
385 tracked_objects::ScopedTracker tracking_profile( | |
386 FROM_HERE_WITH_EXPLICIT_FUNCTION( | |
387 "424386 SSLSessionCacheOpenSSLImpl::RemoveSessionCallbackStatic")); | |
388 | |
389 GetCache(ctx)->OnSessionRemoved(session); | 353 GetCache(ctx)->OnSessionRemoved(session); |
390 } | 354 } |
391 | 355 |
392 // Called by OpenSSL to generate a new session ID. This happens during a | 356 // Called by OpenSSL to generate a new session ID. This happens during a |
393 // SSL connection operation, when the SSL object doesn't have a session yet. | 357 // SSL connection operation, when the SSL object doesn't have a session yet. |
394 // | 358 // |
395 // A session ID is a random string of bytes used to uniquely identify the | 359 // A session ID is a random string of bytes used to uniquely identify the |
396 // session between a client and a server. | 360 // session between a client and a server. |
397 // | 361 // |
398 // |ssl| is a SSL connection handle. Ignored here. | 362 // |ssl| is a SSL connection handle. Ignored here. |
399 // |id| is the target buffer where the ID must be generated. | 363 // |id| is the target buffer where the ID must be generated. |
400 // |*id_len| is, on input, the size of the desired ID. It will be 16 for | 364 // |*id_len| is, on input, the size of the desired ID. It will be 16 for |
401 // SSLv2, and 32 for anything else. OpenSSL allows an implementation | 365 // SSLv2, and 32 for anything else. OpenSSL allows an implementation |
402 // to change it on output, but this will not happen here. | 366 // to change it on output, but this will not happen here. |
403 // | 367 // |
404 // The function must ensure the generated ID is really unique, i.e. that | 368 // The function must ensure the generated ID is really unique, i.e. that |
405 // another session in the cache doesn't already use the same value. It must | 369 // another session in the cache doesn't already use the same value. It must |
406 // return 1 to indicate success, or 0 for failure. | 370 // return 1 to indicate success, or 0 for failure. |
407 static int GenerateSessionIdStatic(const SSL* ssl, | 371 static int GenerateSessionIdStatic(const SSL* ssl, |
408 unsigned char* id, | 372 unsigned char* id, |
409 unsigned* id_len) { | 373 unsigned* id_len) { |
410 // TODO(vadimt): Remove ScopedTracker below once crbug.com/424386 is fixed. | |
411 tracked_objects::ScopedTracker tracking_profile( | |
412 FROM_HERE_WITH_EXPLICIT_FUNCTION( | |
413 "424386 SSLSessionCacheOpenSSLImpl::GenerateSessionIdStatic")); | |
414 | |
415 if (!GetCache(ssl->ctx)->OnGenerateSessionId(id, *id_len)) | 374 if (!GetCache(ssl->ctx)->OnGenerateSessionId(id, *id_len)) |
416 return 0; | 375 return 0; |
417 | 376 |
418 return 1; | 377 return 1; |
419 } | 378 } |
420 | 379 |
421 // Add |session| to the cache in association with |cache_key|. If a session | 380 // Add |session| to the cache in association with |cache_key|. If a session |
422 // already exists, it is replaced with the new one. This assumes that the | 381 // already exists, it is replaced with the new one. This assumes that the |
423 // caller already incremented the session's reference count. | 382 // caller already incremented the session's reference count. |
424 void OnSessionAdded(SSL* ssl, SSL_SESSION* session) { | 383 void OnSessionAdded(SSL* ssl, SSL_SESSION* session) { |
(...skipping 116 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
541 return impl_->SetSSLSessionWithKey(ssl, cache_key); | 500 return impl_->SetSSLSessionWithKey(ssl, cache_key); |
542 } | 501 } |
543 | 502 |
544 void SSLSessionCacheOpenSSL::MarkSSLSessionAsGood(SSL* ssl) { | 503 void SSLSessionCacheOpenSSL::MarkSSLSessionAsGood(SSL* ssl) { |
545 return impl_->MarkSSLSessionAsGood(ssl); | 504 return impl_->MarkSSLSessionAsGood(ssl); |
546 } | 505 } |
547 | 506 |
548 void SSLSessionCacheOpenSSL::Flush() { impl_->Flush(); } | 507 void SSLSessionCacheOpenSSL::Flush() { impl_->Flush(); } |
549 | 508 |
550 } // namespace net | 509 } // namespace net |
OLD | NEW |