--- /dev/null
+/*
+ * 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.
+ */
+
+dnssec-policy "migrate" {
+ dnskey-ttl 7200;
+
+ keys {
+ ksk key-directory lifetime unlimited algorithm @DEFAULT_ALGORITHM@;
+ zsk key-directory lifetime P60D algorithm @DEFAULT_ALGORITHM@;
+ };
+};
+
+dnssec-policy "timing-metadata" {
+ dnskey-ttl 300;
+
+ signatures-refresh P1W;
+ signatures-validity P2W;
+ signatures-validity-dnskey P2W;
+
+ keys {
+ ksk key-directory lifetime P60D algorithm @DEFAULT_ALGORITHM@;
+ zsk key-directory lifetime P60D algorithm @DEFAULT_ALGORITHM@;
+ };
+
+ // Together 12h
+ zone-propagation-delay 3600;
+ max-zone-ttl 11h;
+
+ // Together 3h
+ parent-propagation-delay pt1h;
+ parent-ds-ttl 7200;
+};
+
+/*
+ * This policy tests migration from existing keys with 1024 bits RSASHA1 keys
+ * to ECDSAP256SHA256 keys.
+ */
+dnssec-policy "migrate-nomatch-algnum" {
+ dnskey-ttl 300;
+
+ keys {
+ ksk key-directory lifetime unlimited algorithm ecdsa256;
+ zsk key-directory lifetime P60D algorithm ecdsa256;
+ };
+
+ // Together 12h
+ zone-propagation-delay 3600;
+ max-zone-ttl 11h;
+
+ // Together 3h
+ parent-propagation-delay pt1h;
+ parent-ds-ttl 7200;
+};
+
+/*
+ * This policy tests migration from existing keys with 2048 bits RSASHA256 keys
+ * to 3072 bits RSASHA256 keys.
+ */
+dnssec-policy "migrate-nomatch-alglen" {
+ dnskey-ttl 300;
+
+ keys {
+ ksk key-directory lifetime unlimited algorithm rsasha256 3072;
+ zsk key-directory lifetime P60D algorithm rsasha256 3072;
+ };
+
+ // Together 12h
+ zone-propagation-delay 3600;
+ max-zone-ttl 11h;
+
+ // Together 3h
+ parent-propagation-delay pt1h;
+ parent-ds-ttl 7200;
+};
+
+/*
+ * This policy tests migration from existing KSK and ZSK to CSK.
+ * The keys clause matches the default policy.
+ */
+dnssec-policy "migrate-nomatch-kzc" {
+ dnskey-ttl 300;
+
+ keys {
+ csk key-directory lifetime unlimited algorithm @DEFAULT_ALGORITHM@;
+ };
+
+ // Together 12h
+ zone-propagation-delay 3600;
+ max-zone-ttl 11h;
+
+ // Together 3h
+ parent-propagation-delay pt1h;
+ parent-ds-ttl 7200;
+};
--- /dev/null
+/*
+ * 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.
+ */
+
+// NS3
+
+include "kasp.conf";
+
+options {
+ query-source address 10.53.0.3;
+ notify-source 10.53.0.3;
+ transfer-source 10.53.0.3;
+ port @PORT@;
+ pid-file "named.pid";
+ listen-on { 10.53.0.3; };
+ listen-on-v6 { none; };
+ allow-transfer { any; };
+ recursion no;
+ dnssec-validation no;
+};
+
+key rndc_key {
+ secret "1234abcd8765";
+ algorithm @DEFAULT_HMAC@;
+};
+
+controls {
+ inet 10.53.0.3 port @CONTROLPORT@ allow { any; } keys { rndc_key; };
+};
+
+/* These are zones that migrate to dnssec-policy. */
+zone "migrate.kasp" {
+ type primary;
+ file "migrate.kasp.db";
+ dnssec-policy "migrate";
+ inline-signing no;
+ allow-update { any; };
+};
+
+zone "csk.kasp" {
+ type primary;
+ file "csk.kasp.db";
+ dnssec-policy "default";
+ inline-signing no;
+ allow-update { any; };
+};
+
+zone "csk-nosep.kasp" {
+ type primary;
+ file "csk-nosep.kasp.db";
+ dnssec-policy "default";
+ inline-signing no;
+ allow-update { any; };
+};
+
+zone "rumoured.kasp" {
+ type primary;
+ file "rumoured.kasp.db";
+ dnssec-policy "timing-metadata";
+ inline-signing no;
+ allow-update { any; };
+};
+
+zone "omnipresent.kasp" {
+ type primary;
+ file "omnipresent.kasp.db";
+ dnssec-policy "timing-metadata";
+ inline-signing no;
+ allow-update { any; };
+};
+
+zone "migrate-nomatch-algnum.kasp" {
+ type primary;
+ file "migrate-nomatch-algnum.kasp.db";
+ dnssec-policy "migrate-nomatch-algnum";
+ inline-signing no;
+ allow-update { any; };
+};
+
+zone "migrate-nomatch-alglen.kasp" {
+ type primary;
+ file "migrate-nomatch-alglen.kasp.db";
+ dnssec-policy "migrate-nomatch-alglen";
+ inline-signing no;
+ allow-update { any; };
+};
+
+zone "migrate-nomatch-kzc.kasp" {
+ type primary;
+ file "migrate-nomatch-kzc.kasp.db";
+ dnssec-policy "migrate-nomatch-kzc";
+ inline-signing no;
+ allow-update { any; };
+};
--- /dev/null
+#!/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
+
+echo_i "ns3/setup.sh"
+
+setup() {
+ zone="$1"
+ echo_i "setting up zone: $zone"
+ zonefile="${zone}.db"
+ infile="${zone}.db.infile"
+}
+
+# Make lines shorter by storing key states in environment variables.
+H="HIDDEN"
+R="RUMOURED"
+O="OMNIPRESENT"
+U="UNRETENTIVE"
+
+# Set up a zone with auto-dnssec maintain to migrate to dnssec-policy.
+setup migrate.kasp
+echo "$zone" >>zones
+ksktimes="-P now -A now -P sync now"
+zsktimes="-P now -A now"
+KSK=$($KEYGEN -a $DEFAULT_ALGORITHM -L 7200 -f KSK $ksktimes $zone 2>keygen.out.$zone.1)
+ZSK=$($KEYGEN -a $DEFAULT_ALGORITHM -L 7200 $zsktimes $zone 2>keygen.out.$zone.2)
+cat template.db.in "${KSK}.key" "${ZSK}.key" >"$infile"
+private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$KSK" >>"$infile"
+private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$ZSK" >>"$infile"
+$SIGNER -S -x -s now-1h -e now+2w -o $zone -O full -f $zonefile $infile >signer.out.$zone.1 2>&1
+
+# Set up Single-Type Signing Scheme zones with auto-dnssec maintain to
+# migrate to dnssec-policy. This is a zone that has 'update-check-ksk no;'
+# configured, meaning the zone is signed with a single CSK.
+setup csk.kasp
+echo "$zone" >>zones
+csktimes="-P now -A now -P sync now"
+CSK=$($KEYGEN -a $DEFAULT_ALGORITHM -L 7200 -f KSK $csktimes $zone 2>keygen.out.$zone.1)
+cat template.db.in "${CSK}.key" >"$infile"
+private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$CSK" >>"$infile"
+$SIGNER -S -z -s now-1h -e now+2w -o $zone -O full -f $zonefile $infile >signer.out.$zone.1 2>&1
+
+setup csk-nosep.kasp
+echo "$zone" >>zones
+csktimes="-P now -A now -P sync now"
+CSK=$($KEYGEN -a $DEFAULT_ALGORITHM -L 7200 $csktimes $zone 2>keygen.out.$zone.1)
+cat template.db.in "${CSK}.key" >"$infile"
+private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$CSK" >>"$infile"
+$SIGNER -S -z -s now-1h -e now+2w -o $zone -O full -f $zonefile $infile >signer.out.$zone.1 2>&1
+
+# Set up a zone with auto-dnssec maintain to migrate to dnssec-policy, but this
+# time the existing keys do not match the policy. The existing keys are
+# RSASHA256 keys, and will be migrated to a dnssec-policy that dictates
+# ECDSAP256SHA256 keys.
+setup migrate-nomatch-algnum.kasp
+echo "$zone" >>zones
+Tds="now-3h" # Time according to dnssec-policy that DS will be OMNIPRESENT
+Tkey="now-3900s" # DNSKEY TTL + propagation delay
+Tsig="now-12h" # Zone's maximum TTL + propagation delay
+ksktimes="-P ${Tkey} -A ${Tkey} -P sync ${Tds}"
+zsktimes="-P ${Tkey} -A ${Tsig}"
+KSK=$($KEYGEN -a RSASHA256 -b 2048 -L 300 -f KSK $ksktimes $zone 2>keygen.out.$zone.1)
+ZSK=$($KEYGEN -a RSASHA256 -b 2048 -L 300 $zsktimes $zone 2>keygen.out.$zone.2)
+cat template.db.in "${KSK}.key" "${ZSK}.key" >"$infile"
+private_type_record $zone 5 "$KSK" >>"$infile"
+private_type_record $zone 5 "$ZSK" >>"$infile"
+$SIGNER -S -x -s now-1h -e now+2w -o $zone -O full -f $zonefile $infile >signer.out.$zone.1 2>&1
+
+# Set up a zone with auto-dnssec maintain to migrate to dnssec-policy, but this
+# time the existing keys do not match the policy. The existing keys are
+# 2048 bits RSASHA256 keys, and will be migrated to a dnssec-policy that
+# dictates 3072 bits RSASHA256 keys.
+setup migrate-nomatch-alglen.kasp
+echo "$zone" >>zones
+Tds="now-3h" # Time according to dnssec-policy that DS will be OMNIPRESENT
+Tkey="now-3900s" # DNSKEY TTL + propagation delay
+Tsig="now-12h" # Zone's maximum TTL + propagation delay
+ksktimes="-P ${Tkey} -A ${Tkey} -P sync ${Tds}"
+zsktimes="-P ${Tkey} -A ${Tsig}"
+KSK=$($KEYGEN -a RSASHA256 -b 2048 -L 300 -f KSK $ksktimes $zone 2>keygen.out.$zone.1)
+ZSK=$($KEYGEN -a RSASHA256 -b 2048 -L 300 $zsktimes $zone 2>keygen.out.$zone.2)
+cat template.db.in "${KSK}.key" "${ZSK}.key" >"$infile"
+private_type_record $zone 5 "$KSK" >>"$infile"
+private_type_record $zone 5 "$ZSK" >>"$infile"
+$SIGNER -S -x -s now-1h -e now+2w -o $zone -O full -f $zonefile $infile >signer.out.$zone.1 2>&1
+
+# Set up a zone with auto-dnssec maintain to migrate to default dnssec-policy.
+# The zone is signed with KSK/ZSK split, but the dnssec-policy uses CSK.
+setup migrate-nomatch-kzc.kasp
+echo "$zone" >>zones
+Tds="now-3h" # Time according to dnssec-policy that DS will be OMNIPRESENT
+Tkey="now-3900s" # DNSKEY TTL + propagation delay
+Tsig="now-12h" # Zone's maximum TTL + propagation delay
+ksktimes="-P ${Tkey} -A ${Tkey} -P sync ${Tds}"
+zsktimes="-P ${Tkey} -A ${Tsig}"
+KSK=$($KEYGEN -a $DEFAULT_ALGORITHM -L 300 -f KSK $ksktimes $zone 2>keygen.out.$zone.1)
+ZSK=$($KEYGEN -a $DEFAULT_ALGORITHM -L 300 $zsktimes $zone 2>keygen.out.$zone.2)
+cat template.db.in "${KSK}.key" "${ZSK}.key" >"$infile"
+cp $infile $zonefile
+private_type_record $zone 5 "$KSK" >>"$infile"
+private_type_record $zone 5 "$ZSK" >>"$infile"
+$SIGNER -PS -x -s now-1h -e now+2w -o $zone -O raw -f "${zonefile}.signed" $infile >signer.out.$zone.1 2>&1
+
+#
+# Set up zones to test time metadata correctly sets state.
+#
+
+# Key states expected to be rumoured after migration.
+setup rumoured.kasp
+echo "$zone" >>zones
+Tds="now-2h"
+Tkey="now-300s"
+Tsig="now-11h"
+ksktimes="-P ${Tkey} -A ${Tkey} -P sync ${Tds}"
+zsktimes="-P ${Tkey} -A ${Tsig}"
+KSK=$($KEYGEN -a $DEFAULT_ALGORITHM -L 300 -f KSK $ksktimes $zone 2>keygen.out.$zone.1)
+ZSK=$($KEYGEN -a $DEFAULT_ALGORITHM -L 300 $zsktimes $zone 2>keygen.out.$zone.2)
+cat template.db.in "${KSK}.key" "${ZSK}.key" >"$infile"
+private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$KSK" >>"$infile"
+private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$ZSK" >>"$infile"
+$SIGNER -S -x -s now-1h -e now+2w -o $zone -O full -f $zonefile $infile >signer.out.$zone.1 2>&1
+
+# Key states expected to be omnipresent after migration.
+setup omnipresent.kasp
+echo "$zone" >>zones
+Tds="now-3h" # Time according to dnssec-policy that DS will be OMNIPRESENT
+Tkey="now-3900s" # DNSKEY TTL + propagation delay
+Tsig="now-12h" # Zone's maximum TTL + propagation delay
+ksktimes="-P ${Tkey} -A ${Tkey} -P sync ${Tds}"
+zsktimes="-P ${Tkey} -A ${Tsig}"
+KSK=$($KEYGEN -a $DEFAULT_ALGORITHM -L 300 -f KSK $ksktimes $zone 2>keygen.out.$zone.1)
+ZSK=$($KEYGEN -a $DEFAULT_ALGORITHM -L 300 $zsktimes $zone 2>keygen.out.$zone.2)
+cat template.db.in "${KSK}.key" "${ZSK}.key" >"$infile"
+private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$KSK" >>"$infile"
+private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$ZSK" >>"$infile"
+$SIGNER -S -x -s now-1h -e now+2w -o $zone -O full -f $zonefile $infile >signer.out.$zone.1 2>&1
--- /dev/null
+; 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.
+
+$TTL 300
+@ IN SOA mname1. . (
+ 1 ; serial
+ 20 ; refresh (20 seconds)
+ 20 ; retry (20 seconds)
+ 1814400 ; expire (3 weeks)
+ 3600 ; minimum (1 hour)
+ )
+
+ NS ns3
+ns3 A 10.53.0.3
+
+a A 10.0.0.1
+b A 10.0.0.2
+c A 10.0.0.3
--- /dev/null
+/*
+ * 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.
+ */
+
+// NS4
+
+options {
+ query-source address 10.53.0.4;
+ notify-source 10.53.0.4;
+ transfer-source 10.53.0.4;
+ port @PORT@;
+ pid-file "named.pid";
+ listen-on { 10.53.0.4; };
+ listen-on-v6 { none; };
+ allow-transfer { any; };
+ recursion no;
+ key-directory ".";
+ dnssec-validation no;
+};
+
+key rndc_key {
+ secret "1234abcd8765";
+ algorithm @DEFAULT_HMAC@;
+};
+
+controls {
+ inet 10.53.0.4 port @CONTROLPORT@ allow { any; } keys { rndc_key; };
+};
+
+dnssec-policy "rsasha256" {
+ keys {
+ zsk key-directory lifetime P3M algorithm 8 2048;
+ ksk key-directory lifetime P1Y algorithm 8 2048;
+ };
+
+ dnskey-ttl 300;
+ publish-safety 1h;
+ retire-safety 1h;
+
+ signatures-refresh 5d;
+ signatures-validity 14d;
+ signatures-validity-dnskey 14d;
+
+ max-zone-ttl 1d;
+ zone-propagation-delay 300;
+
+ parent-ds-ttl 86400;
+ parent-propagation-delay 3h;
+};
+
+key "external" {
+ algorithm @DEFAULT_HMAC@;
+ secret "YPfMoAk6h+3iN8MDRQC004iSNHY=";
+};
+
+key "internal" {
+ algorithm @DEFAULT_HMAC@;
+ secret "4xILSZQnuO1UKubXHkYUsvBRPu8=";
+};
+
+view "ext" {
+ match-clients { key "external"; };
+
+ zone "view-rsasha256.kasp" {
+ type primary;
+ file "view-rsasha256.kasp.ext.db";
+ dnssec-policy "rsasha256";
+ inline-signing no;
+ allow-update { any; };
+ };
+};
+
+view "int" {
+ match-clients { key "internal"; };
+
+ zone "view-rsasha256.kasp" {
+ type primary;
+ file "view-rsasha256.kasp.int.db";
+ dnssec-policy "rsasha256";
+ inline-signing no;
+ allow-update { any; };
+ };
+};
--- /dev/null
+#!/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
+
+echo_i "ns4/setup.sh"
+
+# Make lines shorter by storing key states in environment variables.
+H="HIDDEN"
+R="RUMOURED"
+O="OMNIPRESENT"
+U="UNRETENTIVE"
+
+zone="view-rsasha256.kasp"
+algo="RSASHA256"
+num="8"
+echo "$zone" >>zones
+
+# Set up zones in views with auto-dnssec maintain to migrate to dnssec-policy.
+# The keys for these zones are in use long enough that they should start a
+# rollover for the ZSK (P3M), but not long enough to initiate a KSK rollover (P1Y).
+ksktimes="-P -93d -A -93d -P sync -93d"
+zsktimes="-P -93d -A -93d"
+KSK=$($KEYGEN -a $algo -L 300 -b 2048 -f KSK $ksktimes $zone 2>keygen.out.$zone.1)
+ZSK=$($KEYGEN -a $algo -L 300 -b 2048 $zsktimes $zone 2>keygen.out.$zone.2)
+
+echo_i "setting up zone $zone (external)"
+view="ext"
+zonefile="${zone}.${view}.db"
+cat template.$view.db.in "${KSK}.key" "${ZSK}.key" >"$zonefile"
+
+echo_i "setting up zone $zone (internal)"
+view="int"
+zonefile="${zone}.${view}.db"
+cat template.$view.db.in "${KSK}.key" "${ZSK}.key" >"$zonefile"
--- /dev/null
+; 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.
+
+$TTL 300
+@ IN SOA mname1. . (
+ 1 ; serial
+ 20 ; refresh (20 seconds)
+ 20 ; retry (20 seconds)
+ 1814400 ; expire (3 weeks)
+ 3600 ; minimum (1 hour)
+ )
+
+ NS ns4
+ns4 A 10.53.0.4
+
+view TXT "external"
+
+a A 10.0.0.1
+b A 10.0.0.2
+c A 10.0.0.3
--- /dev/null
+; 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.
+
+$TTL 300
+@ IN SOA mname1. . (
+ 1 ; serial
+ 20 ; refresh (20 seconds)
+ 20 ; retry (20 seconds)
+ 1814400 ; expire (3 weeks)
+ 3600 ; minimum (1 hour)
+ )
+
+ NS ns4
+ns4 A 10.53.0.4
+
+view TXT "internal"
+
+a A 10.0.0.1
+b A 10.0.0.2
+c A 10.0.0.3
--- /dev/null
+#!/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
+
+set -e
+
+# Setup zones
+(
+ cd ns3
+ $SHELL setup.sh
+)
+(
+ cd ns4
+ $SHELL setup.sh
+)
--- /dev/null
+# 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.
+
+import os
+
+from datetime import timedelta
+
+import pytest
+
+pytest.importorskip("dns", minversion="2.0.0")
+import isctest
+import isctest.mark
+
+pytestmark = pytest.mark.extra_artifacts(
+ [
+ "*.axfr",
+ "*.created",
+ "created.key-*",
+ "dig.out*",
+ "ns*/*.mkeys*",
+ "ns*/dsset-*",
+ "ns*/K*.key",
+ "ns*/K*.private",
+ "ns*/K*.state",
+ "ns*/kasp.conf",
+ "ns*/keygen.out*",
+ "ns*/managed-keys.bind*",
+ "ns*/named.conf",
+ "ns*/named.memstats",
+ "ns*/named.run",
+ "ns*/signer.out*",
+ "ns*/zones",
+ "ns*/*.db",
+ "ns*/*.db.infile",
+ "ns*/*.db.jbk",
+ "ns*/*.db.jnl",
+ "ns*/*.db.signed*",
+ "python.out.*",
+ "retired.*",
+ "rndc.dnssec.*",
+ "unused.key*",
+ "verify.out.*",
+ ]
+)
+
+default_config = {
+ "dnskey-ttl": timedelta(hours=1),
+ "ds-ttl": timedelta(days=1),
+ "key-directory": "{keydir}",
+ "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),
+}
+
+standard_config = {
+ "dnskey-ttl": timedelta(seconds=7200),
+ "ds-ttl": timedelta(days=1),
+ "key-directory": "{keydir}",
+ "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),
+}
+
+timing_config = {
+ "dnskey-ttl": timedelta(seconds=300),
+ "ds-ttl": timedelta(seconds=7200),
+ "key-directory": "{keydir}",
+ "max-zone-ttl": timedelta(hours=11),
+ "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(seconds=3600),
+}
+
+migrate_config = {
+ "dnskey-ttl": timedelta(seconds=300),
+ "ds-ttl": timedelta(seconds=7200),
+ "key-directory": "{keydir}",
+ "max-zone-ttl": timedelta(hours=11),
+ "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(seconds=3600),
+}
+
+view_config = {
+ "dnskey-ttl": timedelta(seconds=300),
+ "ds-ttl": timedelta(seconds=86400),
+ "key-directory": "{keydir}",
+ "max-zone-ttl": timedelta(days=1),
+ "parent-propagation-delay": timedelta(hours=3),
+ "publish-safety": timedelta(hours=1),
+ "retire-safety": timedelta(hours=1),
+ "signatures-refresh": timedelta(days=5),
+ "signatures-validity": timedelta(days=14),
+ "zone-propagation-delay": timedelta(seconds=300),
+}
+
+lifetime = {
+ "P60D": int(timedelta(days=60).total_seconds()),
+ "P3M": int(timedelta(days=31 * 3).total_seconds()),
+ "P1Y": int(timedelta(days=365).total_seconds()),
+}
+
+
+@pytest.mark.parametrize(
+ "params",
+ [
+ # Testing good migration (KSK/ZSK).
+ pytest.param(
+ {
+ "zone": "migrate.kasp",
+ "policy": "migrate",
+ "server": "ns3",
+ "config": standard_config,
+ "offset": 0,
+ "key-properties": [
+ f"ksk 0 {os.environ['DEFAULT_ALGORITHM_NUMBER']} {os.environ['DEFAULT_BITS']} goal:omnipresent dnskey:rumoured krrsig:rumoured ds:rumoured",
+ f"zsk {lifetime['P60D']} {os.environ['DEFAULT_ALGORITHM_NUMBER']} {os.environ['DEFAULT_BITS']} goal:omnipresent dnskey:rumoured zrrsig:rumoured",
+ ],
+ },
+ id="migrate.kasp",
+ ),
+ # Testing a good migration (CSK).
+ pytest.param(
+ {
+ "zone": "csk.kasp",
+ "policy": "default",
+ "server": "ns3",
+ "config": default_config,
+ "offset": 0,
+ "key-properties": [
+ f"csk 0 {os.environ['DEFAULT_ALGORITHM_NUMBER']} {os.environ['DEFAULT_BITS']} goal:omnipresent dnskey:rumoured krrsig:rumoured zrrsig:rumoured ds:rumoured",
+ ],
+ },
+ id="csk.kasp",
+ ),
+ # Testing a good migration (CSK, no SEP).
+ pytest.param(
+ {
+ "zone": "csk-nosep.kasp",
+ "policy": "default",
+ "server": "ns3",
+ "config": default_config,
+ "offset": 0,
+ "key-properties": [
+ f"csk 0 {os.environ['DEFAULT_ALGORITHM_NUMBER']} {os.environ['DEFAULT_BITS']} goal:omnipresent dnskey:rumoured krrsig:rumoured zrrsig:rumoured ds:rumoured",
+ ],
+ },
+ id="csk-nosep.kasp",
+ ),
+ # Testing key states derived from timing metadata: rumoured.
+ pytest.param(
+ {
+ "zone": "rumoured.kasp",
+ "policy": "timing-metadata",
+ "server": "ns3",
+ "config": timing_config,
+ "offset": -timedelta(seconds=300),
+ "key-properties": [
+ f"ksk {lifetime['P60D']} {os.environ['DEFAULT_ALGORITHM_NUMBER']} {os.environ['DEFAULT_BITS']} goal:omnipresent dnskey:rumoured krrsig:rumoured ds:rumoured",
+ f"zsk {lifetime['P60D']} {os.environ['DEFAULT_ALGORITHM_NUMBER']} {os.environ['DEFAULT_BITS']} goal:omnipresent dnskey:rumoured zrrsig:rumoured",
+ ],
+ },
+ id="rumoured.kasp",
+ ),
+ # Testing key states derived from timing metadata: omnipresent.
+ pytest.param(
+ {
+ "zone": "omnipresent.kasp",
+ "policy": "timing-metadata",
+ "server": "ns3",
+ "config": timing_config,
+ "offset": -timedelta(seconds=3900),
+ "key-properties": [
+ f"ksk {lifetime['P60D']} {os.environ['DEFAULT_ALGORITHM_NUMBER']} {os.environ['DEFAULT_BITS']} goal:omnipresent dnskey:omnipresent krrsig:omnipresent ds:omnipresent",
+ f"zsk {lifetime['P60D']} {os.environ['DEFAULT_ALGORITHM_NUMBER']} {os.environ['DEFAULT_BITS']} goal:omnipresent dnskey:omnipresent zrrsig:omnipresent",
+ ],
+ },
+ id="omnipresent.kasp",
+ ),
+ # Test migration to dnssec-policy, existing keys do not match key algorithm.
+ pytest.param(
+ {
+ "zone": "migrate-nomatch-algnum.kasp",
+ "policy": "migrate-nomatch-algnum",
+ "server": "ns3",
+ "config": migrate_config,
+ "offset": -timedelta(seconds=3900),
+ "key-properties": [
+ "ksk - 8 2048 goal:hidden dnskey:omnipresent krrsig:omnipresent ds:omnipresent",
+ "zsk - 8 2048 goal:hidden dnskey:omnipresent zrrsig:omnipresent",
+ f"ksk 0 {os.environ['DEFAULT_ALGORITHM_NUMBER']} {os.environ['DEFAULT_BITS']} goal:omnipresent dnskey:rumoured krrsig:rumoured ds:hidden",
+ f"zsk {lifetime['P60D']} {os.environ['DEFAULT_ALGORITHM_NUMBER']} {os.environ['DEFAULT_BITS']} goal:omnipresent dnskey:rumoured zrrsig:rumoured",
+ ],
+ },
+ id="migrate-nomatch-algnum.kasp",
+ ),
+ # Test migration to dnssec-policy, existing keys do not match key length.
+ pytest.param(
+ {
+ "zone": "migrate-nomatch-alglen.kasp",
+ "policy": "migrate-nomatch-alglen",
+ "server": "ns3",
+ "config": migrate_config,
+ "offset": -timedelta(seconds=3900),
+ "key-properties": [
+ "ksk - 8 2048 goal:hidden dnskey:omnipresent krrsig:omnipresent ds:omnipresent",
+ "zsk - 8 2048 goal:hidden dnskey:omnipresent zrrsig:omnipresent",
+ "ksk 0 8 3072 goal:omnipresent dnskey:rumoured krrsig:rumoured ds:hidden",
+ # This key is considered to be prepublished, so it is not yet signing.
+ f"zsk {lifetime['P60D']} 8 3072 goal:omnipresent dnskey:rumoured zrrsig:hidden",
+ ],
+ },
+ id="migrate-nomatch-alglen.kasp",
+ ),
+ # Test migration to dnssec-policy, existing keys do not match role (KSK/ZSK -> CSK).
+ pytest.param(
+ {
+ "zone": "migrate-nomatch-kzc.kasp",
+ "policy": "migrate-nomatch-kzc",
+ "server": "ns3",
+ "config": migrate_config,
+ "offset": -timedelta(seconds=3900),
+ "key-properties": [
+ f"ksk - {os.environ['DEFAULT_ALGORITHM_NUMBER']} {os.environ['DEFAULT_BITS']} goal:hidden dnskey:omnipresent krrsig:omnipresent ds:omnipresent",
+ f"zsk - {os.environ['DEFAULT_ALGORITHM_NUMBER']} {os.environ['DEFAULT_BITS']} goal:hidden dnskey:omnipresent zrrsig:omnipresent",
+ # This key is considered to be prepublished, so it is not yet signing, nor is the DS introduced.
+ f"csk 0 {os.environ['DEFAULT_ALGORITHM_NUMBER']} {os.environ['DEFAULT_BITS']} goal:omnipresent dnskey:rumoured krrsig:rumoured zrrsig:hidden ds:hidden",
+ ],
+ },
+ id="migrate-nomatch-kzc.kasp",
+ ),
+ # Test good migration with views.
+ pytest.param(
+ {
+ "zone": "view-rsasha256.kasp",
+ "policy": "rsasha256",
+ "server": "ns4",
+ "config": view_config,
+ "offset": -timedelta(days=31 * 3),
+ "key-properties": [
+ f"zsk {lifetime['P3M']} 8 2048 goal:hidden dnskey:omnipresent zrrsig:omnipresent",
+ f"zsk {lifetime['P3M']} 8 2048 goal:omnipresent dnskey:rumoured zrrsig:hidden",
+ f"ksk {lifetime['P1Y']} 8 2048 goal:omnipresent dnskey:omnipresent krrsig:omnipresent ds:omnipresent",
+ ],
+ "view": "ext",
+ "tsig": "external:YPfMoAk6h+3iN8MDRQC004iSNHY=",
+ },
+ id="view-rsasha256.kasp (external)",
+ ),
+ pytest.param(
+ {
+ "zone": "view-rsasha256.kasp",
+ "policy": "rsasha256",
+ "server": "ns4",
+ "config": view_config,
+ "offset": -timedelta(days=31 * 3),
+ "key-properties": [
+ f"zsk {lifetime['P3M']} 8 2048 goal:hidden dnskey:omnipresent zrrsig:omnipresent",
+ f"zsk {lifetime['P3M']} 8 2048 goal:omnipresent dnskey:rumoured zrrsig:hidden",
+ f"ksk {lifetime['P1Y']} 8 2048 goal:omnipresent dnskey:omnipresent krrsig:omnipresent ds:omnipresent",
+ ],
+ "view": "int",
+ "tsig": "internal:4xILSZQnuO1UKubXHkYUsvBRPu8=",
+ },
+ id="view-rsasha256.kasp (internal)",
+ ),
+ ],
+)
+def test_migrate2kasp_case(servers, params):
+ # Get test parameters.
+ zone = params["zone"]
+ policy = params["policy"]
+ server = servers[params["server"]]
+ keydir = server.identifier
+ view = params.get("view", None)
+ tsig = None
+ if "tsig" in params:
+ secret = params["tsig"]
+ tsig = f"{os.environ['DEFAULT_HMAC']}:{secret}"
+
+ isctest.kasp.wait_keymgr_done(server, zone)
+
+ params["config"]["key-directory"] = params["config"]["key-directory"].replace(
+ "{keydir}", keydir
+ )
+ ttl = int(params["config"]["dnskey-ttl"].total_seconds())
+
+ # Test case.
+ isctest.log.info(f"check test case zone {zone} policy {policy}")
+
+ # First make sure the zone is signed.
+ isctest.kasp.check_dnssec_verify(server, zone, tsig=tsig)
+
+ # Key properties.
+ expected = isctest.kasp.policy_to_properties(ttl=ttl, keys=params["key-properties"])
+
+ # Special case: CSK without SEP bit set.
+ if zone == "csk-nosep.kasp":
+ expected[0].properties["role_full"] = "zone-signing"
+ expected[0].properties["flags"] = 256
+
+ # Key files.
+ keys = isctest.kasp.keydir_to_keylist(zone, params["config"]["key-directory"])
+ ksks = [k for k in keys if k.is_ksk()]
+ zsks = [k for k in keys if not k.is_ksk()]
+ isctest.kasp.check_keys(zone, keys, expected)
+
+ offset = params["offset"] if "offset" in params else None
+
+ for expect in expected:
+ expect.set_expected_keytimes(params["config"], offset=offset, migrate=True)
+
+ isctest.kasp.check_dnssecstatus(server, zone, ksks + zsks, policy=policy, view=view)
+ isctest.kasp.check_apex(server, zone, ksks, zsks, tsig=tsig)
+ isctest.kasp.check_subdomain(server, zone, ksks, zsks, tsig=tsig)
+
+ if "additional-tests" in params:
+ for additional_test in params["additional-tests"]:
+ callback = additional_test["callback"]
+ arguments = additional_test["arguments"]
+ callback(*arguments, params=params, ksks=ksks, zsks=zsks)