From: Matthijs Mekking Date: Tue, 18 Mar 2025 07:41:02 +0000 (+0100) Subject: Convert kasp multi-signer tests to pytest X-Git-Tag: v9.21.9~15^2~6 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=8ee02190a5f924517b4350e1f985e5df773420fb;p=thirdparty%2Fbind9.git Convert kasp multi-signer tests to pytest Move the multi-signer test scenarios to the rollover directory and convert tests to pytest. - If the KeyProperties set the "legacy" to True, don't set expected key times, nor check them. Also, when a matching key is found, set key.external to True. - External keys don't show up in the 'rndc dnssec -status' output so skip them in the 'check_dnssecstatus' function. External keys never sign RRsets, so also skip those keys in the '_check_signatures' function. - Key properties strings now can set expected key tag ranges, and if KeyProperties have tag ranges set, they are checked. --- diff --git a/bin/tests/system/isctest/kasp.py b/bin/tests/system/isctest/kasp.py index d6bd930d877..35d8c6e82a9 100644 --- a/bin/tests/system/isctest/kasp.py +++ b/bin/tests/system/isctest/kasp.py @@ -291,6 +291,7 @@ class Key: self.keyfile = f"{self.path}.key" self.statefile = f"{self.path}.state" self.tag = int(self.name[-5:]) + self.external = False def get_timing( self, metadata: str, must_exist: bool = True @@ -572,6 +573,14 @@ class Key: if not self.is_metadata_consistent(key, properties.metadata): return False + # Check tag range. + if "keytag-min" in properties.properties: + if self.tag < properties.properties["keytag-min"]: + return False + if "keytag-max" in properties.properties: + if self.tag > properties.properties["keytag-max"]: + return False + # A match is found. return True @@ -767,7 +776,8 @@ def check_dnssecstatus(server, zone, keys, policy=None, view=None): assert f"dnssec-policy: {policy}" in response for key in keys: - assert f"key: {key.tag}" in response + if not key.external: + assert f"key: {key.tag}" in response def _check_signatures( @@ -780,6 +790,9 @@ def _check_signatures( krrsig = not zrrsig for key in keys: + if key.external: + continue + ksigning, zsigning = key.get_signing_state( offline_ksk=offline_ksk, zsk_missing=zsk_missing ) @@ -1248,6 +1261,7 @@ def policy_to_properties(ttl, keys: List[str]) -> List[KeyProperties]: sets the given state to the specific value - "missing", set if the private key file for this key is not available. - "offset", an offset for testing key rollover timings + - "tag-range", followed by - to test key tag ranges """ proplist = [] count = 0 @@ -1297,6 +1311,11 @@ def policy_to_properties(ttl, keys: List[str]) -> List[KeyProperties]: elif line[i].startswith("offset:"): keyval = line[i].split(":") keyprop.properties["offset"] = timedelta(seconds=int(keyval[1])) + elif line[i].startswith("tag-range:"): + keyval = line[i].split(":") + tagrange = keyval[1].split("-") + keyprop.properties["keytag-min"] = int(tagrange[0]) + keyprop.properties["keytag-max"] = int(tagrange[1]) elif line[i] == "missing": keyprop.properties["private"] = False else: diff --git a/bin/tests/system/kasp/ns3/named-fips.conf.in b/bin/tests/system/kasp/ns3/named-fips.conf.in index 92e15368846..8368c4822e7 100644 --- a/bin/tests/system/kasp/ns3/named-fips.conf.in +++ b/bin/tests/system/kasp/ns3/named-fips.conf.in @@ -204,25 +204,6 @@ zone "rumoured.kasp" { dnssec-policy "rsasha256"; }; -/* RFC 8901 Multi-signer Model 2. */ -zone "multisigner-model2.kasp" { - type primary; - file "multisigner-model2.kasp.db"; - dnssec-policy "multisigner-model2"; - allow-update { any; }; -}; - -/* - * A zone that starts with keys that have tags that are - * outside of the desired multi-signer key tag range. - */ -zone "single-to-multisigner.kasp" { - type primary; - file "single-to-multisigner.kasp.db"; - dnssec-policy "multisigner-model2"; - allow-update { any; }; -}; - /* * Different algorithms. */ diff --git a/bin/tests/system/kasp/ns3/policies/kasp-fips.conf.in b/bin/tests/system/kasp/ns3/policies/kasp-fips.conf.in index 2649b056d86..68f932bcf10 100644 --- a/bin/tests/system/kasp/ns3/policies/kasp-fips.conf.in +++ b/bin/tests/system/kasp/ns3/policies/kasp-fips.conf.in @@ -23,16 +23,6 @@ dnssec-policy "default-dynamic" { inline-signing no; }; -dnssec-policy "multisigner-model2" { - dnskey-ttl 3600; - inline-signing no; - - keys { - ksk key-directory lifetime unlimited algorithm @DEFAULT_ALGORITHM@ tag-range 32768 65535; - zsk key-directory lifetime unlimited algorithm @DEFAULT_ALGORITHM@ tag-range 32768 65535; - }; -}; - dnssec-policy "migrate-to-dnssec-policy" { dnskey-ttl 1234; diff --git a/bin/tests/system/kasp/ns3/setup.sh b/bin/tests/system/kasp/ns3/setup.sh index 5432bfecc85..7eeb2488384 100644 --- a/bin/tests/system/kasp/ns3/setup.sh +++ b/bin/tests/system/kasp/ns3/setup.sh @@ -50,7 +50,7 @@ for zn in default dnssec-keygen some-keys legacy-keys pregenerated \ rumoured rsasha256 rsasha512 ecdsa256 ecdsa384 \ dynamic dynamic-inline-signing inline-signing \ checkds-ksk checkds-doubleksk checkds-csk inherit unlimited \ - multisigner-model2 keystore; do + keystore; do setup "${zn}.kasp" cp template.db.in "$zonefile" done @@ -127,23 +127,6 @@ echo_i "setting up zone: $zone" $KEYGEN -G -k rsasha256 -l policies/kasp.conf $zone >keygen.out.$zone.1 2>&1 $KEYGEN -G -k rsasha256 -l policies/kasp.conf $zone >keygen.out.$zone.2 2>&1 -zone="multisigner-model2.kasp" -echo_i "setting up zone: $zone" -KSK=$($KEYGEN -a $DEFAULT_ALGORITHM -f KSK -L 3600 -M 32768:65535 $zone 2>keygen.out.$zone.1) -ZSK=$($KEYGEN -a $DEFAULT_ALGORITHM -L 3600 -M 32768:65535 $zone 2>keygen.out.$zone.2) -cat "${KSK}.key" | grep -v ";.*" >>"${zone}.db" -cat "${ZSK}.key" | grep -v ";.*" >>"${zone}.db" -# Import the ZSK sets of the other providers into their DNSKEY RRset. -# ZSK1 is from a different provider and is added to the unsigned zonefile. -# ZSK2 is also from a different provider and is added with a Dynamic Update. -ZSK1=$($KEYGEN -K ../ -a $DEFAULT_ALGORITHM -L 3600 -M 0:32767 $zone 2>keygen.out.$zone.3) -ZSK2=$($KEYGEN -K ../ -a $DEFAULT_ALGORITHM -L 3600 -M 0:32767 $zone 2>keygen.out.$zone.4) -cat "../${ZSK1}.key" | grep -v ";.*" >>"${zone}.db" -cat "../${ZSK1}.key" | grep -v ";.*" >"${zone}.zsk1" -cat "../${ZSK2}.key" | grep -v ";.*" >"${zone}.zsk2" -rm -f "../${ZSK1}.*" -rm -f "../${ZSK2}.*" - zone="rumoured.kasp" echo_i "setting up zone: $zone" Tpub="now" @@ -174,17 +157,6 @@ private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "keys/$CSK" >>"$infile" cp $infile $zonefile $SIGNER -PS -K keys -z -x -s now-2w -e now-1mi -o $zone -f "${zonefile}.signed" $infile >signer.out.$zone.1 2>&1 -# We are changing an existing single-signed zone to multi-signed -# zone where the key tags do not match the dnssec-policy key tag range -setup single-to-multisigner.kasp -T="now-1d" -KSK=$($KEYGEN -a $DEFAULT_ALGORITHM -M 0:32767 -L 3600 -f KSK $ksktimes $zone 2>keygen.out.$zone.1) -ZSK=$($KEYGEN -a $DEFAULT_ALGORITHM -M 0:32767 -L 3600 $zsktimes $zone 2>keygen.out.$zone.2) -$SETTIME -s -g $O -d $O $T -k $O $T -r $O $T "$KSK" >settime.out.$zone.1 2>&1 -$SETTIME -s -g $O -k $O $T -z $O $T "$ZSK" >settime.out.$zone.2 2>&1 -cat template.db.in "${KSK}.key" "${ZSK}.key" >"$infile" -$SIGNER -PS -z -x -s now-2w -e now-1mi -o $zone -f "${zonefile}" $infile >signer.out.$zone.1 2>&1 - # Treat the next zones as if they were signed six months ago. T="now-6mo" keytimes="-P $T -A $T" diff --git a/bin/tests/system/kasp/tests.sh b/bin/tests/system/kasp/tests.sh index 47af94bad17..b83b6a16d6f 100644 --- a/bin/tests/system/kasp/tests.sh +++ b/bin/tests/system/kasp/tests.sh @@ -206,169 +206,6 @@ set_keytimes_autosign_policy() { set_addkeytime "KEY2" "REMOVED" "${retired}" 695100 } -# -# Testing RFC 8901 Multi-Signer Model 2. -# -set_zone "multisigner-model2.kasp" -set_policy "multisigner-model2" "2" "3600" -set_server "ns3" "10.53.0.3" -key_clear "KEY1" -key_clear "KEY2" -key_clear "KEY3" -key_clear "KEY4" - -# Key properties. -set_keyrole "KEY1" "ksk" -set_keylifetime "KEY1" "0" -set_keyalgorithm "KEY1" "$DEFAULT_ALGORITHM_NUMBER" "$DEFAULT_ALGORITHM" "$DEFAULT_BITS" -set_keysigning "KEY1" "yes" -set_zonesigning "KEY1" "no" - -set_keyrole "KEY2" "zsk" -set_keylifetime "KEY2" "0" -set_keyalgorithm "KEY2" "$DEFAULT_ALGORITHM_NUMBER" "$DEFAULT_ALGORITHM" "$DEFAULT_BITS" -set_keysigning "KEY2" "no" -set_zonesigning "KEY2" "yes" - -set_keystate "KEY1" "GOAL" "omnipresent" -set_keystate "KEY1" "STATE_DNSKEY" "rumoured" -set_keystate "KEY1" "STATE_KRRSIG" "rumoured" -set_keystate "KEY1" "STATE_DS" "hidden" -set_keystate "KEY2" "GOAL" "omnipresent" -set_keystate "KEY2" "STATE_DNSKEY" "rumoured" -set_keystate "KEY2" "STATE_ZRRSIG" "rumoured" - -check_keys -check_dnssecstatus "$SERVER" "$POLICY" "$ZONE" -check_apex -check_subdomain -dnssec_verify - -# Check that the ZSKs from the other providers are published. -zsks_are_published() { - num=$1 - dig_with_opts +short "$ZONE" "@${SERVER}" DNSKEY >"dig.out.$DIR.test$n" || return 1 - # We should have three ZSKs. - lines=$(grep "256 3 13" dig.out.$DIR.test$n | wc -l) - test "$lines" -eq $num || return 1 - # And one KSK. - lines=$(grep "257 3 13" dig.out.$DIR.test$n | wc -l) - test "$lines" -eq 1 || return 1 -} -n=$((n + 1)) -echo_i "check initial number of ZSKs (one from us and one from another provider) for zone ${ZONE} ($n)" -ret=0 -retry_quiet 10 zsks_are_published 2 || ret=1 -test "$ret" -eq 0 || echo_i "failed" -status=$((status + ret)) - -n=$((n + 1)) -echo_i "update zone with ZSK from another provider for zone ${ZONE} ($n)" -ret=0 -( - echo zone ${ZONE} - echo server 10.53.0.3 "$PORT" - echo update add $(cat "${DIR}/${ZONE}.zsk2") - echo send -) | $NSUPDATE -retry_quiet 10 zsks_are_published 3 || ret=1 -test "$ret" -eq 0 || echo_i "failed" -status=$((status + ret)) - -n=$((n + 1)) -echo_i "remove ZSKs from the other providers for zone ${ZONE} ($n)" -ret=0 -( - echo zone ${ZONE} - echo server 10.53.0.3 "$PORT" - echo update del $(cat "${DIR}/${ZONE}.zsk1") - echo update del $(cat "${DIR}/${ZONE}.zsk2") - echo send -) | $NSUPDATE -retry_quiet 10 zsks_are_published 1 || ret=1 -test "$ret" -eq 0 || echo_i "failed" -status=$((status + ret)) - -# -# A zone transitioning from single-signed to multi-signed. -# We should have the old omnipresent keys outside of the -# desired key range and the new keys in the desired key range -# KEY1 and KEY2 are the new keys. KEY3 and KEY4 are the old keys. -# -set_zone "single-to-multisigner.kasp" -set_policy "multisigner-model2" "4" "3600" -set_server "ns3" "10.53.0.3" -key_clear "KEY1" -key_clear "KEY2" -key_clear "KEY3" -key_clear "KEY4" - -# Key properties. -set_keyrole "KEY1" "ksk" -set_keylifetime "KEY1" "0" -set_keyalgorithm "KEY1" "$DEFAULT_ALGORITHM_NUMBER" "$DEFAULT_ALGORITHM" "$DEFAULT_BITS" -set_keysigning "KEY1" "yes" -set_zonesigning "KEY1" "no" - -set_keyrole "KEY2" "zsk" -set_keylifetime "KEY2" "0" -set_keyalgorithm "KEY2" "$DEFAULT_ALGORITHM_NUMBER" "$DEFAULT_ALGORITHM" "$DEFAULT_BITS" -set_keysigning "KEY2" "no" -set_zonesigning "KEY2" "no" # waiting for DNSKEY to be omnipresent - -set_keyrole "KEY3" "ksk" -set_keyalgorithm "KEY3" "$DEFAULT_ALGORITHM_NUMBER" "$DEFAULT_ALGORITHM" "$DEFAULT_BITS" -set_keysigning "KEY3" "yes" -set_zonesigning "KEY3" "no" - -set_keyrole "KEY4" "zsk" -set_keyalgorithm "KEY4" "$DEFAULT_ALGORITHM_NUMBER" "$DEFAULT_ALGORITHM" "$DEFAULT_BITS" -set_keysigning "KEY4" "no" -set_zonesigning "KEY4" "yes" - -set_keystate "KEY1" "GOAL" "omnipresent" -set_keystate "KEY1" "STATE_DNSKEY" "rumoured" -set_keystate "KEY1" "STATE_KRRSIG" "rumoured" -set_keystate "KEY1" "STATE_DS" "hidden" - -set_keystate "KEY2" "GOAL" "omnipresent" -set_keystate "KEY2" "STATE_DNSKEY" "rumoured" -set_keystate "KEY2" "STATE_ZRRSIG" "hidden" # waiting for DNSKEY to be omnipresent - -set_keystate "KEY3" "GOAL" "hidden" -set_keystate "KEY3" "STATE_DNSKEY" "omnipresent" -set_keystate "KEY3" "STATE_KRRSIG" "omnipresent" -set_keystate "KEY3" "STATE_DS" "omnipresent" - -set_keystate "KEY4" "GOAL" "hidden" -set_keystate "KEY4" "STATE_DNSKEY" "omnipresent" -set_keystate "KEY4" "STATE_ZRRSIG" "omnipresent" - -check_keys -check_dnssecstatus "$SERVER" "$POLICY" "$ZONE" -check_apex -check_subdomain -dnssec_verify - -# KEY1 tag range 32768 65535 -# KEY2 tag range 32768 65535 -# KEY3 tag range 0 32767 -# KEY4 tag range 0 32767 -n=$((n + 1)) -echo_i "check that the key IDs are in the expected ranges ($n)" -ret=0 -test $(key_get KEY1 ID) -ge 32768 -a $(key_get KEY1 ID) -le 65535 || ret=1 -test $(key_get KEY2 ID) -ge 32768 -a $(key_get KEY2 ID) -le 65535 || ret=1 -test $(key_get KEY3 ID) -ge 0 -a $(key_get KEY3 ID) -le 32767 || ret=1 -test $(key_get KEY4 ID) -ge 0 -a $(key_get KEY4 ID) -le 32767 || ret=1 - -test $(key_get KEY1 RID) -ge 32768 -a $(key_get KEY1 RID) -le 65535 || ret=1 -test $(key_get KEY2 RID) -ge 32768 -a $(key_get KEY2 RID) -le 65535 || ret=1 -test $(key_get KEY3 RID) -ge 0 -a $(key_get KEY3 RID) -le 32767 || ret=1 -test $(key_get KEY4 RID) -ge 0 -a $(key_get KEY4 RID) -le 32767 || ret=1 -test "$ret" -eq 0 || echo_i "failed" -status=$((status + ret)) - # # Testing DNSSEC introduction. # diff --git a/bin/tests/system/rollover/ns3/kasp.conf.j2 b/bin/tests/system/rollover/ns3/kasp.conf.j2 index bbecf098a8f..2ab26877f0e 100644 --- a/bin/tests/system/rollover/ns3/kasp.conf.j2 +++ b/bin/tests/system/rollover/ns3/kasp.conf.j2 @@ -19,3 +19,13 @@ dnssec-policy "manual-rollover" { zsk key-directory lifetime unlimited algorithm @DEFAULT_ALGORITHM@; }; }; + +dnssec-policy "multisigner-model2" { + dnskey-ttl 3600; + inline-signing no; + + keys { + ksk key-directory lifetime unlimited algorithm @DEFAULT_ALGORITHM@ tag-range 32768 65535; + zsk key-directory lifetime unlimited algorithm @DEFAULT_ALGORITHM@ tag-range 32768 65535; + }; +}; diff --git a/bin/tests/system/rollover/ns3/named.conf.j2 b/bin/tests/system/rollover/ns3/named.conf.j2 index b11a77fc060..573865d1b96 100644 --- a/bin/tests/system/rollover/ns3/named.conf.j2 +++ b/bin/tests/system/rollover/ns3/named.conf.j2 @@ -48,3 +48,22 @@ zone "manual-rollover.kasp" { file "manual-rollover.kasp.db"; dnssec-policy "manual-rollover"; }; + +/* RFC 8901 Multi-signer Model 2. */ +zone "multisigner-model2.kasp" { + type primary; + file "multisigner-model2.kasp.db"; + dnssec-policy "multisigner-model2"; + allow-update { any; }; +}; + +/* + * A zone that starts with keys that have tags that are + * outside of the desired multi-signer key tag range. + */ +zone "single-to-multisigner.kasp" { + type primary; + file "single-to-multisigner.kasp.db"; + dnssec-policy "multisigner-model2"; + allow-update { any; }; +}; diff --git a/bin/tests/system/rollover/ns3/setup.sh b/bin/tests/system/rollover/ns3/setup.sh index 59fd259aed4..969b6a7e6c1 100644 --- a/bin/tests/system/rollover/ns3/setup.sh +++ b/bin/tests/system/rollover/ns3/setup.sh @@ -52,3 +52,30 @@ private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$KSK" >>"$infile" private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$ZSK" >>"$infile" cp $infile $zonefile $SIGNER -PS -x -o $zone -O raw -f "${zonefile}.signed" $infile >signer.out.$zone.1 2>&1 + +# Multi-signer zones. +setup "multisigner-model2.kasp" +cp template.db.in "$zonefile" +KSK=$($KEYGEN -a $DEFAULT_ALGORITHM -f KSK -L 3600 -M 32768:65535 $zone 2>keygen.out.$zone.1) +ZSK=$($KEYGEN -a $DEFAULT_ALGORITHM -L 3600 -M 32768:65535 $zone 2>keygen.out.$zone.2) +cat "${KSK}.key" | grep -v ";.*" >>"${zone}.db" +cat "${ZSK}.key" | grep -v ";.*" >>"${zone}.db" +# Import a ZSK of another provider into the DNSKEY RRset. +ZSK1=$($KEYGEN -K ../ -a $DEFAULT_ALGORITHM -L 3600 -M 0:32767 $zone 2>keygen.out.$zone.3) +cat "../${ZSK1}.key" | grep -v ";.*" >>"${zone}.db" + +# We are changing an existing single-signed zone to multi-signed +# zone where the key tags do not match the dnssec-policy key tag range +setup single-to-multisigner.kasp +T="now-7d" +S="now-8635mi" # T - 1d5m +keytimes="-P $T -A $T" +cdstimes="-P sync $S" +KSK=$($KEYGEN -a $DEFAULT_ALGORITHM -M 0:32767 -L 3600 -f KSK $keytimes $cdstimes $zone 2>keygen.out.$zone.1) +ZSK=$($KEYGEN -a $DEFAULT_ALGORITHM -M 0:32767 -L 3600 $keytimes $zone 2>keygen.out.$zone.2) +$SETTIME -s -g $O -d $O $T -k $O $T -r $O $T "$KSK" >settime.out.$zone.1 2>&1 +$SETTIME -s -g $O -k $O $T -z $O $T "$ZSK" >settime.out.$zone.2 2>&1 +cat template.db.in "${KSK}.key" "${ZSK}.key" >"$infile" +$SIGNER -PS -z -x -s now-2w -e now-1mi -o $zone -f "${zonefile}" $infile >signer.out.$zone.1 2>&1 +echo "Lifetime: 0" >>"${KSK}".state +echo "Lifetime: 0" >>"${ZSK}".state diff --git a/bin/tests/system/rollover/tests_rollover.py b/bin/tests/system/rollover/tests_rollover.py index d85ff71c268..a055639d36a 100644 --- a/bin/tests/system/rollover/tests_rollover.py +++ b/bin/tests/system/rollover/tests_rollover.py @@ -25,8 +25,11 @@ pytestmark = pytest.mark.extra_artifacts( [ "*.axfr*", "dig.out*", + "K*.key*", + "K*.private*", "ns*/*.db", "ns*/*.db.infile", + "ns*/*.db.jnl", "ns*/*.db.jbk", "ns*/*.db.signed", "ns*/*.db.signed.jnl", @@ -220,3 +223,162 @@ def test_rollover_manual(servers): zsk = expected[3].key response = server.rndc(f"dnssec -rollover -key {zsk.tag} {zone}") assert "key is not actively signing" in response + + +def test_rollover_multisigner(servers): + server = servers["ns3"] + policy = "multisigner-model2" + config = { + "dnskey-ttl": timedelta(hours=1), + "ds-ttl": timedelta(days=1), + "max-zone-ttl": timedelta(days=1), + "parent-propagation-delay": timedelta(hours=1), + "publish-safety": timedelta(hours=1), + "retire-safety": timedelta(hours=1), + "signatures-refresh": timedelta(days=5), + "signatures-validity": timedelta(days=14), + "zone-propagation-delay": timedelta(minutes=5), + } + ttl = int(config["dnskey-ttl"].total_seconds()) + alg = os.environ["DEFAULT_ALGORITHM_NUMBER"] + size = os.environ["DEFAULT_BITS"] + + offset = -timedelta(days=7) + offval = int(offset.total_seconds()) + + def keygen(zone): + keygen_command = [ + os.environ.get("KEYGEN"), + "-a", + alg, + "-L", + "3600", + "-M", + "0:32767", + zone, + ] + + return isctest.run.cmd(keygen_command, log_stdout=True).stdout.decode("utf-8") + + def nsupdate(updates): + message = dns.update.UpdateMessage(zone) + for update in updates: + if update[0] == 0: + message.delete(update[1], update[2], update[3]) + else: + message.add(update[1], update[2], update[3], update[4]) + + try: + response = isctest.query.udp( + message, server.ip, server.ports.dns, timeout=3 + ) + assert response.rcode() == dns.rcode.NOERROR + except dns.exception.Timeout: + isctest.log.info(f"error: update timeout for {zone}") + + zone = "multisigner-model2.kasp" + key_properties = [ + f"ksk unlimited {alg} {size} goal:omnipresent dnskey:rumoured krrsig:rumoured ds:hidden tag-range:32768-65535", + f"zsk unlimited {alg} {size} goal:omnipresent dnskey:rumoured zrrsig:rumoured tag-range:32768-65535", + ] + expected = isctest.kasp.policy_to_properties(ttl, key_properties) + + newprops = [f"zsk unlimited {alg} {size} tag-range:0-32767"] + expected2 = isctest.kasp.policy_to_properties(ttl, newprops) + expected2[0].properties["private"] = False + expected2[0].properties["legacy"] = True + expected = expected + expected2 + + ownkeys = isctest.kasp.keydir_to_keylist(zone, server.identifier) + extkeys = isctest.kasp.keydir_to_keylist(zone) + keys = ownkeys + extkeys + ksks = [k for k in ownkeys if k.is_ksk()] + zsks = [k for k in ownkeys if not k.is_ksk()] + zsks = zsks + extkeys + + isctest.kasp.check_zone_is_signed(server, zone) + isctest.kasp.check_keys(zone, keys, expected) + for kp in expected: + kp.set_expected_keytimes(config) + isctest.kasp.check_keytimes(keys, expected) + isctest.kasp.check_dnssecstatus(server, zone, keys, policy=policy) + isctest.kasp.check_apex(server, zone, ksks, zsks) + isctest.kasp.check_subdomain(server, zone, ksks, zsks) + isctest.kasp.check_dnssec_verify(server, zone) + + # Update zone with ZSK from another provider for zone. + out = keygen(zone) + newkeys = isctest.kasp.keystr_to_keylist(out) + newprops = [f"zsk unlimited {alg} {size} tag-range:0-32767"] + expected2 = isctest.kasp.policy_to_properties(ttl, newprops) + expected2[0].properties["private"] = False + expected2[0].properties["legacy"] = True + expected = expected + expected2 + + dnskey = newkeys[0].dnskey().split() + rdata = " ".join(dnskey[4:]) + + updates = [[1, f"{dnskey[0]}", 3600, "DNSKEY", rdata]] + nsupdate(updates) + + keys = keys + newkeys + zsks = zsks + newkeys + isctest.kasp.check_keys(zone, keys, expected) + isctest.kasp.check_apex(server, zone, ksks, zsks) + isctest.kasp.check_subdomain(server, zone, ksks, zsks) + isctest.kasp.check_dnssec_verify(server, zone) + + # Remove ZSKs from the other providers for zone. + dnskey2 = extkeys[0].dnskey().split() + rdata2 = " ".join(dnskey2[4:]) + updates = [ + [0, f"{dnskey[0]}", "DNSKEY", rdata], + [0, f"{dnskey2[0]}", "DNSKEY", rdata2], + ] + nsupdate(updates) + + expected = isctest.kasp.policy_to_properties(ttl, key_properties) + keys = ownkeys + ksks = [k for k in ownkeys if k.is_ksk()] + zsks = [k for k in ownkeys if not k.is_ksk()] + isctest.kasp.check_keys(zone, keys, expected) + isctest.kasp.check_apex(server, zone, ksks, zsks) + isctest.kasp.check_subdomain(server, zone, ksks, zsks) + isctest.kasp.check_dnssec_verify(server, zone) + + # A zone transitioning from single-signed to multi-signed. We should have + # the old omnipresent keys outside of the desired key range and the new + # keys in the desired key range. + zone = "single-to-multisigner.kasp" + key_properties = [ + f"ksk unlimited {alg} {size} goal:omnipresent dnskey:rumoured krrsig:rumoured ds:hidden tag-range:32768-65535", + f"zsk unlimited {alg} {size} goal:omnipresent dnskey:rumoured zrrsig:hidden tag-range:32768-65535", + f"ksk unlimited {alg} {size} goal:hidden dnskey:omnipresent krrsig:omnipresent ds:omnipresent tag-range:0-32767 offset:{offval}", + f"zsk unlimited {alg} {size} goal:hidden dnskey:omnipresent zrrsig:omnipresent tag-range:0-32767 offset:{offval}", + ] + expected = isctest.kasp.policy_to_properties(ttl, key_properties) + keys = isctest.kasp.keydir_to_keylist(zone, server.identifier) + ksks = [k for k in keys if k.is_ksk()] + zsks = [k for k in keys if not k.is_ksk()] + + isctest.kasp.check_zone_is_signed(server, zone) + isctest.kasp.check_keys(zone, keys, expected) + + for kp in expected: + kp.set_expected_keytimes(config) + + start = expected[0].key.get_timing("Created") + expected[2].timing["Retired"] = start + expected[2].timing["Removed"] = expected[2].timing["Retired"] + Iret( + config, zsk=False, ksk=True + ) + expected[3].timing["Retired"] = start + expected[3].timing["Removed"] = expected[3].timing["Retired"] + Iret( + config, zsk=True, ksk=False + ) + + isctest.kasp.check_keytimes(keys, expected) + isctest.kasp.check_dnssecstatus(server, zone, keys, policy=policy) + isctest.kasp.check_apex(server, zone, ksks, zsks) + isctest.kasp.check_subdomain(server, zone, ksks, zsks) + isctest.kasp.check_dnssec_verify(server, zone)