From 5efcb6a5a90898d029e1f383dc16ce2678735b46 Mon Sep 17 00:00:00 2001 From: Fedor Vorobev Date: Wed, 28 Jan 2026 15:35:59 +0100 Subject: [PATCH] Backport fix for manual DNSSEC key rolllovers. Resolves: RHEL-144421 --- bind-9.20-robust-key-rollovers-tests.patch | 144 +++++++++++++++++++++ bind-9.20-robust-key-rollovers.patch | 97 ++++++++++++++ bind.spec | 8 +- 3 files changed, 248 insertions(+), 1 deletion(-) create mode 100644 bind-9.20-robust-key-rollovers-tests.patch create mode 100644 bind-9.20-robust-key-rollovers.patch diff --git a/bind-9.20-robust-key-rollovers-tests.patch b/bind-9.20-robust-key-rollovers-tests.patch new file mode 100644 index 0000000..9e8cb77 --- /dev/null +++ b/bind-9.20-robust-key-rollovers-tests.patch @@ -0,0 +1,144 @@ +diff --git a/bin/tests/system/nsec3/ns3/named.conf.in b/bin/tests/system/nsec3/ns3/named.conf.in +index 022e9421bc..2bee4f898a 100644 +--- a/bin/tests/system/nsec3/ns3/named.conf.in ++++ b/bin/tests/system/nsec3/ns3/named.conf.in +@@ -68,7 +68,7 @@ zone "nsec-to-nsec3.kasp" { + + /* + * This zone starts with NSEC, but will be reconfigured to use NSEC3. +- * This should work despite the incompatible RSAHSHA1 algorithm, ++ * This should work despite the incompatible RSASHA1 algorithm, + * because the DS is still in hidden state. + */ + zone "rsasha1-to-nsec3.kasp" { +@@ -92,7 +92,7 @@ zone "rsasha1-to-nsec3-wait.kasp" { + + /* + * This zone starts with NSEC3, but will be reconfigured to use NSEC with an +- * NSEC only algorithm. This should work despite the incompatible RSAHSHA1 ++ * NSEC only algorithm. This should work despite the incompatible RSASHA1 + * algorithm, because the DS is still in hidden state. + */ + zone "nsec3-to-rsasha1.kasp" { +diff --git a/bin/tests/system/nsec3/ns3/setup.sh b/bin/tests/system/nsec3/ns3/setup.sh +index 5ddcfc01b0..3cd7210192 100644 +--- a/bin/tests/system/nsec3/ns3/setup.sh ++++ b/bin/tests/system/nsec3/ns3/setup.sh +@@ -35,24 +35,23 @@ if ( + cd .. + $SHELL ../testcrypto.sh -q RSASHA1 + ); then +- for zn in rsasha1-to-nsec3 rsasha1-to-nsec3-wait nsec3-to-rsasha1 \ +- nsec3-to-rsasha1-ds; do +- setup "${zn}.kasp" +- done +- + longago="now-1y" +- keytimes="-P ${longago} -A ${longago}" ++ keytimes="-P ${longago} -A ${longago} -P sync ${longago}" + O="omnipresent" + +- zone="rsasha1-to-nsec3-wait.kasp" +- CSK=$($KEYGEN -k "rsasha1" -l named.conf $keytimes $zone 2>keygen.out.$zone) +- echo_i "Created key file $CSK" +- $SETTIME -s -g $O -k $O $longago -r $O $longago -z $O $longago -d $O $longago "$CSK" >settime.out.$zone 2>&1 ++ for zn in nsec3-to-rsasha1 nsec3-to-rsasha1-ds; do ++ setup "${zn}.kasp" ++ CSK=$($KEYGEN -k "default" -l named.conf $keytimes $zone 2>keygen.out.$zone) ++ $SETTIME -s -g $O -k $O $longago -r $O $longago -z $O $longago -d $O $longago "$CSK" >settime.out.$zone 2>&1 ++ cat $CSK.key >>$zonefile ++ done + +- zone="nsec3-to-rsasha1-ds.kasp" +- CSK=$($KEYGEN -k "default" -l named.conf $keytimes $zone 2>keygen.out.$zone) +- echo_i "Created key file $CSK" +- $SETTIME -s -g $O -k $O $longago -r $O $longago -z $O $longago -d $O $longago "$CSK" >settime.out.$zone 2>&1 ++ for zn in rsasha1-to-nsec3 rsasha1-to-nsec3-wait; do ++ setup "${zn}.kasp" ++ CSK=$($KEYGEN -k "rsasha1" -l named.conf $keytimes $zone 2>keygen.out.$zone) ++ $SETTIME -s -g $O -k $O $longago -r $O $longago -z $O $longago -d $O $longago "$CSK" >settime.out.$zone 2>&1 ++ cat $CSK.key >>$zonefile ++ done + else + echo_i "skip: skip rsasha1 zones - signing with RSASHA1 not supported" + fi +diff --git a/bin/tests/system/nsec3/tests.sh b/bin/tests/system/nsec3/tests.sh +index 6cb28583c6..b8e9152cf9 100644 +--- a/bin/tests/system/nsec3/tests.sh ++++ b/bin/tests/system/nsec3/tests.sh +@@ -80,10 +80,10 @@ set_key_rsasha1_values() { + set_zonesigning $1 "yes" + + set_keystate $1 "GOAL" "omnipresent" +- set_keystate $1 "STATE_DNSKEY" "rumoured" +- set_keystate $1 "STATE_KRRSIG" "rumoured" +- set_keystate $1 "STATE_ZRRSIG" "rumoured" +- set_keystate $1 "STATE_DS" "hidden" ++ set_keystate $1 "STATE_DNSKEY" "omnipresent" ++ set_keystate $1 "STATE_KRRSIG" "omnipresent" ++ set_keystate $1 "STATE_ZRRSIG" "omnipresent" ++ set_keystate $1 "STATE_DS" "omnipresent" + } + + # Update the key states. +@@ -251,21 +251,21 @@ if ($SHELL ../testcrypto.sh -q RSASHA1); then + set_zone_policy "rsasha1-to-nsec3-wait.kasp" "rsasha1" 1 3600 + set_server "ns3" "10.53.0.3" + set_key_rsasha1_values "KEY1" +- set_key_states "KEY1" "omnipresent" "omnipresent" "omnipresent" "omnipresent" "omnipresent" + echo_i "initial check zone ${ZONE}" + check_nsec + + # Zone: nsec3-to-rsasha1.kasp. + set_zone_policy "nsec3-to-rsasha1.kasp" "nsec3" 1 3600 + set_server "ns3" "10.53.0.3" +- set_key_rsasha1_values "KEY1" ++ set_key_default_values "KEY1" ++ set_key_states "KEY1" "omnipresent" "omnipresent" "omnipresent" "omnipresent" "omnipresent" + echo_i "initial check zone ${ZONE}" + check_nsec3 + + # Zone: nsec3-to-rsasha1-ds.kasp. + set_zone_policy "nsec3-to-rsasha1-ds.kasp" "nsec3" 1 3600 + set_server "ns3" "10.53.0.3" +- set_key_rsasha1_values "KEY1" ++ set_key_default_values "KEY1" + set_key_states "KEY1" "omnipresent" "omnipresent" "omnipresent" "omnipresent" "omnipresent" + echo_i "initial check zone ${ZONE}" + check_nsec3 +@@ -385,12 +385,10 @@ if ($SHELL ../testcrypto.sh -q RSASHA1); then + set_zone_policy "rsasha1-to-nsec3.kasp" "nsec3" 2 3600 + set_server "ns3" "10.53.0.3" + set_key_rsasha1_values "KEY1" +- set_key_states "KEY1" "hidden" "unretentive" "unretentive" "unretentive" "hidden" +- set_keysigning "KEY1" "no" +- set_zonesigning "KEY1" "no" ++ set_key_states "KEY1" "hidden" "omnipresent" "omnipresent" "omnipresent" "omnipresent" + set_key_default_values "KEY2" + echo_i "check zone ${ZONE} after reconfig" +- check_nsec3 ++ check_nsec + + # Zone: rsasha1-to-nsec3-wait.kasp. + set_zone_policy "rsasha1-to-nsec3-wait.kasp" "nsec3" 2 3600 +@@ -406,10 +404,9 @@ if ($SHELL ../testcrypto.sh -q RSASHA1); then + set_nsec3param "1" "0" "0" + set_server "ns3" "10.53.0.3" + set_key_default_values "KEY1" +- set_key_states "KEY1" "hidden" "unretentive" "unretentive" "unretentive" "hidden" +- set_keysigning "KEY1" "no" +- set_zonesigning "KEY1" "no" ++ set_key_states "KEY1" "hidden" "omnipresent" "omnipresent" "omnipresent" "omnipresent" + set_key_rsasha1_values "KEY2" ++ set_key_states "KEY2" "omnipresent" "rumoured" "rumoured" "rumoured" "hidden" + echo_i "check zone ${ZONE} after reconfig" + check_nsec + +@@ -420,6 +417,7 @@ if ($SHELL ../testcrypto.sh -q RSASHA1); then + set_key_default_values "KEY1" + set_key_states "KEY1" "hidden" "omnipresent" "omnipresent" "omnipresent" "omnipresent" + set_key_rsasha1_values "KEY2" ++ set_key_states "KEY2" "omnipresent" "rumoured" "rumoured" "rumoured" "hidden" + echo_i "check zone ${ZONE} after reconfig" + check_nsec + diff --git a/bind-9.20-robust-key-rollovers.patch b/bind-9.20-robust-key-rollovers.patch new file mode 100644 index 0000000..9d87306 --- /dev/null +++ b/bind-9.20-robust-key-rollovers.patch @@ -0,0 +1,97 @@ +diff --git a/lib/dns/keymgr.c b/lib/dns/keymgr.c +index cbcd3c992e..fc92f9dbf5 100644 +--- a/lib/dns/keymgr.c ++++ b/lib/dns/keymgr.c +@@ -1225,19 +1225,18 @@ static bool + keymgr_transition_allowed(dns_dnsseckeylist_t *keyring, dns_dnsseckey_t *key, + int type, dst_key_state_t next_state, + bool secure_to_insecure) { ++ bool rule1a, rule1b, rule2a, rule2b, rule3a, rule3b; ++ rule1a = keymgr_have_ds(keyring, key, type, NA, secure_to_insecure); ++ rule1b = keymgr_have_ds(keyring, key, type, next_state, secure_to_insecure); ++ rule2a = keymgr_have_dnskey(keyring, key, type, NA); ++ rule2b = keymgr_have_dnskey(keyring, key, type, next_state); ++ rule3a = keymgr_have_rrsig(keyring, key, type, NA); ++ rule3b = keymgr_have_rrsig(keyring, key, type, next_state); ++ + /* Debug logging. */ + if (isc_log_wouldlog(dns_lctx, ISC_LOG_DEBUG(1))) { +- bool rule1a, rule1b, rule2a, rule2b, rule3a, rule3b; + char keystr[DST_KEY_FORMATSIZE]; + dst_key_format(key->key, keystr, sizeof(keystr)); +- rule1a = keymgr_have_ds(keyring, key, type, NA, +- secure_to_insecure); +- rule1b = keymgr_have_ds(keyring, key, type, next_state, +- secure_to_insecure); +- rule2a = keymgr_have_dnskey(keyring, key, type, NA); +- rule2b = keymgr_have_dnskey(keyring, key, type, next_state); +- rule3a = keymgr_have_rrsig(keyring, key, type, NA); +- rule3b = keymgr_have_rrsig(keyring, key, type, next_state); + isc_log_write( + dns_lctx, DNS_LOGCATEGORY_DNSSEC, DNS_LOGMODULE_DNSSEC, + ISC_LOG_DEBUG(1), +@@ -1250,30 +1249,40 @@ keymgr_transition_allowed(dns_dnsseckeylist_t *keyring, dns_dnsseckey_t *key, + rule3a ? "true" : "false", rule3b ? "true" : "false"); + } + +- return +- /* +- * Rule 1: There must be a DS at all times. +- * First check the current situation: if the rule check fails, +- * we allow the transition to attempt to move us out of the +- * invalid state. If the rule check passes, also check if +- * the next state is also still a valid situation. +- */ +- (!keymgr_have_ds(keyring, key, type, NA, secure_to_insecure) || +- keymgr_have_ds(keyring, key, type, next_state, +- secure_to_insecure)) && +- /* +- * Rule 2: There must be a DNSKEY at all times. Again, first +- * check the current situation, then assess the next state. +- */ +- (!keymgr_have_dnskey(keyring, key, type, NA) || +- keymgr_have_dnskey(keyring, key, type, next_state)) && +- /* +- * Rule 3: There must be RRSIG records at all times. Again, +- * first check the current situation, then assess the next +- * state. +- */ +- (!keymgr_have_rrsig(keyring, key, type, NA) || +- keymgr_have_rrsig(keyring, key, type, next_state)); ++ /* ++ * Rule checking: ++ * First check the current situation: if the rule check fails, ++ * we allow the transition to attempt to move us out of the ++ * invalid state. If the rule check passes, also check if ++ * the next state is also still a valid situation. ++ */ ++ char keystr2[DST_KEY_FORMATSIZE]; ++ dst_key_format(key->key, keystr2, sizeof(keystr2)); ++ ++ /* ++ * Rule 1: There must be a DS at all times. ++ */ ++ if (!rule1a && !rule1b && next_state == UNRETENTIVE) { ++ return false; ++ } ++ /* ++ * Rule 2: There must be a DNSKEY at all times. Again, first ++ * check the current situation, then assess the next state. ++ */ ++ if (!rule2a && !rule2b && next_state == UNRETENTIVE) { ++ return false; ++ } ++ /* ++ * Rule 3: There must be RRSIG records at all times. Again, ++ * first check the current situation, then assess the next ++ * state. ++ */ ++ if (!rule3a && !rule3b && next_state == UNRETENTIVE) { ++ return false; ++ } ++ ++ return (!rule1a || rule1b) && (!rule2a || rule2b) && ++ (!rule3a || rule3b); + } + + /* diff --git a/bind.spec b/bind.spec index 6a9b260..ade1f2d 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: 15%{?dist} +Release: 16%{?dist} Epoch: 32 Url: https://www.isc.org/downloads/bind/ # @@ -157,6 +157,9 @@ Patch225: bind-9.18-CVE-2025-40780.patch Patch226: bind-9.20-CVE-2025-8677-dual-signing.patch # https://gitlab.isc.org/isc-projects/bind9/-/merge_requests/11195 Patch227: bind-9.20-CVE-2025-8677-dual-signing-test.patch +# https://gitlab.isc.org/isc-projects/bind9/-/merge_requests/11329 +Patch228: bind-9.20-robust-key-rollovers.patch +Patch229: bind-9.20-robust-key-rollovers-tests.patch %{?systemd_ordering} # https://fedoraproject.org/wiki/Changes/RPMSuportForSystemdSysusers @@ -958,6 +961,9 @@ fi; %endif %changelog +* Wed Jan 28 2026 Fedor Vorobev - 32:9.18.33-16 +- Backport fix for manual DNSSEC key rolllovers. (RHEL-144421) + * Wed Jan 28 2026 Petr Menšík - 32:9.18.33-15 - Add forgotten _libdir/named into bind-chroot tmpfiles (RHEL-132053)