From: Nicki Křížek Date: Tue, 10 Jun 2025 14:33:08 +0000 (+0200) Subject: Isolate rollover-ksk-3crowd test case X-Git-Tag: v9.21.11~38^2~4 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=bc7be041e198b2fbe731f3875a1e7e62886a332a;p=thirdparty%2Fbind9.git Isolate rollover-ksk-3crowd test case --- diff --git a/bin/tests/system/rollover-ksk-3crowd/common.py b/bin/tests/system/rollover-ksk-3crowd/common.py new file mode 120000 index 00000000000..64b8084c5ac --- /dev/null +++ b/bin/tests/system/rollover-ksk-3crowd/common.py @@ -0,0 +1 @@ +../rollover/common.py \ No newline at end of file diff --git a/bin/tests/system/rollover-ksk-3crowd/ns3/kasp.conf.j2 b/bin/tests/system/rollover-ksk-3crowd/ns3/kasp.conf.j2 new file mode 120000 index 00000000000..138fa689390 --- /dev/null +++ b/bin/tests/system/rollover-ksk-3crowd/ns3/kasp.conf.j2 @@ -0,0 +1 @@ +../../rollover-ksk-doubleksk/ns3/kasp.conf.j2 \ No newline at end of file diff --git a/bin/tests/system/rollover-ksk-3crowd/ns3/named.common.conf.j2 b/bin/tests/system/rollover-ksk-3crowd/ns3/named.common.conf.j2 new file mode 120000 index 00000000000..5dc26178cb1 --- /dev/null +++ b/bin/tests/system/rollover-ksk-3crowd/ns3/named.common.conf.j2 @@ -0,0 +1 @@ +../../rollover/ns3/named.common.conf.j2 \ No newline at end of file diff --git a/bin/tests/system/rollover-ksk-3crowd/ns3/named.conf.j2 b/bin/tests/system/rollover-ksk-3crowd/ns3/named.conf.j2 new file mode 100644 index 00000000000..ae01f2eaeba --- /dev/null +++ b/bin/tests/system/rollover-ksk-3crowd/ns3/named.conf.j2 @@ -0,0 +1,23 @@ +/* + * 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 "kasp.conf"; +include "named.common.conf"; + +zone "three-is-a-crowd.kasp" { + type primary; + file "three-is-a-crowd.kasp.db"; + inline-signing yes; + /* Use same policy as KSK rollover test zones. */ + dnssec-policy "ksk-doubleksk"; +}; diff --git a/bin/tests/system/rollover-ksk-3crowd/ns3/template.db.in b/bin/tests/system/rollover-ksk-3crowd/ns3/template.db.in new file mode 120000 index 00000000000..ce6d526285a --- /dev/null +++ b/bin/tests/system/rollover-ksk-3crowd/ns3/template.db.in @@ -0,0 +1 @@ +../../rollover/ns3/template.db.in \ No newline at end of file diff --git a/bin/tests/system/rollover-ksk-3crowd/setup.sh b/bin/tests/system/rollover-ksk-3crowd/setup.sh new file mode 100644 index 00000000000..558c77b4305 --- /dev/null +++ b/bin/tests/system/rollover-ksk-3crowd/setup.sh @@ -0,0 +1,82 @@ +#!/bin/sh -e + +# 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. + +# shellcheck source=conf.sh +. ../conf.sh + +cd "ns3" + +setup() { + zone="$1" + echo_i "setting up zone: $zone" + zonefile="${zone}.db" + infile="${zone}.db.infile" + echo "$zone" >>zones +} + +# Set in the key state files the Predecessor/Successor fields. +# Key $1 is the predecessor of key $2. +key_successor() { + id1=$(keyfile_to_key_id "$1") + id2=$(keyfile_to_key_id "$2") + echo "Predecessor: ${id1}" >>"${2}.state" + echo "Successor: ${id2}" >>"${1}.state" +} + +# Make lines shorter by storing key states in environment variables. +H="HIDDEN" +R="RUMOURED" +O="OMNIPRESENT" +U="UNRETENTIVE" + +# Test #2375, the "three is a crowd" bug, where a new key is introduced but the +# previous rollover has not finished yet. In other words, we have a key KEY2 +# that is the successor of key KEY1, and we introduce a new key KEY3 that is +# the successor of key KEY2: +# +# KEY1 < KEY2 < KEY3. +# +# The expected behavior is that all three keys remain in the zone, and not +# the bug behavior where KEY2 is removed and immediately replaced with KEY3. +# +# Set up a zone that has a KSK (KEY1) and have the successor key (KEY2) +# published as well. +setup three-is-a-crowd.kasp +# These times are the same as step3.ksk-doubleksk.autosign. +TpubN="now-60d" +TactN="now-1413h" +TretN="now" +TremN="now+50h" +TpubN1="now-27h" +TsbmN1="now" +TactN1="${TretN}" +TretN1="now+60d" +TremN1="now+1490h" +ksktimes="-P ${TpubN} -A ${TpubN} -P sync ${TactN} -I ${TretN} -D ${TremN} -D sync ${TactN1}" +newtimes="-P ${TpubN1} -A ${TactN1} -P sync ${TsbmN1} -I ${TretN1} -D ${TremN1}" +zsktimes="-P ${TpubN} -A ${TpubN}" +KSK1=$($KEYGEN -a $DEFAULT_ALGORITHM -L 7200 -f KSK $ksktimes $zone 2>keygen.out.$zone.1) +KSK2=$($KEYGEN -a $DEFAULT_ALGORITHM -L 7200 -f KSK $newtimes $zone 2>keygen.out.$zone.2) +ZSK=$($KEYGEN -a $DEFAULT_ALGORITHM -L 7200 $zsktimes $zone 2>keygen.out.$zone.3) +$SETTIME -s -g $H -k $O $TactN -r $O $TactN -d $O $TactN "$KSK1" >settime.out.$zone.1 2>&1 +$SETTIME -s -g $O -k $R $TpubN1 -r $R $TpubN1 -d $H $TpubN1 "$KSK2" >settime.out.$zone.2 2>&1 +$SETTIME -s -g $O -k $O $TactN -z $O $TactN "$ZSK" >settime.out.$zone.3 2>&1 +# Set key rollover relationship. +key_successor $KSK1 $KSK2 +# Sign zone. +cat template.db.in "${KSK1}.key" "${KSK2}.key" "${ZSK}.key" >"$infile" +private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$KSK1" >>"$infile" +private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$KSK2" >>"$infile" +private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$ZSK" >>"$infile" +cp $infile $zonefile +$SIGNER -S -x -G "cds:sha-256" -s now-1h -e now+2w -o $zone -O raw -f "${zonefile}.signed" $infile >signer.out.$zone.1 2>&1 diff --git a/bin/tests/system/rollover-ksk-3crowd/tests_rollover_three_is_a_crowd.py b/bin/tests/system/rollover-ksk-3crowd/tests_rollover_three_is_a_crowd.py new file mode 100644 index 00000000000..f30c2061d2f --- /dev/null +++ b/bin/tests/system/rollover-ksk-3crowd/tests_rollover_three_is_a_crowd.py @@ -0,0 +1,94 @@ +# 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. + +# pylint: disable=redefined-outer-name,unused-import + +from datetime import timedelta + +import isctest +from isctest.kasp import KeyTimingMetadata +from common import ( + pytestmark, + alg, + size, + KSK_CONFIG, + KSK_LIFETIME_POLICY, + KSK_IPUB, + KSK_IRET, +) + + +CDSS = ["CDS (SHA-256)"] +POLICY = "ksk-doubleksk" +OFFSET1 = -int(timedelta(days=60).total_seconds()) +OFFSET2 = -int(timedelta(hours=27).total_seconds()) +TTL = int(KSK_CONFIG["dnskey-ttl"].total_seconds()) + + +def test_rollover_ksk_three_is_a_crowd(alg, size, servers): + """Test #2375: Scheduled rollovers are happening faster than they can finish.""" + server = servers["ns3"] + zone = "three-is-a-crowd.kasp" + + step = { + "zone": zone, + "cdss": CDSS, + "keyprops": [ + f"ksk {KSK_LIFETIME_POLICY} {alg} {size} goal:hidden dnskey:omnipresent krrsig:omnipresent ds:unretentive offset:{OFFSET1}", + f"ksk {KSK_LIFETIME_POLICY} {alg} {size} goal:omnipresent dnskey:omnipresent krrsig:omnipresent ds:rumoured offset:{OFFSET2}", + f"zsk unlimited {alg} {size} goal:omnipresent dnskey:omnipresent zrrsig:omnipresent offset:{OFFSET1}", + ], + "keyrelationships": [0, 1], + } + isctest.kasp.check_rollover_step(servers["ns3"], KSK_CONFIG, POLICY, step) + + # Rollover successor KSK (with DS in rumoured state). + expected = isctest.kasp.policy_to_properties(TTL, step["keyprops"]) + keys = isctest.kasp.keydir_to_keylist(zone, server.identifier) + isctest.kasp.check_keys(zone, keys, expected) + key = expected[1].key + now = KeyTimingMetadata.now() + with server.watch_log_from_here() as watcher: + server.rndc(f"dnssec -rollover -key {key.tag} -when {now} {zone}") + watcher.wait_for_line(f"keymgr: {zone} done") + + # We now expect four keys (3x KSK, 1x ZSK). + step = { + "zone": zone, + "cdss": CDSS, + "keyprops": [ + f"ksk {KSK_LIFETIME_POLICY} {alg} {size} goal:hidden dnskey:omnipresent krrsig:omnipresent ds:unretentive offset:{OFFSET1}", + f"ksk {KSK_LIFETIME_POLICY} {alg} {size} goal:hidden dnskey:omnipresent krrsig:omnipresent ds:rumoured offset:{OFFSET2}", + f"ksk {KSK_LIFETIME_POLICY} {alg} {size} goal:omnipresent dnskey:rumoured krrsig:rumoured ds:hidden offset:0", + f"zsk unlimited {alg} {size} goal:omnipresent dnskey:omnipresent zrrsig:omnipresent offset:{OFFSET1}", + ], + "check-keytimes": False, # checked manually with modified values + } + isctest.kasp.check_rollover_step(servers["ns3"], KSK_CONFIG, POLICY, step) + + expected = isctest.kasp.policy_to_properties(TTL, step["keyprops"]) + keys = isctest.kasp.keydir_to_keylist(zone, server.identifier) + isctest.kasp.check_keys(zone, keys, expected) + + expected[0].metadata["Successor"] = expected[1].key.tag + expected[1].metadata["Predecessor"] = expected[0].key.tag + # Three is a crowd scenario. + expected[1].metadata["Successor"] = expected[2].key.tag + expected[2].metadata["Predecessor"] = expected[1].key.tag + isctest.kasp.check_keyrelationships(keys, expected) + for kp in expected: + kp.set_expected_keytimes(KSK_CONFIG) + + # The first successor KSK is already being retired. + expected[1].timing["Retired"] = now + KSK_IPUB + expected[1].timing["Removed"] = now + KSK_IPUB + KSK_IRET + + isctest.kasp.check_keytimes(keys, expected) diff --git a/bin/tests/system/rollover-ksk-doubleksk/tests_rollover_ksk_doubleksk.py b/bin/tests/system/rollover-ksk-doubleksk/tests_rollover_ksk_doubleksk.py index 85e13f29cf8..4b0652c7f4a 100644 --- a/bin/tests/system/rollover-ksk-doubleksk/tests_rollover_ksk_doubleksk.py +++ b/bin/tests/system/rollover-ksk-doubleksk/tests_rollover_ksk_doubleksk.py @@ -18,43 +18,31 @@ from common import ( pytestmark, alg, size, - DEFAULT_CONFIG, + KSK_CONFIG, + KSK_LIFETIME, + KSK_LIFETIME_POLICY, + KSK_IPUB, + KSK_IPUBC, + KSK_IRET, + KSK_KEYTTLPROP, TIMEDELTA, ) CDSS = ["CDS (SHA-256)"] -CONFIG = { - "dnskey-ttl": TIMEDELTA["PT2H"], - "ds-ttl": TIMEDELTA["PT1H"], - "max-zone-ttl": TIMEDELTA["P1D"], - "parent-propagation-delay": TIMEDELTA["PT1H"], - "publish-safety": TIMEDELTA["P1D"], - "purge-keys": TIMEDELTA["PT1H"], - "retire-safety": TIMEDELTA["P2D"], - "signatures-refresh": TIMEDELTA["P7D"], - "signatures-validity": TIMEDELTA["P14D"], - "zone-propagation-delay": TIMEDELTA["PT1H"], -} POLICY = "ksk-doubleksk" -KSK_LIFETIME = TIMEDELTA["P60D"] -LIFETIME_POLICY = int(KSK_LIFETIME.total_seconds()) -IPUB = Ipub(CONFIG) -IPUBC = IpubC(CONFIG) -IRET = Iret(CONFIG, zsk=False, ksk=True) -KEYTTLPROP = CONFIG["dnskey-ttl"] + CONFIG["zone-propagation-delay"] OFFSETS = {} OFFSETS["step1-p"] = -int(TIMEDELTA["P7D"].total_seconds()) -OFFSETS["step2-p"] = -int(KSK_LIFETIME.total_seconds() - IPUBC.total_seconds()) +OFFSETS["step2-p"] = -int(KSK_LIFETIME.total_seconds() - KSK_IPUBC.total_seconds()) OFFSETS["step2-s"] = 0 OFFSETS["step3-p"] = -int(KSK_LIFETIME.total_seconds()) -OFFSETS["step3-s"] = -int(IPUBC.total_seconds()) -OFFSETS["step4-p"] = OFFSETS["step3-p"] - int(IRET.total_seconds()) -OFFSETS["step4-s"] = OFFSETS["step3-s"] - int(IRET.total_seconds()) -OFFSETS["step5-p"] = OFFSETS["step4-p"] - int(KEYTTLPROP.total_seconds()) -OFFSETS["step5-s"] = OFFSETS["step4-s"] - int(KEYTTLPROP.total_seconds()) -OFFSETS["step6-p"] = OFFSETS["step5-p"] - int(CONFIG["purge-keys"].total_seconds()) -OFFSETS["step6-s"] = OFFSETS["step5-s"] - int(CONFIG["purge-keys"].total_seconds()) +OFFSETS["step3-s"] = -int(KSK_IPUBC.total_seconds()) +OFFSETS["step4-p"] = OFFSETS["step3-p"] - int(KSK_IRET.total_seconds()) +OFFSETS["step4-s"] = OFFSETS["step3-s"] - int(KSK_IRET.total_seconds()) +OFFSETS["step5-p"] = OFFSETS["step4-p"] - int(KSK_KEYTTLPROP.total_seconds()) +OFFSETS["step5-s"] = OFFSETS["step4-s"] - int(KSK_KEYTTLPROP.total_seconds()) +OFFSETS["step6-p"] = OFFSETS["step5-p"] - int(KSK_CONFIG["purge-keys"].total_seconds()) +OFFSETS["step6-s"] = OFFSETS["step5-s"] - int(KSK_CONFIG["purge-keys"].total_seconds()) def test_ksk_doubleksk_step1(alg, size, servers): @@ -64,14 +52,14 @@ def test_ksk_doubleksk_step1(alg, size, servers): "cdss": CDSS, "keyprops": [ f"zsk unlimited {alg} {size} goal:omnipresent dnskey:omnipresent zrrsig:omnipresent offset:{OFFSETS['step1-p']}", - f"ksk {LIFETIME_POLICY} {alg} {size} goal:omnipresent dnskey:omnipresent krrsig:omnipresent ds:omnipresent offset:{OFFSETS['step1-p']}", + f"ksk {KSK_LIFETIME_POLICY} {alg} {size} goal:omnipresent dnskey:omnipresent krrsig:omnipresent ds:omnipresent offset:{OFFSETS['step1-p']}", ], # Next key event is when the successor KSK needs to be published. # That is the KSK lifetime - prepublication time (minus time # already passed). - "nextev": KSK_LIFETIME - IPUB - timedelta(days=7), + "nextev": KSK_LIFETIME - KSK_IPUB - timedelta(days=7), } - isctest.kasp.check_rollover_step(servers["ns3"], CONFIG, POLICY, step) + isctest.kasp.check_rollover_step(servers["ns3"], KSK_CONFIG, POLICY, step) def test_ksk_doubleksk_step2(alg, size, servers): @@ -85,14 +73,14 @@ def test_ksk_doubleksk_step2(alg, size, servers): "cdss": CDSS, "keyprops": [ f"zsk unlimited {alg} {size} goal:omnipresent dnskey:omnipresent zrrsig:omnipresent offset:{OFFSETS['step2-p']}", - f"ksk {LIFETIME_POLICY} {alg} {size} goal:hidden dnskey:omnipresent krrsig:omnipresent ds:omnipresent offset:{OFFSETS['step2-p']}", - f"ksk {LIFETIME_POLICY} {alg} {size} goal:omnipresent dnskey:rumoured krrsig:rumoured ds:hidden offset:{OFFSETS['step2-s']}", + f"ksk {KSK_LIFETIME_POLICY} {alg} {size} goal:hidden dnskey:omnipresent krrsig:omnipresent ds:omnipresent offset:{OFFSETS['step2-p']}", + f"ksk {KSK_LIFETIME_POLICY} {alg} {size} goal:omnipresent dnskey:rumoured krrsig:rumoured ds:hidden offset:{OFFSETS['step2-s']}", ], "keyrelationships": [1, 2], # Next key event is when the successor KSK becomes OMNIPRESENT. - "nextev": IPUB, + "nextev": KSK_IPUB, } - isctest.kasp.check_rollover_step(servers["ns3"], CONFIG, POLICY, step) + isctest.kasp.check_rollover_step(servers["ns3"], KSK_CONFIG, POLICY, step) def test_ksk_doubleksk_step3(alg, size, servers): @@ -108,17 +96,17 @@ def test_ksk_doubleksk_step3(alg, size, servers): "cdss": CDSS, "keyprops": [ f"zsk unlimited {alg} {size} goal:omnipresent dnskey:omnipresent zrrsig:omnipresent offset:{OFFSETS['step3-p']}", - f"ksk {LIFETIME_POLICY} {alg} {size} goal:hidden dnskey:omnipresent krrsig:omnipresent ds:unretentive offset:{OFFSETS['step3-p']}", - f"ksk {LIFETIME_POLICY} {alg} {size} goal:omnipresent dnskey:omnipresent krrsig:omnipresent ds:rumoured offset:{OFFSETS['step3-s']}", + f"ksk {KSK_LIFETIME_POLICY} {alg} {size} goal:hidden dnskey:omnipresent krrsig:omnipresent ds:unretentive offset:{OFFSETS['step3-p']}", + f"ksk {KSK_LIFETIME_POLICY} {alg} {size} goal:omnipresent dnskey:omnipresent krrsig:omnipresent ds:rumoured offset:{OFFSETS['step3-s']}", ], "keyrelationships": [1, 2], # Next key event is when the predecessor DS has been replaced with # the successor DS and enough time has passed such that the all # validators that have this DS RRset cached only know about the # successor DS. This is the the retire interval. - "nextev": IRET, + "nextev": KSK_IRET, } - isctest.kasp.check_rollover_step(servers["ns3"], CONFIG, POLICY, step) + isctest.kasp.check_rollover_step(servers["ns3"], KSK_CONFIG, POLICY, step) def test_ksk_doubleksk_step4(alg, size, servers): @@ -133,15 +121,15 @@ def test_ksk_doubleksk_step4(alg, size, servers): "cdss": CDSS, "keyprops": [ f"zsk unlimited {alg} {size} goal:omnipresent dnskey:omnipresent zrrsig:omnipresent offset:{OFFSETS['step4-p']}", - f"ksk {LIFETIME_POLICY} {alg} {size} goal:hidden dnskey:unretentive krrsig:unretentive ds:hidden offset:{OFFSETS['step4-p']}", - f"ksk {LIFETIME_POLICY} {alg} {size} goal:omnipresent dnskey:omnipresent krrsig:omnipresent ds:omnipresent offset:{OFFSETS['step4-s']}", + f"ksk {KSK_LIFETIME_POLICY} {alg} {size} goal:hidden dnskey:unretentive krrsig:unretentive ds:hidden offset:{OFFSETS['step4-p']}", + f"ksk {KSK_LIFETIME_POLICY} {alg} {size} goal:omnipresent dnskey:omnipresent krrsig:omnipresent ds:omnipresent offset:{OFFSETS['step4-s']}", ], "keyrelationships": [1, 2], # Next key event is when the DNSKEY enters the HIDDEN state. # This is the DNSKEY TTL plus zone propagation delay. - "nextev": KEYTTLPROP, + "nextev": KSK_KEYTTLPROP, } - isctest.kasp.check_rollover_step(servers["ns3"], CONFIG, POLICY, step) + isctest.kasp.check_rollover_step(servers["ns3"], KSK_CONFIG, POLICY, step) def test_ksk_doubleksk_step5(alg, size, servers): @@ -154,15 +142,15 @@ def test_ksk_doubleksk_step5(alg, size, servers): "cdss": CDSS, "keyprops": [ f"zsk unlimited {alg} {size} goal:omnipresent dnskey:omnipresent zrrsig:omnipresent offset:{OFFSETS['step5-p']}", - f"ksk {LIFETIME_POLICY} {alg} {size} goal:hidden dnskey:hidden krrsig:hidden ds:hidden offset:{OFFSETS['step5-p']}", - f"ksk {LIFETIME_POLICY} {alg} {size} goal:omnipresent dnskey:omnipresent krrsig:omnipresent ds:omnipresent offset:{OFFSETS['step5-s']}", + f"ksk {KSK_LIFETIME_POLICY} {alg} {size} goal:hidden dnskey:hidden krrsig:hidden ds:hidden offset:{OFFSETS['step5-p']}", + f"ksk {KSK_LIFETIME_POLICY} {alg} {size} goal:omnipresent dnskey:omnipresent krrsig:omnipresent ds:omnipresent offset:{OFFSETS['step5-s']}", ], "keyrelationships": [1, 2], # Next key event is when the new successor needs to be published. # This is the KSK lifetime minus Ipub minus Iret minus time elapsed. - "nextev": KSK_LIFETIME - IPUB - IRET - KEYTTLPROP, + "nextev": KSK_LIFETIME - KSK_IPUB - KSK_IRET - KSK_KEYTTLPROP, } - isctest.kasp.check_rollover_step(servers["ns3"], CONFIG, POLICY, step) + isctest.kasp.check_rollover_step(servers["ns3"], KSK_CONFIG, POLICY, step) def test_ksk_doubleksk_step6(alg, size, servers): @@ -172,8 +160,8 @@ def test_ksk_doubleksk_step6(alg, size, servers): "cdss": CDSS, "keyprops": [ f"zsk unlimited {alg} {size} goal:omnipresent dnskey:omnipresent zrrsig:omnipresent offset:{OFFSETS['step6-p']}", - f"ksk {LIFETIME_POLICY} {alg} {size} goal:omnipresent dnskey:omnipresent krrsig:omnipresent ds:omnipresent offset:{OFFSETS['step6-s']}", + f"ksk {KSK_LIFETIME_POLICY} {alg} {size} goal:omnipresent dnskey:omnipresent krrsig:omnipresent ds:omnipresent offset:{OFFSETS['step6-s']}", ], "nextev": None, } - isctest.kasp.check_rollover_step(servers["ns3"], CONFIG, POLICY, step) + isctest.kasp.check_rollover_step(servers["ns3"], KSK_CONFIG, POLICY, step) diff --git a/bin/tests/system/rollover/common.py b/bin/tests/system/rollover/common.py index a5429e195c4..1e3ab1585a8 100644 --- a/bin/tests/system/rollover/common.py +++ b/bin/tests/system/rollover/common.py @@ -108,6 +108,24 @@ ALGOROLL_OFFSETS["step6"] = ALGOROLL_OFFSETS["step5"] - int( ALGOROLL_IRET.total_seconds() ) ALGOROLL_OFFVAL = -DURATION["P7D"] +KSK_CONFIG = { + "dnskey-ttl": TIMEDELTA["PT2H"], + "ds-ttl": TIMEDELTA["PT1H"], + "max-zone-ttl": TIMEDELTA["P1D"], + "parent-propagation-delay": TIMEDELTA["PT1H"], + "publish-safety": TIMEDELTA["P1D"], + "purge-keys": TIMEDELTA["PT1H"], + "retire-safety": TIMEDELTA["P2D"], + "signatures-refresh": TIMEDELTA["P7D"], + "signatures-validity": TIMEDELTA["P14D"], + "zone-propagation-delay": TIMEDELTA["PT1H"], +} +KSK_LIFETIME = TIMEDELTA["P60D"] +KSK_LIFETIME_POLICY = int(KSK_LIFETIME.total_seconds()) +KSK_IPUB = Ipub(KSK_CONFIG) +KSK_IPUBC = IpubC(KSK_CONFIG) +KSK_IRET = Iret(KSK_CONFIG, zsk=False, ksk=True) +KSK_KEYTTLPROP = KSK_CONFIG["dnskey-ttl"] + KSK_CONFIG["zone-propagation-delay"] @pytest.fixture diff --git a/bin/tests/system/rollover/ns3/kasp.conf.j2 b/bin/tests/system/rollover/ns3/kasp.conf.j2 index 80e76fae87a..209d72cb09e 100644 --- a/bin/tests/system/rollover/ns3/kasp.conf.j2 +++ b/bin/tests/system/rollover/ns3/kasp.conf.j2 @@ -67,26 +67,3 @@ dnssec-policy "zsk-prepub" { zone-propagation-delay PT1H; max-zone-ttl 1d; }; - -dnssec-policy "ksk-doubleksk" { - signatures-refresh P1W; - signatures-validity P2W; - signatures-validity-dnskey P2W; - - dnskey-ttl 2h; - publish-safety P1D; - retire-safety P2D; - purge-keys PT1H; - - cdnskey no; - keys { - ksk key-directory lifetime P60D algorithm @DEFAULT_ALGORITHM@; - zsk key-directory lifetime unlimited algorithm @DEFAULT_ALGORITHM@; - }; - - zone-propagation-delay PT1H; - max-zone-ttl 1d; - - parent-ds-ttl 3600; - parent-propagation-delay PT1H; -}; diff --git a/bin/tests/system/rollover/ns3/named.conf.j2 b/bin/tests/system/rollover/ns3/named.conf.j2 index 20e597d7ac5..25e7e9b6ee9 100644 --- a/bin/tests/system/rollover/ns3/named.conf.j2 +++ b/bin/tests/system/rollover/ns3/named.conf.j2 @@ -100,14 +100,3 @@ zone "step6.zsk-prepub.autosign" { file "step6.zsk-prepub.autosign.db"; dnssec-policy "zsk-prepub"; }; - -/* - * Zone for testing GL #2375: Three is a crowd. - */ -zone "three-is-a-crowd.kasp" { - type primary; - file "three-is-a-crowd.kasp.db"; - inline-signing yes; - /* Use same policy as KSK rollover test zones. */ - dnssec-policy "ksk-doubleksk"; -}; diff --git a/bin/tests/system/rollover/ns3/setup.sh b/bin/tests/system/rollover/ns3/setup.sh index 9fa044b09f1..82271ff007e 100644 --- a/bin/tests/system/rollover/ns3/setup.sh +++ b/bin/tests/system/rollover/ns3/setup.sh @@ -315,45 +315,3 @@ private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$ZSK1" >>"$infile" private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$ZSK2" >>"$infile" cp $infile $zonefile $SIGNER -S -x -s now-1h -e now+2w -o $zone -O raw -f "${zonefile}.signed" $infile >signer.out.$zone.1 2>&1 - -# Test #2375, the "three is a crowd" bug, where a new key is introduced but the -# previous rollover has not finished yet. In other words, we have a key KEY2 -# that is the successor of key KEY1, and we introduce a new key KEY3 that is -# the successor of key KEY2: -# -# KEY1 < KEY2 < KEY3. -# -# The expected behavior is that all three keys remain in the zone, and not -# the bug behavior where KEY2 is removed and immediately replaced with KEY3. -# -# Set up a zone that has a KSK (KEY1) and have the successor key (KEY2) -# published as well. -setup three-is-a-crowd.kasp -# These times are the same as step3.ksk-doubleksk.autosign. -TpubN="now-60d" -TactN="now-1413h" -TretN="now" -TremN="now+50h" -TpubN1="now-27h" -TsbmN1="now" -TactN1="${TretN}" -TretN1="now+60d" -TremN1="now+1490h" -ksktimes="-P ${TpubN} -A ${TpubN} -P sync ${TactN} -I ${TretN} -D ${TremN} -D sync ${TactN1}" -newtimes="-P ${TpubN1} -A ${TactN1} -P sync ${TsbmN1} -I ${TretN1} -D ${TremN1}" -zsktimes="-P ${TpubN} -A ${TpubN}" -KSK1=$($KEYGEN -a $DEFAULT_ALGORITHM -L 7200 -f KSK $ksktimes $zone 2>keygen.out.$zone.1) -KSK2=$($KEYGEN -a $DEFAULT_ALGORITHM -L 7200 -f KSK $newtimes $zone 2>keygen.out.$zone.2) -ZSK=$($KEYGEN -a $DEFAULT_ALGORITHM -L 7200 $zsktimes $zone 2>keygen.out.$zone.3) -$SETTIME -s -g $H -k $O $TactN -r $O $TactN -d $O $TactN "$KSK1" >settime.out.$zone.1 2>&1 -$SETTIME -s -g $O -k $R $TpubN1 -r $R $TpubN1 -d $H $TpubN1 "$KSK2" >settime.out.$zone.2 2>&1 -$SETTIME -s -g $O -k $O $TactN -z $O $TactN "$ZSK" >settime.out.$zone.3 2>&1 -# Set key rollover relationship. -key_successor $KSK1 $KSK2 -# Sign zone. -cat template.db.in "${KSK1}.key" "${KSK2}.key" "${ZSK}.key" >"$infile" -private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$KSK1" >>"$infile" -private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$KSK2" >>"$infile" -private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$ZSK" >>"$infile" -cp $infile $zonefile -$SIGNER -S -x -G "cds:sha-256" -s now-1h -e now+2w -o $zone -O raw -f "${zonefile}.signed" $infile >signer.out.$zone.1 2>&1 diff --git a/bin/tests/system/rollover/tests_rollover.py b/bin/tests/system/rollover/tests_rollover.py index 02f07969b2d..5b176aae676 100644 --- a/bin/tests/system/rollover/tests_rollover.py +++ b/bin/tests/system/rollover/tests_rollover.py @@ -536,91 +536,3 @@ def test_rollover_zsk_prepublication(servers): for step in steps: isctest.kasp.check_rollover_step(server, config, policy, step) - - -def test_rollover_ksk_doubleksk(servers): - server = servers["ns3"] - policy = "ksk-doubleksk" - cdss = ["CDS (SHA-256)"] - config = { - "dnskey-ttl": timedelta(hours=2), - "ds-ttl": timedelta(seconds=3600), - "max-zone-ttl": timedelta(days=1), - "parent-propagation-delay": timedelta(hours=1), - "publish-safety": timedelta(days=1), - "purge-keys": timedelta(hours=1), - "retire-safety": timedelta(days=2), - "signatures-refresh": timedelta(days=7), - "signatures-validity": timedelta(days=14), - "zone-propagation-delay": timedelta(hours=1), - } - ttl = int(config["dnskey-ttl"].total_seconds()) - alg = os.environ["DEFAULT_ALGORITHM_NUMBER"] - size = os.environ["DEFAULT_BITS"] - ksk_lifetime = timedelta(days=60) - lifetime_policy = int(ksk_lifetime.total_seconds()) - - ipub = Ipub(config) - iret = Iret(config, zsk=False, ksk=True) - - # Test #2375: Scheduled rollovers are happening faster than they can finish. - isctest.log.info( - "check that fast rollovers do not remove dependent keys from zone (#2375)" - ) - offset1 = -int(timedelta(days=60).total_seconds()) - offset2 = -int(timedelta(hours=27).total_seconds()) - zone = "three-is-a-crowd.kasp" - step = { - "zone": zone, - "cdss": cdss, - "keyprops": [ - f"ksk {lifetime_policy} {alg} {size} goal:hidden dnskey:omnipresent krrsig:omnipresent ds:unretentive offset:{offset1}", - f"ksk {lifetime_policy} {alg} {size} goal:omnipresent dnskey:omnipresent krrsig:omnipresent ds:rumoured offset:{offset2}", - f"zsk unlimited {alg} {size} goal:omnipresent dnskey:omnipresent zrrsig:omnipresent offset:{offset1}", - ], - "keyrelationships": [0, 1], - } - isctest.kasp.check_rollover_step(servers["ns3"], config, policy, step) - - # Rollover successor KSK (with DS in rumoured state). - expected = isctest.kasp.policy_to_properties(ttl, step["keyprops"]) - keys = isctest.kasp.keydir_to_keylist(zone, server.identifier) - isctest.kasp.check_keys(zone, keys, expected) - key = expected[1].key - now = KeyTimingMetadata.now() - with server.watch_log_from_here() as watcher: - server.rndc(f"dnssec -rollover -key {key.tag} -when {now} {zone}") - watcher.wait_for_line(f"keymgr: {zone} done") - - # We now expect four keys (3x KSK, 1x ZSK). - step = { - "zone": zone, - "cdss": cdss, - "keyprops": [ - f"ksk {lifetime_policy} {alg} {size} goal:hidden dnskey:omnipresent krrsig:omnipresent ds:unretentive offset:{offset1}", - f"ksk {lifetime_policy} {alg} {size} goal:hidden dnskey:omnipresent krrsig:omnipresent ds:rumoured offset:{offset2}", - f"ksk {lifetime_policy} {alg} {size} goal:omnipresent dnskey:rumoured krrsig:rumoured ds:hidden offset:0", - f"zsk unlimited {alg} {size} goal:omnipresent dnskey:omnipresent zrrsig:omnipresent offset:{offset1}", - ], - "check-keytimes": False, # checked manually with modified values - } - isctest.kasp.check_rollover_step(servers["ns3"], config, policy, step) - - expected = isctest.kasp.policy_to_properties(ttl, step["keyprops"]) - keys = isctest.kasp.keydir_to_keylist(zone, server.identifier) - isctest.kasp.check_keys(zone, keys, expected) - - expected[0].metadata["Successor"] = expected[1].key.tag - expected[1].metadata["Predecessor"] = expected[0].key.tag - # Three is a crowd scenario. - expected[1].metadata["Successor"] = expected[2].key.tag - expected[2].metadata["Predecessor"] = expected[1].key.tag - isctest.kasp.check_keyrelationships(keys, expected) - for kp in expected: - kp.set_expected_keytimes(config, offset=None) - - # The first successor KSK is already being retired. - expected[1].timing["Retired"] = now + ipub - expected[1].timing["Removed"] = now + ipub + iret - - isctest.kasp.check_keytimes(keys, expected)