]> git.ipfire.org Git - thirdparty/bind9.git/commitdiff
Test migration to dnssec-policy
authorMatthijs Mekking <matthijs@isc.org>
Mon, 28 Jul 2025 08:05:46 +0000 (10:05 +0200)
committerMatthijs Mekking <matthijs@isc.org>
Tue, 19 Aug 2025 14:07:12 +0000 (14:07 +0000)
Various test cases where legacy keys exist and are used to migrate to
dnssec-policy. These once existed as shell script but were removed
because auto-dnssec was removed. But the test cases are still useful
if one wants to migrate to dnssec-policy with such legacy keys.

The tests were previously removed in commit
906dd57b68dab3526af82ec266f413e11391394d as part of MR !8085.

bin/tests/system/migrate2kasp/ns3/kasp.conf.j2 [new file with mode: 0644]
bin/tests/system/migrate2kasp/ns3/named.conf.j2 [new file with mode: 0644]
bin/tests/system/migrate2kasp/ns3/setup.sh [new file with mode: 0644]
bin/tests/system/migrate2kasp/ns3/template.db.in [new file with mode: 0644]
bin/tests/system/migrate2kasp/ns4/named.conf.j2 [new file with mode: 0644]
bin/tests/system/migrate2kasp/ns4/setup.sh [new file with mode: 0644]
bin/tests/system/migrate2kasp/ns4/template.ext.db.in [new file with mode: 0644]
bin/tests/system/migrate2kasp/ns4/template.int.db.in [new file with mode: 0644]
bin/tests/system/migrate2kasp/setup.sh [new file with mode: 0644]
bin/tests/system/migrate2kasp/tests_migrate2kasp.py [new file with mode: 0644]

diff --git a/bin/tests/system/migrate2kasp/ns3/kasp.conf.j2 b/bin/tests/system/migrate2kasp/ns3/kasp.conf.j2
new file mode 100644 (file)
index 0000000..55a827b
--- /dev/null
@@ -0,0 +1,104 @@
+/*
+ * 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;
+};
diff --git a/bin/tests/system/migrate2kasp/ns3/named.conf.j2 b/bin/tests/system/migrate2kasp/ns3/named.conf.j2
new file mode 100644 (file)
index 0000000..3bf1b59
--- /dev/null
@@ -0,0 +1,103 @@
+/*
+ * 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; };
+};
diff --git a/bin/tests/system/migrate2kasp/ns3/setup.sh b/bin/tests/system/migrate2kasp/ns3/setup.sh
new file mode 100644 (file)
index 0000000..ef2623b
--- /dev/null
@@ -0,0 +1,148 @@
+#!/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
diff --git a/bin/tests/system/migrate2kasp/ns3/template.db.in b/bin/tests/system/migrate2kasp/ns3/template.db.in
new file mode 100644 (file)
index 0000000..5850e01
--- /dev/null
@@ -0,0 +1,26 @@
+; 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
diff --git a/bin/tests/system/migrate2kasp/ns4/named.conf.j2 b/bin/tests/system/migrate2kasp/ns4/named.conf.j2
new file mode 100644 (file)
index 0000000..a365492
--- /dev/null
@@ -0,0 +1,92 @@
+/*
+ * 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; };
+       };
+};
diff --git a/bin/tests/system/migrate2kasp/ns4/setup.sh b/bin/tests/system/migrate2kasp/ns4/setup.sh
new file mode 100644 (file)
index 0000000..914e001
--- /dev/null
@@ -0,0 +1,46 @@
+#!/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"
diff --git a/bin/tests/system/migrate2kasp/ns4/template.ext.db.in b/bin/tests/system/migrate2kasp/ns4/template.ext.db.in
new file mode 100644 (file)
index 0000000..06a7148
--- /dev/null
@@ -0,0 +1,28 @@
+; 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
diff --git a/bin/tests/system/migrate2kasp/ns4/template.int.db.in b/bin/tests/system/migrate2kasp/ns4/template.int.db.in
new file mode 100644 (file)
index 0000000..735c6bc
--- /dev/null
@@ -0,0 +1,28 @@
+; 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
diff --git a/bin/tests/system/migrate2kasp/setup.sh b/bin/tests/system/migrate2kasp/setup.sh
new file mode 100644 (file)
index 0000000..bf03478
--- /dev/null
@@ -0,0 +1,27 @@
+#!/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
+)
diff --git a/bin/tests/system/migrate2kasp/tests_migrate2kasp.py b/bin/tests/system/migrate2kasp/tests_migrate2kasp.py
new file mode 100644 (file)
index 0000000..95b37d7
--- /dev/null
@@ -0,0 +1,343 @@
+# 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)