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