| // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 
 | // Use of this source code is governed by a BSD-style license that can be | 
 | // found in the LICENSE file. | 
 |  | 
 | #include "crypto/openssl_util.h" | 
 |  | 
 | #include <openssl/err.h> | 
 | #include <openssl/ssl.h> | 
 | #include <openssl/cpu.h> | 
 |  | 
 | #include "base/logging.h" | 
 | #include "base/memory/scoped_vector.h" | 
 | #include "base/memory/singleton.h" | 
 | #include "base/strings/string_piece.h" | 
 | #include "base/synchronization/lock.h" | 
 | #include "build/build_config.h" | 
 |  | 
 | #if defined(OS_ANDROID) && defined(ARCH_CPU_ARMEL) | 
 | #include <cpu-features.h> | 
 | #include "base/cpu.h" | 
 | #endif | 
 |  | 
 | namespace crypto { | 
 |  | 
 | namespace { | 
 |  | 
 | void CurrentThreadId(CRYPTO_THREADID* id) { | 
 |   CRYPTO_THREADID_set_numeric( | 
 |       id, static_cast<unsigned long>(base::PlatformThread::CurrentId())); | 
 | } | 
 |  | 
 | // Singleton for initializing and cleaning up the OpenSSL library. | 
 | class OpenSSLInitSingleton { | 
 |  public: | 
 |   static OpenSSLInitSingleton* GetInstance() { | 
 |     // We allow the SSL environment to leak for multiple reasons: | 
 |     //   -  it is used from a non-joinable worker thread that is not stopped on | 
 |     //      shutdown, hence may still be using OpenSSL library after the AtExit | 
 |     //      runner has completed. | 
 |     //   -  There are other OpenSSL related singletons (e.g. the client socket | 
 |     //      context) who's cleanup depends on the global environment here, but | 
 |     //      we can't control the order the AtExit handlers will run in so | 
 |     //      allowing the global environment to leak at least ensures it is | 
 |     //      available for those other singletons to reliably cleanup. | 
 |     return Singleton<OpenSSLInitSingleton, | 
 |                LeakySingletonTraits<OpenSSLInitSingleton> >::get(); | 
 |   } | 
 |  private: | 
 |   friend struct DefaultSingletonTraits<OpenSSLInitSingleton>; | 
 |   OpenSSLInitSingleton() { | 
 | #if defined(OS_ANDROID) && defined(ARCH_CPU_ARMEL) | 
 |     const bool has_neon = | 
 |         (android_getCpuFeatures() & ANDROID_CPU_ARM_FEATURE_NEON) != 0; | 
 |     // CRYPTO_set_NEON_capable is called before |SSL_library_init| because this | 
 |     // stops BoringSSL from probing for NEON support via SIGILL in the case | 
 |     // that getauxval isn't present. | 
 |     CRYPTO_set_NEON_capable(has_neon); | 
 |     // See https://code.google.com/p/chromium/issues/detail?id=341598 | 
 |     base::CPU cpu; | 
 |     CRYPTO_set_NEON_functional(!cpu.has_broken_neon()); | 
 | #endif | 
 |  | 
 |     SSL_load_error_strings(); | 
 |     SSL_library_init(); | 
 |     int num_locks = CRYPTO_num_locks(); | 
 |     locks_.reserve(num_locks); | 
 |     for (int i = 0; i < num_locks; ++i) | 
 |       locks_.push_back(new base::Lock()); | 
 |     CRYPTO_set_locking_callback(LockingCallback); | 
 |     CRYPTO_THREADID_set_callback(CurrentThreadId); | 
 |   } | 
 |  | 
 |   ~OpenSSLInitSingleton() { | 
 |     CRYPTO_set_locking_callback(NULL); | 
 |     EVP_cleanup(); | 
 |     ERR_free_strings(); | 
 |   } | 
 |  | 
 |   static void LockingCallback(int mode, int n, const char* file, int line) { | 
 |     OpenSSLInitSingleton::GetInstance()->OnLockingCallback(mode, n, file, line); | 
 |   } | 
 |  | 
 |   void OnLockingCallback(int mode, int n, const char* file, int line) { | 
 |     CHECK_LT(static_cast<size_t>(n), locks_.size()); | 
 |     if (mode & CRYPTO_LOCK) | 
 |       locks_[n]->Acquire(); | 
 |     else | 
 |       locks_[n]->Release(); | 
 |   } | 
 |  | 
 |   // These locks are used and managed by OpenSSL via LockingCallback(). | 
 |   ScopedVector<base::Lock> locks_; | 
 |  | 
 |   DISALLOW_COPY_AND_ASSIGN(OpenSSLInitSingleton); | 
 | }; | 
 |  | 
 | // Callback routine for OpenSSL to print error messages. |str| is a | 
 | // NULL-terminated string of length |len| containing diagnostic information | 
 | // such as the library, function and reason for the error, the file and line | 
 | // where the error originated, plus potentially any context-specific | 
 | // information about the error. |context| contains a pointer to user-supplied | 
 | // data, which is currently unused. | 
 | // If this callback returns a value <= 0, OpenSSL will stop processing the | 
 | // error queue and return, otherwise it will continue calling this function | 
 | // until all errors have been removed from the queue. | 
 | int OpenSSLErrorCallback(const char* str, size_t len, void* context) { | 
 |   DVLOG(1) << "\t" << base::StringPiece(str, len); | 
 |   return 1; | 
 | } | 
 |  | 
 | }  // namespace | 
 |  | 
 | void EnsureOpenSSLInit() { | 
 |   (void)OpenSSLInitSingleton::GetInstance(); | 
 | } | 
 |  | 
 | void ClearOpenSSLERRStack(const tracked_objects::Location& location) { | 
 |   if (logging::DEBUG_MODE && VLOG_IS_ON(1)) { | 
 |     int error_num = ERR_peek_error(); | 
 |     if (error_num == 0) | 
 |       return; | 
 |  | 
 |     std::string message; | 
 |     location.Write(true, true, &message); | 
 |     DVLOG(1) << "OpenSSL ERR_get_error stack from " << message; | 
 |     ERR_print_errors_cb(&OpenSSLErrorCallback, NULL); | 
 |   } else { | 
 |     ERR_clear_error(); | 
 |   } | 
 | } | 
 |  | 
 | }  // namespace crypto |