chg: dev: unify explicit fetching and libcrypto handling

Unify libcrypto initialization and explicit digest fetching in a single place.

It will remove the remaining implicit fetching and deduplicate explicit
fetching inside the codebase. Initialization has been moved in to ensure
OpenSSL cleanup is done only after fetched contextes are destroyed.

Merge branch 'aydin/libdns-explicit-fetch' into 'main'

See merge request isc-projects/bind9!9288
This commit is contained in:
Aydın Mercan 2024-10-16 12:53:31 +00:00
commit 94e5061151
13 changed files with 273 additions and 253 deletions

View file

@ -36,6 +36,7 @@
#endif /* HAVE_LIBIDN2 */
#include <isc/base64.h>
#include <isc/crypto.h>
#include <isc/file.h>
#include <isc/getaddresses.h>
#include <isc/hex.h>
@ -4754,7 +4755,7 @@ destroy_libs(void) {
isc_managers_destroy(&mctx, &loopmgr, &netmgr);
#if ENABLE_LEAK_DETECTION
isc__tls_setdestroycheck(true);
isc__crypto_setdestroycheck(true);
isc__uv_setdestroycheck(true);
isc__xml_setdestroycheck(true);
#endif

View file

@ -27,6 +27,7 @@
#include <isc/attributes.h>
#include <isc/backtrace.h>
#include <isc/commandline.h>
#include <isc/crypto.h>
#include <isc/dir.h>
#include <isc/file.h>
#include <isc/fips.h>
@ -1565,7 +1566,7 @@ main(int argc, char *argv[]) {
isc_managers_destroy(&named_g_mctx, &named_g_loopmgr, &named_g_netmgr);
#if ENABLE_LEAK_DETECTION
isc__tls_setdestroycheck(true);
isc__crypto_setdestroycheck(true);
isc__uv_setdestroycheck(true);
isc__xml_setdestroycheck(true);
#endif

View file

@ -690,9 +690,9 @@ opensslecdsa_createctx(dst_key_t *key, dst_context_t *dctx) {
DST_RET(dst__openssl_toresult(ISC_R_NOMEMORY));
}
if (dctx->key->key_alg == DST_ALG_ECDSA256) {
type = EVP_sha256();
type = isc__crypto_sha256;
} else {
type = EVP_sha384();
type = isc__crypto_sha384;
}
if (dctx->use == DO_SIGN) {

View file

@ -202,13 +202,13 @@ opensslrsa_createctx(dst_key_t *key, dst_context_t *dctx) {
switch (dctx->key->key_alg) {
case DST_ALG_RSASHA1:
case DST_ALG_NSEC3RSASHA1:
type = EVP_sha1(); /* SHA1 + RSA */
type = isc__crypto_sha1; /* SHA1 + RSA */
break;
case DST_ALG_RSASHA256:
type = EVP_sha256(); /* SHA256 + RSA */
type = isc__crypto_sha256; /* SHA256 + RSA */
break;
case DST_ALG_RSASHA512:
type = EVP_sha512();
type = isc__crypto_sha512;
break;
default:
UNREACHABLE();
@ -1236,17 +1236,17 @@ check_algorithm(unsigned char algorithm) {
switch (algorithm) {
case DST_ALG_RSASHA1:
case DST_ALG_NSEC3RSASHA1:
type = EVP_sha1(); /* SHA1 + RSA */
type = isc__crypto_sha1; /* SHA1 + RSA */
sig = sha1_sig;
len = sizeof(sha1_sig) - 1;
break;
case DST_ALG_RSASHA256:
type = EVP_sha256(); /* SHA256 + RSA */
type = isc__crypto_sha256; /* SHA256 + RSA */
sig = sha256_sig;
len = sizeof(sha256_sig) - 1;
break;
case DST_ALG_RSASHA512:
type = EVP_sha512();
type = isc__crypto_sha512;
sig = sha512_sig;
len = sizeof(sha512_sig) - 1;
break;

View file

@ -17,6 +17,7 @@ libisc_la_HEADERS = \
include/isc/commandline.h \
include/isc/condition.h \
include/isc/counter.h \
include/isc/crypto.h \
include/isc/dir.h \
include/isc/dnsstream.h \
include/isc/endian.h \
@ -124,6 +125,7 @@ libisc_la_SOURCES = \
commandline.c \
condition.c \
counter.c \
crypto.c \
dir.c \
entropy.c \
errno.c \

207
lib/isc/crypto.c Normal file
View file

@ -0,0 +1,207 @@
/*
* 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/err.h>
#include <openssl/rand.h>
#include <openssl/ssl.h>
#include <isc/crypto.h>
#include <isc/mem.h>
#include <isc/util.h>
static isc_mem_t *isc__crypto_mctx = NULL;
const EVP_MD *isc__crypto_md5 = NULL;
const EVP_MD *isc__crypto_sha1 = NULL;
const EVP_MD *isc__crypto_sha224 = NULL;
const EVP_MD *isc__crypto_sha256 = NULL;
const EVP_MD *isc__crypto_sha384 = NULL;
const EVP_MD *isc__crypto_sha512 = NULL;
#if OPENSSL_VERSION_NUMBER >= 0x30000000L
#define md_register_algorithm(alg, algname) \
{ \
REQUIRE(isc__crypto_##alg == NULL); \
isc__crypto_##alg = EVP_MD_fetch(NULL, algname, NULL); \
if (isc__crypto_##alg == NULL) { \
ERR_clear_error(); \
} \
}
#define md_unregister_algorithm(alg) \
{ \
if (isc__crypto_##alg != NULL) { \
EVP_MD_free(UNCONST(isc__crypto_##alg)); \
isc__crypto_##alg = NULL; \
} \
}
#else /* OPENSSL_VERSION_NUMBER >= 0x30000000L */
#define md_register_algorithm(alg, algname) \
{ \
isc__crypto_##alg = EVP_##alg(); \
if (isc__crypto_##alg == NULL) { \
ERR_clear_error(); \
} \
}
#define md_unregister_algorithm(alg)
#endif /* OPENSSL_VERSION_NUMBER >= 0x30000000L */
#if !defined(LIBRESSL_VERSION_NUMBER) && OPENSSL_VERSION_NUMBER >= 0x30000000L
/*
* This was crippled with LibreSSL, so just skip it:
* https://cvsweb.openbsd.org/src/lib/libcrypto/Attic/mem.c
*/
#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, 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, 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, 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 */
#endif /* !defined(LIBRESSL_VERSION_NUMBER) */
void
isc__crypto_setdestroycheck(bool check) {
isc_mem_setdestroycheck(isc__crypto_mctx, check);
}
void
isc__crypto_initialize(void) {
uint64_t opts = OPENSSL_INIT_LOAD_CONFIG;
isc_mem_create(&isc__crypto_mctx);
isc_mem_setname(isc__crypto_mctx, "OpenSSL");
isc_mem_setdestroycheck(isc__crypto_mctx, false);
#if !defined(LIBRESSL_VERSION_NUMBER) && OPENSSL_VERSION_NUMBER >= 0x30000000L
/*
* CRYPTO_set_mem_(_ex)_functions() returns 1 on success or 0 on
* failure, which means OpenSSL already allocated some memory. There's
* nothing we can do about it.
*/
(void)CRYPTO_set_mem_functions(isc__crypto_malloc_ex,
isc__crypto_realloc_ex,
isc__crypto_free_ex);
#endif /* !defined(LIBRESSL_VERSION_NUMBER) && OPENSSL_VERSION_NUMBER >= \
0x30000000L */
#if defined(OPENSSL_INIT_NO_ATEXIT)
/*
* We call OPENSSL_cleanup() manually, in a correct order, thus disable
* the automatic atexit() handler.
*/
opts |= OPENSSL_INIT_NO_ATEXIT;
#endif
RUNTIME_CHECK(OPENSSL_init_ssl(opts, NULL) == 1);
/* Protect ourselves against unseeded PRNG */
if (RAND_status() != 1) {
FATAL_ERROR("OpenSSL pseudorandom number generator "
"cannot be initialized (see the `PRNG not "
"seeded' message in the OpenSSL FAQ)");
}
#if defined(ENABLE_FIPS_MODE)
if (!isc_fips_mode()) {
if (isc_fips_set_mode(1) != ISC_R_SUCCESS) {
isc_tlserr2result(ISC_LOGCATEGORY_GENERAL,
ISC_LOGMODULE_OTHER, "FIPS_mode_set",
ISC_R_CRYPTOFAILURE);
exit(EXIT_FAILURE);
}
}
#endif
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");
}
void
isc__crypto_shutdown(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);
OPENSSL_cleanup();
isc_mem_destroy(&isc__crypto_mctx);
}
#undef md_unregister_algorithm
#undef md_register_algorithm

View file

@ -0,0 +1,38 @@
/*
* 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.
*/
#pragma once
#include <openssl/evp.h>
#include <isc/types.h>
extern const EVP_MD *isc__crypto_md5;
extern const EVP_MD *isc__crypto_sha1;
extern const EVP_MD *isc__crypto_sha224;
extern const EVP_MD *isc__crypto_sha256;
extern const EVP_MD *isc__crypto_sha384;
extern const EVP_MD *isc__crypto_sha512;
/**
* Private
*/
void
isc__crypto_setdestroycheck(bool check);
void
isc__crypto_initialize(void);
void
isc__crypto_shutdown(void);

View file

@ -18,6 +18,7 @@
#pragma once
#include <isc/crypto.h>
#include <isc/lang.h>
#include <isc/result.h>
#include <isc/types.h>
@ -37,19 +38,12 @@ typedef void isc_md_t;
*/
typedef void isc_md_type_t;
extern const isc_md_type_t *isc__md_md5;
extern const isc_md_type_t *isc__md_sha1;
extern const isc_md_type_t *isc__md_sha224;
extern const isc_md_type_t *isc__md_sha256;
extern const isc_md_type_t *isc__md_sha384;
extern const isc_md_type_t *isc__md_sha512;
#define ISC_MD_MD5 isc__md_md5
#define ISC_MD_SHA1 isc__md_sha1
#define ISC_MD_SHA224 isc__md_sha224
#define ISC_MD_SHA256 isc__md_sha256
#define ISC_MD_SHA384 isc__md_sha384
#define ISC_MD_SHA512 isc__md_sha512
#define ISC_MD_MD5 isc__crypto_md5
#define ISC_MD_SHA1 isc__crypto_sha1
#define ISC_MD_SHA224 isc__crypto_sha224
#define ISC_MD_SHA256 isc__crypto_sha256
#define ISC_MD_SHA384 isc__crypto_sha384
#define ISC_MD_SHA512 isc__crypto_sha512
#define ISC_MD5_DIGESTLENGTH isc_md_type_get_size(ISC_MD_MD5)
#define ISC_MD5_BLOCK_LENGTH isc_md_type_get_block_size(ISC_MD_MD5)
@ -196,13 +190,3 @@ isc_md_type_get_size(const isc_md_type_t *md_type);
*/
size_t
isc_md_type_get_block_size(const isc_md_type_t *md_type);
/**
* Private
*/
void
isc__md_initialize(void);
void
isc__md_shutdown(void);

View file

@ -608,15 +608,6 @@ isc_tlsctx_set_random_session_id_context(isc_tlsctx_t *ctx);
*\li 'ctx' - a valid non-NULL pointer;
*/
void
isc__tls_initialize(void);
void
isc__tls_shutdown(void);
void
isc__tls_setdestroycheck(bool check);
#define isc_tlserr2result(category, module, funcname, fallback) \
isc__tlserr2result(category, module, funcname, fallback, __FILE__, \
__LINE__)

View file

@ -17,6 +17,7 @@
#include <openssl/err.h>
#include <openssl/opensslv.h>
#include <isc/crypto.h>
#include <isc/iterated_hash.h>
#include <isc/thread.h>
#include <isc/util.h>
@ -89,7 +90,6 @@ isc__iterated_hash_shutdown(void) {
static thread_local bool initialized = false;
static thread_local EVP_MD_CTX *mdctx = NULL;
static thread_local EVP_MD_CTX *basectx = NULL;
static thread_local EVP_MD *md = NULL;
int
isc_iterated_hash(unsigned char *out, const unsigned int hashalg,
@ -149,10 +149,8 @@ isc__iterated_hash_initialize(void) {
INSIST(basectx != NULL);
mdctx = EVP_MD_CTX_new();
INSIST(mdctx != NULL);
md = EVP_MD_fetch(NULL, "SHA1", NULL);
INSIST(md != NULL);
RUNTIME_CHECK(EVP_DigestInit_ex(basectx, md, NULL) == 1);
RUNTIME_CHECK(EVP_DigestInit_ex(basectx, isc__crypto_sha1, NULL) == 1);
initialized = true;
}
@ -168,8 +166,6 @@ isc__iterated_hash_shutdown(void) {
REQUIRE(basectx != NULL);
EVP_MD_CTX_free(basectx);
basectx = NULL;
EVP_MD_free(md);
md = NULL;
initialized = false;
}

View file

@ -13,9 +13,9 @@
/*! \file */
#include <isc/crypto.h>
#include <isc/hash.h>
#include <isc/iterated_hash.h>
#include <isc/log.h>
#include <isc/md.h>
#include <isc/mem.h>
#include <isc/os.h>
@ -48,10 +48,9 @@ isc__initialize(void) {
isc__mutex_initialize();
isc__mem_initialize();
isc__log_initialize();
isc__tls_initialize();
isc__crypto_initialize();
isc__uv_initialize();
isc__xml_initialize();
isc__md_initialize();
isc__hash_initialize();
isc__iterated_hash_initialize();
(void)isc_os_ncpus();
@ -61,10 +60,9 @@ isc__initialize(void) {
void
isc__shutdown(void) {
isc__iterated_hash_shutdown();
isc__md_shutdown();
isc__xml_shutdown();
isc__uv_shutdown();
isc__tls_shutdown();
isc__crypto_shutdown();
isc__log_shutdown();
isc__mem_shutdown();
isc__mutex_shutdown();

View file

@ -167,62 +167,3 @@ end:
return (res);
}
#ifndef UNIT_TESTING
const isc_md_type_t *isc__md_md5 = NULL;
const isc_md_type_t *isc__md_sha1 = NULL;
const isc_md_type_t *isc__md_sha224 = NULL;
const isc_md_type_t *isc__md_sha256 = NULL;
const isc_md_type_t *isc__md_sha384 = NULL;
const isc_md_type_t *isc__md_sha512 = NULL;
#if OPENSSL_VERSION_NUMBER >= 0x30000000L
#define md_register_algorithm(alg, algname) \
{ \
REQUIRE(isc__md_##alg == NULL); \
isc__md_##alg = EVP_MD_fetch(NULL, algname, NULL); \
if (isc__md_##alg == NULL) { \
ERR_clear_error(); \
} \
}
#define md_unregister_algorithm(alg) \
{ \
if (isc__md_##alg != NULL) { \
EVP_MD_free(*(isc_md_type_t **)&isc__md_##alg); \
isc__md_##alg = NULL; \
} \
}
#else
#define md_register_algorithm(alg, algname) \
{ \
isc__md_##alg = EVP_##alg(); \
if (isc__md_##alg == NULL) { \
ERR_clear_error(); \
} \
}
#define md_unregister_algorithm(alg)
#endif
void
isc__md_initialize(void) {
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");
}
void
isc__md_shutdown(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);
}
#endif /* UNIT_TESTING */

View file

@ -34,6 +34,7 @@
#include <openssl/x509v3.h>
#include <isc/atomic.h>
#include <isc/crypto.h>
#include <isc/fips.h>
#include <isc/ht.h>
#include <isc/log.h>
@ -55,146 +56,6 @@
#define COMMON_SSL_OPTIONS \
(SSL_OP_NO_COMPRESSION | SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION)
static isc_mem_t *isc__tls_mctx = NULL;
#if !defined(LIBRESSL_VERSION_NUMBER) && OPENSSL_VERSION_NUMBER >= 0x30000000L
/*
* This was crippled with LibreSSL, so just skip it:
* https://cvsweb.openbsd.org/src/lib/libcrypto/Attic/mem.c
*/
#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__tls_{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__tls_malloc_ex(size_t size, const char *file, int line) {
return (isc__mem_allocate(isc__tls_mctx, size, 0, file,
(unsigned int)line));
}
static void *
isc__tls_realloc_ex(void *ptr, size_t size, const char *file, int line) {
return (isc__mem_reallocate(isc__tls_mctx, ptr, size, 0, file,
(unsigned int)line));
}
static void
isc__tls_free_ex(void *ptr, const char *file, int line) {
if (ptr == NULL) {
return;
}
if (isc__tls_mctx != NULL) {
isc__mem_free(isc__tls_mctx, ptr, 0, file, (unsigned int)line);
}
}
#else /* ISC_MEM_TRACKLINES */
static void *
isc__tls_malloc_ex(size_t size, const char *file, int line) {
UNUSED(file);
UNUSED(line);
return (isc_mem_allocate(isc__tls_mctx, size));
}
static void *
isc__tls_realloc_ex(void *ptr, size_t size, const char *file, int line) {
UNUSED(file);
UNUSED(line);
return (isc_mem_reallocate(isc__tls_mctx, ptr, size));
}
static void
isc__tls_free_ex(void *ptr, const char *file, int line) {
UNUSED(file);
UNUSED(line);
if (ptr == NULL) {
return;
}
if (isc__tls_mctx != NULL) {
isc__mem_free(isc__tls_mctx, ptr, 0);
}
}
#endif /* ISC_MEM_TRACKLINES */
#endif /* !defined(LIBRESSL_VERSION_NUMBER) */
static void
enable_fips_mode(void) {
#if defined(ENABLE_FIPS_MODE)
if (isc_fips_mode()) {
/*
* FIPS mode is already enabled.
*/
return;
}
if (isc_fips_set_mode(1) != ISC_R_SUCCESS) {
isc_tlserr2result(ISC_LOGCATEGORY_GENERAL, ISC_LOGMODULE_OTHER,
"FIPS_mode_set", ISC_R_CRYPTOFAILURE);
exit(EXIT_FAILURE);
}
#endif
}
void
isc__tls_initialize(void) {
isc_mem_create(&isc__tls_mctx);
isc_mem_setname(isc__tls_mctx, "OpenSSL");
isc_mem_setdestroycheck(isc__tls_mctx, false);
#if !defined(LIBRESSL_VERSION_NUMBER) && OPENSSL_VERSION_NUMBER >= 0x30000000L
/*
* CRYPTO_set_mem_(_ex)_functions() returns 1 on success or 0 on
* failure, which means OpenSSL already allocated some memory. There's
* nothing we can do about it.
*/
(void)CRYPTO_set_mem_functions(isc__tls_malloc_ex, isc__tls_realloc_ex,
isc__tls_free_ex);
#endif /* !defined(LIBRESSL_VERSION_NUMBER) && OPENSSL_VERSION_NUMBER >= \
0x30000000L */
uint64_t opts = OPENSSL_INIT_LOAD_CONFIG;
#if defined(OPENSSL_INIT_NO_ATEXIT)
/*
* We call OPENSSL_cleanup() manually, in a correct order, thus disable
* the automatic atexit() handler.
*/
opts |= OPENSSL_INIT_NO_ATEXIT;
#endif
RUNTIME_CHECK(OPENSSL_init_ssl(opts, NULL) == 1);
/* Protect ourselves against unseeded PRNG */
if (RAND_status() != 1) {
FATAL_ERROR("OpenSSL pseudorandom number generator "
"cannot be initialized (see the `PRNG not "
"seeded' message in the OpenSSL FAQ)");
}
enable_fips_mode();
}
void
isc__tls_shutdown(void) {
OPENSSL_cleanup();
isc_mem_destroy(&isc__tls_mctx);
}
void
isc__tls_setdestroycheck(bool check) {
isc_mem_setdestroycheck(isc__tls_mctx, check);
}
void
isc_tlsctx_free(isc_tlsctx_t **ctxp) {
SSL_CTX *ctx = NULL;
@ -441,7 +302,7 @@ isc_tlsctx_createserver(const char *keyfile, const char *certfile,
-1, -1, 0);
X509_set_issuer_name(cert, name);
X509_sign(cert, pkey, EVP_sha256());
X509_sign(cert, pkey, isc__crypto_sha256);
rv = SSL_CTX_use_certificate(ctx, cert);
if (rv != 1) {
goto ssl_error;