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