/* Copyright (c) 2001, Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. * Copyright (c) 2007-2019, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** * \file crypto_openssl_mgt.c * * \brief Block of functions related to operations from OpenSSL. **/ #include "lib/crypt_ops/compat_openssl.h" #include "lib/crypt_ops/crypto_openssl_mgt.h" #include "lib/crypt_ops/crypto_rand.h" #include "lib/crypt_ops/aes.h" #include "lib/string/util_string.h" #include "lib/lock/compat_mutex.h" #include "lib/log/log.h" #include "lib/log/util_bug.h" #include "lib/testsupport/testsupport.h" #include "lib/thread/threads.h" DISABLE_GCC_WARNING(redundant-decls) #include #include #include #include #include #include #include #include #include #include #include #include ENABLE_GCC_WARNING(redundant-decls) #include #ifndef NEW_THREAD_API /** A number of preallocated mutexes for use by OpenSSL. */ static tor_mutex_t **openssl_mutexes_ = NULL; /** How many mutexes have we allocated for use by OpenSSL? */ static int n_openssl_mutexes_ = 0; #endif /* !defined(NEW_THREAD_API) */ /** Declare STATIC functions */ STATIC char * parse_openssl_version_str(const char *raw_version); #ifndef NEW_THREAD_API STATIC void openssl_locking_cb_(int mode, int n, const char *file, int line); STATIC void tor_set_openssl_thread_id(CRYPTO_THREADID *threadid); #endif /** Log all pending crypto errors at level severity. Use * doing to describe our current activities. */ void crypto_openssl_log_errors(int severity, const char *doing) { unsigned long err; const char *msg, *lib, *func; while ((err = ERR_get_error()) != 0) { msg = (const char*)ERR_reason_error_string(err); lib = (const char*)ERR_lib_error_string(err); func = (const char*)ERR_func_error_string(err); if (!msg) msg = "(null)"; if (!lib) lib = "(null)"; if (!func) func = "(null)"; if (BUG(!doing)) doing = "(null)"; tor_log(severity, LD_CRYPTO, "crypto error while %s: %s (in %s:%s)", doing, msg, lib, func); } } /* Returns a trimmed and human-readable version of an openssl version string * raw_version. They are usually in the form of 'OpenSSL 1.0.0b 10 * May 2012' and this will parse them into a form similar to '1.0.0b' */ STATIC char * parse_openssl_version_str(const char *raw_version) { const char *end_of_version = NULL; /* The output should be something like "OpenSSL 1.0.0b 10 May 2012. Let's trim that down. */ if (!strcmpstart(raw_version, "OpenSSL ")) { raw_version += strlen("OpenSSL "); end_of_version = strchr(raw_version, ' '); } if (end_of_version) return tor_strndup(raw_version, end_of_version-raw_version); else return tor_strdup(raw_version); } static char *crypto_openssl_version_str = NULL; /* Return a human-readable version of the run-time openssl version number. */ const char * crypto_openssl_get_version_str(void) { if (crypto_openssl_version_str == NULL) { const char *raw_version = OpenSSL_version(OPENSSL_VERSION); crypto_openssl_version_str = parse_openssl_version_str(raw_version); } return crypto_openssl_version_str; } static char *crypto_openssl_header_version_str = NULL; /* Return a human-readable version of the compile-time openssl version * number. */ const char * crypto_openssl_get_header_version_str(void) { if (crypto_openssl_header_version_str == NULL) { crypto_openssl_header_version_str = parse_openssl_version_str(OPENSSL_VERSION_TEXT); } return crypto_openssl_header_version_str; } #ifndef OPENSSL_THREADS #error OpenSSL has been built without thread support. Tor requires an \ OpenSSL library with thread support enabled. #endif #ifndef NEW_THREAD_API /** Helper: OpenSSL uses this callback to manipulate mutexes. */ STATIC void openssl_locking_cb_(int mode, int n, const char *file, int line) { (void)file; (void)line; if (!openssl_mutexes_) /* This is not a really good fix for the * "release-freed-lock-from-separate-thread-on-shutdown" problem, but * it can't hurt. */ return; if (mode & CRYPTO_LOCK) tor_mutex_acquire(openssl_mutexes_[n]); else tor_mutex_release(openssl_mutexes_[n]); } STATIC void tor_set_openssl_thread_id(CRYPTO_THREADID *threadid) { CRYPTO_THREADID_set_numeric(threadid, tor_get_thread_id()); } #endif /* !defined(NEW_THREAD_API) */ /** Helper: Construct mutexes, and set callbacks to help OpenSSL handle being * multithreaded. Returns 0. */ static int setup_openssl_threading(void) { #ifndef NEW_THREAD_API int i; int n = CRYPTO_num_locks(); n_openssl_mutexes_ = n; openssl_mutexes_ = tor_calloc(n, sizeof(tor_mutex_t *)); for (i=0; i < n; ++i) openssl_mutexes_[i] = tor_mutex_new(); CRYPTO_set_locking_callback(openssl_locking_cb_); CRYPTO_THREADID_set_callback(tor_set_openssl_thread_id); #endif /* !defined(NEW_THREAD_API) */ return 0; } /** free OpenSSL variables */ static void crypto_openssl_free_all(void) { tor_free(crypto_openssl_version_str); tor_free(crypto_openssl_header_version_str); #ifndef NEW_THREAD_API if (n_openssl_mutexes_) { int n = n_openssl_mutexes_; tor_mutex_t **ms = openssl_mutexes_; int i; openssl_mutexes_ = NULL; n_openssl_mutexes_ = 0; for (i=0;i 0) { crypto_openssl_init_engines(accelName, accelDir); } else { log_info(LD_CRYPTO, "NOT using OpenSSL engine support."); } if (crypto_force_rand_ssleay()) { if (crypto_seed_rng() < 0) return -1; } evaluate_evp_for_aes(-1); evaluate_ctr_for_aes(); return 0; } /** Free crypto resources held by this thread. */ void crypto_openssl_thread_cleanup(void) { #ifndef NEW_THREAD_API ERR_remove_thread_state(NULL); #endif } /** Clean up global resources held by openssl. */ void crypto_openssl_global_cleanup(void) { #ifndef OPENSSL_1_1_API EVP_cleanup(); #endif #ifndef NEW_THREAD_API ERR_remove_thread_state(NULL); #endif #ifndef OPENSSL_1_1_API ERR_free_strings(); #endif #ifndef DISABLE_ENGINES #ifndef OPENSSL_1_1_API ENGINE_cleanup(); #endif #endif CONF_modules_unload(1); #ifndef OPENSSL_1_1_API CRYPTO_cleanup_all_ex_data(); #endif crypto_openssl_free_all(); }