From 6e8e02241057d773c8c6efbf346bd69f6e1a73b2 Mon Sep 17 00:00:00 2001 From: eabdullin Date: Tue, 11 Nov 2025 22:19:02 +0000 Subject: [PATCH] import UBI bind-9.18.33-10.el10_1.2 --- ...9.18-configurable-additional-records.patch | 169 ++++ bind-9.18-dig-idn-input-always-test.patch | 76 ++ bind-9.18-dig-idn-input-always.patch | 98 ++ bind-9.18-partial-additional-records.patch | 54 ++ bind-9.18-pkcs11-provider.patch | 904 ++++++++++++++++++ bind.spec | 40 +- named.logrotate | 4 +- 7 files changed, 1336 insertions(+), 9 deletions(-) create mode 100644 bind-9.18-configurable-additional-records.patch create mode 100644 bind-9.18-dig-idn-input-always-test.patch create mode 100644 bind-9.18-dig-idn-input-always.patch create mode 100644 bind-9.18-partial-additional-records.patch create mode 100644 bind-9.18-pkcs11-provider.patch diff --git a/bind-9.18-configurable-additional-records.patch b/bind-9.18-configurable-additional-records.patch new file mode 100644 index 0000000..260148b --- /dev/null +++ b/bind-9.18-configurable-additional-records.patch @@ -0,0 +1,169 @@ +From cb31d547cd2861230dd209ce2322d96e28369bcb Mon Sep 17 00:00:00 2001 +From: Petr Mensik +Date: Mon, 16 Jun 2025 19:36:13 +0200 +Subject: [PATCH] Support runtime configurable limit of additional records + +Use environment variable NAMED_MAXADDITIONAL to change default built-in +limit. Uses environment variable to avoid the need to support the variable +option in the more recent versions and after upgrades. + +Use debug 1 verbosity for logging parsed limit at the start, but not +changing production logs. +--- + bin/named/main.c | 5 +++++ + bin/named/named.rst | 9 +++++++++ + lib/ns/include/ns/server.h | 13 +++++++++++++ + lib/ns/query.c | 5 +++-- + lib/ns/server.c | 25 +++++++++++++++++++++++++ + 5 files changed, 55 insertions(+), 2 deletions(-) + +diff --git a/bin/named/main.c b/bin/named/main.c +index c8ee00d..ea31c9f 100644 +--- a/bin/named/main.c ++++ b/bin/named/main.c +@@ -1392,6 +1392,11 @@ setup(void) { + if (transferstuck) { + ns_server_setoption(sctx, NS_SERVER_TRANSFERSTUCK, true); + } ++ isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL, ++ NAMED_LOGMODULE_SERVER, ISC_LOG_DEBUG(1), ++ "using max %u additional records", ++ ns_server_getmaxadditionalrecords(sctx)); ++ + } + + static void +diff --git a/bin/named/named.rst b/bin/named/named.rst +index 34325cc..d3e3740 100644 +--- a/bin/named/named.rst ++++ b/bin/named/named.rst +@@ -254,6 +254,15 @@ Files + |named_pid| + The default process-id file. + ++Environment ++~~~~~~~~~~~ ++ ++NAMED_MAXADDITIONAL ++ Red Hat specific extension. Accepts numeric value of maximal NS ++ records, which would get fetched additional addresses. Default ++ value is 13. Allows runtime configurable limit introduced in ++ CVE-2024-11187 fixes. ++ + Notes + ~~~~~ + +diff --git a/lib/ns/include/ns/server.h b/lib/ns/include/ns/server.h +index 6e4309b..963c189 100644 +--- a/lib/ns/include/ns/server.h ++++ b/lib/ns/include/ns/server.h +@@ -128,6 +128,8 @@ struct ns_server { + isc_stats_t *tcpoutstats4; + isc_stats_t *tcpinstats6; + isc_stats_t *tcpoutstats6; ++ ++ unsigned int max_additional_records; + }; + + struct ns_altsecret { +@@ -172,6 +174,17 @@ ns_server_setserverid(ns_server_t *sctx, const char *serverid); + *\li 'sctx' is valid. + */ + ++unsigned int ++ns_server_getmaxadditionalrecords(ns_server_t *sctx); ++/*%< ++ * Returns the maximal number of records with additional addresses ++ * provided. ++ * ++ * Requires: ++ *\li 'sctx' is valid. ++ */ ++ ++ + void + ns_server_setoption(ns_server_t *sctx, unsigned int option, bool value); + /*%< +diff --git a/lib/ns/query.c b/lib/ns/query.c +index 11d2520..f5447e5 100644 +--- a/lib/ns/query.c ++++ b/lib/ns/query.c +@@ -2099,7 +2099,7 @@ addname: + if (client->additionaldepth++ < client->view->max_restarts) { + eresult = dns_rdataset_additionaldata( + trdataset, fname, query_additional_cb, qctx, +- DNS_RDATASET_MAXADDITIONAL); ++ client->sctx->max_additional_records); + } + client->additionaldepth--; + } +@@ -2199,7 +2199,8 @@ regular: + * We don't care if dns_rdataset_additionaldata() fails. + */ + (void)dns_rdataset_additionaldata(rdataset, name, query_additional_cb, +- qctx, DNS_RDATASET_MAXADDITIONAL); ++ qctx, ++ client->sctx->max_additional_records); + CTRACE(ISC_LOG_DEBUG(3), "query_additional: done"); + } + +diff --git a/lib/ns/server.c b/lib/ns/server.c +index 5f1de47..add6f40 100644 +--- a/lib/ns/server.c ++++ b/lib/ns/server.c +@@ -19,6 +19,7 @@ + #include + #include + ++#include + #include + #include + +@@ -35,6 +36,22 @@ + RUNTIME_CHECK(result == ISC_R_SUCCESS); \ + } while (0) + ++/* ++ * CVE-2024-11187 introduced a limit on maximal number of records, ++ * for which additional records would be fetched. Make this limit ++ * configurable runtime only by environment. ++ */ ++static size_t ++initialize_maxadditional(void) { ++ const char *limits; ++ ++ limits = getenv("NAMED_MAXADDITIONAL"); ++ if (limits != NULL) { ++ return strtol(limits, NULL, 10); ++ } ++ return DNS_RDATASET_MAXADDITIONAL; ++} ++ + isc_result_t + ns_server_create(isc_mem_t *mctx, ns_matchview_t matchingview, + ns_server_t **sctxp) { +@@ -99,6 +116,7 @@ ns_server_create(isc_mem_t *mctx, ns_matchview_t matchingview, + + sctx->udpsize = 1232; + sctx->transfer_tcp_message_size = 20480; ++ sctx->max_additional_records = initialize_maxadditional(); + + sctx->fuzztype = isc_fuzz_none; + sctx->fuzznotify = NULL; +@@ -235,6 +253,13 @@ ns_server_setserverid(ns_server_t *sctx, const char *serverid) { + return ISC_R_SUCCESS; + } + ++unsigned int ++ns_server_getmaxadditionalrecords(ns_server_t *sctx) { ++ REQUIRE(SCTX_VALID(sctx)); ++ ++ return sctx->max_additional_records; ++} ++ + void + ns_server_setoption(ns_server_t *sctx, unsigned int option, bool value) { + REQUIRE(SCTX_VALID(sctx)); +-- +2.50.1 + diff --git a/bind-9.18-dig-idn-input-always-test.patch b/bind-9.18-dig-idn-input-always-test.patch new file mode 100644 index 0000000..c2a287b --- /dev/null +++ b/bind-9.18-dig-idn-input-always-test.patch @@ -0,0 +1,76 @@ +From 12f50726b6bd8f6b3ed6709695e0f6893bc865c6 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Petr=20Men=C5=A1=C3=ADk?= +Date: Tue, 16 Sep 2025 11:46:03 +0200 +Subject: [PATCH] Fix expectations on idna system test + +IDNA tests always redirect output into the file. That means its +behaviour has changed and is now processing IDN input by default and +just disables IDN output by default. + +New behaviour when redirected is the same as +idnin +noidnout, but does +not fail hard on input errors. +--- + bin/tests/system/idna/tests.sh | 12 ++++++------ + 1 file changed, 6 insertions(+), 6 deletions(-) + +diff --git a/bin/tests/system/idna/tests.sh b/bin/tests/system/idna/tests.sh +index 398b7e1..37f02b1 100644 +--- a/bin/tests/system/idna/tests.sh ++++ b/bin/tests/system/idna/tests.sh +@@ -194,7 +194,7 @@ idna_enabled_test() { + # Note that ASCII characters are converted to lower-case. + + text="Checking valid non-ASCII label" +- idna_test "$text" "" "München" "M\195\188nchen." ++ idna_test "$text" "" "München" "xn--mnchen-3ya." + idna_test "$text" "+noidnin +noidnout" "München" "M\195\188nchen." + idna_test "$text" "+noidnin +idnout" "München" "M\195\188nchen." + idna_test "$text" "+idnin +noidnout" "München" "xn--mnchen-3ya." +@@ -218,7 +218,7 @@ idna_enabled_test() { + # for the valid U-label. + + text="Checking that non-transitional IDNA processing is used" +- idna_test "$text" "" "faß.de" "fa\195\159.de." ++ idna_test "$text" "" "faß.de" "xn--fa-hia.de." + idna_test "$text" "+noidnin +noidnout" "faß.de" "fa\195\159.de." + idna_test "$text" "+noidnin +idnout" "faß.de" "fa\195\159.de." + idna_test "$text" "+idnin +noidnout" "faß.de" "xn--fa-hia.de." +@@ -228,7 +228,7 @@ idna_enabled_test() { + # onto the Greek sigma character ("σ") in IDNA2003. + + text="Second check that non-transitional IDNA processing is used" +- idna_test "$text" "" "βόλος.com" "\206\178\207\140\206\187\206\191\207\130.com." ++ idna_test "$text" "" "βόλος.com" "xn--nxasmm1c.com." + idna_test "$text" "+noidnin +noidnout" "βόλος.com" "\206\178\207\140\206\187\206\191\207\130.com." + idna_test "$text" "+noidnin +idnout" "βόλος.com" "\206\178\207\140\206\187\206\191\207\130.com." + idna_test "$text" "+idnin +noidnout" "βόλος.com" "xn--nxasmm1c.com." +@@ -288,7 +288,7 @@ idna_enabled_test() { + idna_test "$text" "" "xn--xx" "xn--xx." + idna_test "$text" "+noidnin +noidnout" "xn--xx" "xn--xx." + idna_fail "$text" "+noidnin +idnout" "xn--xx" +- idna_fail "$text" "+idnin +noidnout" "xn--xx" ++ idna_test "$text" "+idnin +noidnout" "xn--xx" "xn--xx." + idna_fail "$text" "+idnin +idnout" "xn--xx" + + # Fake A-label - the string does not translate to anything. +@@ -297,7 +297,7 @@ idna_enabled_test() { + idna_test "$text" "" "xn--ahahah" "xn--ahahah." + idna_test "$text" "+noidnin +noidnout" "xn--ahahah" "xn--ahahah." + idna_fail "$text" "+noidnin +idnout" "xn--ahahah" +- idna_fail "$text" "+idnin +noidnout" "xn--ahahah" ++ idna_test "$text" "+idnin +noidnout" "xn--ahahah" "xn--ahahah." + idna_fail "$text" "+idnin +idnout" "xn--ahahah" + + # Too long a label. The punycode string is too long (at 64 characters). +@@ -324,7 +324,7 @@ idna_enabled_test() { + # The +[no]idnout options should not have any effect on the test. + + text="Checking invalid input U-label" +- idna_test "$text" "" "√.com" "\226\136\154.com." ++ idna_test "$text" "" "√.com" "xn--19g.com." + idna_test "$text" "+noidnin +noidnout" "√.com" "\226\136\154.com." + idna_test "$text" "+noidnin +idnout" "√.com" "\226\136\154.com." + idna_test "$text" "+idnin +noidnout" "√.com" "xn--19g.com." +-- +2.51.0 + diff --git a/bind-9.18-dig-idn-input-always.patch b/bind-9.18-dig-idn-input-always.patch new file mode 100644 index 0000000..f2fc9d7 --- /dev/null +++ b/bind-9.18-dig-idn-input-always.patch @@ -0,0 +1,98 @@ +From 17880864f96084c3816ccf7fe441c2d962cfbd92 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Petr=20Men=C5=A1=C3=ADk?= +Date: Wed, 6 Nov 2024 21:29:47 +0100 +Subject: [PATCH] Allow always IDN input in dig +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Even when stdout is non-interactive terminal, allow unicode characters +to be encoded into ACE form. Still disable IDN output, but unless ++noidnin or IDN_DISABLE=1 env is detected, consider input as locale +defined name. + +Provides more isolated change, which issue #3527 introduced similar +behavior into 9.19 with more changes. + +Ignore input IDN errors when stdout is not terminal + +Attempt to prevent visible regressions when enabling IDN on input +always. Instead of new hard failures preventing IDN decoding of input +name just use original input. + +Should make the change backward compatible. When on interactive terminal +behave the same way as before and emit hard errors. Become more +forgiving in scripts where stdout leads to script. Decoding output is +not enabled there and if input decoding fails, just use input as it was. + +Change dig manual +idnin + +Note in manual IDN input is always enabled. But it silently ignores +errors when stdout is not a terminal to prevent regressions. + +Signed-off-by: Petr Menšík +--- + bin/dig/dig.rst | 5 ++--- + bin/dig/dighost.c | 16 ++++++++++++---- + 2 files changed, 14 insertions(+), 7 deletions(-) + +diff --git a/bin/dig/dig.rst b/bin/dig/dig.rst +index 59ac9f1..89613c1 100644 +--- a/bin/dig/dig.rst ++++ b/bin/dig/dig.rst +@@ -446,9 +446,8 @@ abbreviation is unambiguous; for example, :option:`+cd` is equivalent to + This option processes [or does not process] IDN domain names on input. This requires + ``IDN SUPPORT`` to have been enabled at compile time. + +- The default is to process IDN input when standard output is a tty. +- The IDN processing on input is disabled when :program:`dig` output is redirected +- to files, pipes, and other non-tty file descriptors. ++ The default is to process IDN input. The input IDN processing errors are ignored ++ when :program:`dig` output is redirected to files, pipes, and other non-tty file descriptors. + + .. option:: +idnout, +noidnout + +diff --git a/bin/dig/dighost.c b/bin/dig/dighost.c +index 87fbb41..3a1cfa1 100644 +--- a/bin/dig/dighost.c ++++ b/bin/dig/dighost.c +@@ -604,7 +604,7 @@ dig_lookup_t * + make_empty_lookup(void) { + dig_lookup_t *looknew; + #ifdef HAVE_LIBIDN2 +- bool idn_allowed = isatty(1) ? (getenv("IDN_DISABLE") == NULL) : false; ++ bool idn_allowed = (getenv("IDN_DISABLE") == NULL); + #endif /* HAVE_LIBIDN2 */ + + debug("make_empty_lookup()"); +@@ -623,7 +623,7 @@ make_empty_lookup(void) { + .badcookie = true, + #ifdef HAVE_LIBIDN2 + .idnin = idn_allowed, +- .idnout = idn_allowed, ++ .idnout = isatty(1) && idn_allowed, + #endif /* HAVE_LIBIDN2 */ + .udpsize = -1, + .edns = -1, +@@ -4867,8 +4867,16 @@ idn_locale_to_ace(const char *src, char *dst, size_t dstlen) { + res = idn2_to_ascii_lz(src, &ascii_src, IDN2_TRANSITIONAL); + } + if (res != IDN2_OK) { +- fatal("'%s' is not a legal IDNA2008 name (%s), use +noidnin", +- src, idn2_strerror(res)); ++ if (isatty(1)) { ++ fatal("'%s' is not a legal IDNA2008 name (%s), use +noidnin", ++ src, idn2_strerror(res)); ++ } else { ++ /* In case of non-terminal output silently ignore errors ++ * in IDN input decoding. */ ++ (void)strlcpy(dst, src, dstlen); ++ resetlocale(LC_ALL); ++ return; ++ } + } + + /* +-- +2.51.0 + diff --git a/bind-9.18-partial-additional-records.patch b/bind-9.18-partial-additional-records.patch new file mode 100644 index 0000000..6834616 --- /dev/null +++ b/bind-9.18-partial-additional-records.patch @@ -0,0 +1,54 @@ +From 3f686891729c7d39d879e8b5bb1aa17d874d265d Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Petr=20Men=C5=A1=C3=ADk?= +Date: Thu, 19 Jun 2025 19:51:43 +0200 +Subject: [PATCH] Limit number of additional records fetched + +Limit number of started fetches for additional zone instead of doing +none. Keep limit of NS filled with additional records, but present at +least some if possible. + +Might help broken implementations relying on receiving addresses in the +response for NS query in authoritative zone. +--- + lib/dns/rdataset.c | 11 ++++++----- + 1 file changed, 6 insertions(+), 5 deletions(-) + +diff --git a/lib/dns/rdataset.c b/lib/dns/rdataset.c +index 532e49a..bfa8e37 100644 +--- a/lib/dns/rdataset.c ++++ b/lib/dns/rdataset.c +@@ -581,6 +581,7 @@ dns_rdataset_additionaldata(dns_rdataset_t *rdataset, + size_t limit) { + dns_rdata_t rdata = DNS_RDATA_INIT; + isc_result_t result; ++ size_t n = 0; + + /* + * For each rdata in rdataset, call 'add' for each name and type in the +@@ -590,10 +591,6 @@ dns_rdataset_additionaldata(dns_rdataset_t *rdataset, + REQUIRE(DNS_RDATASET_VALID(rdataset)); + REQUIRE((rdataset->attributes & DNS_RDATASETATTR_QUESTION) == 0); + +- if (limit != 0 && dns_rdataset_count(rdataset) > limit) { +- return DNS_R_TOOMANYRECORDS; +- } +- + result = dns_rdataset_first(rdataset); + if (result != ISC_R_SUCCESS) { + return result; +@@ -603,7 +600,11 @@ dns_rdataset_additionaldata(dns_rdataset_t *rdataset, + dns_rdataset_current(rdataset, &rdata); + result = dns_rdata_additionaldata(&rdata, owner_name, add, arg); + if (result == ISC_R_SUCCESS) { +- result = dns_rdataset_next(rdataset); ++ if (limit != 0 && ++n >= limit) { ++ result = DNS_R_TOOMANYRECORDS; ++ } else { ++ result = dns_rdataset_next(rdataset); ++ } + } + dns_rdata_reset(&rdata); + } while (result == ISC_R_SUCCESS); +-- +2.50.1 + 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 221837a..744cf11 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}.2 +Release: 10%{?dist}.2 Epoch: 32 Url: https://www.isc.org/downloads/bind/ # @@ -127,21 +127,31 @@ 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 Patch32: bind-9.21-resume-qmin-cname.patch # downstream only, extra check for above change, RHEL-30407 Patch33: bind-9.18-query-fname-relative.patch +# https://gitlab.isc.org/isc-projects/bind9/-/merge_requests/10611 +Patch34: bind-9.18-partial-additional-records.patch +# downstream only, RHEL-84006 +Patch35: bind-9.18-configurable-additional-records.patch +# https://gitlab.isc.org/isc-projects/bind9/-/merge_requests/9723 +# downstream only +Patch221: bind-9.18-dig-idn-input-always.patch +# downstream only too +Patch222: bind-9.18-dig-idn-input-always-test.patch # https://gitlab.isc.org/isc-projects/bind9/commit/40c396ba2d955c32d70db04e900e40bf96519c59 # https://gitlab.isc.org/isc-projects/bind9/commit/7c5b8ef055900224f0424c341927562c5a9ebe19 -Patch34: bind-9.18-CVE-2025-8677.patch +Patch223: bind-9.18-CVE-2025-8677.patch # https://gitlab.isc.org/isc-projects/bind9/commit/025d61bacd0f57f994a631654aff7a933d89a547 # https://gitlab.isc.org/isc-projects/bind9/commit/cd17dfe696cdf9b8ef23fbc8738de7c79f957846 # https://gitlab.isc.org/isc-projects/bind9/commit/4c6d03b0bb2ffbafcde8e8a5bc0e49908b978a72 -Patch35: bind-9.18-CVE-2025-40778.patch +Patch224: bind-9.18-CVE-2025-40778.patch # https://gitlab.isc.org/isc-projects/bind9/commit/8330b49fb90bfeae14b47b7983e9459cc2bbaffe -Patch36: bind-9.18-CVE-2025-40780.patch +Patch225: bind-9.18-CVE-2025-40780.patch # https://gitlab.isc.org/isc-projects/bind9/-/merge_requests/11194 Patch226: bind-9.20-CVE-2025-8677-dual-signing.patch # https://gitlab.isc.org/isc-projects/bind9/-/merge_requests/11195 @@ -931,14 +941,32 @@ fi; %endif %changelog -* Fri Oct 31 2025 Petr Menšík - 32:9.18.33-4.2 +* Fri Oct 31 2025 Petr Menšík - 32:9.18.33-10.2 - Fix upstream reported regression in recent CVE fix (CVE-2025-8677) -* Thu Oct 23 2025 Petr Menšík - 32:9.18.33-4.1 +* Thu Oct 23 2025 Petr Menšík - 32:9.18.33-10.1 - Refuse malformed DNSKEY records (CVE-2025-8677) - Address various spoofing attacks (CVE-2025-40778) - Prevent cache poisoning due to weak PRNG (CVE-2025-40780) +* Tue Sep 16 2025 Petr Menšík - 32:9.18.33-10 +- Fix failures in idna system test (RHEL-66172) + +* Fri Sep 12 2025 Petr Menšík - 32:9.18.33-9 +- Decode IDN names on input in all situations in utilities (RHEL-66172) + +* Fri Sep 12 2025 Petr Menšík <> - 32:9.18.33-8 +- logrotate: skip if empty and remove old variants (RHEL-113942) + +* Wed Jul 09 2025 Petr Menšík - 32:9.18.33-7 +- Add runtime tunable limit by environment NAMED_MAXADDITIONAL (RHEL-84006) + +* Fri Jun 20 2025 Petr Menšík - 32:9.18.33-6 +- Change additional NS to be served partially (RHEL-84006) + +* 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 diff --git a/named.logrotate b/named.logrotate index 5df448f..5934e52 100644 --- a/named.logrotate +++ b/named.logrotate @@ -2,11 +2,9 @@ missingok su named named create 0644 named named + notifempty postrotate /usr/bin/systemctl reload named.service > /dev/null 2>&1 || true /usr/bin/systemctl reload named-chroot.service > /dev/null 2>&1 || true - /usr/bin/systemctl reload named-sdb.service > /dev/null 2>&1 || true - /usr/bin/systemctl reload named-sdb-chroot.service > /dev/null 2>&1 || true - /usr/bin/systemctl reload named-pkcs11.service > /dev/null 2>&1 || true endscript }