diff options
Diffstat (limited to 'lib/isc/tls.c')
-rw-r--r-- | lib/isc/tls.c | 161 |
1 files changed, 161 insertions, 0 deletions
diff --git a/lib/isc/tls.c b/lib/isc/tls.c new file mode 100644 index 0000000..859c73c --- /dev/null +++ b/lib/isc/tls.c @@ -0,0 +1,161 @@ +/* + * Copyright (C) Internet Systems Consortium, Inc. ("ISC") + * + * SPDX-License-Identifier: MPL-2.0 + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, you can obtain one at https://mozilla.org/MPL/2.0/. + * + * See the COPYRIGHT file distributed with this work for additional + * information regarding copyright ownership. + */ + +#include <inttypes.h> + +#include <openssl/bn.h> +#include <openssl/conf.h> +#include <openssl/crypto.h> +#include <openssl/err.h> +#include <openssl/opensslv.h> +#include <openssl/rand.h> +#include <openssl/rsa.h> + +#include <isc/atomic.h> +#include <isc/log.h> +#include <isc/mutex.h> +#include <isc/mutexblock.h> +#include <isc/once.h> +#include <isc/thread.h> +#include <isc/util.h> + +#include "openssl_shim.h" +#include "tls_p.h" + +static isc_once_t init_once = ISC_ONCE_INIT; +static isc_once_t shut_once = ISC_ONCE_INIT; +static atomic_bool init_done = false; +static atomic_bool shut_done = false; + +#if OPENSSL_VERSION_NUMBER < 0x10100000L +static isc_mutex_t *locks = NULL; +static int nlocks; + +static void +isc__tls_lock_callback(int mode, int type, const char *file, int line) { + UNUSED(file); + UNUSED(line); + if ((mode & CRYPTO_LOCK) != 0) { + LOCK(&locks[type]); + } else { + UNLOCK(&locks[type]); + } +} + +static void +isc__tls_set_thread_id(CRYPTO_THREADID *id) { + CRYPTO_THREADID_set_numeric(id, (unsigned long)isc_thread_self()); +} +#endif + +static void +tls_initialize(void) { + REQUIRE(!atomic_load(&init_done)); + +#if OPENSSL_VERSION_NUMBER >= 0x10100000L + RUNTIME_CHECK(OPENSSL_init_ssl(OPENSSL_INIT_ENGINE_ALL_BUILTIN | + OPENSSL_INIT_LOAD_CONFIG, + NULL) == 1); +#else + nlocks = CRYPTO_num_locks(); + /* + * We can't use isc_mem API here, because it's called too + * early and when the isc_mem_debugging flags are changed + * later and ISC_MEM_DEBUGSIZE or ISC_MEM_DEBUGCTX flags are + * added, neither isc_mem_put() nor isc_mem_free() can be used + * to free up the memory allocated here because the flags were + * not set when calling isc_mem_get() or isc_mem_allocate() + * here. + * + * Actually, since this is a single allocation at library load + * and deallocation at library unload, using the standard + * allocator without the tracking is fine for this purpose. + */ + locks = calloc(nlocks, sizeof(locks[0])); + isc_mutexblock_init(locks, nlocks); + CRYPTO_set_locking_callback(isc__tls_lock_callback); + CRYPTO_THREADID_set_callback(isc__tls_set_thread_id); + + CRYPTO_malloc_init(); + ERR_load_crypto_strings(); + SSL_load_error_strings(); + SSL_library_init(); + +#if !defined(OPENSSL_NO_ENGINE) + ENGINE_load_builtin_engines(); +#endif + OpenSSL_add_all_algorithms(); + OPENSSL_load_builtin_modules(); + + CONF_modules_load_file(NULL, NULL, + CONF_MFLAGS_DEFAULT_SECTION | + CONF_MFLAGS_IGNORE_MISSING_FILE); +#endif + + /* Protect ourselves against unseeded PRNG */ + if (RAND_status() != 1) { + FATAL_ERROR(__FILE__, __LINE__, + "OpenSSL pseudorandom number generator " + "cannot be initialized (see the `PRNG not " + "seeded' message in the OpenSSL FAQ)"); + } + + REQUIRE(atomic_compare_exchange_strong(&init_done, &(bool){ false }, + true)); +} + +void +isc__tls_initialize(void) { + isc_result_t result = isc_once_do(&init_once, tls_initialize); + REQUIRE(result == ISC_R_SUCCESS); + REQUIRE(atomic_load(&init_done)); +} + +static void +tls_shutdown(void) { + REQUIRE(atomic_load(&init_done)); + REQUIRE(!atomic_load(&shut_done)); + +#if OPENSSL_VERSION_NUMBER >= 0x10100000L + OPENSSL_cleanup(); +#else + CONF_modules_unload(1); + OBJ_cleanup(); + EVP_cleanup(); +#if !defined(OPENSSL_NO_ENGINE) + ENGINE_cleanup(); +#endif + CRYPTO_cleanup_all_ex_data(); + ERR_remove_thread_state(NULL); + RAND_cleanup(); + ERR_free_strings(); + + CRYPTO_set_locking_callback(NULL); + + if (locks != NULL) { + isc_mutexblock_destroy(locks, nlocks); + free(locks); + locks = NULL; + } +#endif + + REQUIRE(atomic_compare_exchange_strong(&shut_done, &(bool){ false }, + true)); +} + +void +isc__tls_shutdown(void) { + isc_result_t result = isc_once_do(&shut_once, tls_shutdown); + REQUIRE(result == ISC_R_SUCCESS); + REQUIRE(atomic_load(&shut_done)); +} |