]> git.ipfire.org Git - thirdparty/bind9.git/commitdiff
Add NSEC3-to-NSEC rollover regression test
authorAlessio Podda <alessio@isc.org>
Mon, 18 May 2026 22:03:32 +0000 (00:03 +0200)
committerAlessio Podda <alessio@isc.org>
Tue, 30 Jun 2026 12:36:46 +0000 (12:36 +0000)
Before this commit, the NSEC3-to-NSEC transition was only tested by
test_nsec_case[nsec3-to-rsasha1-ds.kasp], which is gated by
RSASHA1_SUPPORTED.

Add another test that does not depend on RSASHA1_SUPPORTED, so this
coverage also runs when RSASHA1 signing is unavailable, such as with
newer OpenSSL configurations.

bin/tests/system/nsec3/ns3/named-common.conf.j2
bin/tests/system/nsec3/ns3/named-fips.conf.j2
bin/tests/system/nsec3/ns3/setup.sh
bin/tests/system/nsec3/tests_nsec3_initial.py
bin/tests/system/nsec3/tests_nsec3_reconfig.py

index bf9c5237eaf5be695aae2f7bac6f3f792fe78bc3..16ddd58b10f5ab112823f97259ff8f340b5e4860 100644 (file)
@@ -25,6 +25,12 @@ dnssec-policy "nsec" {
        // NSEC will be used;
 };
 
+dnssec-policy "nsec-altalg" {
+       keys {
+               csk lifetime unlimited algorithm @ALTERNATIVE_ALGORITHM@;
+       };
+};
+
 dnssec-policy "nsec3" {
        nsec3param;
 };
@@ -36,4 +42,3 @@ dnssec-policy "optout" {
 dnssec-policy "nsec3-other" {
        nsec3param iterations 0 optout yes salt-length 8;
 };
-
index 490f6ec1c7d7b29223ce7b7899d7b1bb6863c37a..32f8bb212d1f73343db9a8bb692addc426c45144 100644 (file)
@@ -1,6 +1,7 @@
 {% set reconfiged = reconfiged | default(False) %}
 {% set nsec_to_nsec3 = "nsec" if not reconfiged else "nsec3" %}
 {% set nsec3_to_nsec = "nsec3" if not reconfiged else "nsec" %}
+{% set nsec3_to_nsec_altalg = "nsec3" if not reconfiged else "nsec-altalg" %}
 {% set nsec3_change = "nsec3" if not reconfiged else "nsec3-other" %}
 {% set nsec3_from_optout = "optout" if not reconfiged else "nsec3" %}
 {% set nsec3_to_optout = "nsec3" if not reconfiged else "optout" %}
@@ -87,6 +88,18 @@ zone "nsec3-to-nsec.kasp" {
 };
 {% endif %}{# nsec3-to-nsec.kasp #}
 
+{% if "nsec3-to-nsec-altalg.kasp" in zones %}
+/*
+ * The zone starts with NSEC3, but will be reconfigured to use NSEC while
+ * rolling to the alternative DNSSEC algorithm.
+ */
+zone "nsec3-to-nsec-altalg.kasp" {
+       type primary;
+       file "nsec3-to-nsec-altalg.kasp.db";
+       dnssec-policy "@nsec3_to_nsec_altalg@";
+};
+{% endif %}{# nsec3-to-nsec-altalg.kasp #}
+
 {% if "nsec3-fails-to-load.kasp" in zones %}
 /*
  * The zone fails to load, this should not prevent shutdown.
index 03b6b81b0d0f7e34d9105c6b900af88208f3d408..522673f9c72f79572c9aa523b8f6ff558bc2f37f 100644 (file)
@@ -30,11 +30,16 @@ for zn in nsec-to-nsec3 nsec3 nsec3-other nsec3-change nsec3-to-nsec \
   setup "${zn}.kasp"
 done
 
-if [ $RSASHA1_SUPPORTED = 1 ]; then
-  longago="now-1y"
-  keytimes="-P ${longago} -A ${longago} -P sync ${longago}"
-  O="omnipresent"
+longago="now-1y"
+keytimes="-P ${longago} -A ${longago} -P sync ${longago}"
+O="omnipresent"
+
+setup "nsec3-to-nsec-altalg.kasp"
+CSK=$($KEYGEN -a $DEFAULT_ALGORITHM -L 3600 -f KSK $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
 
+if [ $RSASHA1_SUPPORTED = 1 ]; then
   for zn in nsec3-to-rsasha1 nsec3-to-rsasha1-ds; do
     setup "${zn}.kasp"
     CSK=$($KEYGEN -a $DEFAULT_ALGORITHM -L 3600 -f KSK $keytimes $zone 2>keygen.out.$zone)
index f0dacdc46176a6c44d117d734eaa2621691dd896..d855032bd131c39fa17a79bd69fb8a79fbf9b889 100644 (file)
@@ -37,6 +37,7 @@ ZONES = {
     "nsec3-dynamic-to-inline.kasp",
     "nsec3-inline-to-dynamic.kasp",
     "nsec3-to-nsec.kasp",
+    "nsec3-to-nsec-altalg.kasp",
     "nsec3-to-optout.kasp",
     "nsec3-from-optout.kasp",
     "nsec3-other.kasp",
@@ -245,6 +246,16 @@ def test_nsec_case(ns3, params):
             },
             id="nsec3-to-nsec.kasp",
         ),
+        pytest.param(
+            {
+                "zone": "nsec3-to-nsec-altalg.kasp",
+                "policy": "nsec3",
+                "key-properties": [
+                    f"csk 0 {Algorithm.default().number} {Algorithm.default().bits} goal:omnipresent dnskey:omnipresent krrsig:omnipresent zrrsig:omnipresent ds:omnipresent",
+                ],
+            },
+            id="nsec3-to-nsec-altalg.kasp",
+        ),
         pytest.param(
             {
                 "zone": "nsec3-to-optout.kasp",
index 9efc486791daf3c1bfa43e3c3262d17488d6f2fc..1a4ba812f0b94ba83544fa7d4ed3739171548bc0 100644 (file)
@@ -29,6 +29,7 @@ pytestmark = NSEC3_MARK
 # include the following zones when rendering named configs
 ZONES = {
     "nsec3-to-nsec.kasp",
+    "nsec3-to-nsec-altalg.kasp",
     "nsec-to-nsec3.kasp",
     "nsec3.kasp",
     "nsec3-dynamic.kasp",
@@ -52,6 +53,18 @@ if os.environ["RSASHA1_SUPPORTED"] == "1":
     )
 
 
+def _algorithm_from_env(prefix):
+    return Algorithm(
+        os.environ[f"{prefix}_ALGORITHM"],
+        int(os.environ[f"{prefix}_ALGORITHM_NUMBER"]),
+        int(os.environ[f"{prefix}_ALGORITHM_DST_NUMBER"]),
+        int(os.environ[f"{prefix}_BITS"]),
+    )
+
+
+ALTERNATIVE = _algorithm_from_env("ALTERNATIVE")
+
+
 def bootstrap():
     return {
         "zones": ZONES,
@@ -74,6 +87,10 @@ def after_servers_start(ns3, templates):
         zone = "rsasha1-to-nsec3-wait.kasp"
         isctest.kasp.check_dnssec_verify(ns3, zone)
 
+    # Ensure the old NSEC3 chain and default-algorithm signatures are fully
+    # established before the NSEC plus algorithm rollover begins.
+    isctest.kasp.check_dnssec_verify(ns3, "nsec3-to-nsec-altalg.kasp")
+
     # Reconfigure.
     data = {
         "reconfiged": True,
@@ -145,6 +162,18 @@ def after_servers_start(ns3, templates):
             },
             id="nsec3-to-nsec.kasp",
         ),
+        pytest.param(
+            {
+                "zone": "nsec3-to-nsec-altalg.kasp",
+                "policy": "nsec-altalg",
+                "key-properties": [
+                    f"csk 0 {Algorithm.default().number} {Algorithm.default().bits} goal:hidden dnskey:omnipresent krrsig:omnipresent zrrsig:omnipresent ds:omnipresent",
+                    f"csk 0 {ALTERNATIVE.number} {ALTERNATIVE.bits} goal:omnipresent dnskey:rumoured krrsig:rumoured zrrsig:rumoured ds:hidden",
+                ],
+            },
+            id="nsec3-to-nsec-altalg.kasp",
+            marks=isctest.mark.with_algorithm(ALTERNATIVE.name),
+        ),
     ],
 )
 def test_nsec_case(ns3, params):