From 35eeefb437aa70ffecf5cbfc75e1d0ce20ab7069 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ayd=C4=B1n=20Mercan?= Date: Tue, 16 Sep 2025 13:43:52 +0200 Subject: [PATCH 01/16] initial openssl version splitting Dealing with OpenSSL has been rapidly turning into an unwieldy situation as post-3.0 changes turn the library into a different beast. Start treating pre and post-3.0 versions differently for easier maintenance. --- .gitlab-ci.yml | 4 +- lib/isc/crypto/meson.build | 16 ++ lib/isc/crypto/ossl1_1.c | 217 +++++++++++++++++++++++++++ lib/isc/{crypto.c => crypto/ossl3.c} | 99 ++---------- lib/isc/crypto/ossl_common.c | 21 +++ lib/isc/include/isc/crypto.h | 12 +- lib/isc/meson.build | 2 +- meson.build | 42 ++++-- 8 files changed, 303 insertions(+), 110 deletions(-) create mode 100644 lib/isc/crypto/meson.build create mode 100644 lib/isc/crypto/ossl1_1.c rename lib/isc/{crypto.c => crypto/ossl3.c} (71%) create mode 100644 lib/isc/crypto/ossl_common.c diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index ba30f9e402..11ec934207 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -1389,15 +1389,13 @@ gcc:trixie:amd64cross32: <<: *debian_trixie_amd64cross32_image <<: *build_job -# Jobs for strict OpenSSL 3.x (no deprecated) GCC builds on Debian "trixie" (amd64) # Run with pkcs11-provider tests - gcc:ossl3:trixie:amd64: <<: *debian_trixie_amd64_image <<: *build_job variables: CC: gcc - CFLAGS: "${CFLAGS_COMMON} -DOPENSSL_NO_DEPRECATED=1 -DOPENSSL_API_COMPAT=30000" + CFLAGS: "${CFLAGS_COMMON}" # See https://gitlab.isc.org/isc-projects/bind9/-/issues/3444 EXTRA_CONFIGURE: "-Doptimization=3 -Djemalloc=disabled -Dleak-detection=disabled" RUN_MESON_INSTALL: 1 diff --git a/lib/isc/crypto/meson.build b/lib/isc/crypto/meson.build new file mode 100644 index 0000000000..e610fbe817 --- /dev/null +++ b/lib/isc/crypto/meson.build @@ -0,0 +1,16 @@ +# 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. + +isc_srcset.add( + when: 'HAVE_OPENSSL_3', + if_true: files('ossl3.c', 'ossl_common.c'), + if_false: files('ossl1_1.c', 'ossl_common.c'), +) diff --git a/lib/isc/crypto/ossl1_1.c b/lib/isc/crypto/ossl1_1.c new file mode 100644 index 0000000000..a8ac863fc6 --- /dev/null +++ b/lib/isc/crypto/ossl1_1.c @@ -0,0 +1,217 @@ +/* + * 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 +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +static isc_mem_t *isc__crypto_mctx = NULL; + +#define md_register_algorithm(alg) \ + { \ + isc__crypto_##alg = UNCONST(EVP_##alg()); \ + if (isc__crypto_##alg == NULL) { \ + ERR_clear_error(); \ + } \ + } + +static isc_result_t +register_algorithms(void) { + if (!isc_crypto_fips_mode()) { + md_register_algorithm(md5); + } + + md_register_algorithm(sha1); + md_register_algorithm(sha224); + md_register_algorithm(sha256); + md_register_algorithm(sha384); + md_register_algorithm(sha512); + + return ISC_R_SUCCESS; +} + +#undef md_unregister_algorithm + +#ifndef LIBRESSL_VERSION_NUMBER +/* + * 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, __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 */ + +#endif /* !LIBRESSL_VERSION_NUMBER */ + +#ifdef HAVE_FIPS_MODE +bool +isc_crypto_fips_mode(void) { + return FIPS_mode() != 0; +} + +isc_result_t +isc_crypto_fips_enable(void) { + if (isc_crypto_fips_mode()) { + return ISC_R_SUCCESS; + } + + if (FIPS_mode_set(1) == 0) { + return isc_tlserr2result(ISC_LOGCATEGORY_GENERAL, + ISC_LOGMODULE_CRYPTO, "FIPS_mode_set", + ISC_R_CRYPTOFAILURE); + } + + register_algorithms(); + + return ISC_R_SUCCESS; +} +#else +bool +isc_crypto_fips_mode(void) { + return false; +} + +isc_result_t +isc_crypto_fips_enable(void) { + return ISC_R_NOTIMPLEMENTED; +} +#endif + +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("OpenSSL", &isc__crypto_mctx); + isc_mem_setdebugging(isc__crypto_mctx, 0); + isc_mem_setdestroycheck(isc__crypto_mctx, false); + +#ifndef LIBRESSL_VERSION_NUMBER + /* + * 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 /* !LIBRESSL_VERSION_NUMBER */ + +#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); + + register_algorithms(); + +#if defined(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) { + OPENSSL_cleanup(); + + isc_mem_detach(&isc__crypto_mctx); +} diff --git a/lib/isc/crypto.c b/lib/isc/crypto/ossl3.c similarity index 71% rename from lib/isc/crypto.c rename to lib/isc/crypto/ossl3.c index 9e4347794f..5f90df2bdd 100644 --- a/lib/isc/crypto.c +++ b/lib/isc/crypto/ossl3.c @@ -14,13 +14,10 @@ #include #include #include +#include #include #include -#if OPENSSL_VERSION_NUMBER >= 0x30000000L -#include -#endif /* OPENSSL_VERSION_NUMBER >= 0x30000000L */ - #include #include #include @@ -29,18 +26,8 @@ static isc_mem_t *isc__crypto_mctx = NULL; -#if OPENSSL_VERSION_NUMBER >= 0x30000000L static OSSL_PROVIDER *base = NULL, *fips = NULL; -#endif /* OPENSSL_VERSION_NUMBER >= 0x30000000L */ -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); \ @@ -50,23 +37,13 @@ const EVP_MD *isc__crypto_sha512 = NULL; } \ } -#define md_unregister_algorithm(alg) \ - { \ - if (isc__crypto_##alg != NULL) { \ - EVP_MD_free(UNCONST(isc__crypto_##alg)); \ - isc__crypto_##alg = NULL; \ - } \ +#define md_unregister_algorithm(alg) \ + { \ + if (isc__crypto_##alg != NULL) { \ + EVP_MD_free(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 */ static isc_result_t register_algorithms(void) { @@ -96,12 +73,6 @@ unregister_algorithms(void) { #undef md_unregister_algorithm #undef md_register_algorithm -#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 @@ -165,9 +136,6 @@ isc__crypto_free_ex(void *ptr, const char *file, int line) { #endif /* ISC_MEM_TRACKLINES */ -#endif /* !defined(LIBRESSL_VERSION_NUMBER) */ - -#if defined(HAVE_EVP_DEFAULT_PROPERTIES_ENABLE_FIPS) bool isc_crypto_fips_mode(void) { return EVP_default_properties_is_fips_enabled(NULL) != 0; @@ -208,40 +176,6 @@ isc_crypto_fips_enable(void) { return ISC_R_SUCCESS; } -#elif defined(HAVE_FIPS_MODE) -bool -isc_crypto_fips_mode(void) { - return FIPS_mode() != 0; -} - -isc_result_t -isc_crypto_fips_enable(void) { - if (isc_crypto_fips_mode()) { - return ISC_R_SUCCESS; - } - - if (FIPS_mode_set(1) == 0) { - return isc_tlserr2result(ISC_LOGCATEGORY_GENERAL, - ISC_LOGMODULE_CRYPTO, "FIPS_mode_set", - ISC_R_CRYPTOFAILURE); - } - - unregister_algorithms(); - register_algorithms(); - - return ISC_R_SUCCESS; -} -#else -bool -isc_crypto_fips_mode(void) { - return false; -} - -isc_result_t -isc_crypto_fips_enable(void) { - return ISC_R_NOTIMPLEMENTED; -} -#endif void isc__crypto_setdestroycheck(bool check) { @@ -250,13 +184,16 @@ isc__crypto_setdestroycheck(bool check) { void isc__crypto_initialize(void) { - uint64_t opts = OPENSSL_INIT_LOAD_CONFIG; + /* + * We call OPENSSL_cleanup() manually, in a correct order, thus disable + * the automatic atexit() handler. + */ + 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); -#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 @@ -265,16 +202,6 @@ isc__crypto_initialize(void) { (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); @@ -302,7 +229,6 @@ void isc__crypto_shutdown(void) { unregister_algorithms(); -#if OPENSSL_VERSION_NUMBER >= 0x30000000L if (base != NULL) { OSSL_PROVIDER_unload(base); } @@ -310,7 +236,6 @@ isc__crypto_shutdown(void) { if (fips != NULL) { OSSL_PROVIDER_unload(fips); } -#endif /* OPENSSL_VERSION_NUMBER >= 0x30000000L */ OPENSSL_cleanup(); diff --git a/lib/isc/crypto/ossl_common.c b/lib/isc/crypto/ossl_common.c new file mode 100644 index 0000000000..1d940fa109 --- /dev/null +++ b/lib/isc/crypto/ossl_common.c @@ -0,0 +1,21 @@ +/* + * 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 + +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; diff --git a/lib/isc/include/isc/crypto.h b/lib/isc/include/isc/crypto.h index 14bdd46933..a7dc9f45a4 100644 --- a/lib/isc/include/isc/crypto.h +++ b/lib/isc/include/isc/crypto.h @@ -17,12 +17,12 @@ #include -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; +extern EVP_MD *isc__crypto_md5; +extern EVP_MD *isc__crypto_sha1; +extern EVP_MD *isc__crypto_sha224; +extern EVP_MD *isc__crypto_sha256; +extern EVP_MD *isc__crypto_sha384; +extern EVP_MD *isc__crypto_sha512; bool isc_crypto_fips_mode(void); diff --git a/lib/isc/meson.build b/lib/isc/meson.build index d4db21672e..645ff469cf 100644 --- a/lib/isc/meson.build +++ b/lib/isc/meson.build @@ -20,6 +20,7 @@ endif # isc_inc += include_directories('include') isc_inc_p += include_directories('.') +subdir('crypto') subdir('netmgr') isc_srcset.add( @@ -75,7 +76,6 @@ isc_srcset.add( 'base64.c', 'commandline.c', 'counter.c', - 'crypto.c', 'dir.c', 'errno.c', 'errno2result.c', diff --git a/meson.build b/meson.build index e979c79040..2529a0155b 100644 --- a/meson.build +++ b/meson.build @@ -602,21 +602,37 @@ openssl_dep = [ dependency('libssl', version: '>=1.1.1'), ] -foreach fn, header : { - 'EVP_default_properties_enable_fips': '#include ', - 'FIPS_mode': '#include ', -} - if cc.has_function(fn, prefix: header, dependencies: openssl_dep) - config.set('HAVE_OPENSSL_FIPS_TOGGLE', 1) - config.set('HAVE_@0@'.format(fn.to_upper()), 1) - endif -endforeach - -fips_opt.require( - config.has('HAVE_OPENSSL_FIPS_TOGGLE'), - error_message: 'OpenSSL FIPS mode requested but not available', +# OpenSSL-forks usually set their own version number which can be greater than 3.0.0. +# To understand if the library is pre or post-3.0, use the OPENSSL_VERSION_NUMBER value. +openssl_version_number = cc.get_define( + 'OPENSSL_VERSION_NUMBER', + dependencies: openssl_dep, + prefix: '#include ', ) +config.set('OPENSSL_NO_DEPRECATED', true) +if openssl_version_number.version_compare('>=3.0.0') + config.set('HAVE_OPENSSL_3', true) + config.set('OPENSSL_API_COMPAT', 30000) +else + config.set('HAVE_OPENSSL_3', false) + config.set('OPENSSL_API_COMPAT', 10100) + + config.set( + 'HAVE_FIPS_MODE', + cc.has_function( + 'FIPS_mode', + prefix: '#include ', + dependencies: openssl_dep, + ), + ) + + fips_opt.require( + config.get('HAVE_FIPS_MODE'), + error_message: 'OpenSSL FIPS mode requested but not available', + ) +endif + # Hash and curve probe if cc.has_header_symbol('openssl/evp.h', 'NID_ED448', dependencies: openssl_dep) config.set('HAVE_OPENSSL_ED448', 1) From f9ec4a1cdfcb9430d565c4a9a81a8825d298c498 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ayd=C4=B1n=20Mercan?= Date: Tue, 16 Sep 2025 15:11:37 +0200 Subject: [PATCH 02/16] switch isc_md_type_t to a proper enum Get rid of the OpenSSL-isms that plague the codebase where the hash type is `EVP_MD *` By using a proper enum, alongside the cleanup, we also get the ability to use constants for known hash sizes instead of having a function call every time. `EVP_MD_CTX_get0_md` has been removed instead of being adapted since it wasn't used anymore. --- lib/dns/catz.c | 2 +- lib/dns/ds.c | 2 +- lib/dns/dst_api.c | 12 +++---- lib/dns/hmac_link.c | 23 ++++++------ lib/dns/opensslecdsa_link.c | 8 +++-- lib/dns/opensslrsa_link.c | 15 ++++---- lib/isc/crypto/crypto_p.h | 18 ++++++++++ lib/isc/crypto/ossl1_1.c | 27 +++++++------- lib/isc/crypto/ossl3.c | 50 ++++++++++++-------------- lib/isc/crypto/ossl_common.c | 17 +++++---- lib/isc/hmac.c | 19 +++++----- lib/isc/include/isc/crypto.h | 9 ----- lib/isc/include/isc/hmac.h | 14 ++------ lib/isc/include/isc/md.h | 69 ++++++++++++++---------------------- lib/isc/iterated_hash.c | 7 ++-- lib/isc/md.c | 45 ++++++++++------------- lib/isc/openssl_shim.h | 4 --- lib/isc/tls.c | 6 +++- lib/isccc/cc.c | 4 +-- meson.build | 1 - tests/isc/hmac_test.c | 4 +-- tests/isc/md_test.c | 6 ++-- 22 files changed, 170 insertions(+), 192 deletions(-) create mode 100644 lib/isc/crypto/crypto_p.h diff --git a/lib/dns/catz.c b/lib/dns/catz.c index 410e00f078..6e16621204 100644 --- a/lib/dns/catz.c +++ b/lib/dns/catz.c @@ -1859,7 +1859,7 @@ dns_catz_generate_masterfilename(dns_catz_zone_t *catz, dns_catz_entry_t *entry, isc_buffer_subtract(tbuf, 1); /* __catz__.db */ - rlen = (isc_md_type_get_size(ISC_MD_SHA256) * 2 + 1) + 12; + rlen = (ISC_SHA256_DIGESTLENGTH * 2 + 1) + 12; /* optionally prepend with / */ if (entry->opts.zonedir != NULL) { diff --git a/lib/dns/ds.c b/lib/dns/ds.c index e8c71a80c7..bc937c8eec 100644 --- a/lib/dns/ds.c +++ b/lib/dns/ds.c @@ -41,7 +41,7 @@ dns_ds_fromkeyrdata(const dns_name_t *owner, dns_rdata_t *key, unsigned int privatelen = 0; isc_region_t r; isc_md_t *md; - const isc_md_type_t *md_type = NULL; + isc_md_type_t md_type = ISC_MD_UNKNOWN; REQUIRE(key != NULL); REQUIRE(key->type == dns_rdatatype_dnskey || diff --git a/lib/dns/dst_api.c b/lib/dns/dst_api.c index 2f4ebf9753..b8b673043b 100644 --- a/lib/dns/dst_api.c +++ b/lib/dns/dst_api.c @@ -1321,22 +1321,22 @@ dst_key_sigsize(const dst_key_t *key, unsigned int *n) { *n = DNS_SIG_ED448SIZE; break; case DST_ALG_HMACMD5: - *n = isc_md_type_get_size(ISC_MD_MD5); + *n = ISC_MD5_DIGESTLENGTH; break; case DST_ALG_HMACSHA1: - *n = isc_md_type_get_size(ISC_MD_SHA1); + *n = ISC_SHA1_DIGESTLENGTH; break; case DST_ALG_HMACSHA224: - *n = isc_md_type_get_size(ISC_MD_SHA224); + *n = ISC_SHA224_DIGESTLENGTH; break; case DST_ALG_HMACSHA256: - *n = isc_md_type_get_size(ISC_MD_SHA256); + *n = ISC_SHA256_DIGESTLENGTH; break; case DST_ALG_HMACSHA384: - *n = isc_md_type_get_size(ISC_MD_SHA384); + *n = ISC_SHA384_DIGESTLENGTH; break; case DST_ALG_HMACSHA512: - *n = isc_md_type_get_size(ISC_MD_SHA512); + *n = ISC_SHA512_DIGESTLENGTH; break; case DST_ALG_GSSAPI: *n = 128; /*%< XXX */ diff --git a/lib/dns/hmac_link.c b/lib/dns/hmac_link.c index 320b8adb85..40a87aac70 100644 --- a/lib/dns/hmac_link.c +++ b/lib/dns/hmac_link.c @@ -141,7 +141,7 @@ } static isc_result_t -hmac_fromdns(const isc_md_type_t *type, dst_key_t *key, isc_buffer_t *data); +hmac_fromdns(isc_md_type_t type, dst_key_t *key, isc_buffer_t *data); struct dst_hmac_key { uint8_t key[ISC_MAX_BLOCK_SIZE]; @@ -161,8 +161,7 @@ getkeybits(dst_key_t *key, struct dst_private_element *element) { } static isc_result_t -hmac_createctx(const isc_md_type_t *type, const dst_key_t *key, - dst_context_t *dctx) { +hmac_createctx(isc_md_type_t type, const dst_key_t *key, dst_context_t *dctx) { isc_result_t result; const dst_hmac_key_t *hkey = key->keydata.hmac_key; isc_hmac_t *ctx = isc_hmac_new(); /* Either returns or abort()s */ @@ -252,8 +251,7 @@ hmac_verify(const dst_context_t *dctx, const isc_region_t *sig) { } static bool -hmac_compare(const isc_md_type_t *type, const dst_key_t *key1, - const dst_key_t *key2) { +hmac_compare(isc_md_type_t type, const dst_key_t *key1, const dst_key_t *key2) { dst_hmac_key_t *hkey1, *hkey2; hkey1 = key1->keydata.hmac_key; @@ -270,7 +268,7 @@ hmac_compare(const isc_md_type_t *type, const dst_key_t *key1, } static isc_result_t -hmac_generate(const isc_md_type_t *type, dst_key_t *key) { +hmac_generate(isc_md_type_t type, dst_key_t *key) { isc_buffer_t b; isc_result_t result; unsigned int bytes, len; @@ -327,7 +325,7 @@ hmac_todns(const dst_key_t *key, isc_buffer_t *data) { } static isc_result_t -hmac_fromdns(const isc_md_type_t *type, dst_key_t *key, isc_buffer_t *data) { +hmac_fromdns(isc_md_type_t type, dst_key_t *key, isc_buffer_t *data) { dst_hmac_key_t *hkey; unsigned int keylen; isc_region_t r; @@ -363,7 +361,7 @@ hmac_fromdns(const isc_md_type_t *type, dst_key_t *key, isc_buffer_t *data) { } static int -hmac__get_tag_key(const isc_md_type_t *type) { +hmac__get_tag_key(isc_md_type_t type) { if (type == ISC_MD_MD5) { return TAG_HMACMD5_KEY; } else if (type == ISC_MD_SHA1) { @@ -382,7 +380,7 @@ hmac__get_tag_key(const isc_md_type_t *type) { } static int -hmac__get_tag_bits(const isc_md_type_t *type) { +hmac__get_tag_bits(isc_md_type_t type) { if (type == ISC_MD_MD5) { return TAG_HMACMD5_BITS; } else if (type == ISC_MD_SHA1) { @@ -401,8 +399,7 @@ hmac__get_tag_bits(const isc_md_type_t *type) { } static isc_result_t -hmac_tofile(const isc_md_type_t *type, const dst_key_t *key, - const char *directory) { +hmac_tofile(isc_md_type_t type, const dst_key_t *key, const char *directory) { dst_hmac_key_t *hkey; dst_private_t priv; int bytes = (key->key_size + 7) / 8; @@ -434,7 +431,7 @@ hmac_tofile(const isc_md_type_t *type, const dst_key_t *key, } static int -hmac__to_dst_alg(const isc_md_type_t *type) { +hmac__to_dst_alg(isc_md_type_t type) { if (type == ISC_MD_MD5) { return DST_ALG_HMACMD5; } else if (type == ISC_MD_SHA1) { @@ -453,7 +450,7 @@ hmac__to_dst_alg(const isc_md_type_t *type) { } static isc_result_t -hmac_parse(const isc_md_type_t *type, dst_key_t *key, isc_lex_t *lexer, +hmac_parse(isc_md_type_t type, dst_key_t *key, isc_lex_t *lexer, dst_key_t *pub) { dst_private_t priv; isc_result_t result = ISC_R_SUCCESS, tresult; diff --git a/lib/dns/opensslecdsa_link.c b/lib/dns/opensslecdsa_link.c index 54213d5cdf..7bd3729b8b 100644 --- a/lib/dns/opensslecdsa_link.c +++ b/lib/dns/opensslecdsa_link.c @@ -26,6 +26,7 @@ #include #endif +#include #include #include #include @@ -39,6 +40,9 @@ #include "dst_parse.h" #include "openssl_shim.h" +/* TODO(aydin): remove this crap */ +extern EVP_MD *isc__crypto_md[]; + #ifndef NID_X9_62_prime256v1 #error "P-256 group is not known (NID_X9_62_prime256v1)" #endif /* ifndef NID_X9_62_prime256v1 */ @@ -684,9 +688,9 @@ opensslecdsa_createctx(dst_key_t *key, dst_context_t *dctx) { CLEANUP(dst__openssl_toresult(ISC_R_NOMEMORY)); } if (dctx->key->key_alg == DST_ALG_ECDSA256) { - type = isc__crypto_sha256; + type = isc__crypto_md[ISC_MD_SHA256]; } else { - type = isc__crypto_sha384; + type = isc__crypto_md[ISC_MD_SHA384]; } if (dctx->use == DO_SIGN) { diff --git a/lib/dns/opensslrsa_link.c b/lib/dns/opensslrsa_link.c index 465e1f663d..bc79ae0100 100644 --- a/lib/dns/opensslrsa_link.c +++ b/lib/dns/opensslrsa_link.c @@ -39,6 +39,9 @@ #define OPENSSLRSA_MAX_MODULUS_BITS 4096 +/* TODO(aydin): remove this crap */ +extern EVP_MD *isc__crypto_md[]; + typedef struct rsa_components { bool bnfree; const BIGNUM *e, *n, *d, *p, *q, *dmp1, *dmq1, *iqmp; @@ -210,15 +213,15 @@ opensslrsa_createctx(dst_key_t *key, dst_context_t *dctx) { switch (dctx->key->key_alg) { case DST_ALG_RSASHA1: case DST_ALG_NSEC3RSASHA1: - type = isc__crypto_sha1; /* SHA1 + RSA */ + type = isc__crypto_md[ISC_MD_SHA1]; /* SHA1 + RSA */ break; case DST_ALG_RSASHA256: case DST_ALG_RSASHA256PRIVATEOID: - type = isc__crypto_sha256; /* SHA256 + RSA */ + type = isc__crypto_md[ISC_MD_SHA256]; /* SHA256 + RSA */ break; case DST_ALG_RSASHA512: case DST_ALG_RSASHA512PRIVATEOID: - type = isc__crypto_sha512; + type = isc__crypto_md[ISC_MD_SHA512]; break; default: UNREACHABLE(); @@ -1312,19 +1315,19 @@ check_algorithm(unsigned short algorithm) { switch (algorithm) { case DST_ALG_RSASHA1: case DST_ALG_NSEC3RSASHA1: - type = isc__crypto_sha1; /* SHA1 + RSA */ + type = isc__crypto_md[ISC_MD_SHA1]; /* SHA1 + RSA */ sig = sha1_sig; len = sizeof(sha1_sig) - 1; break; case DST_ALG_RSASHA256: case DST_ALG_RSASHA256PRIVATEOID: - type = isc__crypto_sha256; /* SHA256 + RSA */ + type = isc__crypto_md[ISC_MD_SHA256]; /* SHA256 + RSA */ sig = sha256_sig; len = sizeof(sha256_sig) - 1; break; case DST_ALG_RSASHA512: case DST_ALG_RSASHA512PRIVATEOID: - type = isc__crypto_sha512; + type = isc__crypto_md[ISC_MD_SHA512]; sig = sha512_sig; len = sizeof(sha512_sig) - 1; break; diff --git a/lib/isc/crypto/crypto_p.h b/lib/isc/crypto/crypto_p.h new file mode 100644 index 0000000000..899d9a2b40 --- /dev/null +++ b/lib/isc/crypto/crypto_p.h @@ -0,0 +1,18 @@ +/* + * 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 + +extern EVP_MD *isc__crypto_md[]; diff --git a/lib/isc/crypto/ossl1_1.c b/lib/isc/crypto/ossl1_1.c index a8ac863fc6..6920273b67 100644 --- a/lib/isc/crypto/ossl1_1.c +++ b/lib/isc/crypto/ossl1_1.c @@ -19,31 +19,34 @@ #include #include +#include #include #include #include +#include "crypto_p.h" + static isc_mem_t *isc__crypto_mctx = NULL; -#define md_register_algorithm(alg) \ - { \ - isc__crypto_##alg = UNCONST(EVP_##alg()); \ - if (isc__crypto_##alg == NULL) { \ - ERR_clear_error(); \ - } \ +#define md_register_algorithm(alg, upperalg) \ + { \ + isc__crypto_md[ISC_MD_##upperalg] = UNCONST(EVP_##alg()); \ + if (isc__crypto_md[ISC_MD_##upperalg] == NULL) { \ + ERR_clear_error(); \ + } \ } static isc_result_t register_algorithms(void) { if (!isc_crypto_fips_mode()) { - md_register_algorithm(md5); + md_register_algorithm(md5, MD5); } - md_register_algorithm(sha1); - md_register_algorithm(sha224); - md_register_algorithm(sha256); - md_register_algorithm(sha384); - md_register_algorithm(sha512); + 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; } diff --git a/lib/isc/crypto/ossl3.c b/lib/isc/crypto/ossl3.c index 5f90df2bdd..00ac7c8257 100644 --- a/lib/isc/crypto/ossl3.c +++ b/lib/isc/crypto/ossl3.c @@ -20,57 +20,51 @@ #include #include +#include #include #include #include +#include "crypto_p.h" + static isc_mem_t *isc__crypto_mctx = NULL; static OSSL_PROVIDER *base = NULL, *fips = NULL; -#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(isc__crypto_##alg); \ - isc__crypto_##alg = NULL; \ - } \ +#define md_register_algorithm(alg) \ + { \ + REQUIRE(isc__crypto_md[ISC_MD_##alg] == NULL); \ + isc__crypto_md[ISC_MD_##alg] = EVP_MD_fetch(NULL, #alg, NULL); \ + if (isc__crypto_md[ISC_MD_##alg] == NULL) { \ + ERR_clear_error(); \ + } \ } static isc_result_t register_algorithms(void) { if (!isc_crypto_fips_mode()) { - md_register_algorithm(md5, "MD5"); + md_register_algorithm(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"); + md_register_algorithm(SHA1); + md_register_algorithm(SHA224); + md_register_algorithm(SHA256); + md_register_algorithm(SHA384); + md_register_algorithm(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); + for (size_t i = 0; i < ISC_MD_MAX; i++) { + if (isc__crypto_md[i] != NULL) { + EVP_MD_free(isc__crypto_md[i]); + isc__crypto_md[i] = NULL; + } + } } -#undef md_unregister_algorithm #undef md_register_algorithm #if ISC_MEM_TRACKLINES diff --git a/lib/isc/crypto/ossl_common.c b/lib/isc/crypto/ossl_common.c index 1d940fa109..41bd284102 100644 --- a/lib/isc/crypto/ossl_common.c +++ b/lib/isc/crypto/ossl_common.c @@ -11,11 +11,16 @@ * information regarding copyright ownership. */ +#include #include -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; +#include +#include + +#include "crypto_p.h" + +EVP_MD *isc__crypto_md[] = { + [ISC_MD_UNKNOWN] = NULL, [ISC_MD_MD5] = NULL, [ISC_MD_SHA1] = NULL, + [ISC_MD_SHA224] = NULL, [ISC_MD_SHA256] = NULL, [ISC_MD_SHA384] = NULL, + [ISC_MD_SHA512] = NULL, +}; diff --git a/lib/isc/hmac.c b/lib/isc/hmac.c index 46582ea9ec..05134cc185 100644 --- a/lib/isc/hmac.c +++ b/lib/isc/hmac.c @@ -23,6 +23,7 @@ #include #include +#include "crypto/crypto_p.h" #include "openssl_shim.h" isc_hmac_t * @@ -43,14 +44,17 @@ isc_hmac_free(isc_hmac_t *hmac_st) { isc_result_t isc_hmac_init(isc_hmac_t *hmac_st, const void *key, const size_t keylen, - const isc_md_type_t *md_type) { + isc_md_type_t type) { EVP_PKEY *pkey; + EVP_MD *md; REQUIRE(hmac_st != NULL); REQUIRE(key != NULL); REQUIRE(keylen <= INT_MAX); + REQUIRE(type < ISC_MD_MAX); - if (md_type == NULL) { + md = isc__crypto_md[type]; + if (md == NULL) { return ISC_R_NOTIMPLEMENTED; } @@ -60,7 +64,7 @@ isc_hmac_init(isc_hmac_t *hmac_st, const void *key, const size_t keylen, return ISC_R_CRYPTOFAILURE; } - if (EVP_DigestSignInit(hmac_st, NULL, md_type, NULL, pkey) != 1) { + if (EVP_DigestSignInit(hmac_st, NULL, md, NULL, pkey) != 1) { EVP_PKEY_free(pkey); ERR_clear_error(); return ISC_R_CRYPTOFAILURE; @@ -119,13 +123,6 @@ isc_hmac_final(isc_hmac_t *hmac_st, unsigned char *digest, return ISC_R_SUCCESS; } -const isc_md_type_t * -isc_hmac_get_md_type(isc_hmac_t *hmac_st) { - REQUIRE(hmac_st != NULL); - - return EVP_MD_CTX_get0_md(hmac_st); -} - size_t isc_hmac_get_size(isc_hmac_t *hmac_st) { REQUIRE(hmac_st != NULL); @@ -141,7 +138,7 @@ isc_hmac_get_block_size(isc_hmac_t *hmac_st) { } isc_result_t -isc_hmac(const isc_md_type_t *type, const void *key, const size_t keylen, +isc_hmac(isc_md_type_t type, const void *key, const size_t keylen, const unsigned char *buf, const size_t len, unsigned char *digest, unsigned int *digestlen) { isc_result_t res; diff --git a/lib/isc/include/isc/crypto.h b/lib/isc/include/isc/crypto.h index a7dc9f45a4..cd32da9391 100644 --- a/lib/isc/include/isc/crypto.h +++ b/lib/isc/include/isc/crypto.h @@ -13,17 +13,8 @@ #pragma once -#include - #include -extern EVP_MD *isc__crypto_md5; -extern EVP_MD *isc__crypto_sha1; -extern EVP_MD *isc__crypto_sha224; -extern EVP_MD *isc__crypto_sha256; -extern EVP_MD *isc__crypto_sha384; -extern EVP_MD *isc__crypto_sha512; - bool isc_crypto_fips_mode(void); /* diff --git a/lib/isc/include/isc/hmac.h b/lib/isc/include/isc/hmac.h index 0a6ba8c4ff..ecfc6e279c 100644 --- a/lib/isc/include/isc/hmac.h +++ b/lib/isc/include/isc/hmac.h @@ -43,7 +43,7 @@ typedef void isc_hmac_t; * of digest written to @digest. */ isc_result_t -isc_hmac(const isc_md_type_t *type, const void *key, const size_t keylen, +isc_hmac(isc_md_type_t type, const void *key, const size_t keylen, const unsigned char *buf, const size_t len, unsigned char *digest, unsigned int *digestlen); @@ -77,7 +77,7 @@ isc_hmac_free(isc_hmac_t *hmac); isc_result_t isc_hmac_init(isc_hmac_t *hmac, const void *key, const size_t keylen, - const isc_md_type_t *type); + isc_md_type_t type); /** * isc_hmac_reset: @@ -118,16 +118,6 @@ isc_result_t isc_hmac_final(isc_hmac_t *hmac, unsigned char *digest, unsigned int *digestlen); -/** - * isc_hmac_md_type: - * @hmac: HMAC context - * - * This function return the isc_md_type_t previously set for the supplied - * HMAC context or NULL if no isc_md_type_t has been set. - */ -const isc_md_type_t * -isc_hmac_get_md_type(isc_hmac_t *hmac); - /** * isc_hmac_get_size: * diff --git a/lib/isc/include/isc/md.h b/lib/isc/include/isc/md.h index 41c3447565..db95d1e84c 100644 --- a/lib/isc/include/isc/md.h +++ b/lib/isc/include/isc/md.h @@ -35,27 +35,29 @@ typedef void isc_md_t; * * Enumeration of supported message digest algorithms. */ -typedef void isc_md_type_t; +typedef enum isc_md_type { + ISC_MD_UNKNOWN = 0x00, + ISC_MD_MD5 = 0x01, + ISC_MD_SHA1 = 0x02, + ISC_MD_SHA224 = 0x03, + ISC_MD_SHA256 = 0x04, + ISC_MD_SHA384 = 0x05, + ISC_MD_SHA512 = 0x06, + ISC_MD_MAX = 0x07, +} isc_md_type_t; -#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) -#define ISC_SHA1_DIGESTLENGTH isc_md_type_get_size(ISC_MD_SHA1) -#define ISC_SHA1_BLOCK_LENGTH isc_md_type_get_block_size(ISC_MD_SHA1) -#define ISC_SHA224_DIGESTLENGTH isc_md_type_get_size(ISC_MD_SHA224) -#define ISC_SHA224_BLOCK_LENGTH isc_md_type_get_block_size(ISC_MD_SHA224) -#define ISC_SHA256_DIGESTLENGTH isc_md_type_get_size(ISC_MD_SHA256) -#define ISC_SHA256_BLOCK_LENGTH isc_md_type_get_block_size(ISC_MD_SHA256) -#define ISC_SHA384_DIGESTLENGTH isc_md_type_get_size(ISC_MD_SHA384) -#define ISC_SHA384_BLOCK_LENGTH isc_md_type_get_block_size(ISC_MD_SHA384) -#define ISC_SHA512_DIGESTLENGTH isc_md_type_get_size(ISC_MD_SHA512) -#define ISC_SHA512_BLOCK_LENGTH isc_md_type_get_block_size(ISC_MD_SHA512) +#define ISC_MD5_DIGESTLENGTH 16 +#define ISC_MD5_BLOCK_LENGTH 64 +#define ISC_SHA1_DIGESTLENGTH 20 +#define ISC_SHA1_BLOCK_LENGTH 64 +#define ISC_SHA224_DIGESTLENGTH 28 +#define ISC_SHA224_BLOCK_LENGTH 64 +#define ISC_SHA256_DIGESTLENGTH 32 +#define ISC_SHA256_BLOCK_LENGTH 64 +#define ISC_SHA384_DIGESTLENGTH 48 +#define ISC_SHA384_BLOCK_LENGTH 128 +#define ISC_SHA512_DIGESTLENGTH 64 +#define ISC_SHA512_BLOCK_LENGTH 128 #define ISC_MAX_MD_SIZE 64U /* EVP_MAX_MD_SIZE */ #define ISC_MAX_BLOCK_SIZE 128U /* ISC_SHA512_BLOCK_LENGTH */ @@ -74,7 +76,7 @@ typedef void isc_md_type_t; * at @digestlen, at most ISC_MAX_MD_SIZE bytes will be written. */ isc_result_t -isc_md(const isc_md_type_t *type, const unsigned char *buf, const size_t len, +isc_md(isc_md_type_t type, const unsigned char *buf, const size_t len, unsigned char *digest, unsigned int *digestlen); /** @@ -93,7 +95,7 @@ isc_md_new(void); * to it. */ void -isc_md_free(isc_md_t *); +isc_md_free(isc_md_t *md); /** * isc_md_init: @@ -104,7 +106,7 @@ isc_md_free(isc_md_t *); * initialized before calling this function. */ isc_result_t -isc_md_init(isc_md_t *, const isc_md_type_t *md_type); +isc_md_init(isc_md_t *md, isc_md_type_t type); /** * isc_md_reset: @@ -144,16 +146,6 @@ isc_md_update(isc_md_t *md, const unsigned char *buf, const size_t len); isc_result_t isc_md_final(isc_md_t *md, unsigned char *digest, unsigned int *digestlen); -/** - * isc_md_get_type: - * @md: message digest contezt - * - * This function return the isc_md_type_t previously set for the supplied - * message digest context or NULL if no isc_md_type_t has been set. - */ -const isc_md_type_t * -isc_md_get_md_type(isc_md_t *md); - /** * isc_md_size: * @@ -172,15 +164,6 @@ isc_md_get_size(isc_md_t *md); size_t isc_md_get_block_size(isc_md_t *md); -/** - * isc_md_size: - * - * This function return the size of the message digest when passed an - * isc_md_type_t , i.e. the size of the hash. - */ -size_t -isc_md_type_get_size(const isc_md_type_t *md_type); - /** * isc_md_block_size: * @@ -188,4 +171,4 @@ isc_md_type_get_size(const isc_md_type_t *md_type); * isc_md_type_t. */ size_t -isc_md_type_get_block_size(const isc_md_type_t *md_type); +isc_md_type_get_block_size(isc_md_type_t type); diff --git a/lib/isc/iterated_hash.c b/lib/isc/iterated_hash.c index dfffe3b129..fae0980907 100644 --- a/lib/isc/iterated_hash.c +++ b/lib/isc/iterated_hash.c @@ -17,11 +17,13 @@ #include #include -#include #include +#include #include #include +#include "crypto/crypto_p.h" + #if OPENSSL_VERSION_NUMBER < 0x30000000L #include @@ -150,7 +152,8 @@ isc__iterated_hash_initialize(void) { mdctx = EVP_MD_CTX_new(); INSIST(mdctx != NULL); - RUNTIME_CHECK(EVP_DigestInit_ex(basectx, isc__crypto_sha1, NULL) == 1); + RUNTIME_CHECK(EVP_DigestInit_ex(basectx, isc__crypto_md[ISC_MD_SHA1], + NULL) == 1); initialized = true; } diff --git a/lib/isc/md.c b/lib/isc/md.c index 8f461d60ca..87a167984c 100644 --- a/lib/isc/md.c +++ b/lib/isc/md.c @@ -20,6 +20,7 @@ #include #include +#include "crypto/crypto_p.h" #include "openssl_shim.h" isc_md_t * @@ -39,14 +40,18 @@ isc_md_free(isc_md_t *md) { } isc_result_t -isc_md_init(isc_md_t *md, const isc_md_type_t *md_type) { - REQUIRE(md != NULL); +isc_md_init(isc_md_t *md, isc_md_type_t type) { + EVP_MD *evp; - if (md_type == NULL) { + REQUIRE(md != NULL); + REQUIRE(type < ISC_MD_MAX); + + evp = isc__crypto_md[type]; + if (evp == NULL) { return ISC_R_NOTIMPLEMENTED; } - if (EVP_DigestInit_ex(md, md_type, NULL) != 1) { + if (EVP_DigestInit_ex(md, evp, NULL) != 1) { ERR_clear_error(); return ISC_R_CRYPTOFAILURE; } @@ -95,13 +100,6 @@ isc_md_final(isc_md_t *md, unsigned char *digest, unsigned int *digestlen) { return ISC_R_SUCCESS; } -const isc_md_type_t * -isc_md_get_md_type(isc_md_t *md) { - REQUIRE(md != NULL); - - return EVP_MD_CTX_get0_md(md); -} - size_t isc_md_get_size(isc_md_t *md) { REQUIRE(md != NULL); @@ -117,38 +115,31 @@ isc_md_get_block_size(isc_md_t *md) { } size_t -isc_md_type_get_size(const isc_md_type_t *md_type) { +isc_md_type_get_block_size(isc_md_type_t type) { + EVP_MD *evp; + + REQUIRE(type < ISC_MD_MAX); STATIC_ASSERT(ISC_MAX_MD_SIZE >= EVP_MAX_MD_SIZE, "Change ISC_MAX_MD_SIZE to be greater than or equal to " "EVP_MAX_MD_SIZE"); - if (md_type != NULL) { - return (size_t)EVP_MD_size(md_type); - } - return ISC_MAX_MD_SIZE; -} - -size_t -isc_md_type_get_block_size(const isc_md_type_t *md_type) { - STATIC_ASSERT(ISC_MAX_MD_SIZE >= EVP_MAX_MD_SIZE, - "Change ISC_MAX_MD_SIZE to be greater than or equal to " - "EVP_MAX_MD_SIZE"); - if (md_type != NULL) { - return (size_t)EVP_MD_block_size(md_type); + evp = isc__crypto_md[type]; + if (evp != NULL) { + return (size_t)EVP_MD_block_size(evp); } return ISC_MAX_MD_SIZE; } isc_result_t -isc_md(const isc_md_type_t *md_type, const unsigned char *buf, const size_t len, +isc_md(isc_md_type_t type, const unsigned char *buf, const size_t len, unsigned char *digest, unsigned int *digestlen) { isc_md_t *md; isc_result_t res; md = isc_md_new(); - res = isc_md_init(md, md_type); + res = isc_md_init(md, type); if (res != ISC_R_SUCCESS) { goto end; } diff --git a/lib/isc/openssl_shim.h b/lib/isc/openssl_shim.h index d2f8eeda72..316d7ae7dd 100644 --- a/lib/isc/openssl_shim.h +++ b/lib/isc/openssl_shim.h @@ -18,10 +18,6 @@ #include #include -#if !HAVE_EVP_MD_CTX_GET0_MD -#define EVP_MD_CTX_get0_md EVP_MD_CTX_md -#endif /* if !HAVE_EVP_MD_CTX_GET0_MD */ - #if !HAVE_BIO_READ_EX int BIO_read_ex(BIO *b, void *data, size_t dlen, size_t *readbytes); diff --git a/lib/isc/tls.c b/lib/isc/tls.c index 215730d76b..7477a1b9de 100644 --- a/lib/isc/tls.c +++ b/lib/isc/tls.c @@ -38,6 +38,7 @@ #include #include #include +#include #include #include #include @@ -51,6 +52,9 @@ #include "openssl_shim.h" +/* TODO(aydin): remove this crap */ +extern EVP_MD *isc__crypto_md[]; + #define COMMON_SSL_OPTIONS \ (SSL_OP_NO_COMPRESSION | SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION) @@ -315,7 +319,7 @@ isc_tlsctx_createserver(const char *keyfile, const char *certfile, -1, -1, 0); X509_set_issuer_name(cert, name); - X509_sign(cert, pkey, isc__crypto_sha256); + X509_sign(cert, pkey, isc__crypto_md[ISC_MD_SHA256]); rv = SSL_CTX_use_certificate(ctx, cert); if (rv != 1) { goto ssl_error; diff --git a/lib/isccc/cc.c b/lib/isccc/cc.c index a8f1a759af..bb3f3530d5 100644 --- a/lib/isccc/cc.c +++ b/lib/isccc/cc.c @@ -242,7 +242,7 @@ list_towire(isccc_sexpr_t *list, isc_buffer_t **buffer) { static isc_result_t sign(unsigned char *data, unsigned int length, unsigned char *out, uint32_t algorithm, isccc_region_t *secret) { - const isc_md_type_t *md_type; + isc_md_type_t md_type; isccc_region_t source, target; unsigned char digest[ISC_MAX_MD_SIZE]; unsigned int digestlen = sizeof(digest); @@ -353,7 +353,7 @@ isccc_cc_towire(isccc_sexpr_t *alist, isc_buffer_t **buffer, uint32_t algorithm, static isc_result_t verify(isccc_sexpr_t *alist, unsigned char *data, unsigned int length, uint32_t algorithm, isccc_region_t *secret) { - const isc_md_type_t *md_type; + isc_md_type_t md_type; isccc_region_t source; isccc_region_t target; isccc_sexpr_t *_auth, *hmacvalue; diff --git a/meson.build b/meson.build index 2529a0155b..443c5760db 100644 --- a/meson.build +++ b/meson.build @@ -642,7 +642,6 @@ foreach fn, header : { 'ERR_get_error_all': '#include ', 'BIO_read_ex': '#include ', 'BIO_write_ex': '#include ', - 'EVP_MD_CTX_get0_md': '#include ', 'EVP_PKEY_eq': '#include ', 'SSL_CTX_set1_cert_store': '#include ', } diff --git a/tests/isc/hmac_test.c b/tests/isc/hmac_test.c index 05b93bf79a..0245d6041b 100644 --- a/tests/isc/hmac_test.c +++ b/tests/isc/hmac_test.c @@ -94,7 +94,7 @@ ISC_RUN_TEST_IMPL(isc_hmac_free) { static void isc_hmac_test(isc_hmac_t *hmac_st, const void *key, size_t keylen, - const isc_md_type_t *type, const char *buf, size_t buflen, + isc_md_type_t type, const char *buf, size_t buflen, const char *result, const size_t repeats) { isc_result_t res; @@ -131,7 +131,7 @@ ISC_RUN_TEST_IMPL(isc_hmac_init) { isc_hmac_t *hmac_st = *state; assert_non_null(hmac_st); - assert_int_equal(isc_hmac_init(hmac_st, "", 0, NULL), + assert_int_equal(isc_hmac_init(hmac_st, "", 0, ISC_MD_UNKNOWN), ISC_R_NOTIMPLEMENTED); if (!isc_crypto_fips_mode()) { diff --git a/tests/isc/md_test.c b/tests/isc/md_test.c index 3602f968e7..b217a25b9c 100644 --- a/tests/isc/md_test.c +++ b/tests/isc/md_test.c @@ -82,8 +82,8 @@ ISC_RUN_TEST_IMPL(isc_md_free) { } static void -isc_md_test(isc_md_t *md, const isc_md_type_t *type, const char *buf, - size_t buflen, const char *result, const size_t repeats) { +isc_md_test(isc_md_t *md, isc_md_type_t type, const char *buf, size_t buflen, + const char *result, const size_t repeats) { isc_result_t res; assert_non_null(md); @@ -118,7 +118,7 @@ ISC_RUN_TEST_IMPL(isc_md_init) { expect_assert_failure(isc_md_init(NULL, ISC_MD_MD5)); - assert_int_equal(isc_md_init(md, NULL), ISC_R_NOTIMPLEMENTED); + assert_int_equal(isc_md_init(md, ISC_MD_UNKNOWN), ISC_R_NOTIMPLEMENTED); if (isc_crypto_fips_mode()) { assert_int_equal(isc_md_init(md, ISC_MD_MD5), From 8f106f2b66a8351e57cfd09be9bd41f1616332e9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ayd=C4=B1n=20Mercan?= Date: Wed, 17 Sep 2025 14:52:35 +0200 Subject: [PATCH 03/16] Separate isc_hmac between pre and post OpenSSL 3.0 Instead of the `EVP_MD_CTX` based functions, use either the new `EVP_MAC` or the old `HMAC_CTX` based functions. `EVP_MAC` is the recommended way using using MAC functions in post-3.0 while `HMAC_CTX` is used internally by `EVP_MD_CTX`, making the latter redundant. --- lib/dns/dst_internal.h | 4 +- lib/dns/hmac_link.c | 147 +++++++++------------ lib/isc/crypto/ossl1_1.c | 185 +++++++++++++++++++++++++++ lib/isc/crypto/ossl3.c | 255 +++++++++++++++++++++++++++++++++++++ lib/isc/hmac.c | 165 ------------------------ lib/isc/include/isc/hmac.h | 96 +++++++------- lib/isc/meson.build | 1 - tests/isc/hmac_test.c | 160 ++++++++++------------- 8 files changed, 618 insertions(+), 395 deletions(-) delete mode 100644 lib/isc/hmac.c diff --git a/lib/dns/dst_internal.h b/lib/dns/dst_internal.h index 51f8cd5d26..bc48c9fec4 100644 --- a/lib/dns/dst_internal.h +++ b/lib/dns/dst_internal.h @@ -62,8 +62,6 @@ typedef struct dst_func dst_func_t; -typedef struct dst_hmac_key dst_hmac_key_t; - /*% * Indicate whether a DST context will be used for signing * or for verification @@ -93,7 +91,7 @@ struct dst_key { union { void *generic; dns_gss_ctx_id_t gssctx; - dst_hmac_key_t *hmac_key; + isc_hmac_key_t *hmac_key; struct { EVP_PKEY *pub; EVP_PKEY *priv; diff --git a/lib/dns/hmac_link.c b/lib/dns/hmac_link.c index 40a87aac70..aa3d5d7141 100644 --- a/lib/dns/hmac_link.c +++ b/lib/dns/hmac_link.c @@ -55,7 +55,7 @@ #define hmac_register_algorithm(alg) \ static isc_result_t hmac##alg##_createctx(dst_key_t *key, \ dst_context_t *dctx) { \ - return (hmac_createctx(ISC_MD_##alg, key, dctx)); \ + return (hmac_createctx(key, dctx)); \ } \ static void hmac##alg##_destroyctx(dst_context_t *dctx) { \ hmac_destroyctx(dctx); \ @@ -74,7 +74,7 @@ } \ static bool hmac##alg##_compare(const dst_key_t *key1, \ const dst_key_t *key2) { \ - return (hmac_compare(ISC_MD_##alg, key1, key2)); \ + return (hmac_compare(key1, key2)); \ } \ static isc_result_t hmac##alg##_generate( \ dst_key_t *key, int pseudorandom_ok, void (*callback)(int)) { \ @@ -130,23 +130,20 @@ void dst__hmac##alg##_init(dst_func_t **funcp) { \ REQUIRE(funcp != NULL); \ if (*funcp == NULL) { \ - isc_hmac_t *ctx = isc_hmac_new(); \ - if (isc_hmac_init(ctx, "test", 4, ISC_MD_##alg) == \ - ISC_R_SUCCESS) \ + uint8_t data[] = "data"; \ + uint8_t mac_buffer[ISC_MAX_MD_SIZE]; \ + unsigned int mac_len = sizeof(mac_buffer); \ + if (isc_hmac(ISC_MD_##alg, "test", 4, data, 4, \ + mac_buffer, &mac_len) == ISC_R_SUCCESS) \ { \ *funcp = &hmac##alg##_functions; \ } \ - isc_hmac_free(ctx); \ } \ } static isc_result_t hmac_fromdns(isc_md_type_t type, dst_key_t *key, isc_buffer_t *data); -struct dst_hmac_key { - uint8_t key[ISC_MAX_BLOCK_SIZE]; -}; - static isc_result_t getkeybits(dst_key_t *key, struct dst_private_element *element) { uint16_t *bits = (uint16_t *)element->data; @@ -161,13 +158,11 @@ getkeybits(dst_key_t *key, struct dst_private_element *element) { } static isc_result_t -hmac_createctx(isc_md_type_t type, const dst_key_t *key, dst_context_t *dctx) { +hmac_createctx(const dst_key_t *key, dst_context_t *dctx) { isc_result_t result; - const dst_hmac_key_t *hkey = key->keydata.hmac_key; isc_hmac_t *ctx = isc_hmac_new(); /* Either returns or abort()s */ - result = isc_hmac_init(ctx, hkey->key, isc_md_type_get_block_size(type), - type); + result = isc_hmac_init(ctx, key->keydata.hmac_key); if (result != ISC_R_SUCCESS) { isc_hmac_free(ctx); return DST_R_UNSUPPORTEDALG; @@ -204,44 +199,35 @@ hmac_adddata(const dst_context_t *dctx, const isc_region_t *data) { static isc_result_t hmac_sign(const dst_context_t *dctx, isc_buffer_t *sig) { isc_hmac_t *ctx = dctx->ctxdata.hmac_ctx; + isc_result_t r; + REQUIRE(ctx != NULL); - unsigned char digest[ISC_MAX_MD_SIZE]; - unsigned int digestlen = sizeof(digest); - if (isc_hmac_final(ctx, digest, &digestlen) != ISC_R_SUCCESS) { - return DST_R_OPENSSLFAILURE; + r = isc_hmac_final(ctx, sig); + + /* Turn CRYPTOFAILURE into OPENSSLFAILURE */ + if (r == ISC_R_CRYPTOFAILURE) { + r = DST_R_OPENSSLFAILURE; } - if (isc_hmac_reset(ctx) != ISC_R_SUCCESS) { - return DST_R_OPENSSLFAILURE; - } - - if (isc_buffer_availablelength(sig) < digestlen) { - return ISC_R_NOSPACE; - } - - isc_buffer_putmem(sig, digest, digestlen); - - return ISC_R_SUCCESS; + return r; } static isc_result_t hmac_verify(const dst_context_t *dctx, const isc_region_t *sig) { isc_hmac_t *ctx = dctx->ctxdata.hmac_ctx; unsigned char digest[ISC_MAX_MD_SIZE]; - unsigned int digestlen = sizeof(digest); + isc_buffer_t hmac; REQUIRE(ctx != NULL); - if (isc_hmac_final(ctx, digest, &digestlen) != ISC_R_SUCCESS) { + isc_buffer_init(&hmac, digest, sizeof(digest)); + + if (isc_hmac_final(ctx, &hmac) != ISC_R_SUCCESS) { return DST_R_OPENSSLFAILURE; } - if (isc_hmac_reset(ctx) != ISC_R_SUCCESS) { - return DST_R_OPENSSLFAILURE; - } - - if (sig->length > digestlen) { + if (sig->length > isc_buffer_usedlength(&hmac)) { return DST_R_VERIFYFAILURE; } @@ -251,8 +237,8 @@ hmac_verify(const dst_context_t *dctx, const isc_region_t *sig) { } static bool -hmac_compare(isc_md_type_t type, const dst_key_t *key1, const dst_key_t *key2) { - dst_hmac_key_t *hkey1, *hkey2; +hmac_compare(const dst_key_t *key1, const dst_key_t *key2) { + isc_hmac_key_t *hkey1, *hkey2; hkey1 = key1->keydata.hmac_key; hkey2 = key2->keydata.hmac_key; @@ -263,8 +249,7 @@ hmac_compare(isc_md_type_t type, const dst_key_t *key1, const dst_key_t *key2) { return false; } - return isc_safe_memequal(hkey1->key, hkey2->key, - isc_md_type_get_block_size(type)); + return isc_hmac_key_equal(hkey1, hkey2); } static isc_result_t @@ -303,31 +288,28 @@ hmac_isprivate(const dst_key_t *key) { static void hmac_destroy(dst_key_t *key) { - dst_hmac_key_t *hkey = key->keydata.hmac_key; - isc_safe_memwipe(hkey, sizeof(*hkey)); - isc_mem_put(key->mctx, hkey, sizeof(*hkey)); - key->keydata.hmac_key = NULL; + isc_hmac_key_destroy(&key->keydata.hmac_key); } static isc_result_t hmac_todns(const dst_key_t *key, isc_buffer_t *data) { - REQUIRE(key != NULL && key->keydata.hmac_key != NULL); - dst_hmac_key_t *hkey = key->keydata.hmac_key; - unsigned int bytes; + isc_region_t raw_key; - bytes = (key->key_size + 7) / 8; - if (isc_buffer_availablelength(data) < bytes) { + REQUIRE(key != NULL && key->keydata.hmac_key != NULL); + + raw_key = isc_hmac_key_expose(key->keydata.hmac_key); + + if (isc_buffer_availablelength(data) < raw_key.length) { return ISC_R_NOSPACE; } - isc_buffer_putmem(data, hkey->key, bytes); - return ISC_R_SUCCESS; + return isc_buffer_copyregion(data, &raw_key); } static isc_result_t hmac_fromdns(isc_md_type_t type, dst_key_t *key, isc_buffer_t *data) { - dst_hmac_key_t *hkey; - unsigned int keylen; + isc_hmac_key_t *hkey = NULL; + isc_result_t result; isc_region_t r; isc_buffer_remainingregion(data, &r); @@ -335,24 +317,12 @@ hmac_fromdns(isc_md_type_t type, dst_key_t *key, isc_buffer_t *data) { return ISC_R_SUCCESS; } - hkey = isc_mem_get(key->mctx, sizeof(dst_hmac_key_t)); - - memset(hkey->key, 0, sizeof(hkey->key)); - - /* Hash the key if the key is longer then chosen MD block size */ - if (r.length > (unsigned int)isc_md_type_get_block_size(type)) { - if (isc_md(type, r.base, r.length, hkey->key, &keylen) != - ISC_R_SUCCESS) - { - isc_mem_put(key->mctx, hkey, sizeof(dst_hmac_key_t)); - return DST_R_OPENSSLFAILURE; - } - } else { - memmove(hkey->key, r.base, r.length); - keylen = r.length; + result = isc_hmac_key_create(type, r.base, r.length, key->mctx, &hkey); + if (result != ISC_R_SUCCESS) { + return DST_R_OPENSSLFAILURE; } - key->key_size = keylen * 8; + key->key_size = isc_hmac_key_expose(hkey).length * 8; key->keydata.hmac_key = hkey; isc_buffer_forward(data, r.length); @@ -362,47 +332,48 @@ hmac_fromdns(isc_md_type_t type, dst_key_t *key, isc_buffer_t *data) { static int hmac__get_tag_key(isc_md_type_t type) { - if (type == ISC_MD_MD5) { + switch (type) { + case ISC_MD_MD5: return TAG_HMACMD5_KEY; - } else if (type == ISC_MD_SHA1) { + case ISC_MD_SHA1: return TAG_HMACSHA1_KEY; - } else if (type == ISC_MD_SHA224) { + case ISC_MD_SHA224: return TAG_HMACSHA224_KEY; - } else if (type == ISC_MD_SHA256) { + case ISC_MD_SHA256: return TAG_HMACSHA256_KEY; - } else if (type == ISC_MD_SHA384) { + case ISC_MD_SHA384: return TAG_HMACSHA384_KEY; - } else if (type == ISC_MD_SHA512) { + case ISC_MD_SHA512: return TAG_HMACSHA512_KEY; - } else { + default: UNREACHABLE(); } } static int hmac__get_tag_bits(isc_md_type_t type) { - if (type == ISC_MD_MD5) { + switch (type) { + case ISC_MD_MD5: return TAG_HMACMD5_BITS; - } else if (type == ISC_MD_SHA1) { + case ISC_MD_SHA1: return TAG_HMACSHA1_BITS; - } else if (type == ISC_MD_SHA224) { + case ISC_MD_SHA224: return TAG_HMACSHA224_BITS; - } else if (type == ISC_MD_SHA256) { + case ISC_MD_SHA256: return TAG_HMACSHA256_BITS; - } else if (type == ISC_MD_SHA384) { + case ISC_MD_SHA384: return TAG_HMACSHA384_BITS; - } else if (type == ISC_MD_SHA512) { + case ISC_MD_SHA512: return TAG_HMACSHA512_BITS; - } else { + default: UNREACHABLE(); } } static isc_result_t hmac_tofile(isc_md_type_t type, const dst_key_t *key, const char *directory) { - dst_hmac_key_t *hkey; + isc_region_t raw_key; dst_private_t priv; - int bytes = (key->key_size + 7) / 8; uint16_t bits; if (key->keydata.hmac_key == NULL) { @@ -413,11 +384,11 @@ hmac_tofile(isc_md_type_t type, const dst_key_t *key, const char *directory) { return DST_R_EXTERNALKEY; } - hkey = key->keydata.hmac_key; + raw_key = isc_hmac_key_expose(key->keydata.hmac_key); priv.elements[0].tag = hmac__get_tag_key(type); - priv.elements[0].length = bytes; - priv.elements[0].data = hkey->key; + priv.elements[0].length = raw_key.length; + priv.elements[0].data = raw_key.base; bits = htons(key->key_bits); diff --git a/lib/isc/crypto/ossl1_1.c b/lib/isc/crypto/ossl1_1.c index 6920273b67..e47e294ddd 100644 --- a/lib/isc/crypto/ossl1_1.c +++ b/lib/isc/crypto/ossl1_1.c @@ -11,21 +11,37 @@ * information regarding copyright ownership. */ +#include + #include #include #include #include #include +#include #include +#include #include +#include #include #include +#include #include #include #include "crypto_p.h" +#define HMAC_KEY_MAGIC ISC_MAGIC('H', 'M', 'A', 'C') + +struct isc_hmac_key { + uint32_t magic; + uint32_t len; + isc_mem_t *mctx; + EVP_MD *md; + uint8_t secret[]; +}; + static isc_mem_t *isc__crypto_mctx = NULL; #define md_register_algorithm(alg, upperalg) \ @@ -53,6 +69,175 @@ register_algorithms(void) { #undef md_unregister_algorithm +/* + * HMAC Notes + * + * For pre-3.0 libcrypto, we use HMAC_CTX instead of the EVP_PKEY API. + * + * EVP_PKEY will call HMAC_* functions internally so there is no need to add + * even more vtables. + */ + +isc_result_t +isc_hmac(isc_md_type_t type, const void *key, const size_t keylen, + const unsigned char *buf, const size_t len, unsigned char *digest, + unsigned int *digestlen) { + EVP_MD *md; + + REQUIRE(type < ISC_MD_MAX); + + md = isc__crypto_md[type]; + if (md == NULL) { + return ISC_R_NOTIMPLEMENTED; + } + + if (HMAC(md, key, keylen, buf, len, digest, digestlen) == NULL) { + ERR_clear_error(); + return ISC_R_CRYPTOFAILURE; + } + + return ISC_R_SUCCESS; +} + +isc_result_t +isc_hmac_key_create(isc_md_type_t type, const void *secret, const size_t len, + isc_mem_t *mctx, isc_hmac_key_t **keyp) { + isc_hmac_key_t *key; + EVP_MD *md; + + REQUIRE(keyp != NULL && *keyp == NULL); + REQUIRE(type < ISC_MD_MAX); + + md = isc__crypto_md[type]; + if (md == NULL) { + return ISC_R_NOTIMPLEMENTED; + } + + key = isc_mem_get(mctx, STRUCT_FLEX_SIZE(key, secret, len)); + *key = (isc_hmac_key_t){ + .magic = HMAC_KEY_MAGIC, + .len = len, + .md = md, + }; + memmove(key->secret, secret, len); + isc_mem_attach(mctx, &key->mctx); + + *keyp = key; + + return ISC_R_SUCCESS; +} + +void +isc_hmac_key_destroy(isc_hmac_key_t **keyp) { + isc_hmac_key_t *key; + + REQUIRE(keyp != NULL && *keyp != NULL); + REQUIRE((*keyp)->magic == HMAC_KEY_MAGIC); + + key = *keyp; + *keyp = NULL; + + key->magic = 0x00; + + isc_safe_memwipe(key->secret, sizeof(key->len)); + + isc_mem_putanddetach(&key->mctx, key, + STRUCT_FLEX_SIZE(key, secret, key->len)); +} + +isc_region_t +isc_hmac_key_expose(isc_hmac_key_t *key) { + REQUIRE(key != NULL && key->magic == HMAC_KEY_MAGIC); + + return (isc_region_t){ .base = key->secret, .length = key->len }; +} + +bool +isc_hmac_key_equal(isc_hmac_key_t *a, isc_hmac_key_t *b) { + REQUIRE(a != NULL && a->magic == HMAC_KEY_MAGIC); + REQUIRE(b != NULL && b->magic == HMAC_KEY_MAGIC); + + if (a->md != b->md) { + return false; + } + + if (a->len != b->len) { + return false; + } + + return isc_safe_memequal(a->secret, b->secret, a->len); +} + +isc_hmac_t * +isc_hmac_new(void) { + HMAC_CTX *ctx = HMAC_CTX_new(); + RUNTIME_CHECK(ctx != NULL); + return ctx; +} + +void +isc_hmac_free(isc_hmac_t *hmac) { + if (hmac != NULL) { + HMAC_CTX_free(hmac); + } +} + +isc_result_t +isc_hmac_init(isc_hmac_t *hmac, isc_hmac_key_t *key) { + REQUIRE(hmac != NULL); + REQUIRE(key != NULL && key->magic == HMAC_KEY_MAGIC); + + if (HMAC_Init_ex(hmac, key->secret, key->len, key->md, NULL) != 1) { + ERR_clear_error(); + return ISC_R_CRYPTOFAILURE; + } + + return ISC_R_SUCCESS; +} + +isc_result_t +isc_hmac_update(isc_hmac_t *hmac, const unsigned char *buf, const size_t len) { + REQUIRE(hmac != NULL); + + if (buf == NULL || len == 0) { + return ISC_R_SUCCESS; + } + + if (HMAC_Update(hmac, buf, len) != 1) { + ERR_clear_error(); + return ISC_R_CRYPTOFAILURE; + } + + return ISC_R_SUCCESS; +} + +isc_result_t +isc_hmac_final(isc_hmac_t *hmac, isc_buffer_t *out) { + unsigned int len; + + REQUIRE(hmac != NULL); + REQUIRE(out != NULL); + + /* + * LibreSSL changes HMAC_size's return from size_t to int but keeps the + * size_t signature in its manpage. + * + * Cast it instead of accepting LibreSSL's man(page)splaining. + */ + len = isc_buffer_availablelength(out); + if (len < (unsigned int)HMAC_size(hmac)) { + return ISC_R_NOSPACE; + } + + if (HMAC_Final(hmac, isc_buffer_used(out), &len) != 1) { + return ISC_R_CRYPTOFAILURE; + } + + isc_buffer_add(out, len); + + return ISC_R_SUCCESS; +} + #ifndef LIBRESSL_VERSION_NUMBER /* * This was crippled with LibreSSL, so just skip it: diff --git a/lib/isc/crypto/ossl3.c b/lib/isc/crypto/ossl3.c index 00ac7c8257..9b6e19bb27 100644 --- a/lib/isc/crypto/ossl3.c +++ b/lib/isc/crypto/ossl3.c @@ -11,6 +11,10 @@ * information regarding copyright ownership. */ +#include +#include + +#include #include #include #include @@ -18,19 +22,64 @@ #include #include +#include #include +#include #include +#include #include #include +#include +#include #include #include #include "crypto_p.h" +struct isc_hmac_key { + uint32_t magic; + uint32_t len; + isc_mem_t *mctx; + const OSSL_PARAM *params; + uint8_t secret[]; +}; + +constexpr uint32_t hmac_key_magic = ISC_MAGIC('H', 'M', 'A', 'C'); + static isc_mem_t *isc__crypto_mctx = NULL; static OSSL_PROVIDER *base = NULL, *fips = NULL; +static EVP_MAC *evp_hmac = NULL; + +static OSSL_PARAM md_to_hmac_params[ISC_MD_MAX][2] = { + [ISC_MD_UNKNOWN] = { OSSL_PARAM_END }, + [ISC_MD_MD5] = { + OSSL_PARAM_utf8_string(OSSL_MAC_PARAM_DIGEST, UNCONST("MD5"), sizeof("MD5") - 1), + OSSL_PARAM_END, + }, + [ISC_MD_SHA1] = { + OSSL_PARAM_utf8_string(OSSL_MAC_PARAM_DIGEST, UNCONST("SHA1"), sizeof("SHA1") - 1), + OSSL_PARAM_END, + }, + [ISC_MD_SHA224] = { + OSSL_PARAM_utf8_string(OSSL_MAC_PARAM_DIGEST, UNCONST("SHA2-224"), sizeof("SHA2-224") - 1), + OSSL_PARAM_END, + }, + [ISC_MD_SHA256] = { + OSSL_PARAM_utf8_string(OSSL_MAC_PARAM_DIGEST, UNCONST("SHA2-256"), sizeof("SHA2-256") - 1), + OSSL_PARAM_END, + }, + [ISC_MD_SHA384] = { + OSSL_PARAM_utf8_string(OSSL_MAC_PARAM_DIGEST, UNCONST("SHA2-384"), sizeof("SHA2-384") - 1), + OSSL_PARAM_END, + }, + [ISC_MD_SHA512] = { + OSSL_PARAM_utf8_string(OSSL_MAC_PARAM_DIGEST, UNCONST("SHA2-512"), sizeof("SHA2-512") - 1), + OSSL_PARAM_END, + }, +}; + #define md_register_algorithm(alg) \ { \ REQUIRE(isc__crypto_md[ISC_MD_##alg] == NULL); \ @@ -52,6 +101,15 @@ register_algorithms(void) { md_register_algorithm(SHA384); md_register_algorithm(SHA512); + /* We _must_ have HMAC */ + evp_hmac = EVP_MAC_fetch(NULL, "HMAC", NULL); + if (evp_hmac == NULL) { + ERR_clear_error(); + FATAL_ERROR("OpenSSL failed to find an HMAC implementation. " + "Please make sure the default provider has an " + "EVP_MAC-HMAC implementation"); + } + return ISC_R_SUCCESS; } @@ -63,10 +121,207 @@ unregister_algorithms(void) { isc__crypto_md[i] = NULL; } } + + INSIST(evp_hmac != NULL); + EVP_MAC_free(evp_hmac); + evp_hmac = NULL; } #undef md_register_algorithm +/* + * HMAC + */ + +/* + * Do not call EVP_Q_mac or HMAC (since it calls EVP_Q_mac internally) + * + * Each invocation of the EVP_Q_mac function causes an explicit fetch. + */ +isc_result_t +isc_hmac(isc_md_type_t type, const void *key, const size_t keylen, + const unsigned char *buf, const size_t len, unsigned char *digest, + unsigned int *digestlen) { + EVP_MAC_CTX *ctx; + size_t maclen; + + REQUIRE(type < ISC_MD_MAX); + + if (isc__crypto_md[type] == NULL) { + return ISC_R_NOTIMPLEMENTED; + } + + ctx = EVP_MAC_CTX_new(evp_hmac); + RUNTIME_CHECK(ctx != NULL); + + if (EVP_MAC_init(ctx, key, keylen, md_to_hmac_params[type]) != 1) { + goto fail; + } + + if (EVP_MAC_update(ctx, buf, len) != 1) { + goto fail; + } + + maclen = *digestlen; + if (EVP_MAC_final(ctx, digest, &maclen, maclen) != 1) { + goto fail; + } + + *digestlen = maclen; + + EVP_MAC_CTX_free(ctx); + return ISC_R_SUCCESS; + +fail: + ERR_clear_error(); + EVP_MAC_CTX_free(ctx); + return ISC_R_CRYPTOFAILURE; +} + +/* + * You do not need to process the key to fit the block size. + * + * https://github.com/openssl/openssl/blob/925e4fba1098036e8f8d22652cff6f64c5c7d571/crypto/hmac/hmac.c#L61-L80 + */ +isc_result_t +isc_hmac_key_create(isc_md_type_t type, const void *secret, const size_t len, + isc_mem_t *mctx, isc_hmac_key_t **keyp) { + isc_hmac_key_t *key; + uint8_t digest[ISC_MAX_MD_SIZE]; + unsigned int digest_len = sizeof(digest); + size_t key_len; + + REQUIRE(keyp != NULL && *keyp == NULL); + REQUIRE(type < ISC_MD_MAX); + + if (isc__crypto_md[type] == NULL) { + return ISC_R_NOTIMPLEMENTED; + } + + if (len > (size_t)EVP_MD_block_size(isc__crypto_md[type])) { + RETERR(isc_md(type, secret, len, digest, &digest_len)); + secret = digest; + key_len = digest_len; + } else { + key_len = len; + } + + key = isc_mem_get(mctx, STRUCT_FLEX_SIZE(key, secret, key_len)); + *key = (isc_hmac_key_t){ + .magic = hmac_key_magic, + .len = key_len, + .params = md_to_hmac_params[type], + }; + memmove(key->secret, secret, key_len); + isc_mem_attach(mctx, &key->mctx); + + *keyp = key; + + return ISC_R_SUCCESS; +} + +void +isc_hmac_key_destroy(isc_hmac_key_t **keyp) { + isc_hmac_key_t *key; + + REQUIRE(keyp != NULL && *keyp != NULL); + REQUIRE((*keyp)->magic == hmac_key_magic); + + key = *keyp; + *keyp = NULL; + + key->magic = 0x00; + + isc_safe_memwipe(key->secret, key->len); + isc_mem_putanddetach(&key->mctx, key, + STRUCT_FLEX_SIZE(key, secret, key->len)); +} + +isc_region_t +isc_hmac_key_expose(isc_hmac_key_t *key) { + REQUIRE(key != NULL && key->magic == hmac_key_magic); + + return (isc_region_t){ .base = key->secret, .length = key->len }; +} + +bool +isc_hmac_key_equal(isc_hmac_key_t *a, isc_hmac_key_t *b) { + REQUIRE(a != NULL && a->magic == hmac_key_magic); + REQUIRE(b != NULL && b->magic == hmac_key_magic); + + if (a->params != b->params) { + return false; + } + + if (a->len != b->len) { + return false; + } + + return isc_safe_memequal(a->secret, b->secret, a->len); +} + +isc_hmac_t * +isc_hmac_new(void) { + EVP_MAC_CTX *ctx = EVP_MAC_CTX_new(evp_hmac); + RUNTIME_CHECK(ctx != NULL); + return ctx; +} + +void +isc_hmac_free(isc_hmac_t *hmac) { + EVP_MAC_CTX_free(hmac); +} + +isc_result_t +isc_hmac_init(isc_hmac_t *hmac, isc_hmac_key_t *key) { + REQUIRE(key != NULL && key->magic == hmac_key_magic); + REQUIRE(hmac != NULL); + + if (EVP_MAC_init(hmac, key->secret, key->len, key->params) != 1) { + ERR_clear_error(); + return ISC_R_CRYPTOFAILURE; + } + + return ISC_R_SUCCESS; +} + +isc_result_t +isc_hmac_update(isc_hmac_t *hmac, const unsigned char *buf, const size_t len) { + REQUIRE(hmac != NULL); + + if (buf == NULL || len == 0) { + return ISC_R_SUCCESS; + } + + if (EVP_MAC_update(hmac, buf, len) != 1) { + ERR_clear_error(); + return ISC_R_CRYPTOFAILURE; + } + + return ISC_R_SUCCESS; +} + +isc_result_t +isc_hmac_final(isc_hmac_t *hmac, isc_buffer_t *out) { + size_t len; + + REQUIRE(hmac != NULL); + + len = isc_buffer_availablelength(out); + if (len < EVP_MAC_CTX_get_mac_size(hmac)) { + return ISC_R_NOSPACE; + } + + if (EVP_MAC_final(hmac, isc_buffer_used(out), &len, len) != 1) { + ERR_clear_error(); + return ISC_R_CRYPTOFAILURE; + } + + isc_buffer_add(out, len); + + return ISC_R_SUCCESS; +} + #if ISC_MEM_TRACKLINES /* * We use the internal isc__mem API here, so we can pass the file and line diff --git a/lib/isc/hmac.c b/lib/isc/hmac.c deleted file mode 100644 index 05134cc185..0000000000 --- a/lib/isc/hmac.c +++ /dev/null @@ -1,165 +0,0 @@ -/* - * 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 -#include -#include - -#include -#include -#include -#include -#include -#include -#include - -#include "crypto/crypto_p.h" -#include "openssl_shim.h" - -isc_hmac_t * -isc_hmac_new(void) { - EVP_MD_CTX *hmac_st = EVP_MD_CTX_new(); - RUNTIME_CHECK(hmac_st != NULL); - return (isc_hmac_t *)hmac_st; -} - -void -isc_hmac_free(isc_hmac_t *hmac_st) { - if (hmac_st == NULL) { - return; - } - - EVP_MD_CTX_free((EVP_MD_CTX *)hmac_st); -} - -isc_result_t -isc_hmac_init(isc_hmac_t *hmac_st, const void *key, const size_t keylen, - isc_md_type_t type) { - EVP_PKEY *pkey; - EVP_MD *md; - - REQUIRE(hmac_st != NULL); - REQUIRE(key != NULL); - REQUIRE(keylen <= INT_MAX); - REQUIRE(type < ISC_MD_MAX); - - md = isc__crypto_md[type]; - if (md == NULL) { - return ISC_R_NOTIMPLEMENTED; - } - - pkey = EVP_PKEY_new_raw_private_key(EVP_PKEY_HMAC, NULL, key, keylen); - if (pkey == NULL) { - ERR_clear_error(); - return ISC_R_CRYPTOFAILURE; - } - - if (EVP_DigestSignInit(hmac_st, NULL, md, NULL, pkey) != 1) { - EVP_PKEY_free(pkey); - ERR_clear_error(); - return ISC_R_CRYPTOFAILURE; - } - - EVP_PKEY_free(pkey); - - return ISC_R_SUCCESS; -} - -isc_result_t -isc_hmac_reset(isc_hmac_t *hmac_st) { - REQUIRE(hmac_st != NULL); - - if (EVP_MD_CTX_reset(hmac_st) != 1) { - ERR_clear_error(); - return ISC_R_CRYPTOFAILURE; - } - - return ISC_R_SUCCESS; -} - -isc_result_t -isc_hmac_update(isc_hmac_t *hmac_st, const unsigned char *buf, - const size_t len) { - REQUIRE(hmac_st != NULL); - - if (buf == NULL || len == 0) { - return ISC_R_SUCCESS; - } - - if (EVP_DigestSignUpdate(hmac_st, buf, len) != 1) { - ERR_clear_error(); - return ISC_R_CRYPTOFAILURE; - } - - return ISC_R_SUCCESS; -} - -isc_result_t -isc_hmac_final(isc_hmac_t *hmac_st, unsigned char *digest, - unsigned int *digestlen) { - REQUIRE(hmac_st != NULL); - REQUIRE(digest != NULL); - REQUIRE(digestlen != NULL); - - size_t len = *digestlen; - - if (EVP_DigestSignFinal(hmac_st, digest, &len) != 1) { - ERR_clear_error(); - return ISC_R_CRYPTOFAILURE; - } - - *digestlen = (unsigned int)len; - - return ISC_R_SUCCESS; -} - -size_t -isc_hmac_get_size(isc_hmac_t *hmac_st) { - REQUIRE(hmac_st != NULL); - - return (size_t)EVP_MD_CTX_size(hmac_st); -} - -int -isc_hmac_get_block_size(isc_hmac_t *hmac_st) { - REQUIRE(hmac_st != NULL); - - return EVP_MD_CTX_block_size(hmac_st); -} - -isc_result_t -isc_hmac(isc_md_type_t type, const void *key, const size_t keylen, - const unsigned char *buf, const size_t len, unsigned char *digest, - unsigned int *digestlen) { - isc_result_t res; - isc_hmac_t *hmac_st = isc_hmac_new(); - - res = isc_hmac_init(hmac_st, key, keylen, type); - if (res != ISC_R_SUCCESS) { - goto end; - } - - res = isc_hmac_update(hmac_st, buf, len); - if (res != ISC_R_SUCCESS) { - goto end; - } - - res = isc_hmac_final(hmac_st, digest, digestlen); - if (res != ISC_R_SUCCESS) { - goto end; - } -end: - isc_hmac_free(hmac_st); - - return res; -} diff --git a/lib/isc/include/isc/hmac.h b/lib/isc/include/isc/hmac.h index ecfc6e279c..06f0893f98 100644 --- a/lib/isc/include/isc/hmac.h +++ b/lib/isc/include/isc/hmac.h @@ -18,12 +18,16 @@ #pragma once +#include + #include #include #include typedef void isc_hmac_t; +typedef struct isc_hmac_key isc_hmac_key_t; + /** * isc_hmac: * @type: the digest type @@ -47,6 +51,46 @@ isc_hmac(isc_md_type_t type, const void *key, const size_t keylen, const unsigned char *buf, const size_t len, unsigned char *digest, unsigned int *digestlen); +/* + * isc_hmac_key_create: + * @type: the digest type + * @secret: the secret key + * @len: length of the secret key + * @mctx: memory context + * @keyp: pointer to the key pointer + * + * This initializes the an HMAC key bound to a specific digest. + */ +isc_result_t +isc_hmac_key_create(isc_md_type_t type, const void *secret, const size_t len, + isc_mem_t *mctx, isc_hmac_key_t **keyp); + +void +isc_hmac_key_destroy(isc_hmac_key_t **keyp); + +/** + * isc_hmac_key_expose: + * @key: The key to be exposed + * + * This function exposes the raw bytes of the HMAC key. + * + * The region is bound to the lifetime of the @key and MUST NOT be used after + * calling isc_hmac_key_destroy. + */ +isc_region_t +isc_hmac_key_expose(isc_hmac_key_t *key); + +/** + * isc_hmac_key_equal: + * @key1: The first key to be compared + * @key2: The second key to be compared + * + * Returns true is the two HMAC keys have the same contents and use the same + * digest function. + */ +bool +isc_hmac_key_equal(isc_hmac_key_t *key1, isc_hmac_key_t *key2); + /** * isc_hmac_new: * @@ -68,26 +112,11 @@ isc_hmac_free(isc_hmac_t *hmac); * isc_hmac_init: * @md: HMAC context * @key: HMAC key - * @keylen: HMAC key length - * @type: digest type * - * This function sets up HMAC context to use a hash function of @type and key - * @key which is @keylen bytes long. - */ - -isc_result_t -isc_hmac_init(isc_hmac_t *hmac, const void *key, const size_t keylen, - isc_md_type_t type); - -/** - * isc_hmac_reset: - * @hmac: HMAC context - * - * This function resets the HMAC context. This can be used to reuse an already - * existing context. + * This function sets up HMAC context to use the secret specified in @key. */ isc_result_t -isc_hmac_reset(isc_hmac_t *hmac); +isc_hmac_init(isc_hmac_t *hmac, isc_hmac_key_t *key); /** * isc_hmac_update: @@ -104,34 +133,13 @@ isc_hmac_update(isc_hmac_t *hmac, const unsigned char *buf, const size_t len); /** * isc_hmac_final: * @hmac: HMAC context - * @digest: the output buffer - * @digestlen: in: the length of @digest - * out: the length of the data written to @digest + * @out: the output buffer * * This function retrieves the message authentication code from @hmac and places - * it in @digest, which must have space for the hash function output. @digestlen - * is used to pass in the length of the digest buffer and returns the length - * of digest written to @digest. After calling this function no additional - * calls to isc_hmac_update() can be made. + * it in @out, which must have space for the hash function output. + * + * After calling this function no additional calls to isc_hmac_update() can be + * made. Use isc_hmac_init() to reset/re-initialize the context. */ isc_result_t -isc_hmac_final(isc_hmac_t *hmac, unsigned char *digest, - unsigned int *digestlen); - -/** - * isc_hmac_get_size: - * - * This function return the size of the message digest when passed an isc_hmac_t - * structure, i.e. the size of the hash. - */ -size_t -isc_hmac_get_size(isc_hmac_t *hmac); - -/** - * isc_hmac_get_block_size: - * - * This function return the block size of the message digest when passed an - * isc_hmac_t structure. - */ -int -isc_hmac_get_block_size(isc_hmac_t *hmac); +isc_hmac_final(isc_hmac_t *hmac, isc_buffer_t *out); diff --git a/lib/isc/meson.build b/lib/isc/meson.build index 645ff469cf..0836490f02 100644 --- a/lib/isc/meson.build +++ b/lib/isc/meson.build @@ -88,7 +88,6 @@ isc_srcset.add( 'helper.c', 'hex.c', 'histo.c', - 'hmac.c', 'ht.c', 'httpd.c', 'interfaceiter.c', diff --git a/tests/isc/hmac_test.c b/tests/isc/hmac_test.c index 0245d6041b..31797f7e44 100644 --- a/tests/isc/hmac_test.c +++ b/tests/isc/hmac_test.c @@ -21,13 +21,6 @@ #include #include -/* - * As a workaround, include an OpenSSL header file before including cmocka.h, - * because OpenSSL 3.1.0 uses __attribute__(malloc), conflicting with a - * redefined malloc in cmocka.h. - */ -#include - #define UNIT_TESTING #include @@ -39,14 +32,11 @@ #include #include -#include "hmac.c" - #include #define TEST_INPUT(x) (x), sizeof(x) - 1 -static int -_setup(void **state) { +ISC_SETUP_TEST_IMPL(hmac_state) { isc_hmac_t *hmac_st = isc_hmac_new(); if (hmac_st == NULL) { return -1; @@ -69,9 +59,7 @@ _reset(void **state) { if (*state == NULL) { return -1; } - if (isc_hmac_reset(*state) != ISC_R_SUCCESS) { - return -1; - } + return 0; } @@ -96,11 +84,16 @@ static void isc_hmac_test(isc_hmac_t *hmac_st, const void *key, size_t keylen, isc_md_type_t type, const char *buf, size_t buflen, const char *result, const size_t repeats) { + isc_hmac_key_t *hkey = NULL; isc_result_t res; + assert_int_equal( + isc_hmac_key_create(type, key, keylen, isc_g_mctx, &hkey), + ISC_R_SUCCESS); assert_non_null(hmac_st); - assert_int_equal(isc_hmac_init(hmac_st, key, keylen, type), - ISC_R_SUCCESS); + + res = isc_hmac_init(hmac_st, hkey); + assert_return_code(res, ISC_R_SUCCESS); for (size_t i = 0; i < repeats; i++) { assert_int_equal(isc_hmac_update(hmac_st, @@ -109,14 +102,16 @@ isc_hmac_test(isc_hmac_t *hmac_st, const void *key, size_t keylen, ISC_R_SUCCESS); } - unsigned char digest[ISC_MAX_MD_SIZE]; - unsigned int digestlen = sizeof(digest); - assert_int_equal(isc_hmac_final(hmac_st, digest, &digestlen), - ISC_R_SUCCESS); + unsigned char raw_digest[ISC_MAX_MD_SIZE]; + isc_buffer_t digest; + + isc_buffer_init(&digest, raw_digest, sizeof(raw_digest)); + assert_int_equal(isc_hmac_final(hmac_st, &digest), ISC_R_SUCCESS); char hexdigest[ISC_MAX_MD_SIZE * 2 + 3]; - isc_region_t r = { .base = digest, .length = digestlen }; + isc_region_t r; isc_buffer_t b; + isc_buffer_usedregion(&digest, &r); isc_buffer_init(&b, hexdigest, sizeof(hexdigest)); res = isc_hex_totext(&r, 0, "", &b); @@ -124,106 +119,86 @@ isc_hmac_test(isc_hmac_t *hmac_st, const void *key, size_t keylen, assert_return_code(res, ISC_R_SUCCESS); assert_memory_equal(hexdigest, result, result ? strlen(result) : 0); - assert_int_equal(isc_hmac_reset(hmac_st), ISC_R_SUCCESS); + + isc_hmac_key_destroy(&hkey); } -ISC_RUN_TEST_IMPL(isc_hmac_init) { - isc_hmac_t *hmac_st = *state; - assert_non_null(hmac_st); +ISC_RUN_TEST_IMPL(isc_hmac_key_create) { + isc_hmac_key_t *key = NULL; - assert_int_equal(isc_hmac_init(hmac_st, "", 0, ISC_MD_UNKNOWN), - ISC_R_NOTIMPLEMENTED); + assert_int_equal( + isc_hmac_key_create(ISC_MD_UNKNOWN, "", 0, isc_g_mctx, &key), + ISC_R_NOTIMPLEMENTED); if (!isc_crypto_fips_mode()) { - expect_assert_failure(isc_hmac_init(NULL, "", 0, ISC_MD_MD5)); + /* + expect_assert_failure(isc_hmac_key_create(ISC_MD_MD5, NULL, 0, + isc_g_mctx, &key)); + */ - expect_assert_failure( - isc_hmac_init(hmac_st, NULL, 0, ISC_MD_MD5)); - - assert_int_equal(isc_hmac_init(hmac_st, "", 0, ISC_MD_MD5), + assert_int_equal(isc_hmac_key_create(ISC_MD_MD5, "", 0, + isc_g_mctx, &key), ISC_R_SUCCESS); - assert_int_equal(isc_hmac_reset(hmac_st), ISC_R_SUCCESS); + isc_hmac_key_destroy(&key); } - assert_int_equal(isc_hmac_init(hmac_st, "", 0, ISC_MD_SHA1), - ISC_R_SUCCESS); - assert_int_equal(isc_hmac_reset(hmac_st), ISC_R_SUCCESS); + assert_int_equal( + isc_hmac_key_create(ISC_MD_SHA1, "", 0, isc_g_mctx, &key), + ISC_R_SUCCESS); + isc_hmac_key_destroy(&key); - assert_int_equal(isc_hmac_init(hmac_st, "", 0, ISC_MD_SHA224), - ISC_R_SUCCESS); - assert_int_equal(isc_hmac_reset(hmac_st), ISC_R_SUCCESS); + assert_int_equal( + isc_hmac_key_create(ISC_MD_SHA224, "", 0, isc_g_mctx, &key), + ISC_R_SUCCESS); + isc_hmac_key_destroy(&key); - assert_int_equal(isc_hmac_init(hmac_st, "", 0, ISC_MD_SHA256), - ISC_R_SUCCESS); - assert_int_equal(isc_hmac_reset(hmac_st), ISC_R_SUCCESS); + assert_int_equal( + isc_hmac_key_create(ISC_MD_SHA256, "", 0, isc_g_mctx, &key), + ISC_R_SUCCESS); + isc_hmac_key_destroy(&key); - assert_int_equal(isc_hmac_init(hmac_st, "", 0, ISC_MD_SHA384), - ISC_R_SUCCESS); - assert_int_equal(isc_hmac_reset(hmac_st), ISC_R_SUCCESS); + assert_int_equal( + isc_hmac_key_create(ISC_MD_SHA384, "", 0, isc_g_mctx, &key), + ISC_R_SUCCESS); + isc_hmac_key_destroy(&key); - assert_int_equal(isc_hmac_init(hmac_st, "", 0, ISC_MD_SHA512), - ISC_R_SUCCESS); - assert_int_equal(isc_hmac_reset(hmac_st), ISC_R_SUCCESS); + assert_int_equal( + isc_hmac_key_create(ISC_MD_SHA512, "", 0, isc_g_mctx, &key), + ISC_R_SUCCESS); + isc_hmac_key_destroy(&key); } ISC_RUN_TEST_IMPL(isc_hmac_update) { isc_hmac_t *hmac_st = *state; assert_non_null(hmac_st); - /* Uses message digest context initialized in isc_hmac_init_test() */ - expect_assert_failure(isc_hmac_update(NULL, NULL, 0)); - assert_int_equal(isc_hmac_update(hmac_st, NULL, 100), ISC_R_SUCCESS); assert_int_equal(isc_hmac_update(hmac_st, (const unsigned char *)"", 0), ISC_R_SUCCESS); } -ISC_RUN_TEST_IMPL(isc_hmac_reset) { - isc_hmac_t *hmac_st = *state; -#if 0 - unsigned char digest[ISC_MAX_MD_SIZE] ISC_ATTR_UNUSED; - unsigned int digestlen ISC_ATTR_UNUSED; -#endif /* if 0 */ - - assert_non_null(hmac_st); - - assert_int_equal(isc_hmac_init(hmac_st, "", 0, ISC_MD_SHA512), - ISC_R_SUCCESS); - assert_int_equal( - isc_hmac_update(hmac_st, (const unsigned char *)"a", 1), - ISC_R_SUCCESS); - assert_int_equal( - isc_hmac_update(hmac_st, (const unsigned char *)"b", 1), - ISC_R_SUCCESS); - - assert_int_equal(isc_hmac_reset(hmac_st), ISC_R_SUCCESS); - -#if 0 - /* - * This test would require OpenSSL compiled with mock_assert(), - * so this could be only manually checked that the test will - * segfault when called by hand - */ - expect_assert_failure(isc_hmac_final(hmac_st, digest, &digestlen)); -#endif /* if 0 */ -} - ISC_RUN_TEST_IMPL(isc_hmac_final) { + isc_hmac_key_t *key = NULL; isc_hmac_t *hmac_st = *state; assert_non_null(hmac_st); + assert_int_equal( + isc_hmac_key_create(ISC_MD_SHA512, "", 0, isc_g_mctx, &key), + ISC_R_SUCCESS); + unsigned char digest[ISC_MAX_MD_SIZE]; - unsigned int digestlen = sizeof(digest); + isc_buffer_t digestbuf; - /* Fail when message digest context is empty */ - expect_assert_failure(isc_hmac_final(NULL, digest, &digestlen)); /* Fail when output buffer is empty */ - expect_assert_failure(isc_hmac_final(hmac_st, NULL, &digestlen)); + isc_buffer_init(&digestbuf, NULL, 0); + assert_int_equal(isc_hmac_final(hmac_st, &digestbuf), ISC_R_NOSPACE); - assert_int_equal(isc_hmac_init(hmac_st, "", 0, ISC_MD_SHA512), - ISC_R_SUCCESS); - /* Fail when the digest length pointer is empty */ - expect_assert_failure(isc_hmac_final(hmac_st, digest, NULL)); + /* Fail when the digest length is empty */ + assert_int_equal(isc_hmac_init(hmac_st, key), ISC_R_SUCCESS); + isc_buffer_init(&digestbuf, digest, 0); + assert_int_equal(isc_hmac_final(hmac_st, &digestbuf), ISC_R_NOSPACE); + + isc_hmac_key_destroy(&key); } ISC_RUN_TEST_IMPL(isc_hmac_md5) { @@ -919,10 +894,7 @@ ISC_RUN_TEST_IMPL(isc_hmac_sha512) { ISC_TEST_LIST_START ISC_TEST_ENTRY(isc_hmac_new) -ISC_TEST_ENTRY_CUSTOM(isc_hmac_init, _reset, _reset) - -ISC_TEST_ENTRY_CUSTOM(isc_hmac_reset, _reset, _reset) - +ISC_TEST_ENTRY(isc_hmac_key_create) ISC_TEST_ENTRY(isc_hmac_md5) ISC_TEST_ENTRY(isc_hmac_sha1) ISC_TEST_ENTRY(isc_hmac_sha224) @@ -937,4 +909,4 @@ ISC_TEST_ENTRY(isc_hmac_free) ISC_TEST_LIST_END -ISC_TEST_MAIN_CUSTOM(_setup, _teardown) +ISC_TEST_MAIN_CUSTOM(setup_test_hmac_state, _teardown) From 5ae9b4d14ca5f4eec606cc1c72b0357182b34374 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ayd=C4=B1n=20Mercan?= Date: Wed, 1 Oct 2025 11:51:43 +0300 Subject: [PATCH 04/16] cleanup unused header in isc/md.h Use `isc/crypto.h` whenever needed instead. --- bin/dnssec/dnssec-signzone.c | 1 + bin/named/server.c | 1 + lib/dns/opensslecdsa_link.c | 1 + lib/dns/openssleddsa_link.c | 1 + lib/isc/include/isc/md.h | 1 - 5 files changed, 4 insertions(+), 1 deletion(-) diff --git a/bin/dnssec/dnssec-signzone.c b/bin/dnssec/dnssec-signzone.c index b28171bf70..27c0845c77 100644 --- a/bin/dnssec/dnssec-signzone.c +++ b/bin/dnssec/dnssec-signzone.c @@ -40,6 +40,7 @@ #include #include #include +#include #include #include #include diff --git a/bin/named/server.c b/bin/named/server.c index 381997626b..9b3f170025 100644 --- a/bin/named/server.c +++ b/bin/named/server.c @@ -32,6 +32,7 @@ #include #include #include +#include #include #include #include diff --git a/lib/dns/opensslecdsa_link.c b/lib/dns/opensslecdsa_link.c index 7bd3729b8b..9203cdba04 100644 --- a/lib/dns/opensslecdsa_link.c +++ b/lib/dns/opensslecdsa_link.c @@ -26,6 +26,7 @@ #include #endif +#include #include #include #include diff --git a/lib/dns/openssleddsa_link.c b/lib/dns/openssleddsa_link.c index 7ef6e495c5..f9f1a0bdf0 100644 --- a/lib/dns/openssleddsa_link.c +++ b/lib/dns/openssleddsa_link.c @@ -20,6 +20,7 @@ #include #include +#include #include #include #include diff --git a/lib/isc/include/isc/md.h b/lib/isc/include/isc/md.h index db95d1e84c..f8f89bba68 100644 --- a/lib/isc/include/isc/md.h +++ b/lib/isc/include/isc/md.h @@ -18,7 +18,6 @@ #pragma once -#include #include #include From c4a25e633c2ef5f6b6c68e5146d80f1055328f6f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ayd=C4=B1n=20Mercan?= Date: Mon, 1 Dec 2025 13:32:46 +0300 Subject: [PATCH 05/16] add openssl_wrap The isc_ossl_wrap API is intended to separate OpenSSL version specific code that needs to expose the libcrypto internals and keep isc_crypto clean. --- lib/isc/include/isc/ossl_wrap.h | 14 ++++++++++++++ lib/isc/meson.build | 1 + lib/isc/ossl_wrap/meson.build | 16 ++++++++++++++++ lib/isc/ossl_wrap/ossl1_1.c | 17 +++++++++++++++++ lib/isc/ossl_wrap/ossl3.c | 17 +++++++++++++++++ lib/isc/ossl_wrap/ossl_common.c | 17 +++++++++++++++++ 6 files changed, 82 insertions(+) create mode 100644 lib/isc/include/isc/ossl_wrap.h create mode 100644 lib/isc/ossl_wrap/meson.build create mode 100644 lib/isc/ossl_wrap/ossl1_1.c create mode 100644 lib/isc/ossl_wrap/ossl3.c create mode 100644 lib/isc/ossl_wrap/ossl_common.c diff --git a/lib/isc/include/isc/ossl_wrap.h b/lib/isc/include/isc/ossl_wrap.h new file mode 100644 index 0000000000..acfe13e762 --- /dev/null +++ b/lib/isc/include/isc/ossl_wrap.h @@ -0,0 +1,14 @@ +/* + * 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 diff --git a/lib/isc/meson.build b/lib/isc/meson.build index 0836490f02..f2c164a5b7 100644 --- a/lib/isc/meson.build +++ b/lib/isc/meson.build @@ -22,6 +22,7 @@ isc_inc_p += include_directories('.') subdir('crypto') subdir('netmgr') +subdir('ossl_wrap') isc_srcset.add( m_dep, diff --git a/lib/isc/ossl_wrap/meson.build b/lib/isc/ossl_wrap/meson.build new file mode 100644 index 0000000000..e610fbe817 --- /dev/null +++ b/lib/isc/ossl_wrap/meson.build @@ -0,0 +1,16 @@ +# 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. + +isc_srcset.add( + when: 'HAVE_OPENSSL_3', + if_true: files('ossl3.c', 'ossl_common.c'), + if_false: files('ossl1_1.c', 'ossl_common.c'), +) diff --git a/lib/isc/ossl_wrap/ossl1_1.c b/lib/isc/ossl_wrap/ossl1_1.c new file mode 100644 index 0000000000..844583345b --- /dev/null +++ b/lib/isc/ossl_wrap/ossl1_1.c @@ -0,0 +1,17 @@ +/* + * 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 +#include + +EMPTY_TRANSLATION_UNIT; diff --git a/lib/isc/ossl_wrap/ossl3.c b/lib/isc/ossl_wrap/ossl3.c new file mode 100644 index 0000000000..844583345b --- /dev/null +++ b/lib/isc/ossl_wrap/ossl3.c @@ -0,0 +1,17 @@ +/* + * 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 +#include + +EMPTY_TRANSLATION_UNIT; diff --git a/lib/isc/ossl_wrap/ossl_common.c b/lib/isc/ossl_wrap/ossl_common.c new file mode 100644 index 0000000000..844583345b --- /dev/null +++ b/lib/isc/ossl_wrap/ossl_common.c @@ -0,0 +1,17 @@ +/* + * 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 +#include + +EMPTY_TRANSLATION_UNIT; From f21d237374cf2ada5da109ea11465f5b306c4722 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ayd=C4=B1n=20Mercan?= Date: Mon, 1 Dec 2025 13:49:46 +0300 Subject: [PATCH 06/16] move openssl error reporting to isc/ossl_wrap While being the best place at the time, the tlserr2result doesn't belong inside TLS code since it is generic to OpenSSL and mostly used in the dst interface. The newly created ossl_wrap interface is the idea place for flushing the OpenSSL thread error queue. --- lib/dns/dst_openssl.h | 22 +++++---- lib/isc/crypto/ossl1_1.c | 13 +++--- lib/isc/crypto/ossl3.c | 19 ++++---- lib/isc/include/isc/ossl_wrap.h | 16 +++++++ lib/isc/include/isc/tls.h | 8 ---- lib/isc/ossl_wrap/ossl_common.c | 82 ++++++++++++++++++++++++++++++++- lib/isc/tls.c | 77 ------------------------------- 7 files changed, 126 insertions(+), 111 deletions(-) diff --git a/lib/dns/dst_openssl.h b/lib/dns/dst_openssl.h index 8d57211af2..55d42645c4 100644 --- a/lib/dns/dst_openssl.h +++ b/lib/dns/dst_openssl.h @@ -21,18 +21,20 @@ #include #include +#include #include -#include -#define dst__openssl_toresult(fallback) \ - isc__tlserr2result(ISC_LOGCATEGORY_INVALID, ISC_LOGMODULE_INVALID, \ - NULL, fallback, __FILE__, __LINE__) -#define dst__openssl_toresult2(funcname, fallback) \ - isc__tlserr2result(DNS_LOGCATEGORY_GENERAL, DNS_LOGMODULE_CRYPTO, \ - funcname, fallback, __FILE__, __LINE__) -#define dst__openssl_toresult3(category, funcname, fallback) \ - isc__tlserr2result(category, DNS_LOGMODULE_CRYPTO, funcname, fallback, \ - __FILE__, __LINE__) +#define dst__openssl_toresult(fallback) \ + isc__ossl_wrap_logged_toresult(ISC_LOGCATEGORY_INVALID, \ + ISC_LOGMODULE_INVALID, NULL, fallback, \ + __FILE__, __LINE__) +#define dst__openssl_toresult2(funcname, fallback) \ + isc__ossl_wrap_logged_toresult(DNS_LOGCATEGORY_GENERAL, \ + DNS_LOGMODULE_CRYPTO, funcname, \ + fallback, __FILE__, __LINE__) +#define dst__openssl_toresult3(category, funcname, fallback) \ + isc__ossl_wrap_logged_toresult(category, DNS_LOGMODULE_CRYPTO, \ + funcname, fallback, __FILE__, __LINE__) isc_result_t dst__openssl_fromlabel(int key_base_id, const char *label, const char *pin, diff --git a/lib/isc/crypto/ossl1_1.c b/lib/isc/crypto/ossl1_1.c index e47e294ddd..6ecbac47bc 100644 --- a/lib/isc/crypto/ossl1_1.c +++ b/lib/isc/crypto/ossl1_1.c @@ -26,8 +26,8 @@ #include #include #include +#include #include -#include #include #include "crypto_p.h" @@ -322,9 +322,9 @@ isc_crypto_fips_enable(void) { } if (FIPS_mode_set(1) == 0) { - return isc_tlserr2result(ISC_LOGCATEGORY_GENERAL, - ISC_LOGMODULE_CRYPTO, "FIPS_mode_set", - ISC_R_CRYPTOFAILURE); + return isc_ossl_wrap_logged_toresult( + ISC_LOGCATEGORY_GENERAL, ISC_LOGMODULE_CRYPTO, + "FIPS_mode_set", ISC_R_CRYPTOFAILURE); } register_algorithms(); @@ -389,8 +389,9 @@ isc__crypto_initialize(void) { /* Protect ourselves against unseeded PRNG */ if (RAND_status() != 1) { - isc_tlserr2result(ISC_LOGCATEGORY_GENERAL, ISC_LOGMODULE_CRYPTO, - "RAND_status", ISC_R_CRYPTOFAILURE); + isc_ossl_wrap_logged_toresult( + 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)"); diff --git a/lib/isc/crypto/ossl3.c b/lib/isc/crypto/ossl3.c index 9b6e19bb27..dc3388a35a 100644 --- a/lib/isc/crypto/ossl3.c +++ b/lib/isc/crypto/ossl3.c @@ -29,9 +29,9 @@ #include #include #include +#include #include #include -#include #include #include "crypto_p.h" @@ -399,7 +399,7 @@ isc_crypto_fips_enable(void) { INSIST(fips == NULL); fips = OSSL_PROVIDER_load(NULL, "fips"); if (fips == NULL) { - return isc_tlserr2result( + return isc_ossl_wrap_logged_toresult( ISC_LOGCATEGORY_GENERAL, ISC_LOGMODULE_CRYPTO, "OSSL_PROVIDER_load", ISC_R_CRYPTOFAILURE); } @@ -408,16 +408,16 @@ isc_crypto_fips_enable(void) { base = OSSL_PROVIDER_load(NULL, "base"); if (base == NULL) { OSSL_PROVIDER_unload(fips); - return isc_tlserr2result( + return isc_ossl_wrap_logged_toresult( 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); + return isc_ossl_wrap_logged_toresult( + ISC_LOGCATEGORY_GENERAL, ISC_LOGMODULE_CRYPTO, + "EVP_default_properties_enable_fips", + ISC_R_CRYPTOFAILURE); } unregister_algorithms(); @@ -466,8 +466,9 @@ isc__crypto_initialize(void) { /* Protect ourselves against unseeded PRNG */ if (RAND_status() != 1) { - isc_tlserr2result(ISC_LOGCATEGORY_GENERAL, ISC_LOGMODULE_CRYPTO, - "RAND_status", ISC_R_CRYPTOFAILURE); + isc_ossl_wrap_logged_toresult( + 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)"); diff --git a/lib/isc/include/isc/ossl_wrap.h b/lib/isc/include/isc/ossl_wrap.h index acfe13e762..4b9b330f04 100644 --- a/lib/isc/include/isc/ossl_wrap.h +++ b/lib/isc/include/isc/ossl_wrap.h @@ -12,3 +12,19 @@ */ #pragma once + +#include +#include + +#define isc_ossl_wrap_logged_toresult(category, module, funcname, fallback) \ + isc__ossl_wrap_logged_toresult(category, module, funcname, fallback, \ + __FILE__, __LINE__) + +isc_result_t +isc_ossl_wrap_toresult(isc_result_t fallback); + +isc_result_t +isc__ossl_wrap_logged_toresult(isc_logcategory_t category, + isc_logmodule_t module, const char *funcname, + isc_result_t fallback, const char *file, + int line); diff --git a/lib/isc/include/isc/tls.h b/lib/isc/include/isc/tls.h index 50755ac2b1..1e10a7d649 100644 --- a/lib/isc/include/isc/tls.h +++ b/lib/isc/include/isc/tls.h @@ -615,11 +615,3 @@ isc_tls_valid_sni_hostname(const char *hostname); * string. Returns 'true' if the hostname is likely a domain name, and * 'false' if it represents an IP address. */ - -#define isc_tlserr2result(category, module, funcname, fallback) \ - isc__tlserr2result(category, module, funcname, fallback, __FILE__, \ - __LINE__) -isc_result_t -isc__tlserr2result(isc_logcategory_t category, isc_logmodule_t module, - const char *funcname, isc_result_t fallback, - const char *file, int line); diff --git a/lib/isc/ossl_wrap/ossl_common.c b/lib/isc/ossl_wrap/ossl_common.c index 844583345b..cf09d93a18 100644 --- a/lib/isc/ossl_wrap/ossl_common.c +++ b/lib/isc/ossl_wrap/ossl_common.c @@ -11,7 +11,87 @@ * information regarding copyright ownership. */ +#include + #include #include -EMPTY_TRANSLATION_UNIT; +#include "../openssl_shim.h" + +isc_result_t +isc_ossl_wrap_toresult(isc_result_t fallback) { + isc_result_t result = fallback; + unsigned long err = ERR_peek_error(); +#ifdef ECDSA_R_RANDOM_NUMBER_GENERATION_FAILED + int lib = ERR_GET_LIB(err); +#endif /* ECDSA_R_RANDOM_NUMBER_GENERATION_FAILED */ + int reason = ERR_GET_REASON(err); + + switch (reason) { + /* + * ERR_* errors are globally unique; others + * are unique per sublibrary + */ + case ERR_R_MALLOC_FAILURE: + result = ISC_R_NOMEMORY; + break; + default: +#ifdef ECDSA_R_RANDOM_NUMBER_GENERATION_FAILED + if (lib == ERR_R_ECDSA_LIB && + reason == ECDSA_R_RANDOM_NUMBER_GENERATION_FAILED) + { + result = ISC_R_NOENTROPY; + break; + } +#endif /* ECDSA_R_RANDOM_NUMBER_GENERATION_FAILED */ + break; + } + + return result; +} + +isc_result_t +isc__ossl_wrap_logged_toresult(isc_logcategory_t category, + isc_logmodule_t module, const char *funcname, + isc_result_t fallback, const char *file, + int line) { + isc_result_t result = isc_ossl_wrap_toresult(fallback); + + /* + * This is an exception - normally, we don't allow this, but the + * compatibility shims in dst_openssl.h needs a call that just + * translates the error code and don't do any logging. + */ + if (category == ISC_LOGCATEGORY_INVALID) { + goto done; + } + + isc_log_write(category, module, ISC_LOG_WARNING, + "%s (%s:%d) failed (%s)", funcname, file, line, + isc_result_totext(result)); + + if (result == ISC_R_NOMEMORY) { + goto done; + } + + for (;;) { + const char *func, *data; + int flags; + unsigned long err = ERR_get_error_all(&file, &line, &func, + &data, &flags); + if (err == 0U) { + break; + } + + char buf[256]; + ERR_error_string_n(err, buf, sizeof(buf)); + + isc_log_write(category, module, ISC_LOG_INFO, "%s:%s:%d:%s", + buf, file, line, + ((flags & ERR_TXT_STRING) != 0) ? data : ""); + } + +done: + ERR_clear_error(); + return result; +} diff --git a/lib/isc/tls.c b/lib/isc/tls.c index 7477a1b9de..c4a3fd5ee9 100644 --- a/lib/isc/tls.c +++ b/lib/isc/tls.c @@ -1550,80 +1550,3 @@ isc_tls_valid_sni_hostname(const char *hostname) { return true; } - -static isc_result_t -isc__tls_toresult(isc_result_t fallback) { - isc_result_t result = fallback; - unsigned long err = ERR_peek_error(); -#if defined(ECDSA_R_RANDOM_NUMBER_GENERATION_FAILED) - int lib = ERR_GET_LIB(err); -#endif /* if defined(ECDSA_R_RANDOM_NUMBER_GENERATION_FAILED) */ - int reason = ERR_GET_REASON(err); - - switch (reason) { - /* - * ERR_* errors are globally unique; others - * are unique per sublibrary - */ - case ERR_R_MALLOC_FAILURE: - result = ISC_R_NOMEMORY; - break; - default: -#if defined(ECDSA_R_RANDOM_NUMBER_GENERATION_FAILED) - if (lib == ERR_R_ECDSA_LIB && - reason == ECDSA_R_RANDOM_NUMBER_GENERATION_FAILED) - { - result = ISC_R_NOENTROPY; - break; - } -#endif /* if defined(ECDSA_R_RANDOM_NUMBER_GENERATION_FAILED) */ - break; - } - - return result; -} - -isc_result_t -isc__tlserr2result(isc_logcategory_t category, isc_logmodule_t module, - const char *funcname, isc_result_t fallback, - const char *file, int line) { - isc_result_t result = isc__tls_toresult(fallback); - - /* - * This is an exception - normally, we don't allow this, but the - * compatibility shims in dst_openssl.h needs a call that just - * translates the error code and don't do any logging. - */ - if (category == ISC_LOGCATEGORY_INVALID) { - goto done; - } - - isc_log_write(category, module, ISC_LOG_WARNING, - "%s (%s:%d) failed (%s)", funcname, file, line, - isc_result_totext(result)); - - if (result == ISC_R_NOMEMORY) { - goto done; - } - - for (;;) { - const char *func, *data; - int flags; - unsigned long err = ERR_get_error_all(&file, &line, &func, - &data, &flags); - if (err == 0U) { - break; - } - - char buf[256]; - ERR_error_string_n(err, buf, sizeof(buf)); - - isc_log_write(category, module, ISC_LOG_INFO, "%s:%s:%d:%s", - buf, file, line, - ((flags & ERR_TXT_STRING) != 0) ? data : ""); - } - -done: - ERR_clear_error(); - return result; -} From f4d88404e2fb7175ea1d302836adc515f7980211 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ayd=C4=B1n=20Mercan?= Date: Mon, 1 Dec 2025 16:23:37 +0300 Subject: [PATCH 07/16] remove libcrypto version specific code in opensslrsa_link Using `EVP_SIGNATURE` explicit algoritms for signatures have been added in OpenSSL 3.4 and so is skipped for the initial OpenSSL version specific code splitting. --- lib/dns/opensslrsa_link.c | 517 ++------------------------------ lib/isc/include/isc/ossl_wrap.h | 77 +++++ lib/isc/ossl_wrap/ossl1_1.c | 265 +++++++++++++++- lib/isc/ossl_wrap/ossl3.c | 327 +++++++++++++++++++- lib/isc/ossl_wrap/ossl_common.c | 27 ++ 5 files changed, 725 insertions(+), 488 deletions(-) diff --git a/lib/dns/opensslrsa_link.c b/lib/dns/opensslrsa_link.c index bc79ae0100..ec24bf202d 100644 --- a/lib/dns/opensslrsa_link.c +++ b/lib/dns/opensslrsa_link.c @@ -19,14 +19,10 @@ #include #include #include -#include #include -#if OPENSSL_VERSION_NUMBER >= 0x30000000L -#include -#include -#endif #include +#include #include #include #include @@ -42,11 +38,6 @@ /* TODO(aydin): remove this crap */ extern EVP_MD *isc__crypto_md[]; -typedef struct rsa_components { - bool bnfree; - const BIGNUM *e, *n, *d, *p, *q, *dmp1, *dmq1, *iqmp; -} rsa_components_t; - /* length byte + 1.2.840.113549.1.1.11 BER encoded RFC 4055 */ static unsigned char oid_rsasha256[] = { 0x0b, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b }; @@ -55,103 +46,6 @@ static unsigned char oid_rsasha256[] = { 0x0b, 0x06, 0x09, 0x2a, 0x86, 0x48, static unsigned char oid_rsasha512[] = { 0x0b, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0d }; -static isc_result_t -opensslrsa_components_get(const dst_key_t *key, rsa_components_t *c, - bool private) { - REQUIRE(c->e == NULL && c->n == NULL && c->d == NULL && c->p == NULL && - c->q == NULL && c->dmp1 == NULL && c->dmq1 == NULL && - c->iqmp == NULL); - - EVP_PKEY *pub = key->keydata.pkeypair.pub; - EVP_PKEY *priv = key->keydata.pkeypair.priv; - - if (private && priv == NULL) { - return DST_R_INVALIDPRIVATEKEY; - } - /* - * NOTE: Errors regarding private compoments are ignored. - * - * OpenSSL allows omitting the parameters for CRT based calculations - * (factors, exponents, coefficients). Only the 'd' parameter is - * mandatory for software keys. - * - * However, for a label based keys, all private key component queries - * can fail if they key is e.g. on a hardware device. - */ -#if OPENSSL_VERSION_NUMBER >= 0x30000000L - if (EVP_PKEY_get_bn_param(pub, OSSL_PKEY_PARAM_RSA_E, - (BIGNUM **)&c->e) != 1) - { - return dst__openssl_toresult(DST_R_OPENSSLFAILURE); - } - - c->bnfree = true; - if (EVP_PKEY_get_bn_param(pub, OSSL_PKEY_PARAM_RSA_N, - (BIGNUM **)&c->n) != 1) - { - return dst__openssl_toresult(DST_R_OPENSSLFAILURE); - } - if (!private) { - return ISC_R_SUCCESS; - } - (void)EVP_PKEY_get_bn_param(priv, OSSL_PKEY_PARAM_RSA_D, - (BIGNUM **)&c->d); - (void)EVP_PKEY_get_bn_param(priv, OSSL_PKEY_PARAM_RSA_FACTOR1, - (BIGNUM **)&c->p); - (void)EVP_PKEY_get_bn_param(priv, OSSL_PKEY_PARAM_RSA_FACTOR2, - (BIGNUM **)&c->q); - (void)EVP_PKEY_get_bn_param(priv, OSSL_PKEY_PARAM_RSA_EXPONENT1, - (BIGNUM **)&c->dmp1); - (void)EVP_PKEY_get_bn_param(priv, OSSL_PKEY_PARAM_RSA_EXPONENT2, - (BIGNUM **)&c->dmq1); - (void)EVP_PKEY_get_bn_param(priv, OSSL_PKEY_PARAM_RSA_COEFFICIENT1, - (BIGNUM **)&c->iqmp); - ERR_clear_error(); - return ISC_R_SUCCESS; -#else - const RSA *rsa = EVP_PKEY_get0_RSA(pub); - if (rsa == NULL) { - return dst__openssl_toresult(DST_R_OPENSSLFAILURE); - } - RSA_get0_key(rsa, &c->n, &c->e, &c->d); - if (c->e == NULL || c->n == NULL) { - return dst__openssl_toresult(DST_R_OPENSSLFAILURE); - } - if (!private) { - return ISC_R_SUCCESS; - } - rsa = EVP_PKEY_get0_RSA(priv); - if (rsa == NULL) { - return dst__openssl_toresult(DST_R_OPENSSLFAILURE); - } - RSA_get0_factors(rsa, &c->p, &c->q); - RSA_get0_crt_params(rsa, &c->dmp1, &c->dmq1, &c->iqmp); - return ISC_R_SUCCESS; -#endif -} - -static void -opensslrsa_components_free(rsa_components_t *c) { - if (!c->bnfree) { - return; - } - /* - * NOTE: BN_free() frees the components of the BIGNUM, and if it was - * created by BN_new(), also the structure itself. BN_clear_free() - * additionally overwrites the data before the memory is returned to the - * system. If a is NULL, nothing is done. - */ - BN_free((BIGNUM *)c->e); - BN_free((BIGNUM *)c->n); - BN_clear_free((BIGNUM *)c->d); - BN_clear_free((BIGNUM *)c->p); - BN_clear_free((BIGNUM *)c->q); - BN_clear_free((BIGNUM *)c->dmp1); - BN_clear_free((BIGNUM *)c->dmq1); - BN_clear_free((BIGNUM *)c->iqmp); - c->bnfree = false; -} - static bool opensslrsa_valid_key_alg(unsigned int key_alg) { switch (key_alg) { @@ -325,29 +219,6 @@ opensslrsa_sign(dst_context_t *dctx, isc_buffer_t *sig) { return ISC_R_SUCCESS; } -static bool -opensslrsa_check_exponent_bits(EVP_PKEY *pkey, int maxbits) { - /* Always use the new API first with OpenSSL 3.x. */ - int bits = INT_MAX; -#if OPENSSL_VERSION_NUMBER >= 0x30000000L - BIGNUM *e = NULL; - if (EVP_PKEY_get_bn_param(pkey, OSSL_PKEY_PARAM_RSA_E, &e) == 1) { - bits = BN_num_bits(e); - BN_free(e); - } -#else - const RSA *rsa = EVP_PKEY_get0_RSA(pkey); - if (rsa != NULL) { - const BIGNUM *ce = NULL; - RSA_get0_key(rsa, NULL, &ce, NULL); - if (ce != NULL) { - bits = BN_num_bits(ce); - } - } -#endif - return bits <= maxbits; -} - static isc_result_t opensslrsa_verify(dst_context_t *dctx, const isc_region_t *sig) { dst_key_t *key = NULL; @@ -364,7 +235,7 @@ opensslrsa_verify(dst_context_t *dctx, const isc_region_t *sig) { evp_md_ctx = dctx->ctxdata.evp_md_ctx; pkey = key->keydata.pkeypair.pub; - if (!opensslrsa_check_exponent_bits(pkey, OPENSSLRSA_MAX_MODULUS_BITS)) + if (!isc_ossl_wrap_rsa_key_bits_leq(pkey, OPENSSLRSA_MAX_MODULUS_BITS)) { return DST_R_VERIFYFAILURE; } @@ -405,344 +276,13 @@ opensslrsa_verify(dst_context_t *dctx, const isc_region_t *sig) { } } -#if OPENSSL_VERSION_NUMBER < 0x30000000L -static int -progress_cb(int p, int n, BN_GENCB *cb) { - void (*fptr)(int); - - UNUSED(n); - - fptr = BN_GENCB_get_arg(cb); - if (fptr != NULL) { - fptr(p); - } - return 1; -} - -static isc_result_t -opensslrsa_generate_pkey(unsigned int key_size, const char *label, BIGNUM *e, - void (*callback)(int), EVP_PKEY **retkey) { - RSA *rsa = NULL; - EVP_PKEY *pkey = NULL; - BN_GENCB *cb = NULL; - isc_result_t result; - - UNUSED(label); - - rsa = RSA_new(); - pkey = EVP_PKEY_new(); - if (rsa == NULL || pkey == NULL) { - CLEANUP(dst__openssl_toresult(DST_R_OPENSSLFAILURE)); - } - - if (EVP_PKEY_set1_RSA(pkey, rsa) != 1) { - CLEANUP(dst__openssl_toresult(DST_R_OPENSSLFAILURE)); - } - - if (callback != NULL) { - cb = BN_GENCB_new(); - if (cb == NULL) { - CLEANUP(dst__openssl_toresult(ISC_R_NOMEMORY)); - } - BN_GENCB_set(cb, progress_cb, (void *)callback); - } - - if (RSA_generate_key_ex(rsa, key_size, e, cb) != 1) { - CLEANUP(dst__openssl_toresult2("RSA_generate_key_ex", - DST_R_OPENSSLFAILURE)); - } - *retkey = pkey; - pkey = NULL; - result = ISC_R_SUCCESS; - -cleanup: - EVP_PKEY_free(pkey); - RSA_free(rsa); - BN_GENCB_free(cb); - return result; -} - -static isc_result_t -opensslrsa_build_pkey(bool private, rsa_components_t *c, EVP_PKEY **retpkey) { - isc_result_t result; - EVP_PKEY *pkey = NULL; - RSA *rsa = RSA_new(); - int status; - - REQUIRE(c->bnfree); - - if (c->n == NULL || c->e == NULL) { - if (private) { - CLEANUP(DST_R_INVALIDPRIVATEKEY); - } - CLEANUP(DST_R_INVALIDPUBLICKEY); - } - - if (rsa == NULL) { - CLEANUP(dst__openssl_toresult2("RSA_new", - DST_R_OPENSSLFAILURE)); - } - - if (RSA_set0_key(rsa, (BIGNUM *)c->n, (BIGNUM *)c->e, (BIGNUM *)c->d) != - 1) - { - CLEANUP(dst__openssl_toresult2("RSA_set0_key", - DST_R_OPENSSLFAILURE)); - } - c->n = NULL; - c->e = NULL; - c->d = NULL; - - if (c->p != NULL || c->q != NULL) { - if (RSA_set0_factors(rsa, (BIGNUM *)c->p, (BIGNUM *)c->q) != 1) - { - CLEANUP(dst__openssl_toresult2("RSA_set0_factors", - DST_R_OPENSSLFAILURE)); - } - c->p = NULL; - c->q = NULL; - } - - if (c->dmp1 != NULL || c->dmq1 != NULL || c->iqmp != NULL) { - if (RSA_set0_crt_params(rsa, (BIGNUM *)c->dmp1, - (BIGNUM *)c->dmq1, - (BIGNUM *)c->iqmp) == 0) - { - CLEANUP(dst__openssl_toresult2("RSA_set0_crt_params", - DST_R_OPENSSLFAILURE)); - } - c->dmp1 = NULL; - c->dmq1 = NULL; - c->iqmp = NULL; - } - - pkey = EVP_PKEY_new(); - if (pkey == NULL) { - CLEANUP(dst__openssl_toresult2("EVP_PKEY_new", - DST_R_OPENSSLFAILURE)); - } - status = EVP_PKEY_set1_RSA(pkey, rsa); - if (status != 1) { - CLEANUP(dst__openssl_toresult2("EVP_PKEY_set1_RSA", - DST_R_OPENSSLFAILURE)); - } - - *retpkey = pkey; - pkey = NULL; - result = ISC_R_SUCCESS; - -cleanup: - EVP_PKEY_free(pkey); - RSA_free(rsa); - opensslrsa_components_free(c); - return result; -} -#else -static int -progress_cb(EVP_PKEY_CTX *ctx) { - void (*fptr)(int); - - fptr = EVP_PKEY_CTX_get_app_data(ctx); - if (fptr != NULL) { - int p = EVP_PKEY_CTX_get_keygen_info(ctx, 0); - fptr(p); - } - return 1; -} - -static isc_result_t -opensslrsa_generate_pkey_with_uri(size_t key_size, const char *label, - EVP_PKEY **retkey) { - EVP_PKEY_CTX *ctx = NULL; - OSSL_PARAM params[4]; - char *uri = UNCONST(label); - isc_result_t result; - int status; - - params[0] = OSSL_PARAM_construct_utf8_string("pkcs11_uri", uri, 0); - params[1] = OSSL_PARAM_construct_utf8_string( - "pkcs11_key_usage", (char *)"digitalSignature", 0); - params[2] = OSSL_PARAM_construct_size_t("rsa_keygen_bits", &key_size); - params[3] = OSSL_PARAM_construct_end(); - - ctx = EVP_PKEY_CTX_new_from_name(NULL, "RSA", "provider=pkcs11"); - if (ctx == NULL) { - CLEANUP(dst__openssl_toresult2("EVP_PKEY_CTX_new_from_name", - DST_R_OPENSSLFAILURE)); - } - - status = EVP_PKEY_keygen_init(ctx); - if (status != 1) { - CLEANUP(dst__openssl_toresult2("EVP_PKEY_keygen_init", - DST_R_OPENSSLFAILURE)); - } - - status = EVP_PKEY_CTX_set_params(ctx, params); - if (status != 1) { - CLEANUP(dst__openssl_toresult2("EVP_PKEY_CTX_set_params", - DST_R_OPENSSLFAILURE)); - } - - status = EVP_PKEY_generate(ctx, retkey); - if (status != 1) { - CLEANUP(dst__openssl_toresult2("EVP_PKEY_generate", - DST_R_OPENSSLFAILURE)); - } - - result = ISC_R_SUCCESS; -cleanup: - EVP_PKEY_CTX_free(ctx); - return result; -} - -static isc_result_t -opensslrsa_generate_pkey(unsigned int key_size, const char *label, BIGNUM *e, - void (*callback)(int), EVP_PKEY **retkey) { - EVP_PKEY_CTX *ctx; - isc_result_t result; - - if (label != NULL) { - return opensslrsa_generate_pkey_with_uri(key_size, label, - retkey); - } - - ctx = EVP_PKEY_CTX_new_from_name(NULL, "RSA", NULL); - if (ctx == NULL) { - CLEANUP(dst__openssl_toresult(DST_R_OPENSSLFAILURE)); - } - - if (EVP_PKEY_keygen_init(ctx) != 1) { - CLEANUP(dst__openssl_toresult(DST_R_OPENSSLFAILURE)); - } - - if (EVP_PKEY_CTX_set_rsa_keygen_bits(ctx, (int)key_size) != 1) { - CLEANUP(dst__openssl_toresult(DST_R_OPENSSLFAILURE)); - } - - if (EVP_PKEY_CTX_set1_rsa_keygen_pubexp(ctx, e) != 1) { - CLEANUP(dst__openssl_toresult(DST_R_OPENSSLFAILURE)); - } - - if (callback != NULL) { - EVP_PKEY_CTX_set_app_data(ctx, (void *)callback); - EVP_PKEY_CTX_set_cb(ctx, progress_cb); - } - - if (EVP_PKEY_keygen(ctx, retkey) != 1) { - CLEANUP(dst__openssl_toresult2("EVP_PKEY_keygen", - DST_R_OPENSSLFAILURE)); - } - result = ISC_R_SUCCESS; -cleanup: - EVP_PKEY_CTX_free(ctx); - return result; -} - -static isc_result_t -opensslrsa_build_pkey(bool private, rsa_components_t *c, EVP_PKEY **retpkey) { - isc_result_t result; - int status; - OSSL_PARAM_BLD *bld = NULL; - OSSL_PARAM *params = NULL; - EVP_PKEY_CTX *ctx = NULL; - - bld = OSSL_PARAM_BLD_new(); - if (bld == NULL) { - CLEANUP(dst__openssl_toresult2("OSSL_PARAM_BLD_new", - DST_R_OPENSSLFAILURE)); - } - if (OSSL_PARAM_BLD_push_BN(bld, OSSL_PKEY_PARAM_RSA_N, c->n) != 1 || - OSSL_PARAM_BLD_push_BN(bld, OSSL_PKEY_PARAM_RSA_E, c->e) != 1) - { - CLEANUP(dst__openssl_toresult2("OSSL_PARAM_BLD_push_BN", - DST_R_OPENSSLFAILURE)); - } - - if (c->d != NULL && - OSSL_PARAM_BLD_push_BN(bld, OSSL_PKEY_PARAM_RSA_D, c->d) != 1) - { - CLEANUP(dst__openssl_toresult2("OSSL_PARAM_BLD_push_BN", - DST_R_OPENSSLFAILURE)); - } - if (c->p != NULL && - OSSL_PARAM_BLD_push_BN(bld, OSSL_PKEY_PARAM_RSA_FACTOR1, c->p) != 1) - { - CLEANUP(dst__openssl_toresult2("OSSL_PARAM_BLD_push_BN", - DST_R_OPENSSLFAILURE)); - } - if (c->q != NULL && - OSSL_PARAM_BLD_push_BN(bld, OSSL_PKEY_PARAM_RSA_FACTOR2, c->q) != 1) - { - CLEANUP(dst__openssl_toresult2("OSSL_PARAM_BLD_push_BN", - DST_R_OPENSSLFAILURE)); - } - if (c->dmp1 != NULL && - OSSL_PARAM_BLD_push_BN(bld, OSSL_PKEY_PARAM_RSA_EXPONENT1, - c->dmp1) != 1) - { - CLEANUP(dst__openssl_toresult2("OSSL_PARAM_BLD_push_BN", - DST_R_OPENSSLFAILURE)); - } - if (c->dmq1 != NULL && - OSSL_PARAM_BLD_push_BN(bld, OSSL_PKEY_PARAM_RSA_EXPONENT2, - c->dmq1) != 1) - { - CLEANUP(dst__openssl_toresult2("OSSL_PARAM_BLD_push_BN", - DST_R_OPENSSLFAILURE)); - } - if (c->iqmp != NULL && - OSSL_PARAM_BLD_push_BN(bld, OSSL_PKEY_PARAM_RSA_COEFFICIENT1, - c->iqmp) != 1) - { - CLEANUP(dst__openssl_toresult2("OSSL_PARAM_BLD_push_BN", - DST_R_OPENSSLFAILURE)); - } - - params = OSSL_PARAM_BLD_to_param(bld); - if (params == NULL) { - CLEANUP(dst__openssl_toresult2("OSSL_PARAM_BLD_to_param", - DST_R_OPENSSLFAILURE)); - } - ctx = EVP_PKEY_CTX_new_from_name(NULL, "RSA", NULL); - if (ctx == NULL) { - CLEANUP(dst__openssl_toresult2("EVP_PKEY_CTX_new_from_name", - DST_R_OPENSSLFAILURE)); - } - status = EVP_PKEY_fromdata_init(ctx); - if (status != 1) { - CLEANUP(dst__openssl_toresult2("EVP_PKEY_fromdata_init", - DST_R_OPENSSLFAILURE)); - } - - status = EVP_PKEY_fromdata( - ctx, retpkey, private ? EVP_PKEY_KEYPAIR : EVP_PKEY_PUBLIC_KEY, - params); - if (status != 1) { - CLEANUP(dst__openssl_toresult2("EVP_PKEY_fromdata", - DST_R_OPENSSLFAILURE)); - } - result = ISC_R_SUCCESS; - -cleanup: - EVP_PKEY_CTX_free(ctx); - OSSL_PARAM_free(params); - OSSL_PARAM_BLD_free(bld); - return result; -} -#endif /* OPENSSL_VERSION_NUMBER < 0x30000000L */ - static isc_result_t opensslrsa_generate(dst_key_t *key, int unused, void (*callback)(int)) { isc_result_t result; - BIGNUM *e = BN_new(); EVP_PKEY *pkey = NULL; UNUSED(unused); - if (e == NULL) { - CLEANUP(dst__openssl_toresult(DST_R_OPENSSLFAILURE)); - } - /* * Reject incorrect RSA key lengths. */ @@ -772,12 +312,13 @@ opensslrsa_generate(dst_key_t *key, int unused, void (*callback)(int)) { UNREACHABLE(); } - /* e = 65537 (0x10001, F4) */ - BN_set_bit(e, 0); - BN_set_bit(e, 16); - - CHECK(opensslrsa_generate_pkey(key->key_size, key->label, e, callback, - &pkey)); + if (key->label != NULL) { + CHECK(isc_ossl_wrap_generate_pkcs11_rsa_key( + key->label, key->key_size, &pkey)); + } else { + CHECK(isc_ossl_wrap_generate_rsa_key(callback, key->key_size, + &pkey)); + } key->keydata.pkeypair.pub = pkey; key->keydata.pkeypair.priv = pkey; @@ -786,7 +327,6 @@ opensslrsa_generate(dst_key_t *key, int unused, void (*callback)(int)) { cleanup: EVP_PKEY_free(pkey); - BN_free(e); return result; } @@ -796,7 +336,7 @@ opensslrsa_todns(const dst_key_t *key, isc_buffer_t *data) { unsigned int e_bytes; unsigned int mod_bytes; isc_result_t result; - rsa_components_t c = { 0 }; + isc_ossl_wrap_rsa_components_t c = { 0 }; REQUIRE(key->keydata.pkeypair.pub != NULL); @@ -822,7 +362,8 @@ opensslrsa_todns(const dst_key_t *key, isc_buffer_t *data) { break; } - CHECK(opensslrsa_components_get(key, &c, false)); + CHECK(isc_ossl_wrap_rsa_public_components(key->keydata.pkeypair.pub, + &c)); mod_bytes = BN_num_bytes(c.n); e_bytes = BN_num_bytes(c.e); @@ -853,9 +394,8 @@ opensslrsa_todns(const dst_key_t *key, isc_buffer_t *data) { isc_buffer_add(data, e_bytes + mod_bytes); - result = ISC_R_SUCCESS; cleanup: - opensslrsa_components_free(&c); + isc_ossl_wrap_rsa_components_cleanup(&c); return result; } @@ -865,7 +405,7 @@ opensslrsa_fromdns(dst_key_t *key, isc_buffer_t *data) { isc_region_t r; unsigned int e_bytes; unsigned int length; - rsa_components_t c = { .bnfree = true }; + isc_ossl_wrap_rsa_components_t c = { .needs_cleanup = true }; REQUIRE(opensslrsa_valid_key_alg(key->key_alg)); @@ -928,10 +468,11 @@ opensslrsa_fromdns(dst_key_t *key, isc_buffer_t *data) { isc_buffer_forward(data, length); key->key_size = BN_num_bits(c.n); - result = opensslrsa_build_pkey(false, &c, &key->keydata.pkeypair.pub); + result = isc_ossl_wrap_load_rsa_public_from_components( + &c, &key->keydata.pkeypair.pub); cleanup: - opensslrsa_components_free(&c); + isc_ossl_wrap_rsa_components_cleanup(&c); return result; } @@ -941,13 +482,16 @@ opensslrsa_tofile(const dst_key_t *key, const char *directory) { dst_private_t priv = { 0 }; unsigned char *bufs[8] = { NULL }; unsigned short i = 0; - rsa_components_t c = { 0 }; + isc_ossl_wrap_rsa_components_t c = { 0 }; if (key->external) { return dst__privstruct_writefile(key, &priv, directory); } - CHECK(opensslrsa_components_get(key, &c, true)); + CHECK(isc_ossl_wrap_rsa_public_components(key->keydata.pkeypair.pub, + &c)); + CHECK(isc_ossl_wrap_rsa_secret_components(key->keydata.pkeypair.priv, + &c)); priv.elements[i].tag = TAG_RSA_MODULUS; priv.elements[i].length = BN_num_bytes(c.n); @@ -1041,7 +585,7 @@ cleanup: priv.elements[i].length); } } - opensslrsa_components_free(&c); + isc_ossl_wrap_rsa_components_cleanup(&c); return result; } @@ -1057,7 +601,7 @@ opensslrsa_parse(dst_key_t *key, isc_lex_t *lexer, dst_key_t *pub) { isc_mem_t *mctx = NULL; const char *label = NULL; EVP_PKEY *pkey = NULL; - rsa_components_t c = { .bnfree = true }; + isc_ossl_wrap_rsa_components_t c = { .needs_cleanup = true }; REQUIRE(key != NULL); REQUIRE(opensslrsa_valid_key_alg(key->key_alg)); @@ -1160,7 +704,8 @@ opensslrsa_parse(dst_key_t *key, isc_lex_t *lexer, dst_key_t *pub) { } key->key_size = BN_num_bits(c.n); - CHECK(opensslrsa_build_pkey(true, &c, &pkey)); + + CHECK(isc_ossl_wrap_load_rsa_secret_from_components(&c, &pkey)); /* Check that the public component matches if given */ if (pub != NULL && EVP_PKEY_eq(pkey, pub->keydata.pkeypair.pub) != 1) { @@ -1172,7 +717,7 @@ opensslrsa_parse(dst_key_t *key, isc_lex_t *lexer, dst_key_t *pub) { pkey = NULL; cleanup: - opensslrsa_components_free(&c); + isc_ossl_wrap_rsa_components_cleanup(&c); EVP_PKEY_free(pkey); if (result != ISC_R_SUCCESS) { key->keydata.generic = NULL; @@ -1192,7 +737,7 @@ opensslrsa_fromlabel(dst_key_t *key, const char *label, const char *pin) { CHECK(dst__openssl_fromlabel(EVP_PKEY_RSA, label, pin, &pubpkey, &privpkey)); - if (!opensslrsa_check_exponent_bits(pubpkey, RSA_MAX_PUBEXP_BITS)) { + if (!isc_ossl_wrap_rsa_key_bits_leq(pubpkey, RSA_MAX_PUBEXP_BITS)) { CLEANUP(ISC_R_RANGE); } @@ -1304,7 +849,7 @@ static const unsigned char sha512_sig[] = static isc_result_t check_algorithm(unsigned short algorithm) { - rsa_components_t c = { .bnfree = true }; + isc_ossl_wrap_rsa_components_t c = { .needs_cleanup = true }; EVP_MD_CTX *evp_md_ctx = EVP_MD_CTX_create(); EVP_PKEY *pkey = NULL; const EVP_MD *type = NULL; @@ -1341,7 +886,7 @@ check_algorithm(unsigned short algorithm) { c.e = BN_bin2bn(e_bytes, sizeof(e_bytes) - 1, NULL); c.n = BN_bin2bn(n_bytes, sizeof(n_bytes) - 1, NULL); - result = opensslrsa_build_pkey(false, &c, &pkey); + result = isc_ossl_wrap_load_rsa_public_from_components(&c, &pkey); INSIST(result == ISC_R_SUCCESS); /* @@ -1355,7 +900,7 @@ check_algorithm(unsigned short algorithm) { } cleanup: - opensslrsa_components_free(&c); + isc_ossl_wrap_rsa_components_cleanup(&c); EVP_PKEY_free(pkey); EVP_MD_CTX_destroy(evp_md_ctx); ERR_clear_error(); diff --git a/lib/isc/include/isc/ossl_wrap.h b/lib/isc/include/isc/ossl_wrap.h index 4b9b330f04..cef8317938 100644 --- a/lib/isc/include/isc/ossl_wrap.h +++ b/lib/isc/include/isc/ossl_wrap.h @@ -13,6 +13,12 @@ #pragma once +#include +#include + +#include +#include + #include #include @@ -20,6 +26,77 @@ isc__ossl_wrap_logged_toresult(category, module, funcname, fallback, \ __FILE__, __LINE__) +typedef struct isc_ossl_wrap_rsa_components { + bool needs_cleanup; + BIGNUM *e, *n, *d, *p, *q, *dmp1, *dmq1, *iqmp; +} isc_ossl_wrap_rsa_components_t; + +isc_result_t +isc_ossl_wrap_generate_rsa_key(void (*callback)(int), size_t bit_size, + EVP_PKEY **pkeyp); +/*% + * Creates a RSA key with the specified bit-size + * + * Requires: + * \li `pkeyp != NULL` + * \li `*pkeyp == NULL` + */ + +isc_result_t +isc_ossl_wrap_generate_pkcs11_rsa_key(char *uri, size_t bit_size, + EVP_PKEY **pkeyp); +/*% + * Creates a RSA key with the specified bit-size using the PKCS11 label + * specified at `uri`. + * + * Requires: + * \li `pkeyp != NULL` + * \li `*pkeyp == NULL` + * \li `uri != NULL` and is a NUL-terminated string + */ + +bool +isc_ossl_wrap_rsa_key_bits_leq(EVP_PKEY *pkey, size_t limit); + +isc_result_t +isc_ossl_wrap_rsa_public_components(EVP_PKEY *pkey, + isc_ossl_wrap_rsa_components_t *c); + +isc_result_t +isc_ossl_wrap_rsa_secret_components(EVP_PKEY *pkey, + isc_ossl_wrap_rsa_components_t *c); + +isc_result_t +isc_ossl_wrap_load_rsa_public_from_components(isc_ossl_wrap_rsa_components_t *c, + EVP_PKEY **pkeyp); +/*% + * Create a verifying `EVP_PKEY` using the public RSA components at `c` + * + * Requires: + * \li `pkeyp != NULL` + * \li `*pkeyp == NULL` + * \li `c != NULL` + * \li `c.n != NULL` + * \li `c.e != NULL` + */ + +isc_result_t +isc_ossl_wrap_load_rsa_secret_from_components(isc_ossl_wrap_rsa_components_t *c, + EVP_PKEY **pkeyp); +/*% + * Create a signing `EVP_PKEY` using the public and secret RSA components at `c` + * + * Requires: + * \li `pkeyp != NULL` + * \li `*pkeyp == NULL` + * \li `c != NULL` + * \li `c.n != NULL` + * \li `c.e != NULL` + */ + +void +isc_ossl_wrap_rsa_components_cleanup(isc_ossl_wrap_rsa_components_t *comp); + isc_result_t isc_ossl_wrap_toresult(isc_result_t fallback); diff --git a/lib/isc/ossl_wrap/ossl1_1.c b/lib/isc/ossl_wrap/ossl1_1.c index 844583345b..32fac0d1d6 100644 --- a/lib/isc/ossl_wrap/ossl1_1.c +++ b/lib/isc/ossl_wrap/ossl1_1.c @@ -11,7 +11,270 @@ * information regarding copyright ownership. */ +#include +#include +#include + #include #include -EMPTY_TRANSLATION_UNIT; +#define OSSL_WRAP_ERROR(fn) \ + isc__ossl_wrap_logged_toresult( \ + ISC_LOGCATEGORY_GENERAL, ISC_LOGMODULE_CRYPTO, fn, \ + ISC_R_CRYPTOFAILURE, __FILE__, __LINE__) + +static int +rsa_keygen_progress_cb(int p, int n, BN_GENCB *cb) { + void (*fptr)(int); + + UNUSED(n); + + fptr = BN_GENCB_get_arg(cb); + if (fptr != NULL) { + fptr(p); + } + return 1; +} + +isc_result_t +isc_ossl_wrap_generate_rsa_key(void (*callback)(int), size_t bit_size, + EVP_PKEY **pkeyp) { + RSA *rsa = NULL; + EVP_PKEY *pkey = NULL; + BN_GENCB *cb = NULL; + isc_result_t result; + BIGNUM *e; + + e = BN_new(); + + /* e = 65537 (0x10001, F4) */ + BN_set_bit(e, 0); + BN_set_bit(e, 16); + + rsa = RSA_new(); + if (rsa == NULL) { + CLEANUP(OSSL_WRAP_ERROR("RSA_new")); + } + + pkey = EVP_PKEY_new(); + if (pkey == NULL) { + CLEANUP(OSSL_WRAP_ERROR("EVP_PKEY_new")); + } + + if (EVP_PKEY_set1_RSA(pkey, rsa) != 1) { + CLEANUP(OSSL_WRAP_ERROR("EVP_PKEY_set1_RSA")); + } + + if (callback != NULL) { + cb = BN_GENCB_new(); + if (cb == NULL) { + CLEANUP(OSSL_WRAP_ERROR("BN_GENCB_new")); + } + + BN_GENCB_set(cb, rsa_keygen_progress_cb, (void *)callback); + } + + if (RSA_generate_key_ex(rsa, bit_size, e, cb) != 1) { + CLEANUP(OSSL_WRAP_ERROR("RSA_generate_key_ex")); + } + *pkeyp = pkey; + pkey = NULL; + result = ISC_R_SUCCESS; + +cleanup: + EVP_PKEY_free(pkey); + RSA_free(rsa); + BN_GENCB_free(cb); + BN_free(e); + return result; +} + +isc_result_t +isc_ossl_wrap_generate_pkcs11_rsa_key(char *uri, size_t bit_size, + EVP_PKEY **pkeyp) { + UNUSED(uri); + + return isc_ossl_wrap_generate_rsa_key(NULL, bit_size, pkeyp); +} + +bool +isc_ossl_wrap_rsa_key_bits_leq(EVP_PKEY *pkey, size_t limit) { + const RSA *rsa; + const BIGNUM *ce; + size_t bits = SIZE_MAX; + + REQUIRE(pkey != NULL); + + rsa = EVP_PKEY_get0_RSA(pkey); + if (rsa != NULL) { + ce = NULL; + RSA_get0_key(rsa, NULL, &ce, NULL); + if (ce != NULL) { + bits = BN_num_bits(ce); + } + } + + return bits <= limit; +} + +isc_result_t +isc_ossl_wrap_rsa_public_components(EVP_PKEY *pkey, + isc_ossl_wrap_rsa_components_t *c) { + isc_result_t result; + const RSA *rsa; + + REQUIRE(pkey != NULL); + REQUIRE(c != NULL && c->e == NULL && c->n == NULL); + + rsa = EVP_PKEY_get0_RSA(pkey); + if (rsa == NULL) { + CLEANUP(OSSL_WRAP_ERROR("EVP_PKEY_get0_RSA")); + } + + RSA_get0_key(rsa, (const BIGNUM **)&c->n, (const BIGNUM **)&c->e, NULL); + + result = ISC_R_SUCCESS; + +cleanup: + return result; +} + +isc_result_t +isc_ossl_wrap_rsa_secret_components(EVP_PKEY *pkey, + isc_ossl_wrap_rsa_components_t *c) { + isc_result_t result; + const RSA *rsa; + + REQUIRE(pkey != NULL); + REQUIRE(c != NULL && c->d == NULL && c->p == NULL && c->q == NULL && + c->dmp1 == NULL && c->dmq1 == NULL && c->iqmp == NULL); + + rsa = EVP_PKEY_get0_RSA(pkey); + if (rsa == NULL) { + CLEANUP(OSSL_WRAP_ERROR("EVP_PKEY_get0_RSA")); + } + + /* + * We don't support PKCS11 with OpenSSL <=1.1.1a + * d *must* succeed. + */ + RSA_get0_key(rsa, NULL, NULL, (const BIGNUM **)&c->d); + if (c->d == NULL) { + CLEANUP(OSSL_WRAP_ERROR("RSA_get0_key")); + } + + RSA_get0_factors(rsa, (const BIGNUM **)&c->p, (const BIGNUM **)&c->q); + RSA_get0_crt_params(rsa, (const BIGNUM **)&c->dmp1, + (const BIGNUM **)&c->dmq1, + (const BIGNUM **)&c->iqmp); + + result = ISC_R_SUCCESS; + +cleanup: + return result; +} + +isc_result_t +isc_ossl_wrap_load_rsa_public_from_components(isc_ossl_wrap_rsa_components_t *c, + EVP_PKEY **pkeyp) { + isc_result_t result; + EVP_PKEY *pkey = NULL; + RSA *rsa = NULL; + + REQUIRE(pkeyp != NULL && *pkeyp == NULL); + REQUIRE(c != NULL && c->e != NULL && c->n != NULL); + REQUIRE(c->needs_cleanup); + + rsa = RSA_new(); + if (rsa == NULL) { + CLEANUP(OSSL_WRAP_ERROR("RSA_new")); + } + + if (RSA_set0_key(rsa, c->n, c->e, NULL) != 1) { + CLEANUP(OSSL_WRAP_ERROR("RSA_set0_key")); + } + + c->n = NULL; + c->e = NULL; + + pkey = EVP_PKEY_new(); + if (pkey == NULL) { + CLEANUP(OSSL_WRAP_ERROR("EVP_PKEY_new")); + } + + if (EVP_PKEY_set1_RSA(pkey, rsa) != 1) { + CLEANUP(OSSL_WRAP_ERROR("EVP_PKEY_set1_RSA")); + } + + *pkeyp = pkey; + pkey = NULL; + result = ISC_R_SUCCESS; + +cleanup: + EVP_PKEY_free(pkey); + RSA_free(rsa); + return result; +} + +isc_result_t +isc_ossl_wrap_load_rsa_secret_from_components(isc_ossl_wrap_rsa_components_t *c, + EVP_PKEY **pkeyp) { + isc_result_t result; + EVP_PKEY *pkey = NULL; + RSA *rsa = NULL; + + REQUIRE(pkeyp != NULL && *pkeyp == NULL); + REQUIRE(c != NULL); + + result = ISC_R_SUCCESS; + + rsa = RSA_new(); + if (rsa == NULL) { + CLEANUP(OSSL_WRAP_ERROR("RSA_new")); + } + + if (RSA_set0_key(rsa, c->n, c->e, c->d) != 1) { + CLEANUP(OSSL_WRAP_ERROR("RSA_set0_key")); + } + + c->n = NULL; + c->e = NULL; + c->d = NULL; + + if (c->p != NULL || c->q != NULL) { + if (RSA_set0_factors(rsa, c->p, c->q) != 1) { + CLEANUP(OSSL_WRAP_ERROR("RSA_set0_factors")); + } + + c->p = NULL; + c->q = NULL; + } + + if (c->dmp1 != NULL || c->dmq1 != NULL || c->iqmp != NULL) { + if (RSA_set0_crt_params(rsa, c->dmp1, c->dmq1, c->iqmp) != 1) { + CLEANUP(OSSL_WRAP_ERROR("RSA_set0_crt_params")); + } + c->dmp1 = NULL; + c->dmq1 = NULL; + c->iqmp = NULL; + } + + pkey = EVP_PKEY_new(); + if (pkey == NULL) { + CLEANUP(OSSL_WRAP_ERROR("EVP_PKEY_new")); + } + + if (EVP_PKEY_set1_RSA(pkey, rsa) != 1) { + CLEANUP(OSSL_WRAP_ERROR("EVP_PKEY_set1_RSA")); + } + + *pkeyp = pkey; + pkey = NULL; + result = ISC_R_SUCCESS; + +cleanup: + EVP_PKEY_free(pkey); + RSA_free(rsa); + isc_ossl_wrap_rsa_components_cleanup(c); + return result; +} diff --git a/lib/isc/ossl_wrap/ossl3.c b/lib/isc/ossl_wrap/ossl3.c index 844583345b..d18beb3e19 100644 --- a/lib/isc/ossl_wrap/ossl3.c +++ b/lib/isc/ossl_wrap/ossl3.c @@ -11,7 +11,332 @@ * information regarding copyright ownership. */ +#include + +#include +#include +#include +#include +#include +#include + #include #include -EMPTY_TRANSLATION_UNIT; +#define OSSL_WRAP_ERROR(fn) \ + isc__ossl_wrap_logged_toresult( \ + ISC_LOGCATEGORY_GENERAL, ISC_LOGMODULE_CRYPTO, fn, \ + ISC_R_CRYPTOFAILURE, __FILE__, __LINE__) + +static int +rsa_keygen_progress_cb(EVP_PKEY_CTX *ctx) { + void (*fptr)(int); + + fptr = EVP_PKEY_CTX_get_app_data(ctx); + if (fptr != NULL) { + int p = EVP_PKEY_CTX_get_keygen_info(ctx, 0); + fptr(p); + } + return 1; +} + +isc_result_t +isc_ossl_wrap_generate_rsa_key(void (*callback)(int), size_t bit_size, + EVP_PKEY **pkeyp) { + isc_result_t result; + EVP_PKEY_CTX *ctx; + BIGNUM *e; + + REQUIRE(pkeyp != NULL && *pkeyp == NULL); + + e = BN_new(); + + /* e = 65537 (0x10001, F4) */ + BN_set_bit(e, 0); + BN_set_bit(e, 16); + + ctx = EVP_PKEY_CTX_new_from_name(NULL, "RSA", NULL); + if (ctx == NULL) { + CLEANUP(OSSL_WRAP_ERROR("EVP_PKEY_CTX_new_from_name")); + } + + if (EVP_PKEY_keygen_init(ctx) != 1) { + CLEANUP(OSSL_WRAP_ERROR("EVP_PKEY_keygen_init")); + } + + if (EVP_PKEY_CTX_set_rsa_keygen_bits(ctx, bit_size) != 1) { + CLEANUP(OSSL_WRAP_ERROR("EVP_PKEY_CTX_set_rsa_keygen_bits")); + } + + if (EVP_PKEY_CTX_set1_rsa_keygen_pubexp(ctx, e) != 1) { + CLEANUP(OSSL_WRAP_ERROR("EVP_PKEY_CTX_set1_rsa_keygen_pubexp")); + } + + if (callback != NULL) { + EVP_PKEY_CTX_set_app_data(ctx, (void *)callback); + EVP_PKEY_CTX_set_cb(ctx, rsa_keygen_progress_cb); + } + + if (EVP_PKEY_keygen(ctx, pkeyp) != 1) { + CLEANUP(OSSL_WRAP_ERROR("EVP_PKEY_keygen")); + } + + result = ISC_R_SUCCESS; + +cleanup: + EVP_PKEY_CTX_free(ctx); + BN_free(e); + return result; +} + +isc_result_t +isc_ossl_wrap_generate_pkcs11_rsa_key(char *uri, size_t bit_size, + EVP_PKEY **pkeyp) { + EVP_PKEY_CTX *ctx = NULL; + OSSL_PARAM params[4]; + isc_result_t result; + int status; + + params[0] = OSSL_PARAM_construct_utf8_string("pkcs11_uri", uri, 0); + params[1] = OSSL_PARAM_construct_utf8_string( + "pkcs11_key_usage", (char *)"digitalSignature", 0); + params[2] = OSSL_PARAM_construct_size_t("rsa_keygen_bits", &bit_size); + params[3] = OSSL_PARAM_construct_end(); + + ctx = EVP_PKEY_CTX_new_from_name(NULL, "RSA", "provider=pkcs11"); + if (ctx == NULL) { + CLEANUP(OSSL_WRAP_ERROR("EVP_PKEY_CTX_new_from_name")); + } + + status = EVP_PKEY_keygen_init(ctx); + if (status != 1) { + CLEANUP(OSSL_WRAP_ERROR("EVP_PKEY_keygen_init")); + } + + status = EVP_PKEY_CTX_set_params(ctx, params); + if (status != 1) { + CLEANUP(OSSL_WRAP_ERROR("EVP_PKEY_CTX_set_params")); + } + + status = EVP_PKEY_generate(ctx, pkeyp); + if (status != 1) { + CLEANUP(OSSL_WRAP_ERROR("EVP_PKEY_generate")); + } + + result = ISC_R_SUCCESS; + +cleanup: + EVP_PKEY_CTX_free(ctx); + return result; +} + +bool +isc_ossl_wrap_rsa_key_bits_leq(EVP_PKEY *pkey, size_t limit) { + size_t bits = SIZE_MAX; + BIGNUM *e = NULL; + if (EVP_PKEY_get_bn_param(pkey, OSSL_PKEY_PARAM_RSA_E, &e) == 1) { + bits = BN_num_bits(e); + BN_free(e); + } + return bits <= limit; +} + +isc_result_t +isc_ossl_wrap_rsa_public_components(EVP_PKEY *pkey, + isc_ossl_wrap_rsa_components_t *c) { + isc_result_t result; + + REQUIRE(pkey != NULL); + REQUIRE(c != NULL && c->e == NULL && c->n == NULL); + + c->needs_cleanup = true; + + if (EVP_PKEY_get_bn_param(pkey, OSSL_PKEY_PARAM_RSA_E, &c->e) != 1) { + CLEANUP(OSSL_WRAP_ERROR("EVP_PKEY_get_bn_param")); + } + + if (EVP_PKEY_get_bn_param(pkey, OSSL_PKEY_PARAM_RSA_N, &c->n) != 1) { + CLEANUP(OSSL_WRAP_ERROR("EVP_PKEY_get_bn_param")); + } + + result = ISC_R_SUCCESS; + +cleanup: + return result; +} + +isc_result_t +isc_ossl_wrap_rsa_secret_components(EVP_PKEY *pkey, + isc_ossl_wrap_rsa_components_t *c) { + REQUIRE(pkey != NULL); + REQUIRE(c != NULL && c->d == NULL && c->p == NULL && c->q == NULL && + c->dmp1 == NULL && c->dmq1 == NULL && c->iqmp == NULL); + + c->needs_cleanup = true; + + /* + * NOTE: Errors regarding private compoments are ignored. + * + * OpenSSL allows omitting the parameters for CRT based calculations + * (factors, exponents, coefficients). Only the 'd' parameter is + * mandatory for software keys. + * + * However, for a label based keys, all private key component queries + * can fail if they key is e.g. on a hardware device. + */ + (void)EVP_PKEY_get_bn_param(pkey, OSSL_PKEY_PARAM_RSA_D, &c->d); + (void)EVP_PKEY_get_bn_param(pkey, OSSL_PKEY_PARAM_RSA_FACTOR1, &c->p); + (void)EVP_PKEY_get_bn_param(pkey, OSSL_PKEY_PARAM_RSA_FACTOR2, &c->q); + (void)EVP_PKEY_get_bn_param(pkey, OSSL_PKEY_PARAM_RSA_EXPONENT1, + &c->dmp1); + (void)EVP_PKEY_get_bn_param(pkey, OSSL_PKEY_PARAM_RSA_EXPONENT2, + &c->dmq1); + (void)EVP_PKEY_get_bn_param(pkey, OSSL_PKEY_PARAM_RSA_COEFFICIENT1, + &c->iqmp); + + ERR_clear_error(); + + return ISC_R_SUCCESS; +} + +isc_result_t +isc_ossl_wrap_load_rsa_public_from_components(isc_ossl_wrap_rsa_components_t *c, + EVP_PKEY **pkeyp) { + OSSL_PARAM_BLD *bld = NULL; + EVP_PKEY_CTX *pctx = NULL; + OSSL_PARAM *params = NULL; + isc_result_t result; + + result = ISC_R_SUCCESS; + + REQUIRE(pkeyp != NULL && *pkeyp == NULL); + REQUIRE(c != NULL && c->n != NULL && c->e != NULL); + + bld = OSSL_PARAM_BLD_new(); + if (bld == NULL) { + CLEANUP(OSSL_WRAP_ERROR("OSSL_PARAM_BLD_new")); + } + + if (OSSL_PARAM_BLD_push_BN(bld, OSSL_PKEY_PARAM_RSA_N, c->n) != 1) { + CLEANUP(OSSL_WRAP_ERROR("OSSL_PARAM_BLD_push_BN")); + } + + if (OSSL_PARAM_BLD_push_BN(bld, OSSL_PKEY_PARAM_RSA_E, c->e) != 1) { + CLEANUP(OSSL_WRAP_ERROR("OSSL_PARAM_BLD_push_BN")); + } + + params = OSSL_PARAM_BLD_to_param(bld); + if (params == NULL) { + CLEANUP(OSSL_WRAP_ERROR("OSSL_PARAM_BLD_to_param")); + } + + pctx = EVP_PKEY_CTX_new_from_name(NULL, "RSA", NULL); + if (pctx == NULL) { + CLEANUP(OSSL_WRAP_ERROR("EVP_PKEY_CTX_new_from_name")); + } + + if (EVP_PKEY_fromdata_init(pctx) != 1) { + CLEANUP(OSSL_WRAP_ERROR("EVP_PKEY_fromdata_init")); + } + + if (EVP_PKEY_fromdata(pctx, pkeyp, EVP_PKEY_PUBLIC_KEY, params) != 1) { + CLEANUP(OSSL_WRAP_ERROR("EVP_PKEY_fromdata")); + } + + result = ISC_R_SUCCESS; + +cleanup: + EVP_PKEY_CTX_free(pctx); + OSSL_PARAM_free(params); + OSSL_PARAM_BLD_free(bld); + return result; +} + +isc_result_t +isc_ossl_wrap_load_rsa_secret_from_components(isc_ossl_wrap_rsa_components_t *c, + EVP_PKEY **pkeyp) { + isc_result_t result; + OSSL_PARAM_BLD *bld = NULL; + EVP_PKEY_CTX *pctx = NULL; + OSSL_PARAM *params = NULL; + + REQUIRE(pkeyp != NULL && *pkeyp == NULL); + + bld = OSSL_PARAM_BLD_new(); + if (bld == NULL) { + CLEANUP(OSSL_WRAP_ERROR("OSSL_PARAM_BLD_new")); + } + + if (OSSL_PARAM_BLD_push_BN(bld, OSSL_PKEY_PARAM_RSA_N, c->n) != 1) { + CLEANUP(OSSL_WRAP_ERROR("OSSL_PARAM_BLD_push_BN")); + } + + if (OSSL_PARAM_BLD_push_BN(bld, OSSL_PKEY_PARAM_RSA_E, c->e) != 1) { + CLEANUP(OSSL_WRAP_ERROR("OSSL_PARAM_BLD_push_BN")); + } + + if (c->d != NULL && + OSSL_PARAM_BLD_push_BN(bld, OSSL_PKEY_PARAM_RSA_D, c->d) != 1) + { + CLEANUP(OSSL_WRAP_ERROR("OSSL_PARAM_BLD_push_BN")); + } + + if (c->p != NULL && + OSSL_PARAM_BLD_push_BN(bld, OSSL_PKEY_PARAM_RSA_FACTOR1, c->p) != 1) + { + CLEANUP(OSSL_WRAP_ERROR("OSSL_PARAM_BLD_push_BN")); + } + + if (c->q != NULL && + OSSL_PARAM_BLD_push_BN(bld, OSSL_PKEY_PARAM_RSA_FACTOR2, c->q) != 1) + { + CLEANUP(OSSL_WRAP_ERROR("OSSL_PARAM_BLD_push_BN")); + } + + if (c->dmp1 != NULL && + OSSL_PARAM_BLD_push_BN(bld, OSSL_PKEY_PARAM_RSA_EXPONENT1, + c->dmp1) != 1) + { + CLEANUP(OSSL_WRAP_ERROR("OSSL_PARAM_BLD_push_BN")); + } + + if (c->dmq1 != NULL && + OSSL_PARAM_BLD_push_BN(bld, OSSL_PKEY_PARAM_RSA_EXPONENT2, + c->dmq1) != 1) + { + CLEANUP(OSSL_WRAP_ERROR("OSSL_PARAM_BLD_push_BN")); + } + + if (c->iqmp != NULL && + OSSL_PARAM_BLD_push_BN(bld, OSSL_PKEY_PARAM_RSA_COEFFICIENT1, + c->iqmp) != 1) + { + CLEANUP(OSSL_WRAP_ERROR("OSSL_PARAM_BLD_push_BN")); + } + + params = OSSL_PARAM_BLD_to_param(bld); + if (params == NULL) { + CLEANUP(OSSL_WRAP_ERROR("OSSL_PARAM_BLD_to_param")); + } + + pctx = EVP_PKEY_CTX_new_from_name(NULL, "RSA", NULL); + if (pctx == NULL) { + CLEANUP(OSSL_WRAP_ERROR("EVP_PKEY_CTX_new_from_name")); + } + + if (EVP_PKEY_fromdata_init(pctx) != 1) { + CLEANUP(OSSL_WRAP_ERROR("EVP_PKEY_fromdata_init")); + } + + if (EVP_PKEY_fromdata(pctx, pkeyp, EVP_PKEY_KEYPAIR, params) != 1) { + CLEANUP(OSSL_WRAP_ERROR("EVP_PKEY_fromdata")); + } + + result = ISC_R_SUCCESS; + +cleanup: + EVP_PKEY_CTX_free(pctx); + OSSL_PARAM_free(params); + OSSL_PARAM_BLD_free(bld); + return result; +} diff --git a/lib/isc/ossl_wrap/ossl_common.c b/lib/isc/ossl_wrap/ossl_common.c index cf09d93a18..0828a37ff0 100644 --- a/lib/isc/ossl_wrap/ossl_common.c +++ b/lib/isc/ossl_wrap/ossl_common.c @@ -11,6 +11,7 @@ * information regarding copyright ownership. */ +#include #include #include @@ -18,6 +19,32 @@ #include "../openssl_shim.h" +void +isc_ossl_wrap_rsa_components_cleanup(isc_ossl_wrap_rsa_components_t *c) { + REQUIRE(c != NULL); + + if (!c->needs_cleanup) { + return; + } + + /* + * NOTE: BN_free() frees the components of the BIGNUM, and if it was + * created by BN_new(), also the structure itself. BN_clear_free() + * additionally overwrites the data before the memory is returned to the + * system. If a is NULL, nothing is done. + */ + BN_free(c->e); + BN_free(c->n); + BN_clear_free(c->d); + BN_clear_free(c->p); + BN_clear_free(c->q); + BN_clear_free(c->dmp1); + BN_clear_free(c->dmq1); + BN_clear_free(c->iqmp); + + c->needs_cleanup = false; +} + isc_result_t isc_ossl_wrap_toresult(isc_result_t fallback) { isc_result_t result = fallback; From 3bd37549942b3ed1e20e2dbdabddeaecb55d8319 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ayd=C4=B1n=20Mercan?= Date: Mon, 1 Dec 2025 17:07:54 +0300 Subject: [PATCH 08/16] remove libcrypto version specific code in opensslecdsa_link Using `EVP_SIGNATURE` explicit algoritms for signatures have been added in OpenSSL 3.4 and so is skipped for the initial OpenSSL version specific code splitting. --- lib/dns/opensslecdsa_link.c | 712 +++++--------------------------- lib/isc/include/isc/ossl_wrap.h | 173 ++++++++ lib/isc/ossl_wrap/ossl1_1.c | 316 ++++++++++++++ lib/isc/ossl_wrap/ossl3.c | 418 +++++++++++++++++++ 4 files changed, 1016 insertions(+), 603 deletions(-) diff --git a/lib/dns/opensslecdsa_link.c b/lib/dns/opensslecdsa_link.c index 9203cdba04..7b89b3f25a 100644 --- a/lib/dns/opensslecdsa_link.c +++ b/lib/dns/opensslecdsa_link.c @@ -17,14 +17,8 @@ #include #include -#include #include #include -#include -#if OPENSSL_VERSION_NUMBER >= 0x30000000L -#include -#include -#endif #include #include @@ -55,37 +49,6 @@ extern EVP_MD *isc__crypto_md[]; #define MAX_PRIVKEY_SIZE (MAX_PUBKEY_SIZE / 2) -#if OPENSSL_VERSION_NUMBER >= 0x30200000L -static isc_result_t -opensslecdsa_set_deterministic(EVP_PKEY_CTX *pctx, unsigned int key_alg) { - unsigned int rfc6979 = 1; - const char *md = NULL; - OSSL_PARAM params[3]; - - switch (key_alg) { - case DST_ALG_ECDSA256: - md = "SHA256"; - break; - case DST_ALG_ECDSA384: - md = "SHA384"; - break; - default: - UNREACHABLE(); - } - - params[0] = OSSL_PARAM_construct_utf8_string("digest", UNCONST(md), 0); - params[1] = OSSL_PARAM_construct_uint("nonce-type", &rfc6979); - params[2] = OSSL_PARAM_construct_end(); - - if (EVP_PKEY_CTX_set_params(pctx, params) != 1) { - return dst__openssl_toresult2("EVP_PKEY_CTX_set_params", - DST_R_OPENSSLFAILURE); - } - - return ISC_R_SUCCESS; -} -#endif /* OPENSSL_VERSION_NUMBER >= 0x30200000L */ - static bool opensslecdsa_valid_key_alg(unsigned int key_alg) { switch (key_alg) { @@ -97,18 +60,6 @@ opensslecdsa_valid_key_alg(unsigned int key_alg) { } } -static int -opensslecdsa_key_alg_to_group_nid(unsigned int key_alg) { - switch (key_alg) { - case DST_ALG_ECDSA256: - return NID_X9_62_prime256v1; - case DST_ALG_ECDSA384: - return NID_secp384r1; - default: - UNREACHABLE(); - } -} - static size_t opensslecdsa_key_alg_to_publickey_size(unsigned int key_alg) { switch (key_alg) { @@ -121,23 +72,6 @@ opensslecdsa_key_alg_to_publickey_size(unsigned int key_alg) { } } -/* - * OpenSSL requires us to set the public key portion, but since our private key - * file format does not contain it directly, we generate it as needed. - */ -static EC_POINT * -opensslecdsa_generate_public_key(const EC_GROUP *group, const BIGNUM *privkey) { - EC_POINT *pubkey = EC_POINT_new(group); - if (pubkey == NULL) { - return NULL; - } - if (EC_POINT_mul(group, pubkey, privkey, NULL, NULL, NULL) != 1) { - EC_POINT_free(pubkey); - return NULL; - } - return pubkey; -} - static int BN_bn2bin_fixed(const BIGNUM *bn, unsigned char *buf, int size) { int bytes = size - BN_num_bytes(bn); @@ -151,534 +85,13 @@ BN_bn2bin_fixed(const BIGNUM *bn, unsigned char *buf, int size) { return size; } -#if OPENSSL_VERSION_NUMBER >= 0x30000000L - -static const char * -opensslecdsa_key_alg_to_group_name(unsigned int key_alg) { - switch (key_alg) { - case DST_ALG_ECDSA256: - return "prime256v1"; - case DST_ALG_ECDSA384: - return "secp384r1"; - default: - UNREACHABLE(); - } -} - -static isc_result_t -opensslecdsa_create_pkey_params(unsigned int key_alg, bool private, - const unsigned char *key, size_t key_len, - EVP_PKEY **pkey) { - isc_result_t result; - int status; - int group_nid = opensslecdsa_key_alg_to_group_nid(key_alg); - const char *groupname = opensslecdsa_key_alg_to_group_name(key_alg); - OSSL_PARAM_BLD *bld = NULL; - OSSL_PARAM *params = NULL; - EVP_PKEY_CTX *ctx = NULL; - EC_POINT *pubkey = NULL; - EC_GROUP *group = NULL; - BIGNUM *priv = NULL; - unsigned char buf[MAX_PUBKEY_SIZE + 1]; - - bld = OSSL_PARAM_BLD_new(); - if (bld == NULL) { - CLEANUP(dst__openssl_toresult2("OSSL_PARAM_BLD_new", - DST_R_OPENSSLFAILURE)); - } - status = OSSL_PARAM_BLD_push_utf8_string( - bld, OSSL_PKEY_PARAM_GROUP_NAME, groupname, 0); - if (status != 1) { - CLEANUP(dst__openssl_toresult2("OSSL_PARAM_BLD_push_" - "utf8_string", - DST_R_OPENSSLFAILURE)); - } - - if (private) { - group = EC_GROUP_new_by_curve_name(group_nid); - if (group == NULL) { - CLEANUP(dst__openssl_toresult2("EC_GROUP_new_by_" - "curve_name", - DST_R_OPENSSLFAILURE)); - } - - priv = BN_bin2bn(key, key_len, NULL); - if (priv == NULL) { - CLEANUP(dst__openssl_toresult2("BN_bin2bn", - DST_R_OPENSSLFAILURE)); - } - - status = OSSL_PARAM_BLD_push_BN(bld, OSSL_PKEY_PARAM_PRIV_KEY, - priv); - if (status != 1) { - CLEANUP(dst__openssl_toresult2("OSSL_PARAM_BLD_push_BN", - DST_R_OPENSSLFAILURE)); - } - - pubkey = opensslecdsa_generate_public_key(group, priv); - if (pubkey == NULL) { - CLEANUP(dst__openssl_toresult(DST_R_OPENSSLFAILURE)); - } - - key = buf; - key_len = EC_POINT_point2oct(group, pubkey, - POINT_CONVERSION_UNCOMPRESSED, buf, - sizeof(buf), NULL); - if (key_len == 0) { - CLEANUP(dst__openssl_toresult2("EC_POINT_point2oct", - DST_R_OPENSSLFAILURE)); - } - } else { - INSIST(key_len + 1 <= sizeof(buf)); - buf[0] = POINT_CONVERSION_UNCOMPRESSED; - memmove(buf + 1, key, key_len); - key = buf; - key_len = key_len + 1; - } - - status = OSSL_PARAM_BLD_push_octet_string(bld, OSSL_PKEY_PARAM_PUB_KEY, - key, key_len); - if (status != 1) { - CLEANUP(dst__openssl_toresult2("OSSL_PARAM_BLD_push_" - "octet_string", - DST_R_OPENSSLFAILURE)); - } - - params = OSSL_PARAM_BLD_to_param(bld); - if (params == NULL) { - CLEANUP(dst__openssl_toresult2("OSSL_PARAM_BLD_to_param", - DST_R_OPENSSLFAILURE)); - } - ctx = EVP_PKEY_CTX_new_from_name(NULL, "EC", NULL); - if (ctx == NULL) { - CLEANUP(dst__openssl_toresult2("EVP_PKEY_CTX_new_from_name", - DST_R_OPENSSLFAILURE)); - } - status = EVP_PKEY_fromdata_init(ctx); - if (status != 1) { - /* This will fail if the default provider is an engine. - * Return ISC_R_FAILURE to retry using the legacy API. */ - CLEANUP(dst__openssl_toresult(ISC_R_FAILURE)); - } - status = EVP_PKEY_fromdata( - ctx, pkey, private ? EVP_PKEY_KEYPAIR : EVP_PKEY_PUBLIC_KEY, - params); - if (status != 1 || *pkey == NULL) { - CLEANUP(dst__openssl_toresult2("EVP_PKEY_fromdata", - DST_R_OPENSSLFAILURE)); - } - - result = ISC_R_SUCCESS; - -cleanup: - OSSL_PARAM_free(params); - OSSL_PARAM_BLD_free(bld); - EVP_PKEY_CTX_free(ctx); - BN_clear_free(priv); - EC_POINT_free(pubkey); - EC_GROUP_free(group); - - return result; -} - -static bool -opensslecdsa_extract_public_key_params(const dst_key_t *key, unsigned char *dst, - size_t dstlen) { - EVP_PKEY *pkey = key->keydata.pkeypair.pub; - BIGNUM *x = NULL; - BIGNUM *y = NULL; - bool ret = false; - - if (EVP_PKEY_get_bn_param(pkey, OSSL_PKEY_PARAM_EC_PUB_X, &x) == 1 && - EVP_PKEY_get_bn_param(pkey, OSSL_PKEY_PARAM_EC_PUB_Y, &y) == 1) - { - BN_bn2bin_fixed(x, &dst[0], dstlen / 2); - BN_bn2bin_fixed(y, &dst[dstlen / 2], dstlen / 2); - ret = true; - } - BN_clear_free(x); - BN_clear_free(y); - return ret; -} - -#endif - -#if OPENSSL_VERSION_NUMBER < 0x30000000L - -static isc_result_t -opensslecdsa_create_pkey_legacy(unsigned int key_alg, bool private, - const unsigned char *key, size_t key_len, - EVP_PKEY **retkey) { - isc_result_t result = ISC_R_SUCCESS; - EC_KEY *eckey = NULL; - EVP_PKEY *pkey = NULL; - BIGNUM *privkey = NULL; - EC_POINT *pubkey = NULL; - unsigned char buf[MAX_PUBKEY_SIZE + 1]; - int group_nid = opensslecdsa_key_alg_to_group_nid(key_alg); - - eckey = EC_KEY_new_by_curve_name(group_nid); - if (eckey == NULL) { - CLEANUP(dst__openssl_toresult(DST_R_OPENSSLFAILURE)); - } - - if (private) { - const EC_GROUP *group = EC_KEY_get0_group(eckey); - - privkey = BN_bin2bn(key, key_len, NULL); - if (privkey == NULL) { - CLEANUP(dst__openssl_toresult(DST_R_OPENSSLFAILURE)); - } - if (!EC_KEY_set_private_key(eckey, privkey)) { - CLEANUP(dst__openssl_toresult(DST_R_INVALIDPRIVATEKEY)); - } - - pubkey = opensslecdsa_generate_public_key(group, privkey); - if (pubkey == NULL) { - CLEANUP(dst__openssl_toresult(DST_R_OPENSSLFAILURE)); - } - if (EC_KEY_set_public_key(eckey, pubkey) != 1) { - CLEANUP(dst__openssl_toresult(DST_R_OPENSSLFAILURE)); - } - } else { - const unsigned char *cp = buf; - INSIST(key_len + 1 <= sizeof(buf)); - buf[0] = POINT_CONVERSION_UNCOMPRESSED; - memmove(buf + 1, key, key_len); - if (o2i_ECPublicKey(&eckey, &cp, key_len + 1) == NULL) { - CLEANUP(dst__openssl_toresult(DST_R_INVALIDPUBLICKEY)); - } - if (EC_KEY_check_key(eckey) != 1) { - CLEANUP(dst__openssl_toresult(DST_R_INVALIDPUBLICKEY)); - } - } - - pkey = EVP_PKEY_new(); - if (pkey == NULL) { - CLEANUP(dst__openssl_toresult(ISC_R_NOMEMORY)); - } - if (!EVP_PKEY_set1_EC_KEY(pkey, eckey)) { - CLEANUP(dst__openssl_toresult(ISC_R_FAILURE)); - } - - *retkey = pkey; - pkey = NULL; - -cleanup: - BN_clear_free(privkey); - EC_POINT_free(pubkey); - EC_KEY_free(eckey); - EVP_PKEY_free(pkey); - return result; -} - -static bool -opensslecdsa_extract_public_key_legacy(const dst_key_t *key, unsigned char *dst, - size_t dstlen) { - EVP_PKEY *pkey = key->keydata.pkeypair.pub; - const EC_KEY *eckey = EVP_PKEY_get0_EC_KEY(pkey); - const EC_GROUP *group = (eckey == NULL) ? NULL - : EC_KEY_get0_group(eckey); - const EC_POINT *pub = (eckey == NULL) ? NULL - : EC_KEY_get0_public_key(eckey); - unsigned char buf[MAX_PUBKEY_SIZE + 1]; - size_t len; - - if (group == NULL || pub == NULL) { - return false; - } - - len = EC_POINT_point2oct(group, pub, POINT_CONVERSION_UNCOMPRESSED, buf, - sizeof(buf), NULL); - if (len == dstlen + 1) { - memmove(dst, buf + 1, dstlen); - return true; - } - return false; -} - -#endif - -static bool -opensslecdsa_extract_public_key(const dst_key_t *key, unsigned char *dst, - size_t dstlen) { -#if OPENSSL_VERSION_NUMBER >= 0x30000000L - if (opensslecdsa_extract_public_key_params(key, dst, dstlen)) { - return true; - } -#else - if (opensslecdsa_extract_public_key_legacy(key, dst, dstlen)) { - return true; - } -#endif - return false; -} - -static isc_result_t -opensslecdsa_create_pkey(unsigned int key_alg, bool private, - const unsigned char *key, size_t key_len, - EVP_PKEY **retkey) { - isc_result_t result; -#if OPENSSL_VERSION_NUMBER >= 0x30000000L - result = opensslecdsa_create_pkey_params(key_alg, private, key, key_len, - retkey); - if (result != ISC_R_FAILURE) { - return result; - } -#else - result = opensslecdsa_create_pkey_legacy(key_alg, private, key, key_len, - retkey); - if (result == ISC_R_SUCCESS) { - return result; - } -#endif - return DST_R_OPENSSLFAILURE; -} - -#if OPENSSL_VERSION_NUMBER >= 0x30000000L - -static isc_result_t -opensslecdsa_generate_pkey_with_uri(int group_nid, const char *label, - EVP_PKEY **retkey) { - int status; - isc_result_t result; - char *uri = UNCONST(label); - EVP_PKEY_CTX *ctx = NULL; - OSSL_PARAM params[3]; - - /* Generate the key's parameters. */ - params[0] = OSSL_PARAM_construct_utf8_string("pkcs11_uri", uri, 0); - params[1] = OSSL_PARAM_construct_utf8_string( - "pkcs11_key_usage", (char *)"digitalSignature", 0); - params[2] = OSSL_PARAM_construct_end(); - - ctx = EVP_PKEY_CTX_new_from_name(NULL, "EC", "provider=pkcs11"); - if (ctx == NULL) { - CLEANUP(dst__openssl_toresult2("EVP_PKEY_CTX_new_from_name", - DST_R_OPENSSLFAILURE)); - } - - status = EVP_PKEY_keygen_init(ctx); - if (status != 1) { - CLEANUP(dst__openssl_toresult2("EVP_PKEY_keygen_init", - DST_R_OPENSSLFAILURE)); - } - - status = EVP_PKEY_CTX_set_params(ctx, params); - if (status != 1) { - CLEANUP(dst__openssl_toresult2("EVP_PKEY_CTX_set_params", - DST_R_OPENSSLFAILURE)); - } - /* - * Setting the P-384 curve doesn't work correctly when using: - * OSSL_PARAM_construct_utf8_string("ec_paramgen_curve", "P-384", 0); - * - * Instead use the OpenSSL function to set the curve nid param. - */ - status = EVP_PKEY_CTX_set_ec_paramgen_curve_nid(ctx, group_nid); - if (status != 1) { - CLEANUP(dst__openssl_toresult2("EVP_PKEY_CTX_set_ec_paramgen_" - "curve_nid", - DST_R_OPENSSLFAILURE)); - } - - /* Generate the key. */ - status = EVP_PKEY_generate(ctx, retkey); - if (status != 1) { - CLEANUP(dst__openssl_toresult2("EVP_PKEY_generate", - DST_R_OPENSSLFAILURE)); - } - - result = ISC_R_SUCCESS; - -cleanup: - EVP_PKEY_CTX_free(ctx); - return result; -} - -static isc_result_t -opensslecdsa_generate_pkey(unsigned int key_alg, const char *label, - EVP_PKEY **retkey) { - isc_result_t result; - EVP_PKEY_CTX *ctx = NULL; - EVP_PKEY *params_pkey = NULL; - int group_nid = opensslecdsa_key_alg_to_group_nid(key_alg); - int status; - - if (label != NULL) { - return opensslecdsa_generate_pkey_with_uri(group_nid, label, - retkey); - } - - /* Generate the key's parameters. */ - ctx = EVP_PKEY_CTX_new_from_name(NULL, "EC", NULL); - if (ctx == NULL) { - CLEANUP(dst__openssl_toresult2("EVP_PKEY_CTX_new_from_name", - DST_R_OPENSSLFAILURE)); - } - status = EVP_PKEY_paramgen_init(ctx); - if (status != 1) { - CLEANUP(dst__openssl_toresult2("EVP_PKEY_paramgen_init", - DST_R_OPENSSLFAILURE)); - } - status = EVP_PKEY_CTX_set_ec_paramgen_curve_nid(ctx, group_nid); - if (status != 1) { - CLEANUP(dst__openssl_toresult2("EVP_PKEY_CTX_set_ec_paramgen_" - "curve_nid", - DST_R_OPENSSLFAILURE)); - } - status = EVP_PKEY_paramgen(ctx, ¶ms_pkey); - if (status != 1 || params_pkey == NULL) { - CLEANUP(dst__openssl_toresult2("EVP_PKEY_paramgen", - DST_R_OPENSSLFAILURE)); - } - EVP_PKEY_CTX_free(ctx); - - /* Generate the key. */ - ctx = EVP_PKEY_CTX_new(params_pkey, NULL); - if (ctx == NULL) { - CLEANUP(dst__openssl_toresult2("EVP_PKEY_CTX_new", - DST_R_OPENSSLFAILURE)); - } - - status = EVP_PKEY_keygen_init(ctx); - if (status != 1) { - CLEANUP(dst__openssl_toresult2("EVP_PKEY_keygen_init", - DST_R_OPENSSLFAILURE)); - } - status = EVP_PKEY_keygen(ctx, retkey); - if (status != 1) { - CLEANUP(dst__openssl_toresult2("EVP_PKEY_keygen", - DST_R_OPENSSLFAILURE)); - } - result = ISC_R_SUCCESS; - -cleanup: - EVP_PKEY_free(params_pkey); - EVP_PKEY_CTX_free(ctx); - return result; -} - -static isc_result_t -opensslecdsa_validate_pkey_group(unsigned int key_alg, EVP_PKEY *pkey) { - const char *groupname = opensslecdsa_key_alg_to_group_name(key_alg); - char gname[64]; - - if (EVP_PKEY_get_group_name(pkey, gname, sizeof(gname), NULL) != 1) { - return DST_R_INVALIDPRIVATEKEY; - } - if (strcmp(gname, groupname) != 0) { - return DST_R_INVALIDPRIVATEKEY; - } - return ISC_R_SUCCESS; -} - -static bool -opensslecdsa_extract_private_key(const dst_key_t *key, unsigned char *buf, - size_t buflen) { - EVP_PKEY *pkey = key->keydata.pkeypair.priv; - BIGNUM *priv = NULL; - - if (EVP_PKEY_get_bn_param(pkey, OSSL_PKEY_PARAM_PRIV_KEY, &priv) != 1) { - return false; - } - - BN_bn2bin_fixed(priv, buf, buflen); - BN_clear_free(priv); - return true; -} - -#else - -static isc_result_t -opensslecdsa_generate_pkey(unsigned int key_alg, const char *label, - EVP_PKEY **retkey) { - isc_result_t result; - EC_KEY *eckey = NULL; - EVP_PKEY *pkey = NULL; - int group_nid; - - UNUSED(label); - - group_nid = opensslecdsa_key_alg_to_group_nid(key_alg); - - eckey = EC_KEY_new_by_curve_name(group_nid); - if (eckey == NULL) { - CLEANUP(dst__openssl_toresult2("EC_KEY_new_by_curve_name", - DST_R_OPENSSLFAILURE)); - } - - if (EC_KEY_generate_key(eckey) != 1) { - CLEANUP(dst__openssl_toresult2("EC_KEY_generate_key", - DST_R_OPENSSLFAILURE)); - } - - pkey = EVP_PKEY_new(); - if (pkey == NULL) { - CLEANUP(dst__openssl_toresult(ISC_R_NOMEMORY)); - } - if (EVP_PKEY_set1_EC_KEY(pkey, eckey) != 1) { - CLEANUP(dst__openssl_toresult2("EVP_PKEY_set1_EC_KEY", - DST_R_OPENSSLFAILURE)); - } - *retkey = pkey; - pkey = NULL; - result = ISC_R_SUCCESS; - -cleanup: - EC_KEY_free(eckey); - EVP_PKEY_free(pkey); - return result; -} - -static isc_result_t -opensslecdsa_validate_pkey_group(unsigned int key_alg, EVP_PKEY *pkey) { - const EC_KEY *eckey = EVP_PKEY_get0_EC_KEY(pkey); - int group_nid; - - if (eckey == NULL) { - return dst__openssl_toresult(DST_R_INVALIDPRIVATEKEY); - } - - group_nid = opensslecdsa_key_alg_to_group_nid(key_alg); - - if (EC_GROUP_get_curve_name(EC_KEY_get0_group(eckey)) != group_nid) { - return DST_R_INVALIDPRIVATEKEY; - } - - return ISC_R_SUCCESS; -} - -static bool -opensslecdsa_extract_private_key(const dst_key_t *key, unsigned char *buf, - size_t buflen) { - const EC_KEY *eckey = NULL; - const BIGNUM *privkey = NULL; - - eckey = EVP_PKEY_get0_EC_KEY(key->keydata.pkeypair.priv); - if (eckey == NULL) { - ERR_clear_error(); - return false; - } - - privkey = EC_KEY_get0_private_key(eckey); - if (privkey == NULL) { - ERR_clear_error(); - return false; - } - - BN_bn2bin_fixed(privkey, buf, buflen); - return true; -} - -#endif /* OPENSSL_VERSION_NUMBER >= 0x30000000L */ - static isc_result_t opensslecdsa_createctx(dst_key_t *key, dst_context_t *dctx) { isc_result_t result = ISC_R_SUCCESS; EVP_MD_CTX *evp_md_ctx; EVP_PKEY_CTX *pctx = NULL; const EVP_MD *type = NULL; + const char *md = NULL; UNUSED(key); REQUIRE(opensslecdsa_valid_key_alg(dctx->key->key_alg)); @@ -690,8 +103,10 @@ opensslecdsa_createctx(dst_key_t *key, dst_context_t *dctx) { } if (dctx->key->key_alg == DST_ALG_ECDSA256) { type = isc__crypto_md[ISC_MD_SHA256]; + md = "SHA256"; } else { type = isc__crypto_md[ISC_MD_SHA384]; + md = "SHA384"; } if (dctx->use == DO_SIGN) { @@ -704,12 +119,15 @@ opensslecdsa_createctx(dst_key_t *key, dst_context_t *dctx) { ISC_R_FAILURE)); } -#if OPENSSL_VERSION_NUMBER >= 0x30200000L if (!isc_crypto_fips_mode()) { - CHECK(opensslecdsa_set_deterministic( - pctx, dctx->key->key_alg)); + result = isc_ossl_wrap_ecdsa_set_deterministic(pctx, + md); + if (result != ISC_R_SUCCESS && + result != ISC_R_NOTIMPLEMENTED) + { + CLEANUP(result); + } } -#endif /* OPENSSL_VERSION_NUMBER >= 0x30200000L */ } else { if (EVP_DigestVerifyInit(evp_md_ctx, NULL, type, NULL, @@ -723,6 +141,7 @@ opensslecdsa_createctx(dst_key_t *key, dst_context_t *dctx) { } dctx->ctxdata.evp_md_ctx = evp_md_ctx; + result = ISC_R_SUCCESS; cleanup: return result; @@ -921,7 +340,31 @@ opensslecdsa_generate(dst_key_t *key, int unused, void (*callback)(int)) { UNUSED(unused); UNUSED(callback); - RETERR(opensslecdsa_generate_pkey(key->key_alg, key->label, &pkey)); + if (key->label != NULL) { + switch (key->key_alg) { + case DST_ALG_ECDSA256: + RETERR(isc_ossl_wrap_generate_pkcs11_p256_key( + key->label, &pkey)); + break; + case DST_ALG_ECDSA384: + RETERR(isc_ossl_wrap_generate_pkcs11_p384_key( + key->label, &pkey)); + break; + default: + UNREACHABLE(); + } + } else { + switch (key->key_alg) { + case DST_ALG_ECDSA256: + RETERR(isc_ossl_wrap_generate_p256_key(&pkey)); + break; + case DST_ALG_ECDSA384: + RETERR(isc_ossl_wrap_generate_p384_key(&pkey)); + break; + default: + UNREACHABLE(); + } + } key->key_size = EVP_PKEY_bits(pkey); key->keydata.pkeypair.priv = pkey; @@ -933,6 +376,7 @@ static isc_result_t opensslecdsa_todns(const dst_key_t *key, isc_buffer_t *data) { isc_result_t result; isc_region_t r; + EVP_PKEY *pkey; size_t keysize; REQUIRE(opensslecdsa_valid_key_alg(key->key_alg)); @@ -943,8 +387,23 @@ opensslecdsa_todns(const dst_key_t *key, isc_buffer_t *data) { if (r.length < keysize) { CLEANUP(ISC_R_NOSPACE); } - if (!opensslecdsa_extract_public_key(key, r.base, keysize)) { - CLEANUP(dst__openssl_toresult(DST_R_OPENSSLFAILURE)); + + pkey = key->keydata.pkeypair.pub; + switch (key->key_alg) { + case DST_ALG_ECDSA256: + if (isc_ossl_wrap_p256_public_region(pkey, r) != ISC_R_SUCCESS) + { + CLEANUP(dst__openssl_toresult(DST_R_OPENSSLFAILURE)); + } + break; + case DST_ALG_ECDSA384: + if (isc_ossl_wrap_p384_public_region(pkey, r) != ISC_R_SUCCESS) + { + CLEANUP(dst__openssl_toresult(DST_R_OPENSSLFAILURE)); + } + break; + default: + UNREACHABLE(); } isc_buffer_add(data, keysize); @@ -972,8 +431,16 @@ opensslecdsa_fromdns(dst_key_t *key, isc_buffer_t *data) { CLEANUP(DST_R_INVALIDPUBLICKEY); } - CHECK(opensslecdsa_create_pkey(key->key_alg, false, r.base, len, - &pkey)); + switch (key->key_alg) { + case DST_ALG_ECDSA256: + CHECK(isc_ossl_wrap_load_p256_public_from_region(r, &pkey)); + break; + case DST_ALG_ECDSA384: + CHECK(isc_ossl_wrap_load_p384_public_from_region(r, &pkey)); + break; + default: + UNREACHABLE(); + } isc_buffer_forward(data, len); key->key_size = EVP_PKEY_bits(pkey); @@ -991,6 +458,7 @@ opensslecdsa_tofile(const dst_key_t *key, const char *directory) { unsigned char buf[MAX_PRIVKEY_SIZE]; size_t keylen = 0; unsigned short i; + EVP_PKEY *pkey; if (key->keydata.pkeypair.pub == NULL) { CLEANUP(DST_R_NULLKEY); @@ -1008,8 +476,23 @@ opensslecdsa_tofile(const dst_key_t *key, const char *directory) { keylen = opensslecdsa_key_alg_to_publickey_size(key->key_alg) / 2; INSIST(keylen <= sizeof(buf)); + pkey = key->keydata.pkeypair.priv; + i = 0; - if (opensslecdsa_extract_private_key(key, buf, keylen)) { + switch (key->key_alg) { + case DST_ALG_ECDSA256: + result = isc_ossl_wrap_p256_secret_region( + pkey, (isc_region_t){ buf, keylen }); + break; + case DST_ALG_ECDSA384: + result = isc_ossl_wrap_p384_secret_region( + pkey, (isc_region_t){ buf, keylen }); + break; + default: + UNREACHABLE(); + } + + if (result == ISC_R_SUCCESS) { priv.elements[i].tag = TAG_ECDSA_PRIVATEKEY; priv.elements[i].length = keylen; priv.elements[i].data = buf; @@ -1039,6 +522,7 @@ static isc_result_t opensslecdsa_parse(dst_key_t *key, isc_lex_t *lexer, dst_key_t *pub) { dst_private_t priv; isc_result_t result; + isc_region_t r; EVP_PKEY *pkey = NULL; const char *label = NULL; int i, privkey_index = -1; @@ -1091,9 +575,21 @@ opensslecdsa_parse(dst_key_t *key, isc_lex_t *lexer, dst_key_t *pub) { CLEANUP(dst__openssl_toresult(DST_R_INVALIDPRIVATEKEY)); } - CHECK(opensslecdsa_create_pkey( - key->key_alg, true, priv.elements[privkey_index].data, - priv.elements[privkey_index].length, &pkey)); + r = (isc_region_t){ + .base = priv.elements[privkey_index].data, + .length = priv.elements[privkey_index].length, + }; + + switch (key->key_alg) { + case DST_ALG_ECDSA256: + CHECK(isc_ossl_wrap_load_p256_secret_from_region(r, &pkey)); + break; + case DST_ALG_ECDSA384: + CHECK(isc_ossl_wrap_load_p384_secret_from_region(r, &pkey)); + break; + default: + UNREACHABLE(); + } /* Check that the public component matches if given */ if (pub != NULL && EVP_PKEY_eq(pkey, pub->keydata.pkeypair.pub) != 1) { @@ -1127,8 +623,18 @@ opensslecdsa_fromlabel(dst_key_t *key, const char *label, const char *pin) { CHECK(dst__openssl_fromlabel(EVP_PKEY_EC, label, pin, &pubpkey, &privpkey)); - CHECK(opensslecdsa_validate_pkey_group(key->key_alg, privpkey)); - CHECK(opensslecdsa_validate_pkey_group(key->key_alg, pubpkey)); + switch (key->key_alg) { + case DST_ALG_ECDSA256: + CHECK(isc_ossl_wrap_validate_p256_pkey(privpkey)); + CHECK(isc_ossl_wrap_validate_p256_pkey(pubpkey)); + break; + case DST_ALG_ECDSA384: + CHECK(isc_ossl_wrap_validate_p384_pkey(privpkey)); + CHECK(isc_ossl_wrap_validate_p384_pkey(pubpkey)); + break; + default: + UNREACHABLE(); + } key->label = isc_mem_strdup(key->mctx, label); key->key_size = EVP_PKEY_bits(privpkey); diff --git a/lib/isc/include/isc/ossl_wrap.h b/lib/isc/include/isc/ossl_wrap.h index cef8317938..96f282a13b 100644 --- a/lib/isc/include/isc/ossl_wrap.h +++ b/lib/isc/include/isc/ossl_wrap.h @@ -31,6 +31,179 @@ typedef struct isc_ossl_wrap_rsa_components { BIGNUM *e, *n, *d, *p, *q, *dmp1, *dmq1, *iqmp; } isc_ossl_wrap_rsa_components_t; +isc_result_t +isc_ossl_wrap_generate_p256_key(EVP_PKEY **pkeyp); +/*% + * Generates an uncompressed, named P-256 secret key. + * + * Requires: + * \li pkeyp != NULL + * \li *pkeyp == NULL + */ + +isc_result_t +isc_ossl_wrap_generate_pkcs11_p256_key(char *uri, EVP_PKEY **pkeyp); +/*% + * Generates a P-256 secret key using the PKCS#11 label specified at `uri`. + * + * Requires: + * \li pkeyp != NULL + * \li *pkeyp == NULL + * \li `uri != NULL` and is a NUL-terminated string + */ + +isc_result_t +isc_ossl_wrap_validate_p256_pkey(EVP_PKEY *pkey); +/*% + * Validatest that a EVP_PKEY is a P-256 EC key. + * + * Requires: + * \li `pkey != NULL` + * \li pkey is a valid EVP_PKEY + */ + +isc_result_t +isc_ossl_wrap_load_p256_public_from_region(isc_region_t region, + EVP_PKEY **pkeyp); +/*% + * Create a verifying `EVP_PKEY` using the P-256 public key pointed by + * `region`. + * + * Requires: + * \li `pkeyp != NULL` + * \li `*pkeyp == NULL` + * \li `region.base != NULL` + * \li `region.length == 64` + */ + +isc_result_t +isc_ossl_wrap_load_p256_secret_from_region(isc_region_t region, + EVP_PKEY **pkeyp); +/*% + * Create a signing `EVP_PKEY` using the P-256 secret key pointed by + * `region`. + * + * Requires: + * \li `pkeyp != NULL` + * \li `*pkeyp == NULL` + * \li `region.base != NULL` + * \li `region.length == 32` + */ + +isc_result_t +isc_ossl_wrap_p256_public_region(EVP_PKEY *pkey, isc_region_t pub); +/*% + * Export the P-256 public key to the region pointed by `pub` + * + * Requires: + * \li `pkey` is a non-NULL, valid, P-256 public key. + * \li `pub` has to a non-NULL pointer with enough space to fit the public key. + */ + +isc_result_t +isc_ossl_wrap_p256_secret_region(EVP_PKEY *pkey, isc_region_t sec); +/*% + * Export the P-256 curve secret key to the region pointed by `sec` + * + * Requires: + * \li `pkey` is a non-NULL, valid P-256 secret key. + * \li `sec` has to a non-NULL pointer with enough space to fit the secret key. + */ + +isc_result_t +isc_ossl_wrap_generate_p384_key(EVP_PKEY **pkeyp); +/*% + * Generates an uncompressed, named P-256 secret key. + * + * Requires: + * \li pkeyp != NULL + * \li *pkeyp == NULL + */ + +isc_result_t +isc_ossl_wrap_generate_pkcs11_p384_key(char *uri, EVP_PKEY **pkeyp); +/*% + * Generates a P-384 secret key using the PKCS#11 label specified at `uri`. + * + * Requires: + * \li pkeyp != NULL + * \li *pkeyp == NULL + * \li `uri != NULL` and is a NUL-terminated string + */ + +isc_result_t +isc_ossl_wrap_load_p384_public_from_region(isc_region_t region, + EVP_PKEY **pkeyp); +/*% + * Create a verifying `EVP_PKEY` using the P-384 public key pointed by + * `region`. + * + * Requires: + * \li `pkeyp != NULL` + * \li `*pkeyp == NULL` + * \li `region.base != NULL` + * \li `region.length == 64` + */ + +isc_result_t +isc_ossl_wrap_load_p384_secret_from_region(isc_region_t region, + EVP_PKEY **pkeyp); +/*% + * Create a signing `EVP_PKEY` using the P-384 secret key pointed by + * `region`. + * + * Requires: + * \li `pkeyp != NULL` + * \li `*pkeyp == NULL` + * \li `region.base != NULL` + * \li `region.length == 32` + */ + +isc_result_t +isc_ossl_wrap_validate_p384_pkey(EVP_PKEY *pkey); + +isc_result_t +isc_ossl_wrap_p384_public_region(EVP_PKEY *pkey, isc_region_t pub); +/*% + * Export the P-384 public key to the region pointed by `pub` + * + * Requires: + * \li `pkey` is a non-NULL, valid, P-384 public key. + * \li `pub` has to a non-NULL pointer with enough space to fit the public key. + */ + +isc_result_t +isc_ossl_wrap_p384_secret_region(EVP_PKEY *pkey, isc_region_t sec); +/*% + * Export the P-384 curve secret key to the region pointed by `sec` + * + * Requires: + * \li `pkey` is a non-NULL, valid P-384 secret key. + * \li `sec` has to a non-NULL pointer with enough space to fit the secret key. + */ + +isc_result_t +isc_ossl_wrap_ecdsa_set_deterministic(EVP_PKEY_CTX *pctx, const char *hash); +/* + * Use deterministic ECDSA to generate signatures. + * + * Returns: + * \li #ISC_R_SUCCESS -- signature set to use RFC6979 + * \li #ISC_R_IGNORE -- FIPS mode is active + * \li #ISC_R_NOTIMPLEMENTED -- libcrypto doesn't support + */ + +isc_result_t +isc_ossl_wrap_ecdsa_set_deterministic(EVP_PKEY_CTX *pctx, const char *hash); +/* + * Use deterministic ECDSA to generate signatures. + * + * Returns: + * \li #ISC_R_SUCCESS -- signature set to use RFC6979 + * \li #ISC_R_IGNORE -- FIPS mode is active + * \li #ISC_R_NOTIMPLEMENTED -- libcrypto doesn't support RFC6979 + */ + isc_result_t isc_ossl_wrap_generate_rsa_key(void (*callback)(int), size_t bit_size, EVP_PKEY **pkeyp); diff --git a/lib/isc/ossl_wrap/ossl1_1.c b/lib/isc/ossl_wrap/ossl1_1.c index 32fac0d1d6..e5d63e2706 100644 --- a/lib/isc/ossl_wrap/ossl1_1.c +++ b/lib/isc/ossl_wrap/ossl1_1.c @@ -12,17 +12,88 @@ */ #include +#include #include #include #include +#include #include +#define MAX_PUBLIC_KEY_SIZE 96 +#define MAX_SECRET_KEY_SIZE 48 + #define OSSL_WRAP_ERROR(fn) \ isc__ossl_wrap_logged_toresult( \ ISC_LOGCATEGORY_GENERAL, ISC_LOGMODULE_CRYPTO, fn, \ ISC_R_CRYPTOFAILURE, __FILE__, __LINE__) +#define P_CURVE_IMPL(curve, nid) \ + isc_result_t isc_ossl_wrap_generate_##curve##_key(EVP_PKEY **pkeyp) { \ + REQUIRE(pkeyp != NULL && *pkeyp == NULL); \ + return generate_ec_key(pkeyp, nid); \ + } \ + isc_result_t isc_ossl_wrap_generate_pkcs11_##curve##_key( \ + char *uri, EVP_PKEY **pkeyp) { \ + UNUSED(uri); \ + return isc_ossl_wrap_generate_##curve##_key(pkeyp); \ + } \ + isc_result_t isc_ossl_wrap_validate_##curve##_pkey(EVP_PKEY *pkey) { \ + REQUIRE(pkey != NULL); \ + return validate_ec_pkey(pkey, nid); \ + } \ + isc_result_t isc_ossl_wrap_load_##curve##_public_from_region( \ + isc_region_t region, EVP_PKEY **pkeyp) { \ + REQUIRE(pkeyp != NULL && *pkeyp == NULL); \ + REQUIRE(region.base != NULL && \ + region.length >= curve##_public_key_size); \ + region.length = curve##_public_key_size; \ + return load_ec_public_from_region(region, pkeyp, nid); \ + } \ + isc_result_t isc_ossl_wrap_load_##curve##_secret_from_region( \ + isc_region_t region, EVP_PKEY **pkeyp) { \ + REQUIRE(pkeyp != NULL && *pkeyp == NULL); \ + REQUIRE(region.base != NULL && \ + region.length >= curve##_secret_key_size); \ + region.length = curve##_secret_key_size; \ + return load_ec_secret_from_region(region, pkeyp, nid); \ + } \ + isc_result_t isc_ossl_wrap_##curve##_public_region(EVP_PKEY *pkey, \ + isc_region_t pub) { \ + REQUIRE(pkey != NULL); \ + REQUIRE(pub.base != NULL && \ + pub.length >= curve##_public_key_size); \ + pub.length = curve##_public_key_size; \ + return ec_public_region(pkey, pub); \ + } \ + isc_result_t isc_ossl_wrap_##curve##_secret_region(EVP_PKEY *pkey, \ + isc_region_t sec) { \ + REQUIRE(pkey != NULL); \ + REQUIRE(sec.base != NULL && \ + sec.length >= curve##_secret_key_size); \ + sec.length = curve##_secret_key_size; \ + return ec_secret_region(pkey, sec); \ + } + +constexpr size_t p256_public_key_size = 64; +constexpr size_t p384_public_key_size = 96; + +constexpr size_t p256_secret_key_size = 32; +constexpr size_t p384_secret_key_size = 48; + +static int +BN_bn2bin_fixed(const BIGNUM *bn, unsigned char *buf, int size) { + int bytes = size - BN_num_bytes(bn); + + INSIST(bytes >= 0); + + while (bytes-- > 0) { + *buf++ = 0; + } + BN_bn2bin(bn, buf); + return size; +} + static int rsa_keygen_progress_cb(int p, int n, BN_GENCB *cb) { void (*fptr)(int); @@ -36,6 +107,251 @@ rsa_keygen_progress_cb(int p, int n, BN_GENCB *cb) { return 1; } +static isc_result_t +generate_ec_key(EVP_PKEY **pkeyp, const int nid) { + isc_result_t result; + EC_KEY *eckey = NULL; + EVP_PKEY *pkey = NULL; + + eckey = EC_KEY_new_by_curve_name(nid); + if (eckey == NULL) { + CLEANUP(OSSL_WRAP_ERROR("EC_KEY_new_by_curve_name")); + } + + if (EC_KEY_generate_key(eckey) != 1) { + CLEANUP(OSSL_WRAP_ERROR("EC_KEY_generate_key")); + } + + pkey = EVP_PKEY_new(); + if (pkey == NULL) { + CLEANUP(OSSL_WRAP_ERROR("EVP_PKEY_new")); + } + + if (EVP_PKEY_set1_EC_KEY(pkey, eckey) != 1) { + CLEANUP(OSSL_WRAP_ERROR("EVP_PKEY_set1_EC_KEY")); + } + + *pkeyp = pkey; + pkey = NULL; + result = ISC_R_SUCCESS; + +cleanup: + EC_KEY_free(eckey); + EVP_PKEY_free(pkey); + return result; +} + +static isc_result_t +validate_ec_pkey(EVP_PKEY *pkey, const int nid) { + const EC_GROUP *group; + const EC_KEY *eckey; + isc_result_t result; + + eckey = EVP_PKEY_get0_EC_KEY(pkey); + if (eckey == NULL) { + CLEANUP(OSSL_WRAP_ERROR("EVP_PKEY_get0_EC_KEY")); + } + + group = EC_KEY_get0_group(eckey); + if (group == NULL) { + CLEANUP(OSSL_WRAP_ERROR("EC_KEY_get0_group")); + } + + if (EC_GROUP_get_curve_name(group) != nid) { + return DST_R_INVALIDPRIVATEKEY; + } + + result = ISC_R_SUCCESS; +cleanup: + return result; +} + +static isc_result_t +load_ec_public_from_region(isc_region_t region, EVP_PKEY **pkeyp, + const int nid) { + isc_result_t result; + const unsigned char *buf_launder; + uint8_t buffer[MAX_PUBLIC_KEY_SIZE + 1]; + EC_KEY *eckey = NULL; + EVP_PKEY *pkey = NULL; + + eckey = EC_KEY_new_by_curve_name(nid); + if (eckey == NULL) { + CLEANUP(OSSL_WRAP_ERROR("EC_KEY_new_curve_by_name")); + } + + buffer[0] = POINT_CONVERSION_UNCOMPRESSED; + memmove(buffer + 1, region.base, region.length); + + buf_launder = buffer; + if (o2i_ECPublicKey(&eckey, &buf_launder, region.length + 1) == NULL) { + CLEANUP(OSSL_WRAP_ERROR("o2i_ECPublicKey")); + } + + if (EC_KEY_check_key(eckey) != 1) { + CLEANUP(OSSL_WRAP_ERROR("EC_KEY_check_key")); + } + + pkey = EVP_PKEY_new(); + if (pkey == NULL) { + CLEANUP(OSSL_WRAP_ERROR("EVP_PKEY_new")); + } + + if (EVP_PKEY_set1_EC_KEY(pkey, eckey) != 1) { + CLEANUP(OSSL_WRAP_ERROR("EVP_PKEY_set1_EC_KEY")); + } + + *pkeyp = pkey; + pkey = NULL; + result = ISC_R_SUCCESS; + +cleanup: + EVP_PKEY_free(pkey); + EC_KEY_free(eckey); + return result; +} + +static isc_result_t +load_ec_secret_from_region(isc_region_t region, EVP_PKEY **pkeyp, + const int nid) { + isc_result_t result; + const EC_GROUP *group = NULL; + EC_POINT *public = NULL; + EVP_PKEY *pkey = NULL; + BIGNUM *private = NULL; + EC_KEY *eckey = NULL; + + eckey = EC_KEY_new_by_curve_name(nid); + if (eckey == NULL) { + CLEANUP(OSSL_WRAP_ERROR("EC_KEY_new_curve_by_name")); + } + + group = EC_KEY_get0_group(eckey); + if (group == NULL) { + CLEANUP(OSSL_WRAP_ERROR("EC_KEY_get0_group")); + } + + private = BN_bin2bn(region.base, region.length, NULL); + if (private == NULL) { + CLEANUP(OSSL_WRAP_ERROR("BN_bin2bn")); + } + + if (EC_KEY_set_private_key(eckey, private) != 1) { + CLEANUP(OSSL_WRAP_ERROR("EC_KEY_set_private_key")); + } + + /* + * OpenSSL requires us to set the public key portion, but since our + * private key file format does not contain it directly, we generate it + * as needed. + */ + public = EC_POINT_new(group); + if (public == NULL) { + CLEANUP(OSSL_WRAP_ERROR("EC_POINT_new")); + } + + if (EC_POINT_mul(group, public, private, NULL, NULL, NULL) != 1) { + CLEANUP(OSSL_WRAP_ERROR("EC_POINT_mul")); + } + + if (EC_KEY_set_public_key(eckey, public) != 1) { + CLEANUP(OSSL_WRAP_ERROR("EC_KEY_set_public_key")); + } + + pkey = EVP_PKEY_new(); + if (pkey == NULL) { + CLEANUP(OSSL_WRAP_ERROR("EVP_PKEY_new")); + } + + if (EVP_PKEY_set1_EC_KEY(pkey, eckey) != 1) { + CLEANUP(OSSL_WRAP_ERROR("EVP_PKEY_set1_EC_KEY")); + } + + *pkeyp = pkey; + pkey = NULL; + result = ISC_R_SUCCESS; + +cleanup: + EVP_PKEY_free(pkey); + EC_POINT_free(public); + BN_clear_free(private); + EC_KEY_free(eckey); + return result; +} + +static isc_result_t +ec_public_region(EVP_PKEY *pkey, isc_region_t pub) { + isc_result_t result; + uint8_t buffer[MAX_PUBLIC_KEY_SIZE + 1]; + const EC_POINT *public; + const EC_GROUP *group; + const EC_KEY *eckey; + size_t len; + + eckey = EVP_PKEY_get0_EC_KEY(pkey); + if (eckey == NULL) { + CLEANUP(OSSL_WRAP_ERROR("EVP_PKEY_get0_EC_KEY")); + } + + group = EC_KEY_get0_group(eckey); + if (group == NULL) { + CLEANUP(OSSL_WRAP_ERROR("EC_KEY_get0_group")); + } + + public = EC_KEY_get0_public_key(eckey); + if (public == NULL) { + CLEANUP(OSSL_WRAP_ERROR("EC_KEY_get0_public_key")); + } + + len = EC_POINT_point2oct(group, public, POINT_CONVERSION_UNCOMPRESSED, + buffer, sizeof(buffer), NULL); + if (len != pub.length + 1) { + CLEANUP(OSSL_WRAP_ERROR("EC_POINT_point2oct")); + } + + memmove(pub.base, buffer + 1, pub.length); + + result = ISC_R_SUCCESS; + +cleanup: + return result; +} + +static isc_result_t +ec_secret_region(EVP_PKEY *pkey, isc_region_t pub) { + const BIGNUM *private; + isc_result_t result; + const EC_KEY *eckey; + + eckey = EVP_PKEY_get0_EC_KEY(pkey); + if (eckey == NULL) { + CLEANUP(OSSL_WRAP_ERROR("EVP_PKEY_get0_EC_KEY")); + } + + private = EC_KEY_get0_private_key(eckey); + if (private == NULL) { + CLEANUP(OSSL_WRAP_ERROR("EC_KEY_get0_private_key")); + } + + BN_bn2bin_fixed(private, pub.base, pub.length); + + result = ISC_R_SUCCESS; + +cleanup: + return result; +} + +P_CURVE_IMPL(p256, NID_X9_62_prime256v1); +P_CURVE_IMPL(p384, NID_secp384r1); + +isc_result_t +isc_ossl_wrap_ecdsa_set_deterministic(EVP_PKEY_CTX *pctx, const char *hash) { + UNUSED(pctx); + UNUSED(hash); + + return ISC_R_NOTIMPLEMENTED; +} + isc_result_t isc_ossl_wrap_generate_rsa_key(void (*callback)(int), size_t bit_size, EVP_PKEY **pkeyp) { diff --git a/lib/isc/ossl_wrap/ossl3.c b/lib/isc/ossl_wrap/ossl3.c index d18beb3e19..0bd116f381 100644 --- a/lib/isc/ossl_wrap/ossl3.c +++ b/lib/isc/ossl_wrap/ossl3.c @@ -15,19 +15,97 @@ #include #include +#include #include #include #include #include #include +#include #include +#define MAX_PUBLIC_KEY_SIZE 96 +#define MAX_SECRET_KEY_SIZE 48 + #define OSSL_WRAP_ERROR(fn) \ isc__ossl_wrap_logged_toresult( \ ISC_LOGCATEGORY_GENERAL, ISC_LOGMODULE_CRYPTO, fn, \ ISC_R_CRYPTOFAILURE, __FILE__, __LINE__) +#define P_CURVE_IMPL(curve, nid) \ + isc_result_t isc_ossl_wrap_generate_##curve##_key(EVP_PKEY **pkeyp) { \ + REQUIRE(pkeyp != NULL && *pkeyp == NULL); \ + return generate_ec_key(pkeyp, nid); \ + } \ + isc_result_t isc_ossl_wrap_generate_pkcs11_##curve##_key( \ + char *uri, EVP_PKEY **pkeyp) { \ + REQUIRE(pkeyp != NULL && *pkeyp == NULL); \ + REQUIRE(uri != NULL); \ + return generate_pkcs11_ec_key(uri, pkeyp, nid); \ + } \ + isc_result_t isc_ossl_wrap_validate_##curve##_pkey(EVP_PKEY *pkey) { \ + REQUIRE(pkey != NULL); \ + return validate_ec_pkey(pkey, curve##_group_name); \ + } \ + isc_result_t isc_ossl_wrap_load_##curve##_public_from_region( \ + isc_region_t region, EVP_PKEY **pkeyp) { \ + REQUIRE(region.base != NULL && \ + region.length <= MAX_PUBLIC_KEY_SIZE); \ + REQUIRE(pkeyp != NULL && *pkeyp == NULL); \ + region.length = curve##_public_key_size; \ + return load_ec_public_from_region(region, pkeyp, \ + curve##_group_name); \ + } \ + isc_result_t isc_ossl_wrap_load_##curve##_secret_from_region( \ + isc_region_t region, EVP_PKEY **pkeyp) { \ + REQUIRE(pkeyp != NULL && *pkeyp == NULL); \ + REQUIRE(region.base != NULL && \ + region.length >= curve##_secret_key_size); \ + region.length = curve##_secret_key_size; \ + return load_ec_secret_from_region(region, pkeyp, \ + curve##_group_name, nid); \ + } \ + isc_result_t isc_ossl_wrap_##curve##_public_region(EVP_PKEY *pkey, \ + isc_region_t pub) { \ + REQUIRE(pkey != NULL); \ + REQUIRE(pub.base != NULL && \ + pub.length >= curve##_public_key_size); \ + pub.length = curve##_public_key_size; \ + return ec_public_region(pkey, pub); \ + } \ + isc_result_t isc_ossl_wrap_##curve##_secret_region(EVP_PKEY *pkey, \ + isc_region_t sec) { \ + REQUIRE(pkey != NULL); \ + REQUIRE(sec.base != NULL && \ + sec.length >= curve##_secret_key_size); \ + sec.length = curve##_secret_key_size; \ + return ec_secret_region(pkey, sec); \ + } + +static char pkcs11_key_usage[] = "digitalSignature"; + +constexpr char *p256_group_name = "prime256v1"; +constexpr char *p384_group_name = "secp384r1"; + +constexpr size_t p256_public_key_size = 64; +constexpr size_t p384_public_key_size = 96; + +constexpr size_t p256_secret_key_size = 32; +constexpr size_t p384_secret_key_size = 48; + +static void +BN_bn2bin_fixed(const BIGNUM *bn, unsigned char *buf, int size) { + int bytes = size - BN_num_bytes(bn); + + INSIST(bytes >= 0); + + while (bytes-- > 0) { + *buf++ = 0; + } + BN_bn2bin(bn, buf); +} + static int rsa_keygen_progress_cb(EVP_PKEY_CTX *ctx) { void (*fptr)(int); @@ -40,6 +118,346 @@ rsa_keygen_progress_cb(EVP_PKEY_CTX *ctx) { return 1; } +static isc_result_t +generate_ec_key(EVP_PKEY **pkeyp, const int nid) { + isc_result_t result; + EVP_PKEY_CTX *pctx = NULL; + EVP_PKEY *params_pkey = NULL; + + /* Generate the key's parameters. */ + pctx = EVP_PKEY_CTX_new_from_name(NULL, "EC", NULL); + if (pctx == NULL) { + CLEANUP(OSSL_WRAP_ERROR("EVP_PKEY_CTX_new_from_name")); + } + + if (EVP_PKEY_paramgen_init(pctx) != 1) { + CLEANUP(OSSL_WRAP_ERROR("EVP_PKEY_paramgen_init")); + } + + if (EVP_PKEY_CTX_set_ec_paramgen_curve_nid(pctx, nid) != 1) { + CLEANUP(OSSL_WRAP_ERROR("EVP_PKEY_CTX_set_ec_paramgen_curve_" + "nid")); + } + + if (EVP_PKEY_paramgen(pctx, ¶ms_pkey) != 1) { + CLEANUP(OSSL_WRAP_ERROR("EVP_PKEY_paramgen")); + } + + if (params_pkey == NULL) { + CLEANUP(OSSL_WRAP_ERROR("EVP_PKEY_paramgen")); + } + + EVP_PKEY_CTX_free(pctx); + + /* Generate the key. */ + pctx = EVP_PKEY_CTX_new(params_pkey, NULL); + if (pctx == NULL) { + CLEANUP(OSSL_WRAP_ERROR("EVP_PKEY_CTX_new")); + } + + if (EVP_PKEY_keygen_init(pctx) != 1) { + CLEANUP(OSSL_WRAP_ERROR("EVP_PKEY_keygen_init")); + } + + if (EVP_PKEY_keygen(pctx, pkeyp) != 1) { + CLEANUP(OSSL_WRAP_ERROR("EVP_PKEY_keygen")); + } + + result = ISC_R_SUCCESS; + +cleanup: + EVP_PKEY_CTX_free(pctx); + EVP_PKEY_free(params_pkey); + return result; +} + +static isc_result_t +generate_pkcs11_ec_key(char *uri, EVP_PKEY **pkeyp, int nid) { + isc_result_t result; + EVP_PKEY_CTX *pctx; + OSSL_PARAM params[3]; + + params[0] = OSSL_PARAM_construct_utf8_string("pkcs11_uri", uri, 0); + params[1] = OSSL_PARAM_construct_utf8_string( + "pkcs11_key_usage", pkcs11_key_usage, + sizeof(pkcs11_key_usage) - 1); + params[2] = OSSL_PARAM_construct_end(); + + pctx = EVP_PKEY_CTX_new_from_name(NULL, "EC", "provider=pkcs11"); + if (pctx == NULL) { + CLEANUP(OSSL_WRAP_ERROR("EVP_PKEY_CTX_new_from_name")); + } + + if (EVP_PKEY_keygen_init(pctx) != 1) { + CLEANUP(OSSL_WRAP_ERROR("EVP_PKEY_keygen_init")); + } + + if (EVP_PKEY_CTX_set_params(pctx, params) != 1) { + CLEANUP(OSSL_WRAP_ERROR("EVP_PKEY_CTX_set_params")); + } + + /* + * Setting the P-384 curve doesn't work correctly when using: + * OSSL_PARAM_construct_utf8_string("ec_paramgen_curve", "P-384", 0); + * + * Instead use the OpenSSL function to set the curve nid param. + */ + if (EVP_PKEY_CTX_set_ec_paramgen_curve_nid(pctx, nid) != 1) { + CLEANUP(OSSL_WRAP_ERROR("EVP_PKEY_CTX_set_ec_paramgen_curve_" + "nid")); + } + + if (EVP_PKEY_generate(pctx, pkeyp) != 1) { + CLEANUP(OSSL_WRAP_ERROR("EVP_PKEY_generate")); + } + + result = ISC_R_SUCCESS; + +cleanup: + EVP_PKEY_CTX_free(pctx); + return result; +} + +static isc_result_t +validate_ec_pkey(EVP_PKEY *pkey, const char *expected) { + isc_result_t result; + char actual[64]; + + if (EVP_PKEY_get_group_name(pkey, actual, sizeof(actual), NULL) != 1) { + CLEANUP(OSSL_WRAP_ERROR("EVP_PKEY_get_group_name")); + } + + if (strcmp(expected, actual) != 0) { + return ISC_R_FAILURE; + } + + result = ISC_R_SUCCESS; + +cleanup: + return result; +} + +static isc_result_t +load_ec_public_from_region(isc_region_t region, EVP_PKEY **pkeyp, + const char *group_name) { + isc_result_t result; + OSSL_PARAM_BLD *bld = NULL; + OSSL_PARAM *params = NULL; + EVP_PKEY_CTX *pctx = NULL; + uint8_t buffer[MAX_PUBLIC_KEY_SIZE + 1]; + + buffer[0] = POINT_CONVERSION_UNCOMPRESSED; + memmove(buffer + 1, region.base, region.length); + + bld = OSSL_PARAM_BLD_new(); + if (bld == NULL) { + CLEANUP(OSSL_WRAP_ERROR("OSSL_PARAM_BLD_new")); + } + + if (OSSL_PARAM_BLD_push_utf8_string(bld, OSSL_PKEY_PARAM_GROUP_NAME, + group_name, 0) != 1) + { + CLEANUP(OSSL_WRAP_ERROR("OSSL_PARAM_BLD_push_utf8_string")); + } + + if (OSSL_PARAM_BLD_push_octet_string(bld, OSSL_PKEY_PARAM_PUB_KEY, + buffer, region.length + 1) != 1) + { + CLEANUP(OSSL_WRAP_ERROR("OSSL_PARAM_BLD_push_octet_string")); + } + + params = OSSL_PARAM_BLD_to_param(bld); + if (params == NULL) { + CLEANUP(OSSL_WRAP_ERROR("OSSL_PARAM_BLD_to_param")); + } + + pctx = EVP_PKEY_CTX_new_from_name(NULL, "EC", NULL); + if (pctx == NULL) { + CLEANUP(OSSL_WRAP_ERROR("EVP_PKEY_CTX_new_from_name")); + } + + if (EVP_PKEY_fromdata_init(pctx) != 1) { + CLEANUP(OSSL_WRAP_ERROR("EVP_PKEY_fromdata_init")); + } + + if (EVP_PKEY_fromdata(pctx, pkeyp, EVP_PKEY_PUBLIC_KEY, params) != 1) { + CLEANUP(OSSL_WRAP_ERROR("EVP_PKEY_fromdata")); + } + + result = ISC_R_SUCCESS; + +cleanup: + OSSL_PARAM_free(params); + OSSL_PARAM_BLD_free(bld); + EVP_PKEY_CTX_free(pctx); + return result; +} + +static isc_result_t +load_ec_secret_from_region(isc_region_t region, EVP_PKEY **pkeyp, + const char *group_name, const int nid) { + uint8_t public[MAX_PUBLIC_KEY_SIZE + 1]; + EVP_PKEY_CTX *pctx = NULL; + OSSL_PARAM_BLD *bld = NULL; + OSSL_PARAM *params = NULL; + EC_POINT *pub_point = NULL; + EC_GROUP *group = NULL; + BIGNUM *private = NULL; + isc_result_t result; + size_t public_len; + + /* + * OpenSSL requires us to set the public key portion, but since our + * private key file format does not contain it directly, we generate it + * as needed. + */ + group = EC_GROUP_new_by_curve_name(nid); + if (group == NULL) { + CLEANUP(OSSL_WRAP_ERROR("EC_GROUP_new_by_curve_name")); + } + + private = BN_bin2bn(region.base, region.length, NULL); + if (private == NULL) { + CLEANUP(OSSL_WRAP_ERROR("BN_bin2bn")); + } + + pub_point = EC_POINT_new(group); + if (pub_point == NULL) { + CLEANUP(OSSL_WRAP_ERROR("EC_POINT_new")); + } + + if (EC_POINT_mul(group, pub_point, private, NULL, NULL, NULL) != 1) { + CLEANUP(OSSL_WRAP_ERROR("EC_POINT_mul")); + } + + public_len = EC_POINT_point2oct(group, pub_point, + POINT_CONVERSION_UNCOMPRESSED, public, + sizeof(public), NULL); + if (public_len == 0) { + CLEANUP(OSSL_WRAP_ERROR("EC_POINT_point2oct")); + } + + bld = OSSL_PARAM_BLD_new(); + if (bld == NULL) { + CLEANUP(OSSL_WRAP_ERROR("OSSL_PARAM_BLD_new")); + } + + if (OSSL_PARAM_BLD_push_utf8_string(bld, OSSL_PKEY_PARAM_GROUP_NAME, + group_name, 0) != 1) + { + CLEANUP(OSSL_WRAP_ERROR("OSSL_PARAM_BLD_push_utf8_string")); + } + + if (OSSL_PARAM_BLD_push_BN(bld, OSSL_PKEY_PARAM_PRIV_KEY, private) != 1) + { + CLEANUP(OSSL_WRAP_ERROR("OSSL_PARAM_BLD_push_BN")); + } + + if (OSSL_PARAM_BLD_push_octet_string(bld, OSSL_PKEY_PARAM_PUB_KEY, + public, public_len) != 1) + { + CLEANUP(OSSL_WRAP_ERROR("OSSL_PARAM_BLD_push_octet_string")); + } + + params = OSSL_PARAM_BLD_to_param(bld); + if (params == NULL) { + CLEANUP(OSSL_WRAP_ERROR("OSSL_PARAM_BLD_to_param")); + } + + pctx = EVP_PKEY_CTX_new_from_name(NULL, "EC", NULL); + if (pctx == NULL) { + CLEANUP(OSSL_WRAP_ERROR("EVP_PKEY_CTX_new_from_name")); + } + + if (EVP_PKEY_fromdata_init(pctx) != 1) { + CLEANUP(OSSL_WRAP_ERROR("EVP_PKEY_fromdata_init")); + } + + if (EVP_PKEY_fromdata(pctx, pkeyp, EVP_PKEY_KEYPAIR, params) != 1) { + CLEANUP(OSSL_WRAP_ERROR("EVP_PKEY_fromdata")); + } + + result = ISC_R_SUCCESS; + +cleanup: + OSSL_PARAM_free(params); + OSSL_PARAM_BLD_free(bld); + EC_POINT_free(pub_point); + BN_clear_free(private); + EC_GROUP_free(group); + EVP_PKEY_CTX_free(pctx); + return result; +} + +static isc_result_t +ec_public_region(EVP_PKEY *pkey, isc_region_t pub) { + isc_result_t result; + BIGNUM *x = NULL; + BIGNUM *y = NULL; + + if (EVP_PKEY_get_bn_param(pkey, OSSL_PKEY_PARAM_EC_PUB_X, &x) != 1) { + CLEANUP(OSSL_WRAP_ERROR("EVP_PKEY_get_bn_param")); + } + + if (EVP_PKEY_get_bn_param(pkey, OSSL_PKEY_PARAM_EC_PUB_Y, &y) != 1) { + CLEANUP(OSSL_WRAP_ERROR("EVP_PKEY_get_bn_param")); + } + + BN_bn2bin_fixed(x, &pub.base[0], pub.length / 2); + BN_bn2bin_fixed(y, &pub.base[pub.length / 2], pub.length / 2); + + result = ISC_R_SUCCESS; + +cleanup: + BN_clear_free(x); + BN_clear_free(y); + return result; +} + +static isc_result_t +ec_secret_region(EVP_PKEY *pkey, isc_region_t sec) { + isc_result_t result; + BIGNUM *priv = NULL; + + if (EVP_PKEY_get_bn_param(pkey, OSSL_PKEY_PARAM_PRIV_KEY, &priv) != 1) { + CLEANUP(OSSL_WRAP_ERROR("EVP_PKEY_get_bn_param")); + } + + BN_bn2bin_fixed(priv, sec.base, sec.length); + + result = ISC_R_SUCCESS; + +cleanup: + BN_clear_free(priv); + return result; +} + +P_CURVE_IMPL(p256, NID_X9_62_prime256v1); +P_CURVE_IMPL(p384, NID_secp384r1); + +isc_result_t +isc_ossl_wrap_ecdsa_set_deterministic(EVP_PKEY_CTX *pctx, const char *hash) { + unsigned int rfc6979 = 1; + isc_result_t result; + OSSL_PARAM params[3]; + + REQUIRE(pctx != NULL && hash != NULL); + + params[0] = OSSL_PARAM_construct_utf8_string("digest", UNCONST(hash), + 0); + params[1] = OSSL_PARAM_construct_uint("nonce-type", &rfc6979); + params[2] = OSSL_PARAM_construct_end(); + + if (EVP_PKEY_CTX_set_params(pctx, params) != 1) { + CLEANUP(OSSL_WRAP_ERROR("EVP_PKEY_CTX_set_params")); + } + + result = ISC_R_SUCCESS; + +cleanup: + return result; +} + isc_result_t isc_ossl_wrap_generate_rsa_key(void (*callback)(int), size_t bit_size, EVP_PKEY **pkeyp) { From fe617aa83079fd2a59e7c2da664b1ccb8ee350f6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ayd=C4=B1n=20Mercan?= Date: Mon, 8 Dec 2025 17:46:27 +0300 Subject: [PATCH 09/16] set parameters in batch for rsa keygen On top on improving readability, doing so allows us to use a uint32_t for setting the e value, getting rid of allocating an unneccessary BIGNUM. --- lib/isc/ossl_wrap/ossl3.c | 52 ++++++++++++++++++++++++--------------- 1 file changed, 32 insertions(+), 20 deletions(-) diff --git a/lib/isc/ossl_wrap/ossl3.c b/lib/isc/ossl_wrap/ossl3.c index 0bd116f381..f5b73e0513 100644 --- a/lib/isc/ossl_wrap/ossl3.c +++ b/lib/isc/ossl_wrap/ossl3.c @@ -463,15 +463,18 @@ isc_ossl_wrap_generate_rsa_key(void (*callback)(int), size_t bit_size, EVP_PKEY **pkeyp) { isc_result_t result; EVP_PKEY_CTX *ctx; - BIGNUM *e; + uint32_t e = 65537; REQUIRE(pkeyp != NULL && *pkeyp == NULL); - e = BN_new(); - - /* e = 65537 (0x10001, F4) */ - BN_set_bit(e, 0); - BN_set_bit(e, 16); + /* + * https://docs.openssl.org/master/man7/EVP_PKEY-RSA/#rsa-key-generation-parameters + */ + const OSSL_PARAM params[3] = { + OSSL_PARAM_uint(OSSL_PKEY_PARAM_RSA_E, &e), + OSSL_PARAM_size_t(OSSL_PKEY_PARAM_RSA_BITS, &bit_size), + OSSL_PARAM_END, + }; ctx = EVP_PKEY_CTX_new_from_name(NULL, "RSA", NULL); if (ctx == NULL) { @@ -482,12 +485,8 @@ isc_ossl_wrap_generate_rsa_key(void (*callback)(int), size_t bit_size, CLEANUP(OSSL_WRAP_ERROR("EVP_PKEY_keygen_init")); } - if (EVP_PKEY_CTX_set_rsa_keygen_bits(ctx, bit_size) != 1) { - CLEANUP(OSSL_WRAP_ERROR("EVP_PKEY_CTX_set_rsa_keygen_bits")); - } - - if (EVP_PKEY_CTX_set1_rsa_keygen_pubexp(ctx, e) != 1) { - CLEANUP(OSSL_WRAP_ERROR("EVP_PKEY_CTX_set1_rsa_keygen_pubexp")); + if (EVP_PKEY_CTX_set_params(ctx, params) != 1) { + CLEANUP(OSSL_WRAP_ERROR("EVP_PKEY_CTX_set_params")); } if (callback != NULL) { @@ -495,7 +494,15 @@ isc_ossl_wrap_generate_rsa_key(void (*callback)(int), size_t bit_size, EVP_PKEY_CTX_set_cb(ctx, rsa_keygen_progress_cb); } - if (EVP_PKEY_keygen(ctx, pkeyp) != 1) { + /* + * EVP_PKEY_keygen is an older function now equivalent to + * EVP_PKEY_generate with an additional check that EVP_PKEY_CTX has been + * initialized with EVP_PKEY_keygen_init. + * + * Since we can guarantee such condition we use EVP_PKEY_generate + * directly. + */ + if (EVP_PKEY_generate(ctx, pkeyp) != 1) { CLEANUP(OSSL_WRAP_ERROR("EVP_PKEY_keygen")); } @@ -503,7 +510,6 @@ isc_ossl_wrap_generate_rsa_key(void (*callback)(int), size_t bit_size, cleanup: EVP_PKEY_CTX_free(ctx); - BN_free(e); return result; } @@ -511,15 +517,21 @@ isc_result_t isc_ossl_wrap_generate_pkcs11_rsa_key(char *uri, size_t bit_size, EVP_PKEY **pkeyp) { EVP_PKEY_CTX *ctx = NULL; - OSSL_PARAM params[4]; isc_result_t result; int status; + size_t len; - params[0] = OSSL_PARAM_construct_utf8_string("pkcs11_uri", uri, 0); - params[1] = OSSL_PARAM_construct_utf8_string( - "pkcs11_key_usage", (char *)"digitalSignature", 0); - params[2] = OSSL_PARAM_construct_size_t("rsa_keygen_bits", &bit_size); - params[3] = OSSL_PARAM_construct_end(); + len = strlen(uri); + INSIST(len != 0); + + /* NUL-terminator should be left out */ + const OSSL_PARAM params[] = { + OSSL_PARAM_utf8_string("pkcs11_uri", uri, len), + OSSL_PARAM_utf8_string("pkcs11_key_usage", pkcs11_key_usage, + sizeof(pkcs11_key_usage) - 1), + OSSL_PARAM_size_t(OSSL_PKEY_PARAM_RSA_BITS, &bit_size), + OSSL_PARAM_END, + }; ctx = EVP_PKEY_CTX_new_from_name(NULL, "RSA", "provider=pkcs11"); if (ctx == NULL) { From 8c69fedc7c07da15758166529ce8720a25f02bb6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ayd=C4=B1n=20Mercan?= Date: Wed, 10 Dec 2025 17:27:32 +0300 Subject: [PATCH 10/16] switch away from ossl_param builders from ecdsa functions --- lib/isc/ossl_wrap/ossl3.c | 150 ++++++++++++++++++++------------------ 1 file changed, 78 insertions(+), 72 deletions(-) diff --git a/lib/isc/ossl_wrap/ossl3.c b/lib/isc/ossl_wrap/ossl3.c index f5b73e0513..836fc0d776 100644 --- a/lib/isc/ossl_wrap/ossl3.c +++ b/lib/isc/ossl_wrap/ossl3.c @@ -21,6 +21,7 @@ #include #include +#include #include #include #include @@ -36,7 +37,7 @@ #define P_CURVE_IMPL(curve, nid) \ isc_result_t isc_ossl_wrap_generate_##curve##_key(EVP_PKEY **pkeyp) { \ REQUIRE(pkeyp != NULL && *pkeyp == NULL); \ - return generate_ec_key(pkeyp, nid); \ + return generate_ec_key(pkeyp, curve##_params); \ } \ isc_result_t isc_ossl_wrap_generate_pkcs11_##curve##_key( \ char *uri, EVP_PKEY **pkeyp) { \ @@ -46,7 +47,7 @@ } \ isc_result_t isc_ossl_wrap_validate_##curve##_pkey(EVP_PKEY *pkey) { \ REQUIRE(pkey != NULL); \ - return validate_ec_pkey(pkey, curve##_group_name); \ + return validate_ec_pkey(pkey, curve##_params); \ } \ isc_result_t isc_ossl_wrap_load_##curve##_public_from_region( \ isc_region_t region, EVP_PKEY **pkeyp) { \ @@ -55,7 +56,7 @@ REQUIRE(pkeyp != NULL && *pkeyp == NULL); \ region.length = curve##_public_key_size; \ return load_ec_public_from_region(region, pkeyp, \ - curve##_group_name); \ + curve##_params); \ } \ isc_result_t isc_ossl_wrap_load_##curve##_secret_from_region( \ isc_region_t region, EVP_PKEY **pkeyp) { \ @@ -64,7 +65,7 @@ region.length >= curve##_secret_key_size); \ region.length = curve##_secret_key_size; \ return load_ec_secret_from_region(region, pkeyp, \ - curve##_group_name, nid); \ + curve##_params); \ } \ isc_result_t isc_ossl_wrap_##curve##_public_region(EVP_PKEY *pkey, \ isc_region_t pub) { \ @@ -85,15 +86,38 @@ static char pkcs11_key_usage[] = "digitalSignature"; -constexpr char *p256_group_name = "prime256v1"; -constexpr char *p384_group_name = "secp384r1"; - constexpr size_t p256_public_key_size = 64; constexpr size_t p384_public_key_size = 96; constexpr size_t p256_secret_key_size = 32; constexpr size_t p384_secret_key_size = 48; +/* + * "group" MUST be the first parameter, we rely on it to get the group name. + */ + +/* clang-format off */ +static const OSSL_PARAM p256_params[] = { + OSSL_PARAM_utf8_string(OSSL_PKEY_PARAM_GROUP_NAME, + UNCONST("prime256v1"), sizeof("prime256v1") - 1), + OSSL_PARAM_utf8_string(OSSL_PKEY_PARAM_EC_ENCODING, + UNCONST("named_curve"), sizeof("named_curve") - 1), + OSSL_PARAM_utf8_string(OSSL_PKEY_PARAM_EC_POINT_CONVERSION_FORMAT, + UNCONST("uncompressed"), sizeof("uncompressed") - 1), + OSSL_PARAM_END, +}; + +static const OSSL_PARAM p384_params[] = { + OSSL_PARAM_utf8_string(OSSL_PKEY_PARAM_GROUP_NAME, + UNCONST("secp384r1"), sizeof("secp384r1") - 1), + OSSL_PARAM_utf8_string(OSSL_PKEY_PARAM_EC_ENCODING, + UNCONST("named_curve"), sizeof("named_curve") - 1), + OSSL_PARAM_utf8_string(OSSL_PKEY_PARAM_EC_POINT_CONVERSION_FORMAT, + UNCONST("uncompressed"), sizeof("uncompressed") - 1), + OSSL_PARAM_END, +}; +/* clang-format on */ + static void BN_bn2bin_fixed(const BIGNUM *bn, unsigned char *buf, int size) { int bytes = size - BN_num_bytes(bn); @@ -119,55 +143,39 @@ rsa_keygen_progress_cb(EVP_PKEY_CTX *ctx) { } static isc_result_t -generate_ec_key(EVP_PKEY **pkeyp, const int nid) { +generate_ec_key(EVP_PKEY **pkeyp, const OSSL_PARAM *const params) { isc_result_t result; EVP_PKEY_CTX *pctx = NULL; - EVP_PKEY *params_pkey = NULL; - /* Generate the key's parameters. */ pctx = EVP_PKEY_CTX_new_from_name(NULL, "EC", NULL); if (pctx == NULL) { CLEANUP(OSSL_WRAP_ERROR("EVP_PKEY_CTX_new_from_name")); } - if (EVP_PKEY_paramgen_init(pctx) != 1) { - CLEANUP(OSSL_WRAP_ERROR("EVP_PKEY_paramgen_init")); - } - - if (EVP_PKEY_CTX_set_ec_paramgen_curve_nid(pctx, nid) != 1) { - CLEANUP(OSSL_WRAP_ERROR("EVP_PKEY_CTX_set_ec_paramgen_curve_" - "nid")); - } - - if (EVP_PKEY_paramgen(pctx, ¶ms_pkey) != 1) { - CLEANUP(OSSL_WRAP_ERROR("EVP_PKEY_paramgen")); - } - - if (params_pkey == NULL) { - CLEANUP(OSSL_WRAP_ERROR("EVP_PKEY_paramgen")); - } - - EVP_PKEY_CTX_free(pctx); - - /* Generate the key. */ - pctx = EVP_PKEY_CTX_new(params_pkey, NULL); - if (pctx == NULL) { - CLEANUP(OSSL_WRAP_ERROR("EVP_PKEY_CTX_new")); - } - if (EVP_PKEY_keygen_init(pctx) != 1) { CLEANUP(OSSL_WRAP_ERROR("EVP_PKEY_keygen_init")); } - if (EVP_PKEY_keygen(pctx, pkeyp) != 1) { - CLEANUP(OSSL_WRAP_ERROR("EVP_PKEY_keygen")); + if (EVP_PKEY_CTX_set_params(pctx, params) != 1) { + CLEANUP(OSSL_WRAP_ERROR("EVP_PKEY_CTX_set_params")); + } + + /* + * EVP_PKEY_keygen is an older function now equivalent to + * EVP_PKEY_generate with an additional check that EVP_PKEY_CTX has been + * initialized with EVP_PKEY_keygen_init. + * + * Since we can guarantee such condition we use EVP_PKEY_generate + * directly. + */ + if (EVP_PKEY_generate(pctx, pkeyp) != 1) { + CLEANUP(OSSL_WRAP_ERROR("EVP_PKEY_generate")); } result = ISC_R_SUCCESS; cleanup: EVP_PKEY_CTX_free(pctx); - EVP_PKEY_free(params_pkey); return result; } @@ -207,6 +215,14 @@ generate_pkcs11_ec_key(char *uri, EVP_PKEY **pkeyp, int nid) { "nid")); } + /* + * EVP_PKEY_keygen is an older function now equivalent to + * EVP_PKEY_generate with an additional check that EVP_PKEY_CTX has been + * initialized with EVP_PKEY_keygen_init. + * + * Since we can guarantee such condition we use EVP_PKEY_generate + * directly. + */ if (EVP_PKEY_generate(pctx, pkeyp) != 1) { CLEANUP(OSSL_WRAP_ERROR("EVP_PKEY_generate")); } @@ -219,15 +235,16 @@ cleanup: } static isc_result_t -validate_ec_pkey(EVP_PKEY *pkey, const char *expected) { +validate_ec_pkey(EVP_PKEY *pkey, const OSSL_PARAM *const curve_params) { isc_result_t result; + const char *expected = curve_params[0].data; char actual[64]; if (EVP_PKEY_get_group_name(pkey, actual, sizeof(actual), NULL) != 1) { CLEANUP(OSSL_WRAP_ERROR("EVP_PKEY_get_group_name")); } - if (strcmp(expected, actual) != 0) { + if (strncmp(expected, actual, curve_params[0].data_size) != 0) { return ISC_R_FAILURE; } @@ -239,38 +256,20 @@ cleanup: static isc_result_t load_ec_public_from_region(isc_region_t region, EVP_PKEY **pkeyp, - const char *group_name) { + const OSSL_PARAM *const curve_params) { isc_result_t result; - OSSL_PARAM_BLD *bld = NULL; - OSSL_PARAM *params = NULL; EVP_PKEY_CTX *pctx = NULL; uint8_t buffer[MAX_PUBLIC_KEY_SIZE + 1]; + OSSL_PARAM params[] = { + curve_params[0], /* group */ + OSSL_PARAM_octet_string(OSSL_PKEY_PARAM_PUB_KEY, buffer, + region.length + 1), + OSSL_PARAM_END, + }; buffer[0] = POINT_CONVERSION_UNCOMPRESSED; memmove(buffer + 1, region.base, region.length); - bld = OSSL_PARAM_BLD_new(); - if (bld == NULL) { - CLEANUP(OSSL_WRAP_ERROR("OSSL_PARAM_BLD_new")); - } - - if (OSSL_PARAM_BLD_push_utf8_string(bld, OSSL_PKEY_PARAM_GROUP_NAME, - group_name, 0) != 1) - { - CLEANUP(OSSL_WRAP_ERROR("OSSL_PARAM_BLD_push_utf8_string")); - } - - if (OSSL_PARAM_BLD_push_octet_string(bld, OSSL_PKEY_PARAM_PUB_KEY, - buffer, region.length + 1) != 1) - { - CLEANUP(OSSL_WRAP_ERROR("OSSL_PARAM_BLD_push_octet_string")); - } - - params = OSSL_PARAM_BLD_to_param(bld); - if (params == NULL) { - CLEANUP(OSSL_WRAP_ERROR("OSSL_PARAM_BLD_to_param")); - } - pctx = EVP_PKEY_CTX_new_from_name(NULL, "EC", NULL); if (pctx == NULL) { CLEANUP(OSSL_WRAP_ERROR("EVP_PKEY_CTX_new_from_name")); @@ -287,19 +286,17 @@ load_ec_public_from_region(isc_region_t region, EVP_PKEY **pkeyp, result = ISC_R_SUCCESS; cleanup: - OSSL_PARAM_free(params); - OSSL_PARAM_BLD_free(bld); EVP_PKEY_CTX_free(pctx); return result; } static isc_result_t load_ec_secret_from_region(isc_region_t region, EVP_PKEY **pkeyp, - const char *group_name, const int nid) { + const OSSL_PARAM *const curve_params) { uint8_t public[MAX_PUBLIC_KEY_SIZE + 1]; - EVP_PKEY_CTX *pctx = NULL; OSSL_PARAM_BLD *bld = NULL; OSSL_PARAM *params = NULL; + EVP_PKEY_CTX *pctx = NULL; EC_POINT *pub_point = NULL; EC_GROUP *group = NULL; BIGNUM *private = NULL; @@ -311,7 +308,7 @@ load_ec_secret_from_region(isc_region_t region, EVP_PKEY **pkeyp, * private key file format does not contain it directly, we generate it * as needed. */ - group = EC_GROUP_new_by_curve_name(nid); + group = EC_GROUP_new_from_params(curve_params, NULL, NULL); if (group == NULL) { CLEANUP(OSSL_WRAP_ERROR("EC_GROUP_new_by_curve_name")); } @@ -342,8 +339,9 @@ load_ec_secret_from_region(isc_region_t region, EVP_PKEY **pkeyp, CLEANUP(OSSL_WRAP_ERROR("OSSL_PARAM_BLD_new")); } - if (OSSL_PARAM_BLD_push_utf8_string(bld, OSSL_PKEY_PARAM_GROUP_NAME, - group_name, 0) != 1) + if (OSSL_PARAM_BLD_push_utf8_string(bld, curve_params[0].key, + curve_params[0].data, + curve_params[0].data_size) != 1) { CLEANUP(OSSL_WRAP_ERROR("OSSL_PARAM_BLD_push_utf8_string")); } @@ -548,6 +546,14 @@ isc_ossl_wrap_generate_pkcs11_rsa_key(char *uri, size_t bit_size, CLEANUP(OSSL_WRAP_ERROR("EVP_PKEY_CTX_set_params")); } + /* + * EVP_PKEY_keygen is an older function now equivalent to + * EVP_PKEY_generate with an additional check that EVP_PKEY_CTX has been + * initialized with EVP_PKEY_keygen_init. + * + * Since we can guarantee such condition we use EVP_PKEY_generate + * directly. + */ status = EVP_PKEY_generate(ctx, pkeyp); if (status != 1) { CLEANUP(OSSL_WRAP_ERROR("EVP_PKEY_generate")); From 21f80a2bd79cb1a5d18c3f6571fc5ce63a33b090 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ayd=C4=B1n=20Mercan?= Date: Mon, 15 Dec 2025 19:26:50 +0300 Subject: [PATCH 11/16] make isc_ossl_wrap_ecdsa_set_deterministic consistent with style --- lib/isc/ossl_wrap/ossl3.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/lib/isc/ossl_wrap/ossl3.c b/lib/isc/ossl_wrap/ossl3.c index 836fc0d776..1478e58683 100644 --- a/lib/isc/ossl_wrap/ossl3.c +++ b/lib/isc/ossl_wrap/ossl3.c @@ -437,15 +437,14 @@ isc_result_t isc_ossl_wrap_ecdsa_set_deterministic(EVP_PKEY_CTX *pctx, const char *hash) { unsigned int rfc6979 = 1; isc_result_t result; - OSSL_PARAM params[3]; + OSSL_PARAM params[3] = { + OSSL_PARAM_construct_utf8_string("digest", UNCONST(hash), 0), + OSSL_PARAM_construct_uint("nonce-type", &rfc6979), + OSSL_PARAM_END, + }; REQUIRE(pctx != NULL && hash != NULL); - params[0] = OSSL_PARAM_construct_utf8_string("digest", UNCONST(hash), - 0); - params[1] = OSSL_PARAM_construct_uint("nonce-type", &rfc6979); - params[2] = OSSL_PARAM_construct_end(); - if (EVP_PKEY_CTX_set_params(pctx, params) != 1) { CLEANUP(OSSL_WRAP_ERROR("EVP_PKEY_CTX_set_params")); } From c2f3a23a3e4b9b695485755c17f1060368d8e6f3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ayd=C4=B1n=20Mercan?= Date: Tue, 13 Jan 2026 13:28:54 +0300 Subject: [PATCH 12/16] expose isc__crypto_md in isc/ossl_wrap.h This is a bit of a namespace convention violation but it fits the spirit of this header since it is exposing OpenSSL-isms to others. Further work is needed to make sure the exposed EVP_MD isn't needed anymore. --- lib/dns/opensslecdsa_link.c | 4 +--- lib/dns/opensslrsa_link.c | 3 --- lib/isc/crypto/crypto_p.h | 18 ------------------ lib/isc/crypto/ossl1_1.c | 2 -- lib/isc/crypto/ossl3.c | 2 -- lib/isc/crypto/ossl_common.c | 3 +-- lib/isc/include/isc/ossl_wrap.h | 7 +++++++ lib/isc/iterated_hash.c | 3 +-- lib/isc/md.c | 2 +- lib/isc/tls.c | 4 +--- 10 files changed, 12 insertions(+), 36 deletions(-) delete mode 100644 lib/isc/crypto/crypto_p.h diff --git a/lib/dns/opensslecdsa_link.c b/lib/dns/opensslecdsa_link.c index 7b89b3f25a..2b7518c576 100644 --- a/lib/dns/opensslecdsa_link.c +++ b/lib/dns/opensslecdsa_link.c @@ -23,6 +23,7 @@ #include #include #include +#include #include #include #include @@ -35,9 +36,6 @@ #include "dst_parse.h" #include "openssl_shim.h" -/* TODO(aydin): remove this crap */ -extern EVP_MD *isc__crypto_md[]; - #ifndef NID_X9_62_prime256v1 #error "P-256 group is not known (NID_X9_62_prime256v1)" #endif /* ifndef NID_X9_62_prime256v1 */ diff --git a/lib/dns/opensslrsa_link.c b/lib/dns/opensslrsa_link.c index ec24bf202d..6b322ff3b3 100644 --- a/lib/dns/opensslrsa_link.c +++ b/lib/dns/opensslrsa_link.c @@ -35,9 +35,6 @@ #define OPENSSLRSA_MAX_MODULUS_BITS 4096 -/* TODO(aydin): remove this crap */ -extern EVP_MD *isc__crypto_md[]; - /* length byte + 1.2.840.113549.1.1.11 BER encoded RFC 4055 */ static unsigned char oid_rsasha256[] = { 0x0b, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b }; diff --git a/lib/isc/crypto/crypto_p.h b/lib/isc/crypto/crypto_p.h deleted file mode 100644 index 899d9a2b40..0000000000 --- a/lib/isc/crypto/crypto_p.h +++ /dev/null @@ -1,18 +0,0 @@ -/* - * 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 - -extern EVP_MD *isc__crypto_md[]; diff --git a/lib/isc/crypto/ossl1_1.c b/lib/isc/crypto/ossl1_1.c index 6ecbac47bc..f672057095 100644 --- a/lib/isc/crypto/ossl1_1.c +++ b/lib/isc/crypto/ossl1_1.c @@ -30,8 +30,6 @@ #include #include -#include "crypto_p.h" - #define HMAC_KEY_MAGIC ISC_MAGIC('H', 'M', 'A', 'C') struct isc_hmac_key { diff --git a/lib/isc/crypto/ossl3.c b/lib/isc/crypto/ossl3.c index dc3388a35a..1c2f3cab9d 100644 --- a/lib/isc/crypto/ossl3.c +++ b/lib/isc/crypto/ossl3.c @@ -34,8 +34,6 @@ #include #include -#include "crypto_p.h" - struct isc_hmac_key { uint32_t magic; uint32_t len; diff --git a/lib/isc/crypto/ossl_common.c b/lib/isc/crypto/ossl_common.c index 41bd284102..8b5d56925b 100644 --- a/lib/isc/crypto/ossl_common.c +++ b/lib/isc/crypto/ossl_common.c @@ -16,8 +16,7 @@ #include #include - -#include "crypto_p.h" +#include EVP_MD *isc__crypto_md[] = { [ISC_MD_UNKNOWN] = NULL, [ISC_MD_MD5] = NULL, [ISC_MD_SHA1] = NULL, diff --git a/lib/isc/include/isc/ossl_wrap.h b/lib/isc/include/isc/ossl_wrap.h index 96f282a13b..4831fab405 100644 --- a/lib/isc/include/isc/ossl_wrap.h +++ b/lib/isc/include/isc/ossl_wrap.h @@ -278,3 +278,10 @@ isc__ossl_wrap_logged_toresult(isc_logcategory_t category, isc_logmodule_t module, const char *funcname, isc_result_t fallback, const char *file, int line); + +/* + * This is a bit of a namespace convention violation but it fits the spirit of + * this header since it is exposing OpenSSL-isms to others. + */ + +extern EVP_MD *isc__crypto_md[]; diff --git a/lib/isc/iterated_hash.c b/lib/isc/iterated_hash.c index fae0980907..7d8c68a396 100644 --- a/lib/isc/iterated_hash.c +++ b/lib/isc/iterated_hash.c @@ -19,11 +19,10 @@ #include #include +#include #include #include -#include "crypto/crypto_p.h" - #if OPENSSL_VERSION_NUMBER < 0x30000000L #include diff --git a/lib/isc/md.c b/lib/isc/md.c index 87a167984c..0c6688f48e 100644 --- a/lib/isc/md.c +++ b/lib/isc/md.c @@ -18,9 +18,9 @@ #include #include +#include #include -#include "crypto/crypto_p.h" #include "openssl_shim.h" isc_md_t * diff --git a/lib/isc/tls.c b/lib/isc/tls.c index c4a3fd5ee9..68c9b495d5 100644 --- a/lib/isc/tls.c +++ b/lib/isc/tls.c @@ -42,6 +42,7 @@ #include #include #include +#include #include #include #include @@ -52,9 +53,6 @@ #include "openssl_shim.h" -/* TODO(aydin): remove this crap */ -extern EVP_MD *isc__crypto_md[]; - #define COMMON_SSL_OPTIONS \ (SSL_OP_NO_COMPRESSION | SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION) From 251af02fe7cef6d4051347fd6f14aac05f8d6c76 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ayd=C4=B1n=20Mercan?= Date: Tue, 13 Jan 2026 13:40:03 +0300 Subject: [PATCH 13/16] make generate_pkcs11_ec_key consistent with others --- lib/isc/ossl_wrap/ossl3.c | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/lib/isc/ossl_wrap/ossl3.c b/lib/isc/ossl_wrap/ossl3.c index 1478e58683..b8da16e8e0 100644 --- a/lib/isc/ossl_wrap/ossl3.c +++ b/lib/isc/ossl_wrap/ossl3.c @@ -12,6 +12,7 @@ */ #include +#include #include #include @@ -183,13 +184,17 @@ static isc_result_t generate_pkcs11_ec_key(char *uri, EVP_PKEY **pkeyp, int nid) { isc_result_t result; EVP_PKEY_CTX *pctx; - OSSL_PARAM params[3]; + size_t len; - params[0] = OSSL_PARAM_construct_utf8_string("pkcs11_uri", uri, 0); - params[1] = OSSL_PARAM_construct_utf8_string( - "pkcs11_key_usage", pkcs11_key_usage, - sizeof(pkcs11_key_usage) - 1); - params[2] = OSSL_PARAM_construct_end(); + INSIST(uri != NULL); + len = strlen(uri); + + const OSSL_PARAM params[] = { + OSSL_PARAM_utf8_string("pkcs11_uri", uri, len), + OSSL_PARAM_utf8_string("pkcs11_key_usage", pkcs11_key_usage, + sizeof(pkcs11_key_usage) - 1), + OSSL_PARAM_END, + }; pctx = EVP_PKEY_CTX_new_from_name(NULL, "EC", "provider=pkcs11"); if (pctx == NULL) { From b748651bb011c9e560636d3fd0af35660697b384 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ayd=C4=B1n=20Mercan?= Date: Wed, 14 Jan 2026 17:32:01 +0300 Subject: [PATCH 14/16] explicitly set ec points properties in pre-3.0 openssl Generating a P-256 key in pre-3.0 wasn't explicitly using uncompressed named curves in DNSSEC but was when generating an epheremal TLS key. --- lib/isc/ossl_wrap/ossl1_1.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lib/isc/ossl_wrap/ossl1_1.c b/lib/isc/ossl_wrap/ossl1_1.c index e5d63e2706..7726e9cac3 100644 --- a/lib/isc/ossl_wrap/ossl1_1.c +++ b/lib/isc/ossl_wrap/ossl1_1.c @@ -122,6 +122,9 @@ generate_ec_key(EVP_PKEY **pkeyp, const int nid) { CLEANUP(OSSL_WRAP_ERROR("EC_KEY_generate_key")); } + EC_KEY_set_asn1_flag(eckey, OPENSSL_EC_NAMED_CURVE); + EC_KEY_set_conv_form(eckey, POINT_CONVERSION_UNCOMPRESSED); + pkey = EVP_PKEY_new(); if (pkey == NULL) { CLEANUP(OSSL_WRAP_ERROR("EVP_PKEY_new")); From 19c9053a6b7f582323770c74e61a53adc2d657c4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ayd=C4=B1n=20Mercan?= Date: Wed, 14 Jan 2026 17:34:35 +0300 Subject: [PATCH 15/16] use isc_ossl_wrap to generate epheremal tls keys --- lib/isc/tls.c | 89 +-------------------------------------------------- 1 file changed, 1 insertion(+), 88 deletions(-) diff --git a/lib/isc/tls.c b/lib/isc/tls.c index 68c9b495d5..9f1aa63969 100644 --- a/lib/isc/tls.c +++ b/lib/isc/tls.c @@ -181,12 +181,6 @@ isc_tlsctx_createserver(const char *keyfile, const char *certfile, X509 *cert = NULL; EVP_PKEY *pkey = NULL; SSL_CTX *ctx = NULL; -#if OPENSSL_VERSION_NUMBER < 0x30000000L - EC_KEY *eckey = NULL; -#else - EVP_PKEY_CTX *pkey_ctx = NULL; - EVP_PKEY *params_pkey = NULL; -#endif /* OPENSSL_VERSION_NUMBER < 0x30000000L */ char errbuf[256]; const SSL_METHOD *method = NULL; @@ -208,79 +202,10 @@ isc_tlsctx_createserver(const char *keyfile, const char *certfile, SSL_CTX_set_min_proto_version(ctx, TLS1_2_VERSION); if (ephemeral) { - const int group_nid = NID_X9_62_prime256v1; - -#if OPENSSL_VERSION_NUMBER < 0x30000000L - eckey = EC_KEY_new_by_curve_name(group_nid); - if (eckey == NULL) { + if (isc_ossl_wrap_generate_p256_key(&pkey) != ISC_R_SUCCESS) { goto ssl_error; } - /* Generate the key. */ - rv = EC_KEY_generate_key(eckey); - if (rv != 1) { - goto ssl_error; - } - pkey = EVP_PKEY_new(); - if (pkey == NULL) { - goto ssl_error; - } - rv = EVP_PKEY_set1_EC_KEY(pkey, eckey); - if (rv != 1) { - goto ssl_error; - } - - /* Use a named curve and uncompressed point conversion form. */ - EC_KEY_set_asn1_flag(EVP_PKEY_get0_EC_KEY(pkey), - OPENSSL_EC_NAMED_CURVE); - EC_KEY_set_conv_form(EVP_PKEY_get0_EC_KEY(pkey), - POINT_CONVERSION_UNCOMPRESSED); - - /* Cleanup */ - EC_KEY_free(eckey); - eckey = NULL; -#else - /* Generate the key's parameters. */ - pkey_ctx = EVP_PKEY_CTX_new_from_name(NULL, "EC", NULL); - if (pkey_ctx == NULL) { - goto ssl_error; - } - rv = EVP_PKEY_paramgen_init(pkey_ctx); - if (rv != 1) { - goto ssl_error; - } - rv = EVP_PKEY_CTX_set_ec_paramgen_curve_nid(pkey_ctx, - group_nid); - if (rv != 1) { - goto ssl_error; - } - rv = EVP_PKEY_paramgen(pkey_ctx, ¶ms_pkey); - if (rv != 1 || params_pkey == NULL) { - goto ssl_error; - } - EVP_PKEY_CTX_free(pkey_ctx); - - /* Generate the key. */ - pkey_ctx = EVP_PKEY_CTX_new(params_pkey, NULL); - if (pkey_ctx == NULL) { - goto ssl_error; - } - rv = EVP_PKEY_keygen_init(pkey_ctx); - if (rv != 1) { - goto ssl_error; - } - rv = EVP_PKEY_keygen(pkey_ctx, &pkey); - if (rv != 1 || pkey == NULL) { - goto ssl_error; - } - - /* Cleanup */ - EVP_PKEY_free(params_pkey); - params_pkey = NULL; - EVP_PKEY_CTX_free(pkey_ctx); - pkey_ctx = NULL; -#endif /* OPENSSL_VERSION_NUMBER < 0x30000000L */ - cert = X509_new(); if (cert == NULL) { goto ssl_error; @@ -358,18 +283,6 @@ ssl_error: if (pkey != NULL) { EVP_PKEY_free(pkey); } -#if OPENSSL_VERSION_NUMBER < 0x30000000L - if (eckey != NULL) { - EC_KEY_free(eckey); - } -#else - if (params_pkey != NULL) { - EVP_PKEY_free(params_pkey); - } - if (pkey_ctx != NULL) { - EVP_PKEY_CTX_free(pkey_ctx); - } -#endif /* OPENSSL_VERSION_NUMBER < 0x30000000L */ return ISC_R_TLSERROR; } From ecb677658f541bac51cd3a70a2166bdd1f853e46 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ayd=C4=B1n=20Mercan?= Date: Wed, 14 Jan 2026 17:40:24 +0300 Subject: [PATCH 16/16] don't transform errors in hmac_sign The change from DST_R_OPENSSLFAILURE to ISC_R_CRYPTOFAILURE seems to be benign. Furthermore it should a bug to rely on the exacts crypto failure code. --- lib/dns/hmac_link.c | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/lib/dns/hmac_link.c b/lib/dns/hmac_link.c index aa3d5d7141..41913095f2 100644 --- a/lib/dns/hmac_link.c +++ b/lib/dns/hmac_link.c @@ -199,18 +199,10 @@ hmac_adddata(const dst_context_t *dctx, const isc_region_t *data) { static isc_result_t hmac_sign(const dst_context_t *dctx, isc_buffer_t *sig) { isc_hmac_t *ctx = dctx->ctxdata.hmac_ctx; - isc_result_t r; REQUIRE(ctx != NULL); - r = isc_hmac_final(ctx, sig); - - /* Turn CRYPTOFAILURE into OPENSSLFAILURE */ - if (r == ISC_R_CRYPTOFAILURE) { - r = DST_R_OPENSSLFAILURE; - } - - return r; + return isc_hmac_final(ctx, sig); } static isc_result_t