xref: /netbsd-src/external/mpl/bind/dist/lib/isc/tls.c (revision 122b5006ee1bd67145794b4cde92f4fe4781a5ec)
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