xref: /netbsd-src/external/mpl/bind/dist/lib/dns/openssl_link.c (revision 9fb66d812c00ebfb445c0b47dea128f32aa6fe96)
1 /*	$NetBSD: openssl_link.c,v 1.5 2021/02/19 16:42:16 christos Exp $	*/
2 
3 /*
4  * Portions 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  * Portions Copyright (C) Network Associates, Inc.
14  *
15  * Permission to use, copy, modify, and/or distribute this software for any
16  * purpose with or without fee is hereby granted, provided that the above
17  * copyright notice and this permission notice appear in all copies.
18  *
19  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC AND NETWORK ASSOCIATES DISCLAIMS
20  * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
21  * WARRANTIES OF MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE
22  * FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
23  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
24  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
25  * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
26  */
27 
28 #include <isc/mem.h>
29 #include <isc/mutex.h>
30 #include <isc/mutexblock.h>
31 #include <isc/platform.h>
32 #include <isc/string.h>
33 #include <isc/thread.h>
34 #include <isc/util.h>
35 
36 #include <dns/log.h>
37 
38 #include <dst/result.h>
39 
40 #include "dst_internal.h"
41 #include "dst_openssl.h"
42 
43 static isc_mem_t *dst__mctx = NULL;
44 
45 #if !defined(OPENSSL_NO_ENGINE)
46 #include <openssl/engine.h>
47 #endif /* if !defined(OPENSSL_NO_ENGINE) */
48 
49 #if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER)
50 static isc_mutex_t *locks = NULL;
51 static int nlocks;
52 #endif /* if OPENSSL_VERSION_NUMBER < 0x10100000L || \
53 	* defined(LIBRESSL_VERSION_NUMBER) */
54 
55 #if !defined(OPENSSL_NO_ENGINE)
56 static ENGINE *e = NULL;
57 #endif /* if !defined(OPENSSL_NO_ENGINE) */
58 
59 static void
60 enable_fips_mode(void) {
61 #ifdef HAVE_FIPS_MODE
62 	if (FIPS_mode() != 0) {
63 		/*
64 		 * FIPS mode is already enabled.
65 		 */
66 		return;
67 	}
68 
69 	if (FIPS_mode_set(1) == 0) {
70 		dst__openssl_toresult2("FIPS_mode_set", DST_R_OPENSSLFAILURE);
71 		exit(1);
72 	}
73 #endif /* HAVE_FIPS_MODE */
74 }
75 
76 #if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER)
77 static void
78 lock_callback(int mode, int type, const char *file, int line) {
79 	UNUSED(file);
80 	UNUSED(line);
81 	if ((mode & CRYPTO_LOCK) != 0) {
82 		LOCK(&locks[type]);
83 	} else {
84 		UNLOCK(&locks[type]);
85 	}
86 }
87 #endif /* if OPENSSL_VERSION_NUMBER < 0x10100000L || \
88 	* defined(LIBRESSL_VERSION_NUMBER) */
89 
90 #if defined(LIBRESSL_VERSION_NUMBER)
91 static unsigned long
92 id_callback(void) {
93 	return ((unsigned long)isc_thread_self());
94 }
95 #endif /* if defined(LIBRESSL_VERSION_NUMBER) */
96 
97 #if OPENSSL_VERSION_NUMBER < 0x10100000L
98 static void
99 _set_thread_id(CRYPTO_THREADID *id) {
100 	CRYPTO_THREADID_set_numeric(id, (unsigned long)isc_thread_self());
101 }
102 #endif /* if OPENSSL_VERSION_NUMBER < 0x10100000L */
103 
104 isc_result_t
105 dst__openssl_init(isc_mem_t *mctx, const char *engine) {
106 	isc_result_t result;
107 
108 	REQUIRE(dst__mctx == NULL);
109 	isc_mem_attach(mctx, &dst__mctx);
110 
111 #if defined(OPENSSL_NO_ENGINE)
112 	UNUSED(engine);
113 #endif /* if defined(OPENSSL_NO_ENGINE) */
114 
115 	enable_fips_mode();
116 
117 #if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER)
118 	nlocks = CRYPTO_num_locks();
119 	locks = isc_mem_allocate(dst__mctx, sizeof(isc_mutex_t) * nlocks);
120 	isc_mutexblock_init(locks, nlocks);
121 	CRYPTO_set_locking_callback(lock_callback);
122 #if defined(LIBRESSL_VERSION_NUMBER)
123 	CRYPTO_set_id_callback(id_callback);
124 #elif OPENSSL_VERSION_NUMBER < 0x10100000L
125 	CRYPTO_THREADID_set_callback(_set_thread_id);
126 #endif /* if defined(LIBRESSL_VERSION_NUMBER) */
127 	ERR_load_crypto_strings();
128 #endif /* if OPENSSL_VERSION_NUMBER < 0x10100000L || \
129 	* defined(LIBRESSL_VERSION_NUMBER) */
130 
131 #if !defined(OPENSSL_NO_ENGINE)
132 #if !defined(CONF_MFLAGS_DEFAULT_SECTION)
133 	OPENSSL_config(NULL);
134 #else  /* if !defined(CONF_MFLAGS_DEFAULT_SECTION) */
135 	/*
136 	 * OPENSSL_config() can only be called a single time as of
137 	 * 1.0.2e so do the steps individually.
138 	 */
139 	OPENSSL_load_builtin_modules();
140 	ENGINE_load_builtin_engines();
141 	ERR_clear_error();
142 	CONF_modules_load_file(NULL, NULL,
143 			       CONF_MFLAGS_DEFAULT_SECTION |
144 				       CONF_MFLAGS_IGNORE_MISSING_FILE);
145 #endif /* if !defined(CONF_MFLAGS_DEFAULT_SECTION) */
146 
147 	if (engine != NULL && *engine == '\0') {
148 		engine = NULL;
149 	}
150 
151 	if (engine != NULL) {
152 		e = ENGINE_by_id(engine);
153 		if (e == NULL) {
154 			result = DST_R_NOENGINE;
155 			goto cleanup_rm;
156 		}
157 		/* This will init the engine. */
158 		if (!ENGINE_set_default(e, ENGINE_METHOD_ALL)) {
159 			result = DST_R_NOENGINE;
160 			goto cleanup_rm;
161 		}
162 	}
163 
164 #endif /* !defined(OPENSSL_NO_ENGINE) */
165 
166 	/* Protect ourselves against unseeded PRNG */
167 	if (RAND_status() != 1) {
168 		FATAL_ERROR(__FILE__, __LINE__,
169 			    "OpenSSL pseudorandom number generator "
170 			    "cannot be initialized (see the `PRNG not "
171 			    "seeded' message in the OpenSSL FAQ)");
172 	}
173 
174 	return (ISC_R_SUCCESS);
175 
176 #if !defined(OPENSSL_NO_ENGINE)
177 cleanup_rm:
178 	if (e != NULL) {
179 		ENGINE_free(e);
180 	}
181 	e = NULL;
182 #endif /* if !defined(OPENSSL_NO_ENGINE) */
183 #if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER)
184 	CRYPTO_set_locking_callback(NULL);
185 	isc_mutexblock_destroy(locks, nlocks);
186 	isc_mem_free(dst__mctx, locks);
187 	locks = NULL;
188 #endif /* if OPENSSL_VERSION_NUMBER < 0x10100000L || \
189 	* defined(LIBRESSL_VERSION_NUMBER) */
190 	return (result);
191 }
192 
193 void
194 dst__openssl_destroy(void) {
195 #if (OPENSSL_VERSION_NUMBER < 0x10100000L) || defined(LIBRESSL_VERSION_NUMBER)
196 	/*
197 	 * Sequence taken from apps_shutdown() in <apps/apps.h>.
198 	 */
199 	CONF_modules_free();
200 	OBJ_cleanup();
201 	EVP_cleanup();
202 #if !defined(OPENSSL_NO_ENGINE)
203 	if (e != NULL) {
204 		ENGINE_free(e);
205 	}
206 	e = NULL;
207 	ENGINE_cleanup();
208 #endif /* if !defined(OPENSSL_NO_ENGINE) */
209 	CRYPTO_cleanup_all_ex_data();
210 	ERR_clear_error();
211 #if OPENSSL_VERSION_NUMBER < 0x10100000L
212 	ERR_remove_thread_state(NULL);
213 #elif defined(LIBRESSL_VERSION_NUMBER)
214 	ERR_remove_state(0);
215 #endif /* if OPENSSL_VERSION_NUMBER < 0x10100000L */
216 	ERR_free_strings();
217 
218 #ifdef DNS_CRYPTO_LEAKS
219 	CRYPTO_mem_leaks_fp(stderr);
220 #endif /* ifdef DNS_CRYPTO_LEAKS */
221 
222 	if (locks != NULL) {
223 		CRYPTO_set_locking_callback(NULL);
224 		isc_mutexblock_destroy(locks, nlocks);
225 		isc_mem_free(dst__mctx, locks);
226 		locks = NULL;
227 	}
228 #endif /* if (OPENSSL_VERSION_NUMBER < 0x10100000L) || \
229 	* defined(LIBRESSL_VERSION_NUMBER) */
230 	isc_mem_detach(&dst__mctx);
231 }
232 
233 static isc_result_t
234 toresult(isc_result_t fallback) {
235 	isc_result_t result = fallback;
236 	unsigned long err = ERR_peek_error();
237 #if defined(ECDSA_R_RANDOM_NUMBER_GENERATION_FAILED)
238 	int lib = ERR_GET_LIB(err);
239 #endif /* if defined(ECDSA_R_RANDOM_NUMBER_GENERATION_FAILED) */
240 	int reason = ERR_GET_REASON(err);
241 
242 	switch (reason) {
243 	/*
244 	 * ERR_* errors are globally unique; others
245 	 * are unique per sublibrary
246 	 */
247 	case ERR_R_MALLOC_FAILURE:
248 		result = ISC_R_NOMEMORY;
249 		break;
250 	default:
251 #if defined(ECDSA_R_RANDOM_NUMBER_GENERATION_FAILED)
252 		if (lib == ERR_R_ECDSA_LIB &&
253 		    reason == ECDSA_R_RANDOM_NUMBER_GENERATION_FAILED) {
254 			result = ISC_R_NOENTROPY;
255 			break;
256 		}
257 #endif /* if defined(ECDSA_R_RANDOM_NUMBER_GENERATION_FAILED) */
258 		break;
259 	}
260 
261 	return (result);
262 }
263 
264 isc_result_t
265 dst__openssl_toresult(isc_result_t fallback) {
266 	isc_result_t result;
267 
268 	result = toresult(fallback);
269 
270 	ERR_clear_error();
271 	return (result);
272 }
273 
274 isc_result_t
275 dst__openssl_toresult2(const char *funcname, isc_result_t fallback) {
276 	return (dst__openssl_toresult3(DNS_LOGCATEGORY_GENERAL, funcname,
277 				       fallback));
278 }
279 
280 isc_result_t
281 dst__openssl_toresult3(isc_logcategory_t *category, const char *funcname,
282 		       isc_result_t fallback) {
283 	isc_result_t result;
284 	unsigned long err;
285 	const char *file, *data;
286 	int line, flags;
287 	char buf[256];
288 
289 	result = toresult(fallback);
290 
291 	isc_log_write(dns_lctx, category, DNS_LOGMODULE_CRYPTO, ISC_LOG_WARNING,
292 		      "%s failed (%s)", funcname, isc_result_totext(result));
293 
294 	if (result == ISC_R_NOMEMORY) {
295 		goto done;
296 	}
297 
298 	for (;;) {
299 		err = ERR_get_error_line_data(&file, &line, &data, &flags);
300 		if (err == 0U) {
301 			goto done;
302 		}
303 		ERR_error_string_n(err, buf, sizeof(buf));
304 		isc_log_write(dns_lctx, category, DNS_LOGMODULE_CRYPTO,
305 			      ISC_LOG_INFO, "%s:%s:%d:%s", buf, file, line,
306 			      ((flags & ERR_TXT_STRING) != 0) ? data : "");
307 	}
308 
309 done:
310 	ERR_clear_error();
311 	return (result);
312 }
313 
314 #if !defined(OPENSSL_NO_ENGINE)
315 ENGINE *
316 dst__openssl_getengine(const char *engine) {
317 	if (engine == NULL) {
318 		return (NULL);
319 	}
320 	if (e == NULL) {
321 		return (NULL);
322 	}
323 	if (strcmp(engine, ENGINE_get_id(e)) == 0) {
324 		return (e);
325 	}
326 	return (NULL);
327 }
328 #endif /* if !defined(OPENSSL_NO_ENGINE) */
329 
330 /*! \file */
331