2
0
mirror of https://gitlab.isc.org/isc-projects/bind9 synced 2025-08-22 18:19:42 +00:00
bind/lib/isc/crypto/ossl3.c
Aydın Mercan ebb514e89d
start treating openssl 3.0 and 1.1 as separate libraries
OpenSSL 3.0 has completely revamed the way applications are supposed to
interact with libcrypto with the old way gaining a hefty perfomance
penalty.

Almost every cryptographic functionality will have a pre-3.0 and
post-3.0 counterpart split by the preprocessor after the migration is
complete.

Instead of having a macros mess everywhere, start the long term plan of
having a cryptographic functionality layer with OpenSSL >=3.0 and
OpenSSL <3.0 as two separate backends.

Start this process by splitting the initialization function.
2025-08-13 15:10:43 +03:00

242 lines
6.2 KiB
C

/*
* Copyright (C) Internet Systems Consortium, Inc. ("ISC")
*
* SPDX-License-Identifier: MPL-2.0
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, you can obtain one at https://mozilla.org/MPL/2.0/.
*
* See the COPYRIGHT file distributed with this work for additional
* information regarding copyright ownership.
*/
#include <openssl/crypto.h>
#include <openssl/err.h>
#include <openssl/evp.h>
#include <openssl/provider.h>
#include <openssl/rand.h>
#include <openssl/ssl.h>
#include <isc/crypto.h>
#include <isc/mem.h>
#include <isc/tls.h>
#include <isc/util.h>
static isc_mem_t *isc__crypto_mctx = NULL;
static OSSL_PROVIDER *base = NULL, *fips = NULL;
EVP_MD *isc__crypto_md5 = NULL;
EVP_MD *isc__crypto_sha1 = NULL;
EVP_MD *isc__crypto_sha224 = NULL;
EVP_MD *isc__crypto_sha256 = NULL;
EVP_MD *isc__crypto_sha384 = NULL;
EVP_MD *isc__crypto_sha512 = NULL;
#if ISC_MEM_TRACKLINES
/*
* We use the internal isc__mem API here, so we can pass the file and line
* arguments passed from OpenSSL >= 1.1.0 to our memory functions for better
* tracking of the OpenSSL allocations. Without this, we would always just see
* isc__crypto_{malloc,realloc,free} in the tracking output, but with this in
* place we get to see the places in the OpenSSL code where the allocations
* happen.
*/
static void *
isc__crypto_malloc_ex(size_t size, const char *file, int line) {
return isc__mem_allocate(isc__crypto_mctx, size, 0, __func__, file,
(unsigned int)line);
}
static void *
isc__crypto_realloc_ex(void *ptr, size_t size, const char *file, int line) {
return isc__mem_reallocate(isc__crypto_mctx, ptr, size, 0, __func__,
file, (unsigned int)line);
}
static void
isc__crypto_free_ex(void *ptr, const char *file, int line) {
if (ptr == NULL) {
return;
}
if (isc__crypto_mctx != NULL) {
isc__mem_free(isc__crypto_mctx, ptr, 0, __func__, file,
(unsigned int)line);
}
}
#else /* ISC_MEM_TRACKLINES */
static void *
isc__crypto_malloc_ex(size_t size, const char *file, int line) {
UNUSED(file);
UNUSED(line);
return isc_mem_allocate(isc__crypto_mctx, size);
}
static void *
isc__crypto_realloc_ex(void *ptr, size_t size, const char *file, int line) {
UNUSED(file);
UNUSED(line);
return isc_mem_reallocate(isc__crypto_mctx, ptr, size);
}
static void
isc__crypto_free_ex(void *ptr, const char *file, int line) {
UNUSED(file);
UNUSED(line);
if (ptr == NULL) {
return;
}
if (isc__crypto_mctx != NULL) {
isc__mem_free(isc__crypto_mctx, ptr, 0);
}
}
#endif /* ISC_MEM_TRACKLINES */
#define md_register_algorithm(alg, algname) \
do { \
REQUIRE(isc__crypto_##alg == NULL); \
isc__crypto_##alg = EVP_MD_fetch(NULL, algname, NULL); \
if (isc__crypto_##alg == NULL) { \
ERR_clear_error(); \
} \
} while (0)
#define md_unregister_algorithm(alg) \
do { \
if (isc__crypto_##alg != NULL) { \
EVP_MD_free(isc__crypto_##alg); \
isc__crypto_##alg = NULL; \
} \
} while (0)
static isc_result_t
register_algorithms(void) {
if (!isc_crypto_fips_mode()) {
md_register_algorithm(md5, "MD5");
}
md_register_algorithm(sha1, "SHA1");
md_register_algorithm(sha224, "SHA224");
md_register_algorithm(sha256, "SHA256");
md_register_algorithm(sha384, "SHA384");
md_register_algorithm(sha512, "SHA512");
return ISC_R_SUCCESS;
}
static void
unregister_algorithms(void) {
md_unregister_algorithm(sha512);
md_unregister_algorithm(sha384);
md_unregister_algorithm(sha256);
md_unregister_algorithm(sha224);
md_unregister_algorithm(sha1);
md_unregister_algorithm(md5);
}
#undef md_unregister_algorithm
#undef md_register_algorithm
bool
isc_crypto_fips_mode(void) {
return EVP_default_properties_is_fips_enabled(NULL) != 0;
}
isc_result_t
isc_crypto_fips_enable(void) {
if (isc_crypto_fips_mode()) {
return ISC_R_SUCCESS;
}
INSIST(fips == NULL);
fips = OSSL_PROVIDER_load(NULL, "fips");
if (fips == NULL) {
return isc_tlserr2result(
ISC_LOGCATEGORY_GENERAL, ISC_LOGMODULE_CRYPTO,
"OSSL_PROVIDER_load", ISC_R_CRYPTOFAILURE);
}
INSIST(base == NULL);
base = OSSL_PROVIDER_load(NULL, "base");
if (base == NULL) {
OSSL_PROVIDER_unload(fips);
return isc_tlserr2result(
ISC_LOGCATEGORY_GENERAL, ISC_LOGMODULE_CRYPTO,
"OSS_PROVIDER_load", ISC_R_CRYPTOFAILURE);
}
if (EVP_default_properties_enable_fips(NULL, 1) == 0) {
return isc_tlserr2result(ISC_LOGCATEGORY_GENERAL,
ISC_LOGMODULE_CRYPTO,
"EVP_default_properties_enable_fips",
ISC_R_CRYPTOFAILURE);
}
unregister_algorithms();
register_algorithms();
return ISC_R_SUCCESS;
}
void
isc__crypto_setdestroycheck(bool check) {
isc_mem_setdestroycheck(isc__crypto_mctx, check);
}
void
isc__crypto_initialize(void) {
constexpr uint64_t opts = OPENSSL_INIT_LOAD_CONFIG |
OPENSSL_INIT_NO_ATEXIT;
isc_mem_create("OpenSSL", &isc__crypto_mctx);
isc_mem_setdebugging(isc__crypto_mctx, 0);
isc_mem_setdestroycheck(isc__crypto_mctx, false);
(void)CRYPTO_set_mem_functions(isc__crypto_malloc_ex,
isc__crypto_realloc_ex,
isc__crypto_free_ex);
RUNTIME_CHECK(OPENSSL_init_ssl(opts, NULL) == 1);
register_algorithms();
#ifdef ENABLE_FIPS_MODE
if (isc_crypto_fips_enable() != ISC_R_SUCCESS) {
ERR_clear_error();
FATAL_ERROR("Failed to toggle FIPS mode but is "
"required for this build");
}
#endif
/* Protect ourselves against unseeded PRNG */
if (RAND_status() != 1) {
isc_tlserr2result(ISC_LOGCATEGORY_GENERAL, ISC_LOGMODULE_CRYPTO,
"RAND_status", ISC_R_CRYPTOFAILURE);
FATAL_ERROR("OpenSSL pseudorandom number generator "
"cannot be initialized (see the `PRNG not "
"seeded' message in the OpenSSL FAQ)");
}
}
void
isc__crypto_shutdown(void) {
unregister_algorithms();
if (base != NULL) {
OSSL_PROVIDER_unload(base);
}
if (fips != NULL) {
OSSL_PROVIDER_unload(fips);
}
OPENSSL_cleanup();
isc_mem_detach(&isc__crypto_mctx);
}