1 /* $NetBSD: tls.c,v 1.2 2021/08/19 11:50:18 christos Exp $ */ 2 3 /* 4 * Copyright (C) Internet Systems Consortium, Inc. ("ISC") 5 * 6 * This Source Code Form is subject to the terms of the Mozilla Public 7 * License, v. 2.0. If a copy of the MPL was not distributed with this 8 * file, you can obtain one at https://mozilla.org/MPL/2.0/. 9 * 10 * See the COPYRIGHT file distributed with this work for additional 11 * information regarding copyright ownership. 12 */ 13 14 #include <inttypes.h> 15 16 #include <openssl/bn.h> 17 #include <openssl/conf.h> 18 #include <openssl/err.h> 19 #include <openssl/opensslv.h> 20 #include <openssl/rand.h> 21 #include <openssl/rsa.h> 22 23 #include <isc/atomic.h> 24 #include <isc/log.h> 25 #include <isc/mutex.h> 26 #include <isc/mutexblock.h> 27 #include <isc/once.h> 28 #include <isc/thread.h> 29 #include <isc/util.h> 30 31 #include "openssl_shim.h" 32 #include "tls_p.h" 33 34 static isc_once_t init_once = ISC_ONCE_INIT; 35 static isc_once_t shut_once = ISC_ONCE_INIT; 36 static atomic_bool init_done = ATOMIC_VAR_INIT(false); 37 static atomic_bool shut_done = ATOMIC_VAR_INIT(false); 38 39 #if OPENSSL_VERSION_NUMBER < 0x10100000L 40 static isc_mutex_t *locks = NULL; 41 static int nlocks; 42 43 static void 44 isc__tls_lock_callback(int mode, int type, const char *file, int line) { 45 UNUSED(file); 46 UNUSED(line); 47 if ((mode & CRYPTO_LOCK) != 0) { 48 LOCK(&locks[type]); 49 } else { 50 UNLOCK(&locks[type]); 51 } 52 } 53 54 static void 55 isc__tls_set_thread_id(CRYPTO_THREADID *id) { 56 CRYPTO_THREADID_set_numeric(id, (unsigned long)isc_thread_self()); 57 } 58 #endif 59 60 static void 61 tls_initialize(void) { 62 REQUIRE(!atomic_load(&init_done)); 63 64 #if OPENSSL_VERSION_NUMBER >= 0x10100000L 65 RUNTIME_CHECK(OPENSSL_init_ssl(OPENSSL_INIT_ENGINE_ALL_BUILTIN | 66 OPENSSL_INIT_LOAD_CONFIG, 67 NULL) == 1); 68 #else 69 nlocks = CRYPTO_num_locks(); 70 /* 71 * We can't use isc_mem API here, because it's called too 72 * early and when the isc_mem_debugging flags are changed 73 * later and ISC_MEM_DEBUGSIZE or ISC_MEM_DEBUGCTX flags are 74 * added, neither isc_mem_put() nor isc_mem_free() can be used 75 * to free up the memory allocated here because the flags were 76 * not set when calling isc_mem_get() or isc_mem_allocate() 77 * here. 78 * 79 * Actually, since this is a single allocation at library load 80 * and deallocation at library unload, using the standard 81 * allocator without the tracking is fine for this purpose. 82 */ 83 locks = calloc(nlocks, sizeof(locks[0])); 84 isc_mutexblock_init(locks, nlocks); 85 CRYPTO_set_locking_callback(isc__tls_lock_callback); 86 CRYPTO_THREADID_set_callback(isc__tls_set_thread_id); 87 88 CRYPTO_malloc_init(); 89 ERR_load_crypto_strings(); 90 SSL_load_error_strings(); 91 SSL_library_init(); 92 93 #if !defined(OPENSSL_NO_ENGINE) 94 ENGINE_load_builtin_engines(); 95 #endif 96 OpenSSL_add_all_algorithms(); 97 OPENSSL_load_builtin_modules(); 98 99 CONF_modules_load_file(NULL, NULL, 100 CONF_MFLAGS_DEFAULT_SECTION | 101 CONF_MFLAGS_IGNORE_MISSING_FILE); 102 #endif 103 104 /* Protect ourselves against unseeded PRNG */ 105 if (RAND_status() != 1) { 106 FATAL_ERROR(__FILE__, __LINE__, 107 "OpenSSL pseudorandom number generator " 108 "cannot be initialized (see the `PRNG not " 109 "seeded' message in the OpenSSL FAQ)"); 110 } 111 112 REQUIRE(atomic_compare_exchange_strong(&init_done, &(bool){ false }, 113 true)); 114 } 115 116 void 117 isc__tls_initialize(void) { 118 isc_result_t result = isc_once_do(&init_once, tls_initialize); 119 REQUIRE(result == ISC_R_SUCCESS); 120 REQUIRE(atomic_load(&init_done)); 121 } 122 123 static void 124 tls_shutdown(void) { 125 REQUIRE(atomic_load(&init_done)); 126 REQUIRE(!atomic_load(&shut_done)); 127 128 #if OPENSSL_VERSION_NUMBER < 0x10100000L 129 130 CONF_modules_unload(1); 131 OBJ_cleanup(); 132 EVP_cleanup(); 133 #if !defined(OPENSSL_NO_ENGINE) 134 ENGINE_cleanup(); 135 #endif 136 CRYPTO_cleanup_all_ex_data(); 137 ERR_remove_thread_state(NULL); 138 RAND_cleanup(); 139 ERR_free_strings(); 140 141 CRYPTO_set_locking_callback(NULL); 142 143 if (locks != NULL) { 144 isc_mutexblock_destroy(locks, nlocks); 145 free(locks); 146 locks = NULL; 147 } 148 #endif 149 150 REQUIRE(atomic_compare_exchange_strong(&shut_done, &(bool){ false }, 151 true)); 152 } 153 154 void 155 isc__tls_shutdown(void) { 156 isc_result_t result = isc_once_do(&shut_once, tls_shutdown); 157 REQUIRE(result == ISC_R_SUCCESS); 158 REQUIRE(atomic_load(&shut_done)); 159 } 160