1 /* $NetBSD: openssl_link.c,v 1.12 2025/01/26 16:25:23 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/fips.h> 33 #include <isc/mem.h> 34 #include <isc/mutex.h> 35 #include <isc/mutexblock.h> 36 #include <isc/result.h> 37 #include <isc/string.h> 38 #include <isc/thread.h> 39 #include <isc/tls.h> 40 #include <isc/util.h> 41 42 #include <dns/log.h> 43 44 #include "dst_internal.h" 45 #include "dst_openssl.h" 46 47 #if !defined(OPENSSL_NO_ENGINE) && OPENSSL_API_LEVEL < 30000 48 #include <openssl/engine.h> 49 #endif /* if !defined(OPENSSL_NO_ENGINE) && OPENSSL_API_LEVEL < 30000 */ 50 #if OPENSSL_VERSION_NUMBER >= 0x30000000L 51 #include <openssl/core_names.h> 52 #include <openssl/store.h> 53 #endif 54 55 #include "openssl_shim.h" 56 57 #define DST_RET(a) \ 58 { \ 59 ret = a; \ 60 goto err; \ 61 } 62 63 #if !defined(OPENSSL_NO_ENGINE) && OPENSSL_API_LEVEL < 30000 64 static ENGINE *global_engine = NULL; 65 #endif /* if !defined(OPENSSL_NO_ENGINE) && OPENSSL_API_LEVEL < 30000 */ 66 67 static void 68 enable_fips_mode(void) { 69 #if defined(ENABLE_FIPS_MODE) 70 if (isc_fips_mode()) { 71 /* 72 * FIPS mode is already enabled. 73 */ 74 return; 75 } 76 77 if (isc_fips_set_mode(1) != ISC_R_SUCCESS) { 78 dst__openssl_toresult2("FIPS_mode_set", DST_R_OPENSSLFAILURE); 79 exit(EXIT_FAILURE); 80 } 81 #endif 82 } 83 84 isc_result_t 85 dst__openssl_init(const char *engine) { 86 enable_fips_mode(); 87 88 if (engine != NULL && *engine == '\0') { 89 engine = NULL; 90 } 91 92 if (engine == NULL) { 93 return ISC_R_SUCCESS; 94 } 95 96 #if !defined(OPENSSL_NO_ENGINE) && OPENSSL_API_LEVEL < 30000 97 global_engine = ENGINE_by_id(engine); 98 if (global_engine == NULL) { 99 goto cleanup_rm; 100 } 101 if (!ENGINE_init(global_engine)) { 102 goto cleanup_rm; 103 } 104 /* This will init the engine. */ 105 if (!ENGINE_set_default(global_engine, ENGINE_METHOD_ALL)) { 106 goto cleanup_init; 107 } 108 return ISC_R_SUCCESS; 109 cleanup_init: 110 ENGINE_finish(global_engine); 111 cleanup_rm: 112 if (global_engine != NULL) { 113 ENGINE_free(global_engine); 114 } 115 ERR_clear_error(); 116 global_engine = NULL; 117 #endif /* if !defined(OPENSSL_NO_ENGINE) && OPENSSL_API_LEVEL < 30000 */ 118 return DST_R_NOENGINE; 119 } 120 121 void 122 dst__openssl_destroy(void) { 123 #if !defined(OPENSSL_NO_ENGINE) && OPENSSL_API_LEVEL < 30000 124 if (global_engine != NULL) { 125 ENGINE_finish(global_engine); 126 ENGINE_free(global_engine); 127 } 128 global_engine = NULL; 129 #endif /* if !defined(OPENSSL_NO_ENGINE) && OPENSSL_API_LEVEL < 30000 */ 130 } 131 132 static isc_result_t 133 toresult(isc_result_t fallback) { 134 isc_result_t result = fallback; 135 unsigned long err = ERR_peek_error(); 136 #if defined(ECDSA_R_RANDOM_NUMBER_GENERATION_FAILED) 137 int lib = ERR_GET_LIB(err); 138 #endif /* if defined(ECDSA_R_RANDOM_NUMBER_GENERATION_FAILED) */ 139 int reason = ERR_GET_REASON(err); 140 141 switch (reason) { 142 /* 143 * ERR_* errors are globally unique; others 144 * are unique per sublibrary 145 */ 146 case ERR_R_MALLOC_FAILURE: 147 result = ISC_R_NOMEMORY; 148 break; 149 default: 150 #if defined(ECDSA_R_RANDOM_NUMBER_GENERATION_FAILED) 151 if (lib == ERR_R_ECDSA_LIB && 152 reason == ECDSA_R_RANDOM_NUMBER_GENERATION_FAILED) 153 { 154 result = ISC_R_NOENTROPY; 155 break; 156 } 157 #endif /* if defined(ECDSA_R_RANDOM_NUMBER_GENERATION_FAILED) */ 158 break; 159 } 160 161 return result; 162 } 163 164 isc_result_t 165 dst__openssl_toresult(isc_result_t fallback) { 166 isc_result_t result; 167 168 result = toresult(fallback); 169 170 ERR_clear_error(); 171 return result; 172 } 173 174 isc_result_t 175 dst___openssl_toresult2(const char *funcname, isc_result_t fallback, 176 const char *file, int line) { 177 return dst___openssl_toresult3(DNS_LOGCATEGORY_GENERAL, funcname, 178 fallback, file, line); 179 } 180 181 isc_result_t 182 dst___openssl_toresult3(isc_logcategory_t *category, const char *funcname, 183 isc_result_t fallback, const char *file, int line) { 184 isc_result_t result; 185 unsigned long err; 186 const char *func, *data; 187 int flags; 188 char buf[256]; 189 190 result = toresult(fallback); 191 192 isc_log_write(dns_lctx, category, DNS_LOGMODULE_CRYPTO, ISC_LOG_WARNING, 193 "%s (%s:%d) failed (%s)", funcname, file, line, 194 isc_result_totext(result)); 195 196 if (result == ISC_R_NOMEMORY) { 197 goto done; 198 } 199 200 for (;;) { 201 err = ERR_get_error_all(&file, &line, &func, &data, &flags); 202 if (err == 0U) { 203 goto done; 204 } 205 ERR_error_string_n(err, buf, sizeof(buf)); 206 isc_log_write(dns_lctx, category, DNS_LOGMODULE_CRYPTO, 207 ISC_LOG_INFO, "%s:%s:%d:%s", buf, file, line, 208 ((flags & ERR_TXT_STRING) != 0) ? data : ""); 209 } 210 211 done: 212 ERR_clear_error(); 213 return result; 214 } 215 216 #if !defined(OPENSSL_NO_ENGINE) && OPENSSL_API_LEVEL < 30000 217 ENGINE * 218 dst__openssl_getengine(const char *engine) { 219 if (engine == NULL) { 220 return NULL; 221 } 222 if (global_engine == NULL) { 223 return NULL; 224 } 225 if (strcmp(engine, ENGINE_get_id(global_engine)) == 0) { 226 return global_engine; 227 } 228 return NULL; 229 } 230 #endif /* if !defined(OPENSSL_NO_ENGINE) && OPENSSL_API_LEVEL < 30000 */ 231 232 static isc_result_t 233 dst__openssl_fromlabel_engine(int key_base_id, const char *engine, 234 const char *label, const char *pin, 235 EVP_PKEY **ppub, EVP_PKEY **ppriv) { 236 #if !defined(OPENSSL_NO_ENGINE) && OPENSSL_API_LEVEL < 30000 237 isc_result_t ret = ISC_R_SUCCESS; 238 ENGINE *e = NULL; 239 240 UNUSED(pin); 241 242 e = dst__openssl_getengine(engine); 243 if (e == NULL) { 244 DST_RET(dst__openssl_toresult(DST_R_NOENGINE)); 245 } 246 247 *ppub = ENGINE_load_public_key(e, label, NULL, NULL); 248 if (*ppub == NULL) { 249 DST_RET(dst__openssl_toresult2("ENGINE_load_public_key", 250 DST_R_OPENSSLFAILURE)); 251 } 252 if (EVP_PKEY_base_id(*ppub) != key_base_id) { 253 DST_RET(DST_R_BADKEYTYPE); 254 } 255 256 *ppriv = ENGINE_load_private_key(e, label, NULL, NULL); 257 if (*ppriv == NULL) { 258 DST_RET(dst__openssl_toresult2("ENGINE_load_private_key", 259 DST_R_OPENSSLFAILURE)); 260 } 261 if (EVP_PKEY_base_id(*ppriv) != key_base_id) { 262 DST_RET(DST_R_BADKEYTYPE); 263 } 264 err: 265 return ret; 266 #else /* if !defined(OPENSSL_NO_ENGINE) && OPENSSL_API_LEVEL < 30000 */ 267 UNUSED(key_base_id); 268 UNUSED(engine); 269 UNUSED(label); 270 UNUSED(pin); 271 UNUSED(ppub); 272 UNUSED(ppriv); 273 return DST_R_NOENGINE; 274 #endif /* if !defined(OPENSSL_NO_ENGINE) && OPENSSL_API_LEVEL < 30000 */ 275 } 276 277 static isc_result_t 278 dst__openssl_fromlabel_provider(int key_base_id, const char *label, 279 const char *pin, EVP_PKEY **ppub, 280 EVP_PKEY **ppriv) { 281 #if OPENSSL_VERSION_NUMBER >= 0x30000000L 282 isc_result_t ret = DST_R_OPENSSLFAILURE; 283 OSSL_STORE_CTX *ctx = NULL; 284 285 UNUSED(pin); 286 287 ctx = OSSL_STORE_open(label, NULL, NULL, NULL, NULL); 288 if (!ctx) { 289 DST_RET(dst__openssl_toresult(DST_R_OPENSSLFAILURE)); 290 } 291 292 while (!OSSL_STORE_eof(ctx)) { 293 OSSL_STORE_INFO *info = OSSL_STORE_load(ctx); 294 if (info == NULL) { 295 continue; 296 } 297 switch (OSSL_STORE_INFO_get_type(info)) { 298 case OSSL_STORE_INFO_PKEY: 299 if (*ppriv != NULL) { 300 OSSL_STORE_INFO_free(info); 301 DST_RET(DST_R_INVALIDPRIVATEKEY); 302 } 303 *ppriv = OSSL_STORE_INFO_get1_PKEY(info); 304 if (EVP_PKEY_get_base_id(*ppriv) != key_base_id) { 305 OSSL_STORE_INFO_free(info); 306 DST_RET(DST_R_BADKEYTYPE); 307 } 308 break; 309 case OSSL_STORE_INFO_PUBKEY: 310 if (*ppub != NULL) { 311 OSSL_STORE_INFO_free(info); 312 DST_RET(DST_R_INVALIDPUBLICKEY); 313 } 314 *ppub = OSSL_STORE_INFO_get1_PUBKEY(info); 315 if (EVP_PKEY_get_base_id(*ppub) != key_base_id) { 316 OSSL_STORE_INFO_free(info); 317 DST_RET(DST_R_BADKEYTYPE); 318 } 319 break; 320 } 321 OSSL_STORE_INFO_free(info); 322 } 323 if (*ppriv != NULL && *ppub != NULL) { 324 ret = ISC_R_SUCCESS; 325 } 326 err: 327 OSSL_STORE_close(ctx); 328 return ret; 329 #else 330 UNUSED(key_base_id); 331 UNUSED(label); 332 UNUSED(pin); 333 UNUSED(ppub); 334 UNUSED(ppriv); 335 return DST_R_OPENSSLFAILURE; 336 #endif 337 } 338 339 isc_result_t 340 dst__openssl_fromlabel(int key_base_id, const char *engine, const char *label, 341 const char *pin, EVP_PKEY **ppub, EVP_PKEY **ppriv) { 342 if (engine == NULL) { 343 return dst__openssl_fromlabel_provider(key_base_id, label, pin, 344 ppub, ppriv); 345 } 346 347 if (*ppub != NULL) { 348 EVP_PKEY_free(*ppub); 349 *ppub = NULL; 350 } 351 352 if (*ppriv != NULL) { 353 EVP_PKEY_free(*ppriv); 354 *ppriv = NULL; 355 } 356 357 return dst__openssl_fromlabel_engine(key_base_id, engine, label, pin, 358 ppub, ppriv); 359 } 360 361 bool 362 dst__openssl_keypair_compare(const dst_key_t *key1, const dst_key_t *key2) { 363 EVP_PKEY *pkey1 = key1->keydata.pkeypair.pub; 364 EVP_PKEY *pkey2 = key2->keydata.pkeypair.pub; 365 366 if (pkey1 == pkey2) { 367 return true; 368 } else if (pkey1 == NULL || pkey2 == NULL) { 369 return false; 370 } 371 372 /* `EVP_PKEY_eq` checks only the public components and parameters. */ 373 if (EVP_PKEY_eq(pkey1, pkey2) != 1) { 374 return false; 375 } 376 /* The private key presence must be same for keys to match. */ 377 if ((key1->keydata.pkeypair.priv != NULL) != 378 (key2->keydata.pkeypair.priv != NULL)) 379 { 380 return false; 381 } 382 return true; 383 } 384 385 bool 386 dst__openssl_keypair_isprivate(const dst_key_t *key) { 387 return key->keydata.pkeypair.priv != NULL; 388 } 389 390 void 391 dst__openssl_keypair_destroy(dst_key_t *key) { 392 if (key->keydata.pkeypair.priv != key->keydata.pkeypair.pub) { 393 EVP_PKEY_free(key->keydata.pkeypair.priv); 394 } 395 EVP_PKEY_free(key->keydata.pkeypair.pub); 396 key->keydata.pkeypair.pub = NULL; 397 key->keydata.pkeypair.priv = NULL; 398 } 399 400 /*! \file */ 401