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