1 /* $NetBSD: openssl_link.c,v 1.10 2024/02/21 22:52:07 christos Exp $ */ 2 3 /* 4 * Copyright (C) Internet Systems Consortium, Inc. ("ISC") 5 * 6 * SPDX-License-Identifier: MPL-2.0 AND ISC 7 * 8 * This Source Code Form is subject to the terms of the Mozilla Public 9 * License, v. 2.0. If a copy of the MPL was not distributed with this 10 * file, you can obtain one at https://mozilla.org/MPL/2.0/. 11 * 12 * See the COPYRIGHT file distributed with this work for additional 13 * information regarding copyright ownership. 14 */ 15 16 /* 17 * Copyright (C) Network Associates, Inc. 18 * 19 * Permission to use, copy, modify, and/or distribute this software for any 20 * purpose with or without fee is hereby granted, provided that the above 21 * copyright notice and this permission notice appear in all copies. 22 * 23 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC AND NETWORK ASSOCIATES DISCLAIMS 24 * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED 25 * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE 26 * FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 27 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 28 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR 29 * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 30 */ 31 32 #include <isc/mem.h> 33 #include <isc/mutex.h> 34 #include <isc/mutexblock.h> 35 #include <isc/result.h> 36 #include <isc/string.h> 37 #include <isc/thread.h> 38 #include <isc/tls.h> 39 #include <isc/util.h> 40 41 #include <dns/log.h> 42 43 #include "dst_internal.h" 44 #include "dst_openssl.h" 45 46 #if !defined(OPENSSL_NO_ENGINE) && OPENSSL_API_LEVEL < 30000 47 #include <openssl/engine.h> 48 #endif /* if !defined(OPENSSL_NO_ENGINE) && OPENSSL_API_LEVEL < 30000 */ 49 50 #include "openssl_shim.h" 51 52 #if !defined(OPENSSL_NO_ENGINE) && OPENSSL_API_LEVEL < 30000 53 static ENGINE *e = NULL; 54 #endif /* if !defined(OPENSSL_NO_ENGINE) && OPENSSL_API_LEVEL < 30000 */ 55 56 static void 57 enable_fips_mode(void) { 58 #ifdef HAVE_FIPS_MODE 59 if (FIPS_mode() != 0) { 60 /* 61 * FIPS mode is already enabled. 62 */ 63 return; 64 } 65 66 if (FIPS_mode_set(1) == 0) { 67 dst__openssl_toresult2("FIPS_mode_set", DST_R_OPENSSLFAILURE); 68 exit(1); 69 } 70 #endif /* HAVE_FIPS_MODE */ 71 } 72 73 isc_result_t 74 dst__openssl_init(const char *engine) { 75 isc_result_t result = ISC_R_SUCCESS; 76 77 enable_fips_mode(); 78 79 #if !defined(OPENSSL_NO_ENGINE) && OPENSSL_API_LEVEL < 30000 80 if (engine != NULL && *engine == '\0') { 81 engine = NULL; 82 } 83 84 if (engine != NULL) { 85 e = ENGINE_by_id(engine); 86 if (e == NULL) { 87 result = DST_R_NOENGINE; 88 goto cleanup_rm; 89 } 90 if (!ENGINE_init(e)) { 91 result = DST_R_NOENGINE; 92 goto cleanup_rm; 93 } 94 /* This will init the engine. */ 95 if (!ENGINE_set_default(e, ENGINE_METHOD_ALL)) { 96 result = DST_R_NOENGINE; 97 goto cleanup_init; 98 } 99 } 100 101 return (ISC_R_SUCCESS); 102 cleanup_init: 103 ENGINE_finish(e); 104 cleanup_rm: 105 if (e != NULL) { 106 ENGINE_free(e); 107 } 108 e = NULL; 109 ERR_clear_error(); 110 #else 111 UNUSED(engine); 112 #endif /* if !defined(OPENSSL_NO_ENGINE) && OPENSSL_API_LEVEL < 30000 */ 113 return (result); 114 } 115 116 void 117 dst__openssl_destroy(void) { 118 #if !defined(OPENSSL_NO_ENGINE) && OPENSSL_API_LEVEL < 30000 119 if (e != NULL) { 120 ENGINE_finish(e); 121 ENGINE_free(e); 122 } 123 e = NULL; 124 #endif /* if !defined(OPENSSL_NO_ENGINE) && OPENSSL_API_LEVEL < 30000 */ 125 } 126 127 static isc_result_t 128 toresult(isc_result_t fallback) { 129 isc_result_t result = fallback; 130 unsigned long err = ERR_peek_error(); 131 #if defined(ECDSA_R_RANDOM_NUMBER_GENERATION_FAILED) 132 int lib = ERR_GET_LIB(err); 133 #endif /* if defined(ECDSA_R_RANDOM_NUMBER_GENERATION_FAILED) */ 134 int reason = ERR_GET_REASON(err); 135 136 switch (reason) { 137 /* 138 * ERR_* errors are globally unique; others 139 * are unique per sublibrary 140 */ 141 case ERR_R_MALLOC_FAILURE: 142 result = ISC_R_NOMEMORY; 143 break; 144 default: 145 #if defined(ECDSA_R_RANDOM_NUMBER_GENERATION_FAILED) 146 if (lib == ERR_R_ECDSA_LIB && 147 reason == ECDSA_R_RANDOM_NUMBER_GENERATION_FAILED) 148 { 149 result = ISC_R_NOENTROPY; 150 break; 151 } 152 #endif /* if defined(ECDSA_R_RANDOM_NUMBER_GENERATION_FAILED) */ 153 break; 154 } 155 156 return (result); 157 } 158 159 isc_result_t 160 dst__openssl_toresult(isc_result_t fallback) { 161 isc_result_t result; 162 163 result = toresult(fallback); 164 165 ERR_clear_error(); 166 return (result); 167 } 168 169 isc_result_t 170 dst__openssl_toresult2(const char *funcname, isc_result_t fallback) { 171 return (dst__openssl_toresult3(DNS_LOGCATEGORY_GENERAL, funcname, 172 fallback)); 173 } 174 175 isc_result_t 176 dst__openssl_toresult3(isc_logcategory_t *category, const char *funcname, 177 isc_result_t fallback) { 178 isc_result_t result; 179 unsigned long err; 180 const char *file, *func, *data; 181 int line, flags; 182 char buf[256]; 183 184 result = toresult(fallback); 185 186 isc_log_write(dns_lctx, category, DNS_LOGMODULE_CRYPTO, ISC_LOG_WARNING, 187 "%s failed (%s)", funcname, isc_result_totext(result)); 188 189 if (result == ISC_R_NOMEMORY) { 190 goto done; 191 } 192 193 for (;;) { 194 err = ERR_get_error_all(&file, &line, &func, &data, &flags); 195 if (err == 0U) { 196 goto done; 197 } 198 ERR_error_string_n(err, buf, sizeof(buf)); 199 isc_log_write(dns_lctx, category, DNS_LOGMODULE_CRYPTO, 200 ISC_LOG_INFO, "%s:%s:%d:%s", buf, file, line, 201 ((flags & ERR_TXT_STRING) != 0) ? data : ""); 202 } 203 204 done: 205 ERR_clear_error(); 206 return (result); 207 } 208 209 #if !defined(OPENSSL_NO_ENGINE) && OPENSSL_API_LEVEL < 30000 210 ENGINE * 211 dst__openssl_getengine(const char *engine) { 212 if (engine == NULL) { 213 return (NULL); 214 } 215 if (e == NULL) { 216 return (NULL); 217 } 218 if (strcmp(engine, ENGINE_get_id(e)) == 0) { 219 return (e); 220 } 221 return (NULL); 222 } 223 #endif /* if !defined(OPENSSL_NO_ENGINE) && OPENSSL_API_LEVEL < 30000 */ 224 225 /*! \file */ 226