diff --git a/bind-9.18-pkcs11-provider.patch b/bind-9.18-pkcs11-provider.patch new file mode 100644 index 0000000..4a48182 --- /dev/null +++ b/bind-9.18-pkcs11-provider.patch @@ -0,0 +1,904 @@ +From ec38a39feabea02eb75f257e8b81cf16aac9d184 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Petr=20Men=C5=A1=C3=ADk?= +Date: Thu, 13 Feb 2025 13:20:28 +0100 +Subject: [PATCH] Backport OpenSSL 3 provider support + +Use gist of 451edf324281d30fbbe5669223dcea331670847c and +5fd6cfc625aa84005618236f4cd699c07367a3dc upstream commits, but do not do +significant rebase together. Move engine loading of EVP_PKEY from label to +openssl_link and copy provider variant from newer. + +Remove legacy RSA calls from _fromlabel to separate engine handling +code. Make rsa_check accepting EVP_PKEY pair only and use conditional +compilation to verify them. Move checking of max exponent bits to +rsa_check too, because it is done from all usages anyway. + +Use rsa_check_legacy in places where bit checking is not necessary. + +Fix keyfromlabel to not use engine parameter for provider keys + +- Rework key checks to not require 'engine' tag, private key + is valid with 'label' tag alone + +- Fix _fromlabel() functions to work with engine == NULL + +- Update dst__openssl_fromlabel_engine() to do provider lookup + only when engine is not set + +(cherry picked from commit de486d0ec5d5642ddb1820a1269f5406a2bb1c64) + +Use dst_key_t label to signal isprivate property as a downstream +alternative to upstream commit 74361b0b6e5a6b17ebeea6afe1ca990395d7a6dd. +That would require additional heavier changes. + +Downstream change: +Move RSA bits check to legacy, let it use rsa_check for newer + +rsabigexponent tests got broken by this change. +--- + lib/dns/dst_openssl.h | 4 + + lib/dns/dst_parse.c | 21 ++-- + lib/dns/openssl_link.c | 161 ++++++++++++++++++++++++++---- + lib/dns/openssldh_link.c | 5 + + lib/dns/opensslecdsa_link.c | 110 ++++++++++----------- + lib/dns/openssleddsa_link.c | 40 +++----- + lib/dns/opensslrsa_link.c | 189 +++++++++++++++--------------------- + 7 files changed, 303 insertions(+), 227 deletions(-) + +diff --git a/lib/dns/dst_openssl.h b/lib/dns/dst_openssl.h +index 819af0f..cd386c0 100644 +--- a/lib/dns/dst_openssl.h ++++ b/lib/dns/dst_openssl.h +@@ -64,4 +64,8 @@ ENGINE * + dst__openssl_getengine(const char *engine); + #endif /* if !defined(OPENSSL_NO_ENGINE) && OPENSSL_API_LEVEL < 30000 */ + ++isc_result_t ++dst__openssl_fromlabel(int key_base_id, const char *engine, const char *label, ++ const char *pin, EVP_PKEY **ppub, EVP_PKEY **ppriv); ++ + ISC_LANG_ENDDECLS +diff --git a/lib/dns/dst_parse.c b/lib/dns/dst_parse.c +index d5ea0e4..addb65e 100644 +--- a/lib/dns/dst_parse.c ++++ b/lib/dns/dst_parse.c +@@ -195,10 +195,9 @@ check_rsa(const dst_private_t *priv, bool external) { + + mask = (1ULL << TAG_SHIFT) - 1; + +- if (have[TAG_RSA_ENGINE & mask]) { ++ if (have[TAG_RSA_LABEL & mask]) { + ok = have[TAG_RSA_MODULUS & mask] && +- have[TAG_RSA_PUBLICEXPONENT & mask] && +- have[TAG_RSA_LABEL & mask]; ++ have[TAG_RSA_PUBLICEXPONENT & mask]; + } else { + ok = have[TAG_RSA_MODULUS & mask] && + have[TAG_RSA_PUBLICEXPONENT & mask] && +@@ -259,11 +258,9 @@ check_ecdsa(const dst_private_t *priv, bool external) { + + mask = (1ULL << TAG_SHIFT) - 1; + +- if (have[TAG_ECDSA_ENGINE & mask]) { +- ok = have[TAG_ECDSA_LABEL & mask]; +- } else { +- ok = have[TAG_ECDSA_PRIVATEKEY & mask]; +- } ++ ok = have[TAG_ECDSA_LABEL & mask] || ++ have[TAG_ECDSA_PRIVATEKEY & mask]; ++ + return ok ? 0 : -1; + } + +@@ -295,11 +292,9 @@ check_eddsa(const dst_private_t *priv, bool external) { + + mask = (1ULL << TAG_SHIFT) - 1; + +- if (have[TAG_EDDSA_ENGINE & mask]) { +- ok = have[TAG_EDDSA_LABEL & mask]; +- } else { +- ok = have[TAG_EDDSA_PRIVATEKEY & mask]; +- } ++ ok = have[TAG_EDDSA_LABEL & mask] || ++ have[TAG_EDDSA_PRIVATEKEY & mask]; ++ + return ok ? 0 : -1; + } + +diff --git a/lib/dns/openssl_link.c b/lib/dns/openssl_link.c +index e3a89f4..62077b6 100644 +--- a/lib/dns/openssl_link.c ++++ b/lib/dns/openssl_link.c +@@ -44,6 +44,9 @@ + #if !defined(OPENSSL_NO_ENGINE) && OPENSSL_API_LEVEL < 30000 + #include + #endif /* if !defined(OPENSSL_NO_ENGINE) && OPENSSL_API_LEVEL < 30000 */ ++#if OPENSSL_VERSION_NUMBER >= 0x30000000L ++#include ++#endif + + #include "openssl_shim.h" + +@@ -51,6 +54,12 @@ + static ENGINE *e = NULL; + #endif /* if !defined(OPENSSL_NO_ENGINE) && OPENSSL_API_LEVEL < 30000 */ + ++#define DST_RET(a) \ ++ { \ ++ ret = a; \ ++ goto err; \ ++ } ++ + static void + enable_fips_mode(void) { + #ifdef HAVE_FIPS_MODE +@@ -70,32 +79,28 @@ enable_fips_mode(void) { + + isc_result_t + dst__openssl_init(const char *engine) { +- isc_result_t result = ISC_R_SUCCESS; +- + enable_fips_mode(); + +-#if !defined(OPENSSL_NO_ENGINE) && OPENSSL_API_LEVEL < 30000 + if (engine != NULL && *engine == '\0') { + engine = NULL; + } + +- if (engine != NULL) { +- e = ENGINE_by_id(engine); +- if (e == NULL) { +- result = DST_R_NOENGINE; +- goto cleanup_rm; +- } +- if (!ENGINE_init(e)) { +- result = DST_R_NOENGINE; +- goto cleanup_rm; +- } +- /* This will init the engine. */ +- if (!ENGINE_set_default(e, ENGINE_METHOD_ALL)) { +- result = DST_R_NOENGINE; +- goto cleanup_init; +- } ++ if (engine == NULL) { ++ return (ISC_R_SUCCESS); + } + ++#if !defined(OPENSSL_NO_ENGINE) && OPENSSL_API_LEVEL < 30000 ++ e = ENGINE_by_id(engine); ++ if (e == NULL) { ++ goto cleanup_rm; ++ } ++ if (!ENGINE_init(e)) { ++ goto cleanup_rm; ++ } ++ /* This will init the engine. */ ++ if (!ENGINE_set_default(e, ENGINE_METHOD_ALL)) { ++ goto cleanup_init; ++ } + return ISC_R_SUCCESS; + cleanup_init: + ENGINE_finish(e); +@@ -105,10 +110,8 @@ cleanup_rm: + } + e = NULL; + ERR_clear_error(); +-#else +- UNUSED(engine); + #endif /* if !defined(OPENSSL_NO_ENGINE) && OPENSSL_API_LEVEL < 30000 */ +- return result; ++ return (DST_R_NOENGINE); + } + + void +@@ -220,4 +223,120 @@ dst__openssl_getengine(const char *engine) { + } + #endif /* if !defined(OPENSSL_NO_ENGINE) && OPENSSL_API_LEVEL < 30000 */ + ++static isc_result_t ++dst__openssl_fromlabel_engine(int key_base_id, const char *engine, ++ const char *label, ++ EVP_PKEY **ppub, EVP_PKEY **ppriv) { ++#if !defined(OPENSSL_NO_ENGINE) && OPENSSL_API_LEVEL < 30000 ++ isc_result_t ret = ISC_R_SUCCESS; ++ ENGINE *e = NULL; ++ EVP_PKEY *pkey = NULL, *pubpkey = NULL; ++ ++ UNUSED(key_base_id); ++ ++ e = dst__openssl_getengine(engine); ++ if (e == NULL) { ++ DST_RET(dst__openssl_toresult(DST_R_NOENGINE)); ++ } ++ ++ pubpkey = ENGINE_load_public_key(e, label, NULL, NULL); ++ if (pubpkey == NULL) { ++ DST_RET(dst__openssl_toresult2("ENGINE_load_public_key", ++ DST_R_OPENSSLFAILURE)); ++ } ++ if (EVP_PKEY_get_base_id(pubpkey) != key_base_id) { ++ DST_RET(DST_R_BADKEYTYPE); ++ } ++ pkey = ENGINE_load_private_key(e, label, NULL, NULL); ++ if (pkey == NULL) { ++ DST_RET(dst__openssl_toresult2("ENGINE_load_private_key", ++ DST_R_OPENSSLFAILURE)); ++ } ++ if (EVP_PKEY_base_id(pkey) != key_base_id) { ++ DST_RET(DST_R_INVALIDPRIVATEKEY); ++ } ++ *ppub = pubpkey; ++ *ppriv = pkey; ++err: ++ return ret; ++#else ++ UNUSED(key_base_id); ++ UNUSED(engine); ++ UNUSED(label); ++ UNUSED(ppub); ++ UNUSED(ppriv); ++ return DST_R_NOENGINE; ++#endif ++} ++ ++ ++static isc_result_t ++dst__openssl_fromlabel_provider(int key_base_id, const char *label, const char *pin, ++ EVP_PKEY **ppub, EVP_PKEY **ppriv) { ++ UNUSED(pin); ++#if OPENSSL_VERSION_NUMBER >= 0x30000000L ++ isc_result_t ret = DST_R_OPENSSLFAILURE; ++ OSSL_STORE_CTX *ctx = NULL; ++ ++ ++ ctx = OSSL_STORE_open(label, NULL, NULL, NULL, NULL); ++ if (!ctx) { ++ DST_RET(dst__openssl_toresult2("OSSL_STORE_open_ex", ++ DST_R_OPENSSLFAILURE)); ++ } ++ ++ while (!OSSL_STORE_eof(ctx)) { ++ OSSL_STORE_INFO *info = OSSL_STORE_load(ctx); ++ if (info == NULL) { ++ continue; ++ } ++ switch (OSSL_STORE_INFO_get_type(info)) { ++ case OSSL_STORE_INFO_PKEY: ++ if (*ppriv != NULL) { ++ DST_RET(DST_R_INVALIDPRIVATEKEY); ++ } ++ *ppriv = OSSL_STORE_INFO_get1_PKEY(info); ++ if (EVP_PKEY_get_base_id(*ppriv) != key_base_id) { ++ DST_RET(DST_R_BADKEYTYPE); ++ } ++ break; ++ case OSSL_STORE_INFO_PUBKEY: ++ if (*ppub != NULL) { ++ DST_RET(DST_R_INVALIDPUBLICKEY); ++ } ++ *ppub = OSSL_STORE_INFO_get1_PUBKEY(info); ++ if (EVP_PKEY_get_base_id(*ppub) != key_base_id) { ++ DST_RET(DST_R_BADKEYTYPE); ++ } ++ break; ++ } ++ OSSL_STORE_INFO_free(info); ++ } ++ if (*ppriv != NULL && *ppub != NULL) { ++ ret = ISC_R_SUCCESS; ++ } ++err: ++ OSSL_STORE_close(ctx); ++ return (ret); ++#else ++ UNUSED(key_base_id); ++ UNUSED(label); ++ UNUSED(ppub); ++ UNUSED(ppriv); ++ return (DST_R_OPENSSLFAILURE); ++#endif ++} ++ ++isc_result_t ++dst__openssl_fromlabel(int key_base_id, const char *engine, const char *label, ++ const char *pin, EVP_PKEY **ppub, EVP_PKEY **ppriv) { ++ if (engine == NULL) { ++ return (dst__openssl_fromlabel_provider(key_base_id, label, ++ pin, ppub, ppriv)); ++ } ++ ++ return (dst__openssl_fromlabel_engine(key_base_id, engine, label, ++ ppub, ppriv)); ++} ++ + /*! \file */ +diff --git a/lib/dns/openssldh_link.c b/lib/dns/openssldh_link.c +index a4ba0f7..38345e6 100644 +--- a/lib/dns/openssldh_link.c ++++ b/lib/dns/openssldh_link.c +@@ -610,6 +610,11 @@ err: + + static bool + openssldh_isprivate(const dst_key_t *key) { ++ if (key->label != NULL) { ++ /* assume that _fromlabel will not pass without loading private key, ++ * but for non-exportable key cannot get d value on the object. */ ++ return true; ++ } + #if OPENSSL_VERSION_NUMBER < 0x30000000L || OPENSSL_API_LEVEL < 30000 + DH *dh = key->keydata.dh; + const BIGNUM *priv_key = NULL; +diff --git a/lib/dns/opensslecdsa_link.c b/lib/dns/opensslecdsa_link.c +index ca12bb5..5d07014 100644 +--- a/lib/dns/opensslecdsa_link.c ++++ b/lib/dns/opensslecdsa_link.c +@@ -617,6 +617,12 @@ opensslecdsa_isprivate(const dst_key_t *key) { + return false; + } + ++ if (key->label != NULL) { ++ /* assume that _fromlabel will not pass without loading private key, ++ * but for non-exportable key cannot get d value on the object. */ ++ return true; ++ } ++ + #if OPENSSL_VERSION_NUMBER < 0x30000000L || OPENSSL_API_LEVEL < 30000 + eckey = EVP_PKEY_get1_EC_KEY(pkey); + +@@ -916,7 +922,7 @@ err: + + #if OPENSSL_VERSION_NUMBER < 0x30000000L || OPENSSL_API_LEVEL < 30000 + static isc_result_t +-ecdsa_check(EC_KEY *eckey, EC_KEY *pubeckey) { ++ecdsa_check_legacy(EC_KEY *eckey, EC_KEY *pubeckey) { + const EC_POINT *pubkey; + + pubkey = EC_KEY_get0_public_key(eckey); +@@ -937,9 +943,42 @@ ecdsa_check(EC_KEY *eckey, EC_KEY *pubeckey) { + + return ISC_R_FAILURE; + } ++ ++static isc_result_t ++ecdsa_check(EVP_PKEY **pkey, EVP_PKEY *pubpkey, int group_nid) { ++ isc_result_t ret = ISC_R_FAILURE; ++ EC_KEY *eckey; ++ EC_KEY *pubeckey; ++ ++ eckey = EVP_PKEY_get1_EC_KEY(*pkey); ++ if (eckey == NULL) { ++ DST_RET(dst__openssl_toresult(DST_R_OPENSSLFAILURE)); ++ } ++ if (EC_GROUP_get_curve_name(EC_KEY_get0_group(eckey)) != group_nid) { ++ DST_RET(DST_R_INVALIDPRIVATEKEY); ++ } ++ ++ pubeckey = EVP_PKEY_get1_EC_KEY(pubpkey); ++ if (pubeckey == NULL) { ++ DST_RET(dst__openssl_toresult(DST_R_OPENSSLFAILURE)); ++ } ++ if (EC_GROUP_get_curve_name(EC_KEY_get0_group(pubeckey)) != group_nid) { ++ DST_RET(DST_R_INVALIDPUBLICKEY); ++ } ++ ++ ret = ecdsa_check_legacy(eckey, pubeckey); ++err: ++ if (pubeckey != NULL) { ++ EC_KEY_free(pubeckey); ++ } ++ if (eckey != NULL) { ++ EC_KEY_free(eckey); ++ } ++ return ret; ++} + #else + static isc_result_t +-ecdsa_check(EVP_PKEY **pkey, EVP_PKEY *pubpkey) { ++ecdsa_check(EVP_PKEY **pkey, EVP_PKEY *pubpkey, int group_nid) { + isc_result_t ret = ISC_R_FAILURE; + int status; + size_t pkey_len = 0; +@@ -954,6 +993,8 @@ ecdsa_check(EVP_PKEY **pkey, EVP_PKEY *pubpkey) { + EVP_PKEY_CTX *ctx = NULL; + EVP_PKEY *pkey_new = NULL; + ++ UNUSED(group_nid); ++ + /* Check if `pkey` has a public key. */ + status = EVP_PKEY_get_octet_string_param(*pkey, OSSL_PKEY_PARAM_PUB_KEY, + NULL, 0, &pkey_len); +@@ -1279,7 +1320,7 @@ opensslecdsa_parse(dst_key_t *key, isc_lex_t *lexer, dst_key_t *pub) { + pubeckey = EVP_PKEY_get1_EC_KEY(pub->keydata.pkey); + } + +- if (ecdsa_check(eckey, pubeckey) != ISC_R_SUCCESS) { ++ if (ecdsa_check_legacy(eckey, pubeckey) != ISC_R_SUCCESS) { + DST_RET(dst__openssl_toresult(DST_R_INVALIDPRIVATEKEY)); + } + +@@ -1288,7 +1329,7 @@ opensslecdsa_parse(dst_key_t *key, isc_lex_t *lexer, dst_key_t *pub) { + } + #else + if (ecdsa_check(&key->keydata.pkey, +- pub == NULL ? NULL : pub->keydata.pkey) != ++ pub == NULL ? NULL : pub->keydata.pkey, NID_undef) != + ISC_R_SUCCESS) + { + DST_RET(dst__openssl_toresult(DST_R_INVALIDPRIVATEKEY)); +@@ -1321,11 +1362,7 @@ err: + static isc_result_t + opensslecdsa_fromlabel(dst_key_t *key, const char *engine, const char *label, + const char *pin) { +-#if !defined(OPENSSL_NO_ENGINE) && OPENSSL_API_LEVEL < 30000 + isc_result_t ret = ISC_R_SUCCESS; +- ENGINE *e; +- EC_KEY *eckey = NULL; +- EC_KEY *pubeckey = NULL; + int group_nid; + EVP_PKEY *pkey = NULL; + EVP_PKEY *pubpkey = NULL; +@@ -1335,13 +1372,9 @@ opensslecdsa_fromlabel(dst_key_t *key, const char *engine, const char *label, + + UNUSED(pin); + +- if (engine == NULL || label == NULL) { ++ if (label == NULL) { + return DST_R_NOENGINE; + } +- e = dst__openssl_getengine(engine); +- if (e == NULL) { +- DST_RET(DST_R_NOENGINE); +- } + + if (key->key_alg == DST_ALG_ECDSA256) { + group_nid = NID_X9_62_prime256v1; +@@ -1349,48 +1382,30 @@ opensslecdsa_fromlabel(dst_key_t *key, const char *engine, const char *label, + group_nid = NID_secp384r1; + } + +- /* Load private key. */ +- pkey = ENGINE_load_private_key(e, label, NULL, NULL); +- if (pkey == NULL) { +- DST_RET(dst__openssl_toresult2("ENGINE_load_private_key", +- DST_R_OPENSSLFAILURE)); ++ ret = dst__openssl_fromlabel(EVP_PKEY_EC, engine, label, pin, ++ &pubpkey, &pkey); ++ if (ret != ISC_R_SUCCESS) { ++ goto err; + } ++ + /* Check base id, group nid */ + if (EVP_PKEY_base_id(pkey) != EVP_PKEY_EC) { + DST_RET(DST_R_INVALIDPRIVATEKEY); + } +- eckey = EVP_PKEY_get1_EC_KEY(pkey); +- if (eckey == NULL) { +- DST_RET(dst__openssl_toresult(DST_R_OPENSSLFAILURE)); +- } +- if (EC_GROUP_get_curve_name(EC_KEY_get0_group(eckey)) != group_nid) { +- DST_RET(DST_R_INVALIDPRIVATEKEY); +- } +- +- /* Load public key. */ +- pubpkey = ENGINE_load_public_key(e, label, NULL, NULL); +- if (pubpkey == NULL) { +- DST_RET(dst__openssl_toresult2("ENGINE_load_public_key", +- DST_R_OPENSSLFAILURE)); +- } + /* Check base id, group nid */ + if (EVP_PKEY_base_id(pubpkey) != EVP_PKEY_EC) { + DST_RET(DST_R_INVALIDPUBLICKEY); + } +- pubeckey = EVP_PKEY_get1_EC_KEY(pubpkey); +- if (pubeckey == NULL) { +- DST_RET(dst__openssl_toresult(DST_R_OPENSSLFAILURE)); +- } +- if (EC_GROUP_get_curve_name(EC_KEY_get0_group(pubeckey)) != group_nid) { +- DST_RET(DST_R_INVALIDPUBLICKEY); +- } + +- if (ecdsa_check(eckey, pubeckey) != ISC_R_SUCCESS) { ++ if (ecdsa_check(&pkey, pubpkey, group_nid) != ISC_R_SUCCESS) { + DST_RET(dst__openssl_toresult(DST_R_INVALIDPRIVATEKEY)); + } + ++ if (engine != NULL) ++ key->engine = isc_mem_strdup(key->mctx, engine); ++ else ++ key->engine = NULL; + key->label = isc_mem_strdup(key->mctx, label); +- key->engine = isc_mem_strdup(key->mctx, engine); + key->key_size = EVP_PKEY_bits(pkey); + key->keydata.pkey = pkey; + pkey = NULL; +@@ -1402,21 +1417,8 @@ err: + if (pkey != NULL) { + EVP_PKEY_free(pkey); + } +- if (pubeckey != NULL) { +- EC_KEY_free(pubeckey); +- } +- if (eckey != NULL) { +- EC_KEY_free(eckey); +- } + + return ret; +-#else +- UNUSED(key); +- UNUSED(engine); +- UNUSED(label); +- UNUSED(pin); +- return DST_R_NOENGINE; +-#endif /* !defined(OPENSSL_NO_ENGINE) && OPENSSL_API_LEVEL < 30000 */ + } + + static dst_func_t opensslecdsa_functions = { +diff --git a/lib/dns/openssleddsa_link.c b/lib/dns/openssleddsa_link.c +index 74dac17..04457fb 100644 +--- a/lib/dns/openssleddsa_link.c ++++ b/lib/dns/openssleddsa_link.c +@@ -361,6 +361,12 @@ openssleddsa_isprivate(const dst_key_t *key) { + return false; + } + ++ if (key->label != NULL) { ++ /* assume that _fromlabel will not pass without loading private key, ++ * but for non-exportable key cannot get d value on the object. */ ++ return true; ++ } ++ + /* Must have a buffer to actually check if there is a private key. */ + if (EVP_PKEY_get_raw_private_key(pkey, buf, &len) == 1) { + return true; +@@ -603,9 +609,7 @@ err: + static isc_result_t + openssleddsa_fromlabel(dst_key_t *key, const char *engine, const char *label, + const char *pin) { +-#if !defined(OPENSSL_NO_ENGINE) && OPENSSL_API_LEVEL < 30000 + isc_result_t ret; +- ENGINE *e; + EVP_PKEY *pkey = NULL, *pubpkey = NULL; + int baseid = EVP_PKEY_NONE; + +@@ -628,28 +632,17 @@ openssleddsa_fromlabel(dst_key_t *key, const char *engine, const char *label, + return ISC_R_NOTIMPLEMENTED; + } + +- if (engine == NULL) { +- return DST_R_NOENGINE; +- } +- e = dst__openssl_getengine(engine); +- if (e == NULL) { +- return DST_R_NOENGINE; +- } +- pkey = ENGINE_load_private_key(e, label, NULL, NULL); +- if (pkey == NULL) { +- return dst__openssl_toresult2("ENGINE_load_private_key", +- ISC_R_NOTFOUND); +- } +- if (EVP_PKEY_base_id(pkey) != baseid) { +- DST_RET(DST_R_INVALIDPRIVATEKEY); +- } ++ DST_RET(dst__openssl_fromlabel(baseid, engine, label, pin, ++ &pubpkey, &pkey)); + +- pubpkey = ENGINE_load_public_key(e, label, NULL, NULL); +- if (eddsa_check(pkey, pubpkey) != ISC_R_SUCCESS) { ++ if (EVP_PKEY_base_id(pkey) != baseid) { + DST_RET(DST_R_INVALIDPRIVATEKEY); + } + +- key->engine = isc_mem_strdup(key->mctx, engine); ++ if (engine != NULL) ++ key->engine = isc_mem_strdup(key->mctx, engine); ++ else ++ key->engine = NULL; + key->label = isc_mem_strdup(key->mctx, label); + key->key_size = EVP_PKEY_bits(pkey); + key->keydata.pkey = pkey; +@@ -664,13 +657,6 @@ err: + EVP_PKEY_free(pkey); + } + return ret; +-#else /* if !defined(OPENSSL_NO_ENGINE) && OPENSSL_API_LEVEL < 30000 */ +- UNUSED(key); +- UNUSED(engine); +- UNUSED(label); +- UNUSED(pin); +- return DST_R_NOENGINE; +-#endif /* if !defined(OPENSSL_NO_ENGINE) && OPENSSL_API_LEVEL < 30000 */ + } + + static dst_func_t openssleddsa_functions = { +diff --git a/lib/dns/opensslrsa_link.c b/lib/dns/opensslrsa_link.c +index 37e8a63..d4fbe97 100644 +--- a/lib/dns/opensslrsa_link.c ++++ b/lib/dns/opensslrsa_link.c +@@ -545,6 +545,12 @@ opensslrsa_isprivate(const dst_key_t *key) { + return false; + } + ++ if (key->label != NULL) { ++ /* assume that _fromlabel will not pass without loading private key, ++ * but for non-exportable key cannot get d value on the object. */ ++ return true; ++ } ++ + #if OPENSSL_VERSION_NUMBER < 0x30000000L || OPENSSL_API_LEVEL < 30000 + rsa = EVP_PKEY_get1_RSA(pkey); + INSIST(rsa != NULL); +@@ -995,7 +1001,7 @@ err: + + #if OPENSSL_VERSION_NUMBER < 0x30000000L || OPENSSL_API_LEVEL < 30000 + static isc_result_t +-rsa_check(RSA *rsa, RSA *pub) { ++rsa_check_legacy(RSA *rsa, RSA *pub) { + const BIGNUM *n1 = NULL, *n2 = NULL; + const BIGNUM *e1 = NULL, *e2 = NULL; + BIGNUM *n = NULL, *e = NULL; +@@ -1050,6 +1056,46 @@ rsa_check(RSA *rsa, RSA *pub) { + + return ISC_R_SUCCESS; + } ++ ++static isc_result_t ++rsa_check(EVP_PKEY *pkey, EVP_PKEY *pubpkey) { ++ isc_result_t ret = ISC_R_FAILURE; ++ RSA *rsa = NULL, *pubrsa = NULL; ++ const BIGNUM *ex = NULL; ++ ++ pubrsa = EVP_PKEY_get1_RSA(pubpkey); ++ if (pubrsa == NULL) { ++ DST_RET(dst__openssl_toresult(DST_R_OPENSSLFAILURE)); ++ } ++ ++ rsa = EVP_PKEY_get1_RSA(pkey); ++ if (rsa == NULL) { ++ DST_RET(dst__openssl_toresult(DST_R_OPENSSLFAILURE)); ++ } ++ ++ ret = rsa_check_legacy(rsa, pubrsa); ++ if (ret != ISC_R_SUCCESS) { ++ DST_RET(ret); ++ } ++ ++ RSA_get0_key(rsa, NULL, &ex, NULL); ++ ++ if (ex == NULL) { ++ DST_RET(dst__openssl_toresult(DST_R_INVALIDPRIVATEKEY)); ++ } ++ if (BN_num_bits(ex) > RSA_MAX_PUBEXP_BITS) { ++ DST_RET(ISC_R_RANGE); ++ } ++ ++err: ++ if (rsa != NULL) { ++ RSA_free(rsa); ++ } ++ if (pubrsa != NULL) { ++ RSA_free(pubrsa); ++ } ++ return ret; ++} + #else + static isc_result_t + rsa_check(EVP_PKEY *pkey, EVP_PKEY *pubpkey) { +@@ -1097,6 +1143,10 @@ rsa_check(EVP_PKEY *pkey, EVP_PKEY *pubpkey) { + } + } + ++ if (BN_num_bits(e1) > RSA_MAX_PUBEXP_BITS) { ++ DST_RET(ISC_R_RANGE); ++ } ++ + if (EVP_PKEY_eq(pkey, pubpkey) == 1) { + DST_RET(ISC_R_SUCCESS); + } +@@ -1119,6 +1169,10 @@ err: + } + #endif /* OPENSSL_VERSION_NUMBER < 0x30000000L || OPENSSL_API_LEVEL < 30000 */ + ++static isc_result_t ++opensslrsa_fromlabel(dst_key_t *key, const char *engine, const char *label, ++ const char *pin); ++ + static isc_result_t + opensslrsa_parse(dst_key_t *key, isc_lex_t *lexer, dst_key_t *pub) { + dst_private_t priv; +@@ -1131,12 +1185,8 @@ opensslrsa_parse(dst_key_t *key, isc_lex_t *lexer, dst_key_t *pub) { + OSSL_PARAM *params = NULL; + EVP_PKEY_CTX *ctx = NULL; + #endif /* OPENSSL_VERSION_NUMBER < 0x30000000L || OPENSSL_API_LEVEL < 30000 */ +-#if !defined(OPENSSL_NO_ENGINE) && OPENSSL_API_LEVEL < 30000 +- const BIGNUM *ex = NULL; +- ENGINE *ep = NULL; +- const char *engine = NULL; +-#endif /* if !defined(OPENSSL_NO_ENGINE) && OPENSSL_API_LEVEL < 30000 */ + isc_mem_t *mctx = NULL; ++ const char *engine = NULL; + const char *label = NULL; + EVP_PKEY *pkey = NULL; + BIGNUM *n = NULL, *e = NULL, *d = NULL; +@@ -1193,46 +1243,7 @@ opensslrsa_parse(dst_key_t *key, isc_lex_t *lexer, dst_key_t *pub) { + * See if we can fetch it. + */ + if (label != NULL) { +-#if !defined(OPENSSL_NO_ENGINE) && OPENSSL_API_LEVEL < 30000 +- if (engine == NULL) { +- DST_RET(DST_R_NOENGINE); +- } +- ep = dst__openssl_getengine(engine); +- if (ep == NULL) { +- DST_RET(dst__openssl_toresult(DST_R_NOENGINE)); +- } +- pkey = ENGINE_load_private_key(ep, label, NULL, NULL); +- if (pkey == NULL) { +- DST_RET(dst__openssl_toresult2("ENGINE_load_private_" +- "key", +- ISC_R_NOTFOUND)); +- } +- key->engine = isc_mem_strdup(key->mctx, engine); +- key->label = isc_mem_strdup(key->mctx, label); +- +- rsa = EVP_PKEY_get1_RSA(pkey); +- if (rsa == NULL) { +- DST_RET(dst__openssl_toresult(DST_R_OPENSSLFAILURE)); +- } +- if (rsa_check(rsa, pubrsa) != ISC_R_SUCCESS) { +- DST_RET(dst__openssl_toresult(DST_R_INVALIDPRIVATEKEY)); +- } +- RSA_get0_key(rsa, NULL, &ex, NULL); +- +- if (ex == NULL) { +- DST_RET(dst__openssl_toresult(DST_R_INVALIDPRIVATEKEY)); +- } +- if (BN_num_bits(ex) > RSA_MAX_PUBEXP_BITS) { +- DST_RET(ISC_R_RANGE); +- } +- +- key->key_size = EVP_PKEY_bits(pkey); +- key->keydata.pkey = pkey; +- pkey = NULL; +- DST_RET(ISC_R_SUCCESS); +-#else /* if !defined(OPENSSL_NO_ENGINE) && OPENSSL_API_LEVEL < 30000 */ +- DST_RET(DST_R_NOENGINE); +-#endif /* if !defined(OPENSSL_NO_ENGINE) && OPENSSL_API_LEVEL < 30000 */ ++ DST_RET(opensslrsa_fromlabel(key, engine, label, NULL)); + } + + for (i = 0; i < priv.nelements; i++) { +@@ -1321,9 +1332,14 @@ opensslrsa_parse(dst_key_t *key, isc_lex_t *lexer, dst_key_t *pub) { + BN_clear_free(iqmp); + } + } +- if (rsa_check(rsa, pubrsa) != ISC_R_SUCCESS) { ++ if (rsa_check_legacy(rsa, pubrsa) != ISC_R_SUCCESS) { + DST_RET(dst__openssl_toresult(DST_R_INVALIDPRIVATEKEY)); + } ++ ++ if (BN_num_bits(e) > RSA_MAX_PUBEXP_BITS) { ++ DST_RET(ISC_R_RANGE); ++ } ++ + #else + bld = OSSL_PARAM_BLD_new(); + if (bld == NULL) { +@@ -1390,17 +1406,12 @@ opensslrsa_parse(dst_key_t *key, isc_lex_t *lexer, dst_key_t *pub) { + DST_RET(dst__openssl_toresult(DST_R_OPENSSLFAILURE)); + } + +- if (rsa_check(pkey, pub != NULL ? pub->keydata.pkey : NULL) != +- ISC_R_SUCCESS) +- { +- DST_RET(dst__openssl_toresult(DST_R_INVALIDPRIVATEKEY)); ++ ret = rsa_check(pkey, pub != NULL ? pub->keydata.pkey : NULL); ++ if (ret != ISC_R_SUCCESS) { ++ DST_RET(ret); + } + #endif /* OPENSSL_VERSION_NUMBER < 0x30000000L || OPENSSL_API_LEVEL < 30000 */ + +- if (BN_num_bits(e) > RSA_MAX_PUBEXP_BITS) { +- DST_RET(ISC_R_RANGE); +- } +- + key->key_size = BN_num_bits(n); + key->keydata.pkey = pkey; + pkey = NULL; +@@ -1464,69 +1475,30 @@ err: + static isc_result_t + opensslrsa_fromlabel(dst_key_t *key, const char *engine, const char *label, + const char *pin) { +-#if !defined(OPENSSL_NO_ENGINE) && OPENSSL_API_LEVEL < 30000 +- ENGINE *e = NULL; + isc_result_t ret = ISC_R_SUCCESS; + EVP_PKEY *pkey = NULL, *pubpkey = NULL; +- RSA *rsa = NULL, *pubrsa = NULL; +- const BIGNUM *ex = NULL; + + UNUSED(pin); + +- if (engine == NULL) { +- DST_RET(DST_R_NOENGINE); +- } +- e = dst__openssl_getengine(engine); +- if (e == NULL) { +- DST_RET(dst__openssl_toresult(DST_R_NOENGINE)); +- } +- +- pubpkey = ENGINE_load_public_key(e, label, NULL, NULL); +- if (pubpkey == NULL) { +- DST_RET(dst__openssl_toresult2("ENGINE_load_public_key", +- DST_R_OPENSSLFAILURE)); +- } +- pubrsa = EVP_PKEY_get1_RSA(pubpkey); +- if (pubrsa == NULL) { +- DST_RET(dst__openssl_toresult(DST_R_OPENSSLFAILURE)); +- } ++ ret = dst__openssl_fromlabel(EVP_PKEY_RSA, engine, label, pin, ++ &pubpkey, &pkey); ++ if (ret != ISC_R_SUCCESS) ++ DST_RET(ret); + +- pkey = ENGINE_load_private_key(e, label, NULL, NULL); +- if (pkey == NULL) { +- DST_RET(dst__openssl_toresult2("ENGINE_load_private_key", +- DST_R_OPENSSLFAILURE)); +- } ++ ret = rsa_check(pkey, pubpkey); ++ if (ret != ISC_R_SUCCESS) ++ DST_RET(ret); + +- key->engine = isc_mem_strdup(key->mctx, engine); ++ if (engine != NULL) ++ key->engine = isc_mem_strdup(key->mctx, engine); ++ else ++ key->engine = NULL; + key->label = isc_mem_strdup(key->mctx, label); +- +- rsa = EVP_PKEY_get1_RSA(pkey); +- if (rsa == NULL) { +- DST_RET(dst__openssl_toresult(DST_R_OPENSSLFAILURE)); +- } +- if (rsa_check(rsa, pubrsa) != ISC_R_SUCCESS) { +- DST_RET(dst__openssl_toresult(DST_R_INVALIDPRIVATEKEY)); +- } +- RSA_get0_key(rsa, NULL, &ex, NULL); +- +- if (ex == NULL) { +- DST_RET(dst__openssl_toresult(DST_R_INVALIDPRIVATEKEY)); +- } +- if (BN_num_bits(ex) > RSA_MAX_PUBEXP_BITS) { +- DST_RET(ISC_R_RANGE); +- } +- + key->key_size = EVP_PKEY_bits(pkey); + key->keydata.pkey = pkey; + pkey = NULL; + + err: +- if (rsa != NULL) { +- RSA_free(rsa); +- } +- if (pubrsa != NULL) { +- RSA_free(pubrsa); +- } + if (pkey != NULL) { + EVP_PKEY_free(pkey); + } +@@ -1534,13 +1506,6 @@ err: + EVP_PKEY_free(pubpkey); + } + return ret; +-#else /* if !defined(OPENSSL_NO_ENGINE) && OPENSSL_API_LEVEL < 30000 */ +- UNUSED(key); +- UNUSED(engine); +- UNUSED(label); +- UNUSED(pin); +- return DST_R_NOENGINE; +-#endif /* if !defined(OPENSSL_NO_ENGINE) && OPENSSL_API_LEVEL < 30000 */ + } + + static dst_func_t opensslrsa_functions = { +-- +2.50.1 + diff --git a/bind.spec b/bind.spec index 98bd9f7..910ddb4 100644 --- a/bind.spec +++ b/bind.spec @@ -80,7 +80,7 @@ License: MPL-2.0 AND ISC AND MIT AND BSD-3-Clause AND BSD-2-Clause # Before rebasing bind, ensure bind-dyndb-ldap is ready to be rebuild and use side-tag with it. # Updating just bind will cause freeipa-dns-server package to be uninstallable. Version: 9.18.33 -Release: 4%{?dist} +Release: 5%{?dist} Epoch: 32 Url: https://www.isc.org/downloads/bind/ # @@ -127,6 +127,7 @@ Patch28: bind-9.20-nsupdate-tls.patch Patch29: bind-9.20-nsupdate-tls-doc.patch # Test suport for patch28 nsupdate Patch30: bind-9.20-nsupdate-tls-test.patch +Patch31: bind-9.18-pkcs11-provider.patch # https://gitlab.isc.org/isc-projects/bind9/-/merge_requests/10562 # https://gitlab.isc.org/isc-projects/bind9/-/issues/5357 # downstream patch fixing bind-dyndb-ldap causing issue @@ -918,6 +919,9 @@ fi; %endif %changelog +* Tue Jun 10 2025 Petr Menšík - 32:9.18.33-5 +- Backport support for OpenSSL provider required for PKCS11 labels + * Tue Jun 10 2025 Petr Mensik - 32:9.18.33-4 - Prevent name.c:670 attributes assertion failed (RHEL-30407) - Add extra checks for relative names