mirror of
https://gitlab.isc.org/isc-projects/bind9
synced 2025-08-22 18:19:42 +00:00
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.
242 lines
6.2 KiB
C
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);
|
|
}
|