1 /* $NetBSD: openssl_link.c,v 1.3 2019/01/09 16:55:11 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 http://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 <config.h> 29 30 #include <isc/mem.h> 31 #include <isc/mutex.h> 32 #include <isc/mutexblock.h> 33 #include <isc/platform.h> 34 #include <isc/string.h> 35 #include <isc/thread.h> 36 #include <isc/util.h> 37 38 #include <dns/log.h> 39 40 #include <dst/result.h> 41 42 #include "dst_internal.h" 43 #include "dst_openssl.h" 44 45 static isc_mem_t *dst__mctx = NULL; 46 47 #if !defined(OPENSSL_NO_ENGINE) 48 #include <openssl/engine.h> 49 #endif 50 51 #if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER) 52 static isc_mutex_t *locks = NULL; 53 static int nlocks; 54 #endif 55 56 #if !defined(OPENSSL_NO_ENGINE) 57 static ENGINE *e = NULL; 58 #endif 59 60 static void 61 enable_fips_mode(void) { 62 #ifdef HAVE_FIPS_MODE 63 if (FIPS_mode() != 0) { 64 /* 65 * FIPS mode is already enabled. 66 */ 67 return; 68 } 69 70 if (FIPS_mode_set(1) == 0) { 71 dst__openssl_toresult2("FIPS_mode_set", DST_R_OPENSSLFAILURE); 72 exit(1); 73 } 74 #endif /* HAVE_FIPS_MODE */ 75 } 76 77 #if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER) 78 static void 79 lock_callback(int mode, int type, const char *file, int line) { 80 UNUSED(file); 81 UNUSED(line); 82 if ((mode & CRYPTO_LOCK) != 0) 83 LOCK(&locks[type]); 84 else 85 UNLOCK(&locks[type]); 86 } 87 #endif 88 89 #if defined(LIBRESSL_VERSION_NUMBER) 90 static unsigned long 91 id_callback(void) { 92 return ((unsigned long)isc_thread_self()); 93 } 94 #endif 95 96 #if OPENSSL_VERSION_NUMBER < 0x10100000L 97 static void 98 _set_thread_id(CRYPTO_THREADID *id) 99 { 100 CRYPTO_THREADID_set_numeric(id, (unsigned long)isc_thread_self()); 101 } 102 #endif 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 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 if (locks == NULL) 121 return (ISC_R_NOMEMORY); 122 isc_mutexblock_init(locks, nlocks); 123 CRYPTO_set_locking_callback(lock_callback); 124 # if defined(LIBRESSL_VERSION_NUMBER) 125 CRYPTO_set_id_callback(id_callback); 126 # elif OPENSSL_VERSION_NUMBER < 0x10100000L 127 CRYPTO_THREADID_set_callback(_set_thread_id); 128 # endif 129 ERR_load_crypto_strings(); 130 #endif 131 132 #if !defined(OPENSSL_NO_ENGINE) 133 #if !defined(CONF_MFLAGS_DEFAULT_SECTION) 134 OPENSSL_config(NULL); 135 #else 136 /* 137 * OPENSSL_config() can only be called a single time as of 138 * 1.0.2e so do the steps individually. 139 */ 140 OPENSSL_load_builtin_modules(); 141 ENGINE_load_builtin_engines(); 142 ERR_clear_error(); 143 CONF_modules_load_file(NULL, NULL, 144 CONF_MFLAGS_DEFAULT_SECTION | 145 CONF_MFLAGS_IGNORE_MISSING_FILE); 146 #endif 147 148 if (engine != NULL && *engine == '\0') 149 engine = NULL; 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 e = NULL; 181 #endif 182 #if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER) 183 CRYPTO_set_locking_callback(NULL); 184 isc_mutexblock_destroy(locks, nlocks); 185 isc_mem_free(dst__mctx, locks); 186 locks = NULL; 187 #endif 188 return (result); 189 } 190 191 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 e = NULL; 204 ENGINE_cleanup(); 205 #endif 206 CRYPTO_cleanup_all_ex_data(); 207 ERR_clear_error(); 208 #if OPENSSL_VERSION_NUMBER < 0x10100000L 209 ERR_remove_thread_state(NULL); 210 #elif defined(LIBRESSL_VERSION_NUMBER) 211 ERR_remove_state(0); 212 #endif 213 ERR_free_strings(); 214 215 #ifdef DNS_CRYPTO_LEAKS 216 CRYPTO_mem_leaks_fp(stderr); 217 #endif 218 219 if (locks != NULL) { 220 CRYPTO_set_locking_callback(NULL); 221 isc_mutexblock_destroy(locks, nlocks); 222 isc_mem_free(dst__mctx, locks); 223 locks = NULL; 224 } 225 #endif 226 isc_mem_detach(&dst__mctx); 227 } 228 229 static isc_result_t 230 toresult(isc_result_t fallback) { 231 isc_result_t result = fallback; 232 unsigned long err = ERR_peek_error(); 233 #if defined(ECDSA_R_RANDOM_NUMBER_GENERATION_FAILED) 234 int lib = ERR_GET_LIB(err); 235 #endif 236 int reason = ERR_GET_REASON(err); 237 238 switch (reason) { 239 /* 240 * ERR_* errors are globally unique; others 241 * are unique per sublibrary 242 */ 243 case ERR_R_MALLOC_FAILURE: 244 result = ISC_R_NOMEMORY; 245 break; 246 default: 247 #if defined(ECDSA_R_RANDOM_NUMBER_GENERATION_FAILED) 248 if (lib == ERR_R_ECDSA_LIB && 249 reason == ECDSA_R_RANDOM_NUMBER_GENERATION_FAILED) { 250 result = ISC_R_NOENTROPY; 251 break; 252 } 253 #endif 254 break; 255 } 256 257 return (result); 258 } 259 260 isc_result_t 261 dst__openssl_toresult(isc_result_t fallback) { 262 isc_result_t result; 263 264 result = toresult(fallback); 265 266 ERR_clear_error(); 267 return (result); 268 } 269 270 isc_result_t 271 dst__openssl_toresult2(const char *funcname, isc_result_t fallback) { 272 return (dst__openssl_toresult3(DNS_LOGCATEGORY_GENERAL, 273 funcname, fallback)); 274 } 275 276 isc_result_t 277 dst__openssl_toresult3(isc_logcategory_t *category, 278 const char *funcname, isc_result_t fallback) { 279 isc_result_t result; 280 unsigned long err; 281 const char *file, *data; 282 int line, flags; 283 char buf[256]; 284 285 result = toresult(fallback); 286 287 isc_log_write(dns_lctx, category, 288 DNS_LOGMODULE_CRYPTO, ISC_LOG_WARNING, 289 "%s failed (%s)", funcname, 290 isc_result_totext(result)); 291 292 if (result == ISC_R_NOMEMORY) 293 goto done; 294 295 for (;;) { 296 err = ERR_get_error_line_data(&file, &line, &data, &flags); 297 if (err == 0U) 298 goto done; 299 ERR_error_string_n(err, buf, sizeof(buf)); 300 isc_log_write(dns_lctx, category, 301 DNS_LOGMODULE_CRYPTO, ISC_LOG_INFO, 302 "%s:%s:%d:%s", buf, file, line, 303 ((flags & ERR_TXT_STRING) != 0) ? data : ""); 304 } 305 306 done: 307 ERR_clear_error(); 308 return (result); 309 } 310 311 #if !defined(OPENSSL_NO_ENGINE) 312 ENGINE * 313 dst__openssl_getengine(const char *engine) { 314 315 if (engine == NULL) 316 return (NULL); 317 if (e == NULL) 318 return (NULL); 319 if (strcmp(engine, ENGINE_get_id(e)) == 0) 320 return (e); 321 return (NULL); 322 } 323 #endif 324 325 /*! \file */ 326