summaryrefslogtreecommitdiffstats
path: root/bin/tests/system/kasp
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 15:59:48 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 15:59:48 +0000
commit3b9b6d0b8e7f798023c9d109c490449d528fde80 (patch)
tree2e1c188dd7b8d7475cd163de9ae02c428343669b /bin/tests/system/kasp
parentInitial commit. (diff)
downloadbind9-3b9b6d0b8e7f798023c9d109c490449d528fde80.tar.xz
bind9-3b9b6d0b8e7f798023c9d109c490449d528fde80.zip
Adding upstream version 1:9.18.19.upstream/1%9.18.19upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'bin/tests/system/kasp')
-rw-r--r--bin/tests/system/kasp/README23
-rw-r--r--bin/tests/system/kasp/clean.sh36
-rw-r--r--bin/tests/system/kasp/kasp.conf27
-rw-r--r--bin/tests/system/kasp/ns2/named.conf.in62
-rw-r--r--bin/tests/system/kasp/ns2/secondary.kasp.db.in29
-rw-r--r--bin/tests/system/kasp/ns2/secondary.kasp.db.in230
-rw-r--r--bin/tests/system/kasp/ns2/setup.sh35
-rw-r--r--bin/tests/system/kasp/ns2/template.tld.db.in27
-rw-r--r--bin/tests/system/kasp/ns3/ed25519.conf29
-rw-r--r--bin/tests/system/kasp/ns3/ed448.conf29
-rw-r--r--bin/tests/system/kasp/ns3/named-fips.conf.in520
-rw-r--r--bin/tests/system/kasp/ns3/named.conf.in30
-rw-r--r--bin/tests/system/kasp/ns3/policies/autosign.conf.in133
-rw-r--r--bin/tests/system/kasp/ns3/policies/kasp-fips.conf.in118
-rw-r--r--bin/tests/system/kasp/ns3/policies/kasp.conf.in34
-rw-r--r--bin/tests/system/kasp/ns3/setup.sh1470
-rw-r--r--bin/tests/system/kasp/ns3/template.db.in27
-rw-r--r--bin/tests/system/kasp/ns3/template2.db.in27
-rw-r--r--bin/tests/system/kasp/ns4/example1.db.in24
-rw-r--r--bin/tests/system/kasp/ns4/example2.db.in24
-rw-r--r--bin/tests/system/kasp/ns4/named.conf.in177
-rw-r--r--bin/tests/system/kasp/ns4/setup.sh33
-rw-r--r--bin/tests/system/kasp/ns4/template.db.in27
-rw-r--r--bin/tests/system/kasp/ns5/named.conf.in133
-rw-r--r--bin/tests/system/kasp/ns5/setup.sh30
-rw-r--r--bin/tests/system/kasp/ns5/template.db.in27
-rw-r--r--bin/tests/system/kasp/ns6/example.db.in26
-rw-r--r--bin/tests/system/kasp/ns6/example2.db.in26
-rw-r--r--bin/tests/system/kasp/ns6/example3.db.in26
-rw-r--r--bin/tests/system/kasp/ns6/named.conf.in98
-rw-r--r--bin/tests/system/kasp/ns6/named2.conf.in186
-rw-r--r--bin/tests/system/kasp/ns6/policies/csk1.conf.in30
-rw-r--r--bin/tests/system/kasp/ns6/policies/csk2.conf.in30
-rw-r--r--bin/tests/system/kasp/ns6/policies/kasp-fips.conf.in63
-rw-r--r--bin/tests/system/kasp/ns6/policies/kasp.conf.in33
-rw-r--r--bin/tests/system/kasp/ns6/setup.sh409
-rw-r--r--bin/tests/system/kasp/ns6/template.db.in27
-rw-r--r--bin/tests/system/kasp/setup.sh80
-rw-r--r--bin/tests/system/kasp/tests.sh4883
-rw-r--r--bin/tests/system/kasp/tests_sh_kasp.py14
40 files changed, 9092 insertions, 0 deletions
diff --git a/bin/tests/system/kasp/README b/bin/tests/system/kasp/README
new file mode 100644
index 0000000..96b0ef7
--- /dev/null
+++ b/bin/tests/system/kasp/README
@@ -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.
+
+The test setup for the KASP tests.
+
+ns1 is reserved for the root server.
+
+ns2 is running primary service for ns3.
+
+ns3 is an authoritative server for the various test domains.
+
+ns4 and ns5 are authoritative servers for various test domains related to views.
+
+ns6 is an authoritative server that tests changes in dnssec-policy (algorithm
+rollover).
diff --git a/bin/tests/system/kasp/clean.sh b/bin/tests/system/kasp/clean.sh
new file mode 100644
index 0000000..db264c2
--- /dev/null
+++ b/bin/tests/system/kasp/clean.sh
@@ -0,0 +1,36 @@
+#!/bin/sh
+
+# 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.
+
+set -e
+
+rm -f ./keygen.*
+rm -f ./K*.private ./K*.key ./K*.state ./K*.cmp
+rm -rf ./keys/
+rm -f dig.out* rrsig.out.* keyevent.out.* verify.out.* zone.out.*
+rm -f ns*/named.conf ns*/named.memstats ns*/named.run*
+rm -f ns*/named-fips.conf
+rm -f ns*/policies/*.conf
+rm -f ns*/*.jnl ns*/*.jbk
+rm -f ns*/K*.private ns*/K*.key ns*/K*.state
+rm -f ns*/dsset-* ns*/*.db ns*/*.db.signed
+rm -f ns*/keygen.out.* ns*/settime.out.* ns*/signer.out.*
+rm -f ns*/managed-keys.bind
+rm -f ns*/*.mkeys
+rm -f ns*/zones ns*/*.db.infile
+rm -f ns*/*.zsk1 ns*/*.zsk2
+rm -f ns3/legacy-keys.*
+rm -f *.created published.test* retired.test*
+rm -f rndc.dnssec.*.out.* rndc.zonestatus.out.*
+rm -f python.out.*
+rm -f *-supported.file
+rm -f created.key-* unused.key-*
diff --git a/bin/tests/system/kasp/kasp.conf b/bin/tests/system/kasp/kasp.conf
new file mode 100644
index 0000000..e7a2eab
--- /dev/null
+++ b/bin/tests/system/kasp/kasp.conf
@@ -0,0 +1,27 @@
+/*
+ * 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.
+ */
+
+/*
+ * This is just a random selection of configuration options.
+ */
+
+dnssec-policy "kasp" {
+ dnskey-ttl 200;
+
+ keys {
+ csk key-directory lifetime P1Y algorithm 13;
+ ksk key-directory lifetime P1Y algorithm 8;
+ zsk key-directory lifetime P30D algorithm 8 2048;
+ zsk key-directory lifetime P6M algorithm 8 3072;
+ };
+};
diff --git a/bin/tests/system/kasp/ns2/named.conf.in b/bin/tests/system/kasp/ns2/named.conf.in
new file mode 100644
index 0000000..bdbacc2
--- /dev/null
+++ b/bin/tests/system/kasp/ns2/named.conf.in
@@ -0,0 +1,62 @@
+/*
+ * 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.
+ */
+
+// NS2
+
+options {
+ query-source address 10.53.0.2;
+ notify-source 10.53.0.2;
+ transfer-source 10.53.0.2;
+ port @PORT@;
+ pid-file "named.pid";
+ listen-on { 10.53.0.2; };
+ listen-on-v6 { none; };
+ allow-transfer { any; };
+ recursion no;
+ dnssec-policy "none";
+ dnssec-validation no;
+};
+
+key rndc_key {
+ secret "1234abcd8765";
+ algorithm @DEFAULT_HMAC@;
+};
+
+controls {
+ inet 10.53.0.2 port @CONTROLPORT@ allow { any; } keys { rndc_key; };
+};
+
+/* Inherit dnssec-policy (which is none) */
+
+zone "unsigned.tld" {
+ type primary;
+ file "unsigned.tld.db";
+};
+
+/* Override dnssec-policy */
+
+zone "signed.tld" {
+ type primary;
+ file "signed.tld.db";
+ dnssec-policy "default";
+ inline-signing yes;
+};
+
+/* Primary service for ns3 */
+
+zone "secondary.kasp" {
+ type primary;
+ file "secondary.kasp.db";
+ allow-transfer { 10.53.0.3; };
+ notify yes;
+};
diff --git a/bin/tests/system/kasp/ns2/secondary.kasp.db.in b/bin/tests/system/kasp/ns2/secondary.kasp.db.in
new file mode 100644
index 0000000..3c8d124
--- /dev/null
+++ b/bin/tests/system/kasp/ns2/secondary.kasp.db.in
@@ -0,0 +1,29 @@
+; 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 secondary.kasp. hostmaster.kasp. (
+ 1 ; serial
+ 20 ; refresh (20 seconds)
+ 20 ; retry (20 seconds)
+ 1814400 ; expire (3 weeks)
+ 3600 ; minimum (1 hour)
+ )
+
+ NS ns2
+ NS ns3
+ns2 A 10.53.0.2
+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/kasp/ns2/secondary.kasp.db.in2 b/bin/tests/system/kasp/ns2/secondary.kasp.db.in2
new file mode 100644
index 0000000..9289831
--- /dev/null
+++ b/bin/tests/system/kasp/ns2/secondary.kasp.db.in2
@@ -0,0 +1,30 @@
+; 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 secondary.kasp. hostmaster.kasp. (
+ 2 ; serial
+ 20 ; refresh (20 seconds)
+ 20 ; retry (20 seconds)
+ 1814400 ; expire (3 weeks)
+ 3600 ; minimum (1 hour)
+ )
+
+ NS ns2
+ NS ns3
+ns2 A 10.53.0.2
+ns3 A 10.53.0.3
+
+a A 10.0.0.11
+b A 10.0.0.2
+c A 10.0.0.3
+d A 10.0.0.4
+
diff --git a/bin/tests/system/kasp/ns2/setup.sh b/bin/tests/system/kasp/ns2/setup.sh
new file mode 100644
index 0000000..cdf0f26
--- /dev/null
+++ b/bin/tests/system/kasp/ns2/setup.sh
@@ -0,0 +1,35 @@
+#!/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 "ns2/setup.sh"
+
+zone="secondary.kasp"
+echo_i "setting up zone: $zone"
+zonefile="${zone}.db"
+infile="${zonefile}.in"
+cp $infile $zonefile
+
+zone="signed.tld"
+echo_i "setting up zone: $zone"
+zonefile="${zone}.db"
+infile="template.tld.db.in"
+cp $infile $zonefile
+
+zone="unsigned.tld"
+echo_i "setting up zone: $zone"
+zonefile="${zone}.db"
+infile="template.tld.db.in"
+cp $infile $zonefile
diff --git a/bin/tests/system/kasp/ns2/template.tld.db.in b/bin/tests/system/kasp/ns2/template.tld.db.in
new file mode 100644
index 0000000..400dc34
--- /dev/null
+++ b/bin/tests/system/kasp/ns2/template.tld.db.in
@@ -0,0 +1,27 @@
+; 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 secondary.kasp. hostmaster.kasp. (
+ 1 ; serial
+ 20 ; refresh (20 seconds)
+ 20 ; retry (20 seconds)
+ 1814400 ; expire (3 weeks)
+ 3600 ; minimum (1 hour)
+ )
+
+ NS ns2
+ns2 A 10.53.0.2
+
+a A 10.0.0.1
+b A 10.0.0.2
+c A 10.0.0.3
+
diff --git a/bin/tests/system/kasp/ns3/ed25519.conf b/bin/tests/system/kasp/ns3/ed25519.conf
new file mode 100644
index 0000000..999fa2f
--- /dev/null
+++ b/bin/tests/system/kasp/ns3/ed25519.conf
@@ -0,0 +1,29 @@
+/*
+ * 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 "ed25519" {
+ dnskey-ttl 1234;
+
+ keys {
+ ksk key-directory lifetime P10Y algorithm 15;
+ zsk key-directory lifetime P5Y algorithm 15;
+ zsk key-directory lifetime P1Y algorithm 15 256;
+ };
+};
+
+zone "ed25519.kasp" {
+ type primary;
+ file "ed25519.kasp.db";
+ inline-signing yes;
+ dnssec-policy "ed25519";
+};
diff --git a/bin/tests/system/kasp/ns3/ed448.conf b/bin/tests/system/kasp/ns3/ed448.conf
new file mode 100644
index 0000000..e9c8312
--- /dev/null
+++ b/bin/tests/system/kasp/ns3/ed448.conf
@@ -0,0 +1,29 @@
+/*
+ * 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 "ed448" {
+ dnskey-ttl 1234;
+
+ keys {
+ ksk key-directory lifetime P10Y algorithm 16;
+ zsk key-directory lifetime P5Y algorithm 16;
+ zsk key-directory lifetime P1Y algorithm 16 456;
+ };
+};
+
+zone "ed448.kasp" {
+ type primary;
+ file "ed448.kasp.db";
+ inline-signing yes;
+ dnssec-policy "ed448";
+};
diff --git a/bin/tests/system/kasp/ns3/named-fips.conf.in b/bin/tests/system/kasp/ns3/named-fips.conf.in
new file mode 100644
index 0000000..a6e8b3a
--- /dev/null
+++ b/bin/tests/system/kasp/ns3/named-fips.conf.in
@@ -0,0 +1,520 @@
+/*
+ * 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 "policies/kasp.conf";
+include "policies/autosign.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-policy "rsasha256";
+ dnssec-validation no;
+};
+
+key rndc_key {
+ secret "1234abcd8765";
+ algorithm @DEFAULT_HMAC@;
+};
+
+controls {
+ inet 10.53.0.3 port @CONTROLPORT@ allow { any; } keys { rndc_key; };
+};
+
+/* Zones that are getting initially signed */
+
+/* The default case: No keys created, using default policy. */
+zone "default.kasp" {
+ type primary;
+ file "default.kasp.db";
+ inline-signing yes;
+ dnssec-policy "default";
+};
+
+/* checkds: Zone with one KSK. */
+zone "checkds-ksk.kasp" {
+ type primary;
+ file "checkds-ksk.kasp.db";
+ inline-signing yes;
+ dnssec-policy "checkds-ksk";
+};
+
+/* checkds: Zone with two KSKs. */
+zone "checkds-doubleksk.kasp" {
+ type primary;
+ file "checkds-doubleksk.kasp.db";
+ inline-signing yes;
+ dnssec-policy "checkds-doubleksk";
+};
+
+/* checkds: Zone with one CSK. */
+zone "checkds-csk.kasp" {
+ type primary;
+ file "checkds-csk.kasp.db";
+ inline-signing yes;
+ dnssec-policy "checkds-csk";
+};
+
+/* Key lifetime unlimited. */
+zone "unlimited.kasp" {
+ type primary;
+ file "unlimited.kasp.db";
+ inline-signing yes;
+ dnssec-policy "unlimited";
+};
+
+/* Manual rollover. */
+zone "manual-rollover.kasp" {
+ type primary;
+ file "manual-rollover.kasp.db";
+ inline-signing yes;
+ dnssec-policy "manual-rollover";
+};
+
+/* A zone that inherits dnssec-policy. */
+zone "inherit.kasp" {
+ type primary;
+ inline-signing yes;
+ file "inherit.kasp.db";
+};
+
+/* A zone that overrides dnssec-policy. */
+zone "unsigned.kasp" {
+ type primary;
+ file "unsigned.kasp.db";
+ inline-signing yes;
+ dnssec-policy "none";
+};
+
+/* A zone that is initially set to insecure. */
+zone "insecure.kasp" {
+ type primary;
+ file "insecure.kasp.db";
+ inline-signing yes;
+ dnssec-policy "insecure";
+};
+
+/* A primary zone with dnssec-policy but keys already created. */
+zone "dnssec-keygen.kasp" {
+ type primary;
+ file "dnssec-keygen.kasp.db";
+ inline-signing yes;
+ dnssec-policy "rsasha256";
+};
+
+/* A secondary zone with dnssec-policy. */
+zone "secondary.kasp" {
+ type secondary;
+ primaries { 10.53.0.2; };
+ file "secondary.kasp.db";
+ inline-signing yes;
+ dnssec-policy "rsasha256";
+};
+
+/* A dynamic zone with dnssec-policy. */
+zone "dynamic.kasp" {
+ type primary;
+ file "dynamic.kasp.db";
+ dnssec-policy "default";
+ allow-update { any; };
+};
+
+/* A dynamic inline-signed zone with dnssec-policy. */
+zone "dynamic-inline-signing.kasp" {
+ type primary;
+ file "dynamic-inline-signing.kasp.db";
+ dnssec-policy "default";
+ allow-update { any; };
+ inline-signing yes;
+};
+
+/* An inline-signed zone with dnssec-policy. */
+zone "inline-signing.kasp" {
+ type primary;
+ file "inline-signing.kasp.db";
+ dnssec-policy "default";
+ inline-signing yes;
+};
+
+/*
+ * A configured dnssec-policy but some keys already created.
+ */
+zone "some-keys.kasp" {
+ type primary;
+ file "some-keys.kasp.db";
+ inline-signing yes;
+ dnssec-policy "rsasha256";
+};
+
+/*
+ * A configured dnssec-policy but some keys already in use.
+ */
+zone "legacy-keys.kasp" {
+ type primary;
+ file "legacy-keys.kasp.db";
+ inline-signing yes;
+ dnssec-policy "migrate-to-dnssec-policy";
+};
+
+/*
+ * A configured dnssec-policy with (too) many keys pregenerated.
+ */
+zone "pregenerated.kasp" {
+ type primary;
+ file "pregenerated.kasp.db";
+ inline-signing yes;
+ dnssec-policy "rsasha256";
+};
+
+/*
+ * A configured dnssec-policy with one rumoured key.
+ * Bugfix case for GL #1593.
+ */
+zone "rumoured.kasp" {
+ type primary;
+ file "rumoured.kasp.db";
+ inline-signing yes;
+ 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; };
+};
+
+/*
+ * Different algorithms.
+ */
+zone "rsasha256.kasp" {
+ type primary;
+ file "rsasha256.kasp.db";
+ inline-signing yes;
+ dnssec-policy "rsasha256";
+};
+zone "rsasha512.kasp" {
+ type primary;
+ file "rsasha512.kasp.db";
+ inline-signing yes;
+ dnssec-policy "rsasha512";
+};
+zone "ecdsa256.kasp" {
+ type primary;
+ file "ecdsa256.kasp.db";
+ inline-signing yes;
+ dnssec-policy "ecdsa256";
+};
+zone "ecdsa384.kasp" {
+ type primary;
+ file "ecdsa384.kasp.db";
+ inline-signing yes;
+ dnssec-policy "ecdsa384";
+};
+
+/*
+ * Zone with too high TTL.
+ */
+zone "max-zone-ttl.kasp" {
+ type primary;
+ file "max-zone-ttl.kasp.db";
+ inline-signing yes;
+ dnssec-policy "ttl";
+};
+
+/*
+ * 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";
+};
+
+/*
+ * Zones in different signing states.
+ */
+
+/*
+ * Zone that has expired signatures.
+ */
+zone "expired-sigs.autosign" {
+ type primary;
+ file "expired-sigs.autosign.db";
+ inline-signing yes;
+ dnssec-policy "autosign";
+};
+
+/*
+ * Zone that has valid, fresh signatures.
+ */
+zone "fresh-sigs.autosign" {
+ type primary;
+ file "fresh-sigs.autosign.db";
+ inline-signing yes;
+ dnssec-policy "autosign";
+};
+
+/*
+ * Zone that has unfresh signatures.
+ */
+zone "unfresh-sigs.autosign" {
+ type primary;
+ file "unfresh-sigs.autosign.db";
+ inline-signing yes;
+ dnssec-policy "autosign";
+};
+
+/*
+ * Zone that has missing private KSK.
+ */
+zone "ksk-missing.autosign" {
+ type primary;
+ file "ksk-missing.autosign.db";
+ inline-signing yes;
+ dnssec-policy "autosign";
+};
+
+/*
+ * Zone that has missing private ZSK.
+ */
+zone "zsk-missing.autosign" {
+ type primary;
+ file "zsk-missing.autosign.db";
+ inline-signing yes;
+ dnssec-policy "autosign";
+};
+
+/*
+ * Zone that has inactive ZSK.
+ */
+zone "zsk-retired.autosign" {
+ type primary;
+ file "zsk-retired.autosign.db";
+ inline-signing yes;
+ dnssec-policy "autosign";
+};
+
+/*
+ * Zones for testing enabling DNSSEC.
+ */
+zone "step1.enable-dnssec.autosign" {
+ type primary;
+ file "step1.enable-dnssec.autosign.db";
+ inline-signing yes;
+ dnssec-policy "enable-dnssec";
+};
+zone "step2.enable-dnssec.autosign" {
+ type primary;
+ file "step2.enable-dnssec.autosign.db";
+ inline-signing yes;
+ dnssec-policy "enable-dnssec";
+};
+zone "step3.enable-dnssec.autosign" {
+ type primary;
+ file "step3.enable-dnssec.autosign.db";
+ inline-signing yes;
+ dnssec-policy "enable-dnssec";
+};
+zone "step4.enable-dnssec.autosign" {
+ type primary;
+ file "step4.enable-dnssec.autosign.db";
+ inline-signing yes;
+ dnssec-policy "enable-dnssec";
+};
+
+/*
+ * Zones for testing ZSK Pre-Publication steps.
+ */
+zone "step1.zsk-prepub.autosign" {
+ type primary;
+ file "step1.zsk-prepub.autosign.db";
+ inline-signing yes;
+ dnssec-policy "zsk-prepub";
+};
+zone "step2.zsk-prepub.autosign" {
+ type primary;
+ file "step2.zsk-prepub.autosign.db";
+ inline-signing yes;
+ dnssec-policy "zsk-prepub";
+};
+zone "step3.zsk-prepub.autosign" {
+ type primary;
+ file "step3.zsk-prepub.autosign.db";
+ inline-signing yes;
+ dnssec-policy "zsk-prepub";
+};
+zone "step4.zsk-prepub.autosign" {
+ type primary;
+ file "step4.zsk-prepub.autosign.db";
+ inline-signing yes;
+ dnssec-policy "zsk-prepub";
+};
+zone "step5.zsk-prepub.autosign" {
+ type primary;
+ file "step5.zsk-prepub.autosign.db";
+ inline-signing yes;
+ dnssec-policy "zsk-prepub";
+};
+zone "step6.zsk-prepub.autosign" {
+ type primary;
+ file "step6.zsk-prepub.autosign.db";
+ inline-signing yes;
+ dnssec-policy "zsk-prepub";
+};
+
+/*
+ * Zones for testing KSK Double-KSK steps.
+ */
+zone "step1.ksk-doubleksk.autosign" {
+ type primary;
+ file "step1.ksk-doubleksk.autosign.db";
+ inline-signing yes;
+ dnssec-policy "ksk-doubleksk";
+};
+zone "step2.ksk-doubleksk.autosign" {
+ type primary;
+ file "step2.ksk-doubleksk.autosign.db";
+ inline-signing yes;
+ dnssec-policy "ksk-doubleksk";
+};
+zone "step3.ksk-doubleksk.autosign" {
+ type primary;
+ file "step3.ksk-doubleksk.autosign.db";
+ inline-signing yes;
+ dnssec-policy "ksk-doubleksk";
+};
+zone "step4.ksk-doubleksk.autosign" {
+ type primary;
+ file "step4.ksk-doubleksk.autosign.db";
+ inline-signing yes;
+ dnssec-policy "ksk-doubleksk";
+};
+zone "step5.ksk-doubleksk.autosign" {
+ type primary;
+ file "step5.ksk-doubleksk.autosign.db";
+ inline-signing yes;
+ dnssec-policy "ksk-doubleksk";
+};
+zone "step6.ksk-doubleksk.autosign" {
+ type primary;
+ file "step6.ksk-doubleksk.autosign.db";
+ inline-signing yes;
+ dnssec-policy "ksk-doubleksk";
+};
+
+/*
+ * Zones for testing CSK rollover steps.
+ */
+zone "step1.csk-roll.autosign" {
+ type primary;
+ file "step1.csk-roll.autosign.db";
+ inline-signing yes;
+ dnssec-policy "csk-roll";
+};
+zone "step2.csk-roll.autosign" {
+ type primary;
+ file "step2.csk-roll.autosign.db";
+ inline-signing yes;
+ dnssec-policy "csk-roll";
+};
+zone "step3.csk-roll.autosign" {
+ type primary;
+ file "step3.csk-roll.autosign.db";
+ inline-signing yes;
+ dnssec-policy "csk-roll";
+};
+zone "step4.csk-roll.autosign" {
+ type primary;
+ file "step4.csk-roll.autosign.db";
+ inline-signing yes;
+ dnssec-policy "csk-roll";
+};
+zone "step5.csk-roll.autosign" {
+ type primary;
+ file "step5.csk-roll.autosign.db";
+ inline-signing yes;
+ dnssec-policy "csk-roll";
+};
+zone "step6.csk-roll.autosign" {
+ type primary;
+ file "step6.csk-roll.autosign.db";
+ inline-signing yes;
+ dnssec-policy "csk-roll";
+};
+zone "step7.csk-roll.autosign" {
+ type primary;
+ file "step7.csk-roll.autosign.db";
+ inline-signing yes;
+ dnssec-policy "csk-roll";
+};
+zone "step8.csk-roll.autosign" {
+ type primary;
+ file "step8.csk-roll.autosign.db";
+ inline-signing yes;
+ dnssec-policy "csk-roll";
+};
+
+zone "step1.csk-roll2.autosign" {
+ type primary;
+ file "step1.csk-roll2.autosign.db";
+ inline-signing yes;
+ dnssec-policy "csk-roll2";
+};
+zone "step2.csk-roll2.autosign" {
+ type primary;
+ file "step2.csk-roll2.autosign.db";
+ inline-signing yes;
+ dnssec-policy "csk-roll2";
+};
+zone "step3.csk-roll2.autosign" {
+ type primary;
+ file "step3.csk-roll2.autosign.db";
+ inline-signing yes;
+ dnssec-policy "csk-roll2";
+};
+zone "step4.csk-roll2.autosign" {
+ type primary;
+ file "step4.csk-roll2.autosign.db";
+ inline-signing yes;
+ dnssec-policy "csk-roll2";
+};
+zone "step5.csk-roll2.autosign" {
+ type primary;
+ file "step5.csk-roll2.autosign.db";
+ inline-signing yes;
+ dnssec-policy "csk-roll2";
+};
+zone "step6.csk-roll2.autosign" {
+ type primary;
+ file "step6.csk-roll2.autosign.db";
+ inline-signing yes;
+ dnssec-policy "csk-roll2";
+};
+zone "step7.csk-roll2.autosign" {
+ type primary;
+ file "step7.csk-roll2.autosign.db";
+ inline-signing yes;
+ dnssec-policy "csk-roll2";
+};
diff --git a/bin/tests/system/kasp/ns3/named.conf.in b/bin/tests/system/kasp/ns3/named.conf.in
new file mode 100644
index 0000000..92e007d
--- /dev/null
+++ b/bin/tests/system/kasp/ns3/named.conf.in
@@ -0,0 +1,30 @@
+/*
+ * 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 "named-fips.conf";
+
+zone "rsasha1.kasp" {
+ type primary;
+ file "rsasha1.kasp.db";
+ inline-signing yes;
+ dnssec-policy "rsasha1";
+};
+
+zone "rsasha1-nsec3.kasp" {
+ type primary;
+ file "rsasha1-nsec3.kasp.db";
+ inline-signing yes;
+ dnssec-policy "rsasha1-nsec3";
+};
diff --git a/bin/tests/system/kasp/ns3/policies/autosign.conf.in b/bin/tests/system/kasp/ns3/policies/autosign.conf.in
new file mode 100644
index 0000000..5564ec5
--- /dev/null
+++ b/bin/tests/system/kasp/ns3/policies/autosign.conf.in
@@ -0,0 +1,133 @@
+/*
+ * 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 "autosign" {
+
+ signatures-refresh P1W;
+ signatures-validity P2W;
+ signatures-validity-dnskey P2W;
+
+ dnskey-ttl 300;
+
+ keys {
+ ksk key-directory lifetime P2Y algorithm @DEFAULT_ALGORITHM@;
+ zsk key-directory lifetime P1Y algorithm @DEFAULT_ALGORITHM@;
+ };
+};
+
+dnssec-policy "enable-dnssec" {
+
+ signatures-refresh P1W;
+ signatures-validity P2W;
+ signatures-validity-dnskey P2W;
+
+ dnskey-ttl 300;
+ max-zone-ttl PT12H;
+ zone-propagation-delay PT5M;
+ retire-safety PT20M;
+ publish-safety PT5M;
+
+ parent-propagation-delay 1h;
+ parent-ds-ttl 2h;
+
+ keys {
+ csk lifetime unlimited algorithm @DEFAULT_ALGORITHM_NUMBER@;
+ };
+};
+
+dnssec-policy "zsk-prepub" {
+
+ signatures-refresh P1W;
+ signatures-validity P2W;
+ signatures-validity-dnskey P2W;
+
+ dnskey-ttl 3600;
+ publish-safety P1D;
+ retire-safety P2D;
+ purge-keys PT1H;
+
+ keys {
+ ksk key-directory lifetime P2Y algorithm @DEFAULT_ALGORITHM@;
+ zsk key-directory lifetime P30D algorithm @DEFAULT_ALGORITHM@;
+ };
+
+ 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;
+
+ keys {
+ ksk key-directory lifetime P60D algorithm @DEFAULT_ALGORITHM@;
+ zsk key-directory lifetime P1Y algorithm @DEFAULT_ALGORITHM@;
+ };
+
+ zone-propagation-delay PT1H;
+ max-zone-ttl 1d;
+
+ parent-ds-ttl 3600;
+ parent-propagation-delay PT1H;
+};
+
+dnssec-policy "csk-roll" {
+
+ signatures-refresh P5D;
+ signatures-validity 30d;
+ signatures-validity-dnskey 30d;
+
+ dnskey-ttl 1h;
+ publish-safety PT1H;
+ retire-safety 2h;
+ purge-keys PT1H;
+
+ keys {
+ csk key-directory lifetime P6M algorithm @DEFAULT_ALGORITHM@;
+ };
+
+ zone-propagation-delay 1h;
+ max-zone-ttl P1D;
+
+ parent-ds-ttl 1h;
+ parent-propagation-delay 1h;
+};
+
+dnssec-policy "csk-roll2" {
+
+ signatures-refresh 12h;
+ signatures-validity P1D;
+ signatures-validity-dnskey P1D;
+
+ dnskey-ttl 1h;
+ publish-safety PT1H;
+ retire-safety 1h;
+ purge-keys 0;
+
+ keys {
+ csk key-directory lifetime P6M algorithm @DEFAULT_ALGORITHM@;
+ };
+
+ zone-propagation-delay PT1H;
+ max-zone-ttl 1d;
+
+ parent-ds-ttl PT1H;
+ parent-propagation-delay P1W;
+};
diff --git a/bin/tests/system/kasp/ns3/policies/kasp-fips.conf.in b/bin/tests/system/kasp/ns3/policies/kasp-fips.conf.in
new file mode 100644
index 0000000..90a92a2
--- /dev/null
+++ b/bin/tests/system/kasp/ns3/policies/kasp-fips.conf.in
@@ -0,0 +1,118 @@
+/*
+ * 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 "unlimited" {
+ dnskey-ttl 1234;
+
+ keys {
+ csk key-directory lifetime unlimited algorithm @DEFAULT_ALGORITHM@;
+ };
+};
+
+dnssec-policy "manual-rollover" {
+ dnskey-ttl 3600;
+
+ keys {
+ ksk key-directory lifetime unlimited algorithm @DEFAULT_ALGORITHM@;
+ zsk key-directory lifetime unlimited algorithm @DEFAULT_ALGORITHM@;
+ };
+};
+
+dnssec-policy "multisigner-model2" {
+ dnskey-ttl 3600;
+
+ keys {
+ ksk key-directory lifetime unlimited algorithm @DEFAULT_ALGORITHM@;
+ zsk key-directory lifetime unlimited algorithm @DEFAULT_ALGORITHM@;
+ };
+};
+
+dnssec-policy "migrate-to-dnssec-policy" {
+ dnskey-ttl 1234;
+
+ keys {
+ ksk key-directory lifetime P6M algorithm 8;
+ zsk key-directory lifetime P6M algorithm 8;
+ };
+};
+
+dnssec-policy "rsasha256" {
+ dnskey-ttl 1234;
+
+ keys {
+ ksk key-directory lifetime P10Y algorithm 8;
+ zsk key-directory lifetime P5Y algorithm 8;
+ zsk key-directory lifetime P1Y algorithm 8 3072;
+ };
+};
+
+dnssec-policy "rsasha512" {
+ dnskey-ttl 1234;
+
+ keys {
+ ksk key-directory lifetime P10Y algorithm 10;
+ zsk key-directory lifetime P5Y algorithm 10;
+ zsk key-directory lifetime P1Y algorithm 10 3072;
+ };
+};
+
+dnssec-policy "ecdsa256" {
+ dnskey-ttl 1234;
+
+ keys {
+ ksk key-directory lifetime P10Y algorithm 13;
+ zsk key-directory lifetime P5Y algorithm 13;
+ zsk key-directory lifetime P1Y algorithm 13 256;
+ };
+};
+
+dnssec-policy "ecdsa384" {
+ dnskey-ttl 1234;
+
+ keys {
+ ksk key-directory lifetime P10Y algorithm 14;
+ zsk key-directory lifetime P5Y algorithm 14;
+ zsk key-directory lifetime P1Y algorithm 14 384;
+ };
+};
+
+dnssec-policy "checkds-ksk" {
+ dnskey-ttl 303;
+
+ keys {
+ ksk key-directory lifetime unlimited algorithm @DEFAULT_ALGORITHM@;
+ zsk key-directory lifetime unlimited algorithm @DEFAULT_ALGORITHM@;
+ };
+};
+
+dnssec-policy "checkds-doubleksk" {
+ dnskey-ttl 303;
+
+ keys {
+ ksk key-directory lifetime unlimited algorithm @DEFAULT_ALGORITHM@;
+ ksk key-directory lifetime unlimited algorithm @DEFAULT_ALGORITHM@;
+ zsk key-directory lifetime unlimited algorithm @DEFAULT_ALGORITHM@;
+ };
+};
+
+dnssec-policy "checkds-csk" {
+ dnskey-ttl 303;
+
+ keys {
+ csk key-directory lifetime unlimited algorithm @DEFAULT_ALGORITHM@;
+ };
+};
+
+dnssec-policy "ttl" {
+ max-zone-ttl 299;
+};
diff --git a/bin/tests/system/kasp/ns3/policies/kasp.conf.in b/bin/tests/system/kasp/ns3/policies/kasp.conf.in
new file mode 100644
index 0000000..cb045bc
--- /dev/null
+++ b/bin/tests/system/kasp/ns3/policies/kasp.conf.in
@@ -0,0 +1,34 @@
+/*
+ * 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 "policies/kasp-fips.conf";
+
+dnssec-policy "rsasha1" {
+ dnskey-ttl 1234;
+
+ keys {
+ ksk key-directory lifetime P10Y algorithm 5;
+ zsk key-directory lifetime P5Y algorithm 5;
+ zsk key-directory lifetime P1Y algorithm 5 2000;
+ };
+};
+
+dnssec-policy "rsasha1-nsec3" {
+ dnskey-ttl 1234;
+
+ keys {
+ ksk key-directory lifetime P10Y algorithm 7;
+ zsk key-directory lifetime P5Y algorithm 7;
+ zsk key-directory lifetime P1Y algorithm 7 2000;
+ };
+};
diff --git a/bin/tests/system/kasp/ns3/setup.sh b/bin/tests/system/kasp/ns3/setup.sh
new file mode 100644
index 0000000..8af40ed
--- /dev/null
+++ b/bin/tests/system/kasp/ns3/setup.sh
@@ -0,0 +1,1470 @@
+#!/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"
+ 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"
+
+#
+# Set up zones that will be initially signed.
+#
+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 \
+ manual-rollover multisigner-model2
+do
+ setup "${zn}.kasp"
+ cp template.db.in "$zonefile"
+done
+
+#
+# Set up RSASHA1 based zones
+#
+for zn in rsasha1 rsasha1-nsec3
+do
+ if (cd ..; $SHELL ../testcrypto.sh -q RSASHA1)
+ then
+ setup "${zn}.kasp"
+ cp template.db.in "$zonefile"
+ else
+ # don't add to zones.
+ echo_i "setting up zone: ${zn}.kasp"
+ cp template.db.in "${zn}.kasp.db"
+ fi
+done
+
+if [ -f ../ed25519-supported.file ]; then
+ setup "ed25519.kasp"
+ cp template.db.in "$zonefile"
+ cat ed25519.conf >> named.conf
+fi
+
+if [ -f ../ed448-supported.file ]; then
+ setup "ed448.kasp"
+ cp template.db.in "$zonefile"
+ cat ed448.conf >> named.conf
+fi
+
+# Set up zones that stay unsigned.
+for zn in unsigned insecure max-zone-ttl
+do
+ zone="${zn}.kasp"
+ echo_i "setting up zone: $zone"
+ zonefile="${zone}.db"
+ infile="${zone}.db.infile"
+ cp template.db.in $infile
+ cp template.db.in $zonefile
+done
+
+# Some of these zones already have keys.
+zone="dnssec-keygen.kasp"
+echo_i "setting up zone: $zone"
+$KEYGEN -k rsasha256 -l policies/kasp.conf $zone > keygen.out.$zone.1 2>&1
+
+zone="some-keys.kasp"
+echo_i "setting up zone: $zone"
+$KEYGEN -G -a RSASHA256 -b 2048 -L 1234 $zone > keygen.out.$zone.1 2>&1
+$KEYGEN -G -a RSASHA256 -f KSK -L 1234 $zone > keygen.out.$zone.2 2>&1
+
+zone="legacy-keys.kasp"
+echo_i "setting up zone: $zone"
+ZSK=$($KEYGEN -a RSASHA256 -b 2048 -L 1234 $zone 2> keygen.out.$zone.1)
+KSK=$($KEYGEN -a RSASHA256 -f KSK -L 1234 $zone 2> keygen.out.$zone.2)
+echo $ZSK > legacy-keys.kasp.zsk
+echo $KSK > legacy-keys.kasp.ksk
+# Predecessor keys:
+Tact="now-9mo"
+Tret="now-3mo"
+ZSK=$($KEYGEN -a RSASHA256 -b 2048 -L 1234 $zone 2> keygen.out.$zone.3)
+KSK=$($KEYGEN -a RSASHA256 -f KSK -L 1234 $zone 2> keygen.out.$zone.4)
+$SETTIME -P $Tact -A $Tact -I $Tret -D $Tret "$ZSK" > settime.out.$zone.1 2>&1
+$SETTIME -P $Tact -A $Tact -I $Tret -D $Tret "$KSK" > settime.out.$zone.2 2>&1
+
+zone="pregenerated.kasp"
+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"
+# Import the ZSK sets of the other providers into their DNSKEY RRset.
+ZSK1=$($KEYGEN -K ../ -a $DEFAULT_ALGORITHM -L 3600 $zone 2> keygen.out.$zone.1)
+ZSK2=$($KEYGEN -K ../ -a $DEFAULT_ALGORITHM -L 3600 $zone 2> keygen.out.$zone.2)
+# ZSK1 will be added to the unsigned zonefile.
+cat "../${ZSK1}.key" | grep -v ";.*" >> "${zone}.db"
+cat "../${ZSK1}.key" | grep -v ";.*" > "${zone}.zsk1"
+rm -f "../${ZSK1}.*"
+# ZSK2 will be used with a Dynamic Update.
+cat "../${ZSK2}.key" | grep -v ";.*" > "${zone}.zsk2"
+rm -f "../${ZSK2}.*"
+
+zone="rumoured.kasp"
+echo_i "setting up zone: $zone"
+Tpub="now"
+Tact="now+1d"
+keytimes="-P ${Tpub} -A ${Tact}"
+KSK=$($KEYGEN -a RSASHA256 -f KSK -L 1234 $keytimes $zone 2> keygen.out.$zone.1)
+ZSK1=$($KEYGEN -a RSASHA256 -b 3072 -L 1234 $keytimes $zone 2> keygen.out.$zone.2)
+ZSK2=$($KEYGEN -a RSASHA256 -L 1234 $keytimes $zone 2> keygen.out.$zone.3)
+$SETTIME -s -g $O -k $R $Tpub -r $R $Tpub -d $H $Tpub "$KSK" > settime.out.$zone.1 2>&1
+$SETTIME -s -g $O -k $R $Tpub -z $R $Tpub "$ZSK1" > settime.out.$zone.2 2>&1
+$SETTIME -s -g $O -k $R $Tpub -z $R $Tpub "$ZSK2" > settime.out.$zone.2 2>&1
+
+#
+# Set up zones that are already signed.
+#
+
+# Zone to test manual rollover.
+setup manual-rollover.kasp
+T="now-1d"
+ksktimes="-P $T -A $T -P sync $T"
+zsktimes="-P $T -A $T"
+KSK=$($KEYGEN -a $DEFAULT_ALGORITHM -L 3600 -f KSK $ksktimes $zone 2> keygen.out.$zone.1)
+ZSK=$($KEYGEN -a $DEFAULT_ALGORITHM -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"
+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
+
+# These signatures are set to expire long in the past, update immediately.
+setup expired-sigs.autosign
+T="now-6mo"
+ksktimes="-P $T -A $T -P sync $T"
+zsktimes="-P $T -A $T"
+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)
+$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"
+private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$KSK" >> "$infile"
+private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$ZSK" >> "$infile"
+cp $infile $zonefile
+$SIGNER -PS -x -s now-2mo -e now-1mo -o $zone -O raw -f "${zonefile}.signed" $infile > signer.out.$zone.1 2>&1
+
+# These signatures are still good, and can be reused.
+setup fresh-sigs.autosign
+T="now-6mo"
+ksktimes="-P $T -A $T -P sync $T"
+zsktimes="-P $T -A $T"
+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)
+$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"
+private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$KSK" >> "$infile"
+private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$ZSK" >> "$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
+
+# These signatures are still good, but not fresh enough, update immediately.
+setup unfresh-sigs.autosign
+T="now-6mo"
+ksktimes="-P $T -A $T -P sync $T"
+zsktimes="-P $T -A $T"
+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)
+$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"
+private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$KSK" >> "$infile"
+private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$ZSK" >> "$infile"
+cp $infile $zonefile
+$SIGNER -S -x -s now-1w -e now+1w -o $zone -O raw -f "${zonefile}.signed" $infile > signer.out.$zone.1 2>&1
+
+# These signatures are still good, but the private KSK is missing.
+setup ksk-missing.autosign
+T="now-6mo"
+ksktimes="-P $T -A $T -P sync $T"
+zsktimes="-P $T -A $T"
+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)
+$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"
+private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$KSK" >> "$infile"
+private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$ZSK" >> "$infile"
+cp $infile $zonefile
+$SIGNER -S -x -s now-1w -e now+1w -o $zone -O raw -f "${zonefile}.signed" $infile > signer.out.$zone.1 2>&1
+echo "KSK: yes" >> "${KSK}".state
+echo "ZSK: no" >> "${KSK}".state
+echo "Lifetime: 63072000" >> "${KSK}".state # PT2Y
+rm -f "${KSK}".private
+
+# These signatures are still good, but the private ZSK is missing.
+setup zsk-missing.autosign
+T="now-6mo"
+ksktimes="-P $T -A $T -P sync $T"
+zsktimes="-P $T -A $T"
+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)
+$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"
+private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$KSK" >> "$infile"
+private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$ZSK" >> "$infile"
+cp $infile $zonefile
+$SIGNER -S -x -s now-1w -e now+1w -o $zone -O raw -f "${zonefile}.signed" $infile > signer.out.$zone.1 2>&1
+echo "KSK: no" >> "${ZSK}".state
+echo "ZSK: yes" >> "${ZSK}".state
+echo "Lifetime: 31536000" >> "${ZSK}".state # PT1Y
+rm -f "${ZSK}".private
+
+# These signatures are already expired, and the private ZSK is retired.
+setup zsk-retired.autosign
+T="now-6mo"
+ksktimes="-P $T -A $T -P sync $T"
+zsktimes="-P $T -A $T -I now"
+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)
+$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"
+private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$KSK" >> "$infile"
+private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$ZSK" >> "$infile"
+cp $infile $zonefile
+$SIGNER -PS -x -s now-2w -e now-1mi -o $zone -O raw -f "${zonefile}.signed" $infile > signer.out.$zone.1 2>&1
+$SETTIME -s -g HIDDEN "$ZSK" > settime.out.$zone.3 2>&1
+
+#
+# The zones at enable-dnssec.autosign represent the various steps of the
+# initial signing of a zone.
+#
+
+# Step 1:
+# This is an unsigned zone and named should perform the initial steps of
+# introducing the DNSSEC records in the right order.
+setup step1.enable-dnssec.autosign
+cp template.db.in $zonefile
+
+# Step 2:
+# The DNSKEY has been published long enough to become OMNIPRESENT.
+setup step2.enable-dnssec.autosign
+# DNSKEY TTL: 300 seconds
+# zone-propagation-delay: 5 minutes (300 seconds)
+# publish-safety: 5 minutes (300 seconds)
+# Total: 900 seconds
+TpubN="now-900s"
+# RRSIG TTL: 12 hour (43200 seconds)
+# zone-propagation-delay: 5 minutes (300 seconds)
+# retire-safety: 20 minutes (1200 seconds)
+# Already passed time: -900 seconds
+# Total: 43800 seconds
+TsbmN="now+43800s"
+keytimes="-P ${TpubN} -P sync ${TsbmN} -A ${TpubN}"
+CSK=$($KEYGEN -k enable-dnssec -l policies/autosign.conf $keytimes $zone 2> keygen.out.$zone.1)
+$SETTIME -s -g $O -k $R $TpubN -r $R $TpubN -d $H $TpubN -z $R $TpubN "$CSK" > settime.out.$zone.1 2>&1
+cat template.db.in "${CSK}.key" > "$infile"
+private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$CSK" >> "$infile"
+cp $infile $zonefile
+$SIGNER -S -z -x -s now-1h -e now+30d -o $zone -O raw -f "${zonefile}.signed" $infile > signer.out.$zone.1 2>&1
+
+# Step 3:
+# The zone signatures have been published long enough to become OMNIPRESENT.
+setup step3.enable-dnssec.autosign
+# Passed time since publications: 43800 + 900 = 44700 seconds.
+TpubN="now-44700s"
+# The key is secure for using in chain of trust when the DNSKEY is OMNIPRESENT.
+TcotN="now-43800s"
+# We can submit the DS now.
+TsbmN="now"
+keytimes="-P ${TpubN} -P sync ${TsbmN} -A ${TpubN}"
+CSK=$($KEYGEN -k enable-dnssec -l policies/autosign.conf $keytimes $zone 2> keygen.out.$zone.1)
+$SETTIME -s -g $O -k $O $TcotN -r $O $TcotN -d $H $TpubN -z $R $TpubN "$CSK" > settime.out.$zone.1 2>&1
+cat template.db.in "${CSK}.key" > "$infile"
+private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$CSK" >> "$infile"
+cp $infile $zonefile
+$SIGNER -S -z -x -s now-1h -e now+30d -o $zone -O raw -f "${zonefile}.signed" $infile > signer.out.$zone.1 2>&1
+
+# Step 4:
+# The DS has been submitted long enough ago to become OMNIPRESENT.
+setup step4.enable-dnssec.autosign
+# DS TTL: 2 hour (7200 seconds)
+# parent-propagation-delay: 1 hour (3600 seconds)
+# retire-safety: 20 minutes (1200 seconds)
+# Total aditional time: 12000 seconds
+# 44700 + 12000 = 56700
+TpubN="now-56700s"
+# 43800 + 12000 = 55800
+TcotN="now-55800s"
+TsbmN="now-12000s"
+keytimes="-P ${TpubN} -P sync ${TsbmN} -A ${TpubN}"
+CSK=$($KEYGEN -k enable-dnssec -l policies/autosign.conf $keytimes $zone 2> keygen.out.$zone.1)
+$SETTIME -s -g $O -P ds $TsbmN -k $O $TcotN -r $O $TcotN -d $R $TsbmN -z $O $TsbmN "$CSK" > settime.out.$zone.1 2>&1
+cat template.db.in "${CSK}.key" > "$infile"
+private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$CSK" >> "$infile"
+cp $infile $zonefile
+$SIGNER -S -z -x -s now-1h -e now+30d -o $zone -O raw -f "${zonefile}.signed" $infile > signer.out.$zone.1 2>&1
+setup step4.enable-dnssec.autosign
+
+#
+# The zones at zsk-prepub.autosign represent the various steps of a ZSK
+# Pre-Publication rollover.
+#
+
+# Step 1:
+# Introduce the first key. This will immediately be active.
+setup step1.zsk-prepub.autosign
+TactN="now"
+ksktimes="-P ${TactN} -A ${TactN} -P sync ${TactN}"
+zsktimes="-P ${TactN} -A ${TactN}"
+KSK=$($KEYGEN -a $DEFAULT_ALGORITHM -L 3600 -f KSK $ksktimes $zone 2> keygen.out.$zone.1)
+ZSK=$($KEYGEN -a $DEFAULT_ALGORITHM -L 3600 $zsktimes $zone 2> keygen.out.$zone.2)
+$SETTIME -s -g $O -k $O $TactN -r $O $TactN -d $O $TactN "$KSK" > settime.out.$zone.1 2>&1
+$SETTIME -s -g $O -k $O $TactN -z $O $TactN "$ZSK" > settime.out.$zone.2 2>&1
+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"
+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
+
+# Step 2:
+# It is time to pre-publish the successor ZSK.
+setup step2.zsk-prepub.autosign
+# According to RFC 7583:
+#
+# Tpub(N+1) <= Tact(N) + Lzsk - Ipub
+# Ipub = Dprp + TTLkey (+publish-safety)
+#
+# |3| |4| |5| |6|
+# | | | |
+# Key N |<-------Lzsk------>|
+# | | | |
+# Key N+1 | |<-Ipub->|<-->|
+# | | | |
+# Key N Tact
+# Key N+1 Tpub Trdy Tact
+#
+# Tnow
+#
+# Lzsk: 30d
+# Dprp: 1h
+# TTLkey: 1h
+# publish-safety: 1d
+# Ipub: 26h
+#
+# Tact(N) = Tnow + Ipub - Lzsk = now + 26h - 30d
+# = now + 26h - 30d = now − 694h
+TactN="now-694h"
+ksktimes="-P ${TactN} -A ${TactN} -P sync ${TactN}"
+zsktimes="-P ${TactN} -A ${TactN}"
+KSK=$($KEYGEN -a $DEFAULT_ALGORITHM -L 3600 -f KSK $ksktimes $zone 2> keygen.out.$zone.1)
+ZSK=$($KEYGEN -a $DEFAULT_ALGORITHM -L 3600 $zsktimes $zone 2> keygen.out.$zone.2)
+$SETTIME -s -g $O -k $O $TactN -r $O $TactN -d $O $TactN "$KSK" > settime.out.$zone.1 2>&1
+$SETTIME -s -g $O -k $O $TactN -z $O $TactN "$ZSK" > settime.out.$zone.2 2>&1
+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"
+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
+
+# Step 3:
+# After the publication interval has passed the DNSKEY of the successor ZSK
+# is OMNIPRESENT and the zone can thus be signed with the successor ZSK.
+setup step3.zsk-prepub.autosign
+# According to RFC 7583:
+#
+# Tpub(N+1) <= Tact(N) + Lzsk - Ipub
+# Tret(N) = Tact(N+1) = Tact(N) + Lzsk
+# Trem(N) = Tret(N) + Iret
+# Iret = Dsgn + Dprp + TTLsig (+retire-safety)
+#
+# |3| |4| |5| |6| |7| |8|
+# | | | | | |
+# Key N |<-------Lzsk------>|<-Iret->|<--->|
+# | | | | | |
+# Key N+1 | |<-Ipub->|<-->|<---Lzsk---- - -
+# | | | | | |
+# Key N Tact Tret Tdea Trem
+# Key N+1 Tpub Trdy Tact
+#
+# Tnow
+#
+# Lzsk: 30d
+# Ipub: 26h
+# Dsgn: 1w
+# Dprp: 1h
+# TTLsig: 1d
+# retire-safety: 2d
+# Iret: 10d1h = 241h
+#
+# Tact(N) = Tnow - Lzsk = now - 30d
+# Tret(N) = now
+# Trem(N) = Tnow + Iret = now + 241h
+# Tpub(N+1) = Tnow - Ipub = now - 26h
+# Tret(N+1) = Tnow + Lzsk = now + 30d
+# Trem(N+1) = Tnow + Lzsk + Iret = now + 30d + 241h
+# = now + 961h
+TactN="now-30d"
+TretN="now"
+TremN="now+241h"
+TpubN1="now-26h"
+TactN1="now"
+TretN1="now+30d"
+TremN1="now+961h"
+ksktimes="-P ${TactN} -A ${TactN} -P sync ${TactN}"
+zsktimes="-P ${TactN} -A ${TactN} -I ${TretN} -D ${TremN}"
+newtimes="-P ${TpubN1} -A ${TactN1} -I ${TretN1} -D ${TremN1}"
+KSK=$($KEYGEN -a $DEFAULT_ALGORITHM -L 3600 -f KSK $ksktimes $zone 2> keygen.out.$zone.1)
+ZSK1=$($KEYGEN -a $DEFAULT_ALGORITHM -L 3600 $zsktimes $zone 2> keygen.out.$zone.2)
+ZSK2=$($KEYGEN -a $DEFAULT_ALGORITHM -L 3600 $newtimes $zone 2> keygen.out.$zone.3)
+$SETTIME -s -g $O -k $O $TactN -r $O $TactN -d $O $TactN "$KSK" > settime.out.$zone.1 2>&1
+$SETTIME -s -g $H -k $O $TactN -z $O $TactN "$ZSK1" > settime.out.$zone.2 2>&1
+$SETTIME -s -g $O -k $R $TpubN1 -z $H $TpubN1 "$ZSK2" > settime.out.$zone.3 2>&1
+# Set key rollover relationship.
+key_successor $ZSK1 $ZSK2
+# Sign zone.
+cat template.db.in "${KSK}.key" "${ZSK1}.key" "${ZSK2}.key" > "$infile"
+private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$KSK" >> "$infile"
+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
+
+# Step 4:
+# After the retire interval has passed the predecessor DNSKEY can be
+# removed from the zone.
+setup step4.zsk-prepub.autosign
+# According to RFC 7583:
+#
+# Tret(N) = Tact(N) + Lzsk
+# Tdea(N) = Tret(N) + Iret
+#
+# |3| |4| |5| |6| |7| |8|
+# | | | | | |
+# Key N |<-------Lzsk------>|<-Iret->|<--->|
+# | | | | | |
+# Key N+1 | |<-Ipub->|<-->|<---Lzsk---- - -
+# | | | | | |
+# Key N Tact Tret Tdea Trem
+# Key N+1 Tpub Trdy Tact
+#
+# Tnow
+#
+# Lzsk: 30d
+# Ipub: 26h
+# Iret: 241h
+#
+# Tact(N) = Tnow - Iret - Lzsk
+# = now - 241h - 30d = now - 241h - 720h
+# = now - 961h
+# Tret(N) = Tnow - Iret = now - 241h
+# Trem(N) = Tnow
+# Tpub(N+1) = Tnow - Iret - Ipub
+# = now - 241h - 26h
+# = now - 267h
+# Tact(N+1) = Tnow - Iret = Tret(N)
+# Tret(N+1) = Tnow - Iret + Lzsk
+# = now - 241h + 30d = now - 241h + 720h
+# = now + 479h
+# Trem(N+1) = Tnow + Lzsk = now + 30d
+TactN="now-961h"
+TretN="now-241h"
+TremN="now"
+TpubN1="now-267h"
+TactN1="${TretN}"
+TretN1="now+479h"
+TremN1="now+30d"
+ksktimes="-P ${TactN} -A ${TactN} -P sync ${TactN}"
+zsktimes="-P ${TactN} -A ${TactN} -I ${TretN} -D ${TremN}"
+newtimes="-P ${TpubN1} -A ${TactN1} -I ${TretN1} -D ${TremN1}"
+KSK=$($KEYGEN -a $DEFAULT_ALGORITHM -L 3600 -f KSK $ksktimes $zone 2> keygen.out.$zone.1)
+ZSK1=$($KEYGEN -a $DEFAULT_ALGORITHM -L 3600 $zsktimes $zone 2> keygen.out.$zone.2)
+ZSK2=$($KEYGEN -a $DEFAULT_ALGORITHM -L 3600 $newtimes $zone 2> keygen.out.$zone.3)
+$SETTIME -s -g $O -k $O $TactN -r $O $TactN -d $O $TactN "$KSK" > settime.out.$zone.1 2>&1
+$SETTIME -s -g $H -k $O $TactN -z $U $TretN "$ZSK1" > settime.out.$zone.2 2>&1
+$SETTIME -s -g $O -k $O $TactN1 -z $R $TactN1 "$ZSK2" > settime.out.$zone.3 2>&1
+# Set key rollover relationship.
+key_successor $ZSK1 $ZSK2
+# Sign zone.
+cat template.db.in "${KSK}.key" "${ZSK1}.key" "${ZSK2}.key" > "$infile"
+cp $infile $zonefile
+$SIGNER -PS -x -s now-2w -e now-1mi -o $zone -O raw -f "${zonefile}.signed" $infile > signer.out.$zone.1 2>&1
+
+# Step 5:
+# The predecessor DNSKEY is removed long enough that is has become HIDDEN.
+setup step5.zsk-prepub.autosign
+# Subtract DNSKEY TTL from all the times (1h).
+# Tact(N) = now - 961h - 1h = now - 962h
+# Tret(N) = now - 241h - 1h = now - 242h
+# Tdea(N) = now - 2d - 1h = now - 49h
+# Trem(N) = now - 1h
+# Tpub(N+1) = now - 267h - 1h = now - 268h
+# Tact(N+1) = Tret(N)
+# Tret(N+1) = now + 479h - 1h = now + 478h
+# Trem(N+1) = now + 30d - 1h = now + 719h
+TactN="now-962h"
+TretN="now-242h"
+TremN="now-1h"
+TdeaN="now-49h"
+TpubN1="now-268h"
+TactN1="${TretN}"
+TretN1="now+478h"
+TremN1="now+719h"
+ksktimes="-P ${TactN} -A ${TactN} -P sync ${TactN}"
+zsktimes="-P ${TactN} -A ${TactN} -I ${TretN} -D ${TremN}"
+newtimes="-P ${TpubN1} -A ${TactN1} -I ${TretN1} -D ${TremN1}"
+KSK=$($KEYGEN -a $DEFAULT_ALGORITHM -L 3600 -f KSK $ksktimes $zone 2> keygen.out.$zone.1)
+ZSK1=$($KEYGEN -a $DEFAULT_ALGORITHM -L 3600 $zsktimes $zone 2> keygen.out.$zone.2)
+ZSK2=$($KEYGEN -a $DEFAULT_ALGORITHM -L 3600 $newtimes $zone 2> keygen.out.$zone.3)
+$SETTIME -s -g $O -k $O $TactN -r $O $TactN -d $O $TactN "$KSK" > settime.out.$zone.1 2>&1
+$SETTIME -s -g $H -k $U $TdeaN -z $H $TdeaN "$ZSK1" > settime.out.$zone.2 2>&1
+$SETTIME -s -g $O -k $O $TactN1 -z $O $TdeaN "$ZSK2" > settime.out.$zone.3 2>&1
+# Set key rollover relationship.
+key_successor $ZSK1 $ZSK2
+# Sign zone.
+cat template.db.in "${KSK}.key" "${ZSK1}.key" "${ZSK2}.key" > "$infile"
+private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$KSK" >> "$infile"
+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
+
+# Step 6:
+# The predecessor DNSKEY can be purged.
+setup step6.zsk-prepub.autosign
+# Subtract purge-keys interval from all the times (1h).
+# Tact(N) = now - 962h - 1h = now - 963h
+# Tret(N) = now - 242h - 1h = now - 243h
+# Tdea(N) = now - 49h - 1h = now - 50h
+# Trem(N) = now - 1h - 1h = now - 2h
+# Tpub(N+1) = now - 268h - 1h = now - 269h
+# Tact(N+1) = Tret(N)
+# Tret(N+1) = now + 478h - 1h = now + 477h
+# Trem(N+1) = now + 719h - 1h = now + 718h
+TactN="now-963h"
+TretN="now-243h"
+TremN="now-2h"
+TdeaN="now-50h"
+TpubN1="now-269h"
+TactN1="${TretN}"
+TretN1="now+477h"
+TremN1="now+718h"
+ksktimes="-P ${TactN} -A ${TactN} -P sync ${TactN}"
+zsktimes="-P ${TactN} -A ${TactN} -I ${TretN} -D ${TremN}"
+newtimes="-P ${TpubN1} -A ${TactN1} -I ${TretN1} -D ${TremN1}"
+KSK=$($KEYGEN -a $DEFAULT_ALGORITHM -L 3600 -f KSK $ksktimes $zone 2> keygen.out.$zone.1)
+ZSK1=$($KEYGEN -a $DEFAULT_ALGORITHM -L 3600 $zsktimes $zone 2> keygen.out.$zone.2)
+ZSK2=$($KEYGEN -a $DEFAULT_ALGORITHM -L 3600 $newtimes $zone 2> keygen.out.$zone.3)
+$SETTIME -s -g $O -k $O $TactN -r $O $TactN -d $O $TactN "$KSK" > settime.out.$zone.1 2>&1
+$SETTIME -s -g $H -k $H $TdeaN -z $H $TdeaN "$ZSK1" > settime.out.$zone.2 2>&1
+$SETTIME -s -g $O -k $O $TactN1 -z $O $TdeaN "$ZSK2" > settime.out.$zone.3 2>&1
+# Set key rollover relationship.
+key_successor $ZSK1 $ZSK2
+# Sign zone.
+cat template.db.in "${KSK}.key" "${ZSK1}.key" "${ZSK2}.key" > "$infile"
+private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$KSK" >> "$infile"
+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
+
+#
+# The zones at ksk-doubleksk.autosign represent the various steps of a KSK
+# Double-KSK rollover.
+#
+
+# Step 1:
+# Introduce the first key. This will immediately be active.
+setup step1.ksk-doubleksk.autosign
+TactN="now"
+ksktimes="-P ${TactN} -A ${TactN} -P sync ${TactN}"
+zsktimes="-P ${TactN} -A ${TactN}"
+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)
+$SETTIME -s -g $O -k $O $TactN -r $O $TactN -d $O $TactN "$KSK" > settime.out.$zone.1 2>&1
+$SETTIME -s -g $O -k $O $TactN -z $O $TactN "$ZSK" > settime.out.$zone.2 2>&1
+cat template.db.in "${KSK}.key" "${ZSK}.key" > "$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
+
+# Step 2:
+# It is time to submit the introduce the new KSK.
+setup step2.ksk-doubleksk.autosign
+# According to RFC 7583:
+#
+# Tpub(N+1) <= Tact(N) + Lksk - Dreg - IpubC
+# IpubC = DprpC + TTLkey (+publish-safety)
+#
+# |1| |2| |3| |4|
+# | | | |
+# Key N |<-IpubC->|<--->|<-Dreg->|<-----Lksk--- - -
+# | | | |
+# Key N+1 | | | |
+# | | | |
+# Key N Tpub Trdy Tsbm Tact
+# Key N+1
+#
+# (continued ...)
+#
+# |5| |6| |7| |8| |9| |10|
+# | | | | | |
+# Key N - - --------------Lksk------->|<-Iret->|<----->|
+# | | | | | |
+# Key N+1 |<-IpubC->|<--->|<-Dreg->|<--------Lksk----- - -
+# | | | | | |
+# Key N Tret Tdea Trem
+# Key N+1 Tpub Trdy Tsbm Tact
+#
+# Tnow
+#
+# Lksk: 60d
+# Dreg: 1d
+# DprpC: 1h
+# TTLkey: 2h
+# publish-safety: 1d
+# IpubC: 27h
+#
+# Tact(N) = Tnow - Lksk + Dreg + IpubC = now - 60d + 27h
+# = now - 1440h + 27h = now - 1413h
+TactN="now-1413h"
+ksktimes="-P ${TactN} -A ${TactN} -P sync ${TactN}"
+zsktimes="-P ${TactN} -A ${TactN}"
+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)
+$SETTIME -s -g $O -k $O $TactN -r $O $TactN -d $O $TactN "$KSK" > settime.out.$zone.1 2>&1
+$SETTIME -s -g $O -k $O $TactN -z $O $TactN "$ZSK" > settime.out.$zone.2 2>&1
+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"
+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
+
+# Step 3:
+# It is time to submit the DS.
+setup step3.ksk-doubleksk.autosign
+# According to RFC 7583:
+#
+# Tsbm(N+1) >= Trdy(N+1)
+# Tact(N+1) = Tsbm(N+1) + Dreg
+# Iret = DprpP + TTLds (+retire-safety)
+#
+# |5| |6| |7| |8| |9| |10|
+# | | | | | |
+# Key N - - --------------Lksk------->|<-Iret->|<----->|
+# | | | | | |
+# Key N+1 |<-IpubC->|<--->|<-Dreg->|<--------Lksk----- - -
+# | | | | | |
+# Key N Tret Tdea Trem
+# Key N+1 Tpub Trdy Tsbm Tact
+#
+# Tnow
+#
+# Lksk: 60d
+# Dreg: N/A
+# DprpP: 1h
+# TTLds: 1h
+# retire-safety: 2d
+# Iret: 50h
+# DprpC: 1h
+# TTLkey: 2h
+# publish-safety: 1d
+# IpubC: 27h
+#
+# Tact(N) = Tnow + Lksk = now - 60d = now - 60d
+# Tret(N) = now
+# Trem(N) = Tnow + Iret = now + 50h
+# Tpub(N+1) = Tnow - IpubC = now - 27h
+# Tsbm(N+1) = now
+# Tact(N+1) = Tret(N)
+# Tret(N+1) = Tnow + Lksk = now + 60d
+# Trem(N+1) = Tnow + Lksk + Iret = now + 60d + 50h
+# = now + 1440h + 50h = 1490h
+TactN="now-60d"
+TretN="now"
+TremN="now+50h"
+TpubN1="now-27h"
+TsbmN1="now"
+TactN1="${TretN}"
+TretN1="now+60d"
+TremN1="now+1490h"
+ksktimes="-P ${TactN} -A ${TactN} -P sync ${TactN} -I ${TretN} -D ${TremN}"
+newtimes="-P ${TpubN1} -A ${TactN1} -P sync ${TsbmN1} -I ${TretN1} -D ${TremN1}"
+zsktimes="-P ${TactN} -A ${TactN}"
+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 -s now-1h -e now+2w -o $zone -O raw -f "${zonefile}.signed" $infile > signer.out.$zone.1 2>&1
+
+# Step 4:
+# The DS should be swapped now.
+setup step4.ksk-doubleksk.autosign
+# According to RFC 7583:
+#
+# Tret(N) = Tsbm(N+1)
+# Tdea(N) = Tret(N) + Iret
+# Tact(N+1) = Tret(N)
+#
+# |5| |6| |7| |8| |9| |10|
+# | | | | | |
+# Key N - - --------------Lksk------->|<-Iret->|<----->|
+# | | | | | |
+# Key N+1 |<-IpubC->|<--->|<-Dreg->|<--------Lksk----- - -
+# | | | | | |
+# Key N Tret Tdea Trem
+# Key N+1 Tpub Trdy Tsbm Tact
+#
+# Tnow
+#
+# Lksk: 60d
+# Dreg: N/A
+# Iret: 50h
+#
+# Tact(N) = Tnow - Lksk - Iret = now - 60d - 50h
+# = now - 1440h - 50h = now - 1490h
+# Tret(N) = Tnow - Iret = now - 50h
+# Trem(N) = Tnow
+# Tpub(N+1) = Tnow - Iret - IpubC = now - 50h - 27h
+# = now - 77h
+# Tsbm(N+1) = Tnow - Iret = now - 50h
+# Tact(N+1) = Tret(N)
+# Tret(N+1) = Tnow + Lksk - Iret = now + 60d - 50h = now + 1390h
+# Trem(N+1) = Tnow + Lksk = now + 60d
+TactN="now-1490h"
+TretN="now-50h"
+TremN="now"
+TpubN1="now-77h"
+TsbmN1="now-50h"
+TactN1="${TretN}"
+TretN1="now+1390h"
+TremN1="now+60d"
+ksktimes="-P ${TactN} -A ${TactN} -P sync ${TactN} -I ${TretN} -D ${TremN}"
+newtimes="-P ${TpubN1} -A ${TretN} -P sync ${TsbmN1} -I ${TretN1} -D ${TremN1}"
+zsktimes="-P ${TactN} -A ${TactN}"
+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 $U $TsbmN1 -D ds $TsbmN1 "$KSK1" > settime.out.$zone.1 2>&1
+$SETTIME -s -g $O -k $O $TsbmN1 -r $O $TsbmN1 -d $R $TsbmN1 -P ds $TsbmN1 "$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 -s now-1h -e now+2w -o $zone -O raw -f "${zonefile}.signed" $infile > signer.out.$zone.1 2>&1
+
+# Step 5:
+# The predecessor DNSKEY is removed long enough that is has become HIDDEN.
+setup step5.ksk-doubleksk.autosign
+# Subtract DNSKEY TTL from all the times (2h).
+# Tact(N) = now - 1490h - 2h = now - 1492h
+# Tret(N) = now - 50h - 2h = now - 52h
+# Trem(N) = now - 2h
+# Tpub(N+1) = now - 77h - 2h = now - 79h
+# Tsbm(N+1) = now - 50h - 2h = now - 52h
+# Tact(N+1) = Tret(N)
+# Tret(N+1) = now + 1390h - 2h = now + 1388h
+# Trem(N+1) = now + 60d - 2h = now + 1442h
+TactN="now-1492h"
+TretN="now-52h"
+TremN="now-2h"
+TpubN1="now-79h"
+TsbmN1="now-52h"
+TactN1="${TretN}"
+TretN1="now+1388h"
+TremN1="now+1442h"
+ksktimes="-P ${TactN} -A ${TactN} -P sync ${TactN} -I ${TretN} -D ${TremN}"
+newtimes="-P ${TpubN1} -A ${TretN} -P sync ${TsbmN1} -I ${TretN1} -D ${TremN1}"
+zsktimes="-P ${TactN} -A ${TactN}"
+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 $U $TretN -r $U $TretN -d $H $TretN "$KSK1" > settime.out.$zone.1 2>&1
+$SETTIME -s -g $O -k $O $TactN1 -r $O $TactN1 -d $O $TactN1 "$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 -s now-1h -e now+2w -o $zone -O raw -f "${zonefile}.signed" $infile > signer.out.$zone.1 2>&1
+
+# Step 6:
+# The predecessor DNSKEY can be purged.
+setup step6.ksk-doubleksk.autosign
+# Subtract purge-keys interval from all the times (1h).
+# Tact(N) = now - 1492h - 1h = now - 1493h
+# Tret(N) = now - 52h - 1h = now - 53h
+# Trem(N) = now - 2h - 1h = now - 3h
+# Tpub(N+1) = now - 79h - 1h = now - 80h
+# Tsbm(N+1) = now - 52h - 1h = now - 53h
+# Tact(N+1) = Tret(N)
+# Tret(N+1) = now + 1388h - 1h = now + 1387h
+# Trem(N+1) = now + 1442h - 1h = now + 1441h
+TactN="now-1493h"
+TretN="now-53h"
+TremN="now-3h"
+TpubN1="now-80h"
+TsbmN1="now-53h"
+TactN1="${TretN}"
+TretN1="now+1387h"
+TremN1="now+1441h"
+ksktimes="-P ${TactN} -A ${TactN} -P sync ${TactN} -I ${TretN} -D ${TremN}"
+newtimes="-P ${TpubN1} -A ${TretN} -P sync ${TsbmN1} -I ${TretN1} -D ${TremN1}"
+zsktimes="-P ${TactN} -A ${TactN}"
+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 $H $TretN -r $H $TretN -d $H $TretN "$KSK1" > settime.out.$zone.1 2>&1
+$SETTIME -s -g $O -k $O $TactN1 -r $O $TactN1 -d $O $TactN1 "$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 -s now-1h -e now+2w -o $zone -O raw -f "${zonefile}.signed" $infile > signer.out.$zone.1 2>&1
+
+#
+# The zones at csk-roll.autosign represent the various steps of a CSK rollover
+# (which is essentially a ZSK Pre-Publication / KSK Double-KSK rollover).
+#
+
+# Step 1:
+# Introduce the first key. This will immediately be active.
+setup step1.csk-roll.autosign
+TactN="now"
+csktimes="-P ${TactN} -P sync ${TactN} -A ${TactN}"
+CSK=$($KEYGEN -k csk-roll -l policies/autosign.conf $csktimes $zone 2> keygen.out.$zone.1)
+$SETTIME -s -g $O -k $O $TactN -r $O $TactN -d $O $TactN -z $O $TactN "$CSK" > settime.out.$zone.1 2>&1
+cat template.db.in "${CSK}.key" > "$infile"
+private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$CSK" >> "$infile"
+cp $infile $zonefile
+$SIGNER -S -z -x -s now-1h -e now+30d -o $zone -O raw -f "${zonefile}.signed" $infile > signer.out.$zone.1 2>&1
+
+# Step 2:
+# It is time to introduce the new CSK.
+setup step2.csk-roll.autosign
+# According to RFC 7583:
+# KSK: Tpub(N+1) <= Tact(N) + Lksk - IpubC
+# ZSK: Tpub(N+1) <= Tact(N) + Lzsk - Ipub
+# IpubC = DprpC + TTLkey (+publish-safety)
+# Ipub = IpubC
+# Lcsk = Lksk = Lzsk
+#
+# Lcsk: 6mo (186d, 4464h)
+# Dreg: N/A
+# DprpC: 1h
+# TTLkey: 1h
+# publish-safety: 1h
+# Ipub: 3h
+#
+# Tact(N) = Tnow - Lcsk + Ipub = now - 186d + 3h
+# = now - 4464h + 3h = now - 4461h
+TactN="now-4461h"
+csktimes="-P ${TactN} -P sync ${TactN} -A ${TactN}"
+CSK=$($KEYGEN -k csk-roll -l policies/autosign.conf $csktimes $zone 2> keygen.out.$zone.1)
+$SETTIME -s -g $O -k $O $TactN -r $O $TactN -d $O $TactN -z $O $TactN "$CSK" > settime.out.$zone.1 2>&1
+cat template.db.in "${CSK}.key" > "$infile"
+private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$CSK" >> "$infile"
+cp $infile $zonefile
+$SIGNER -S -z -x -s now-1h -e now+30d -o $zone -O raw -f "${zonefile}.signed" $infile > signer.out.$zone.1 2>&1
+
+# Step 3:
+# It is time to submit the DS and to roll signatures.
+setup step3.csk-roll.autosign
+# According to RFC 7583:
+#
+# Tsbm(N+1) >= Trdy(N+1)
+# KSK: Tact(N+1) = Tsbm(N+1)
+# ZSK: Tact(N+1) = Tpub(N+1) + Ipub = Tsbm(N+1)
+# KSK: Iret = DprpP + TTLds (+retire-safety)
+# ZSK: IretZ = Dsgn + Dprp + TTLsig (+retire-safety)
+#
+# Lcsk: 186d
+# Dprp: 1h
+# DprpP: 1h
+# Dreg: N/A
+# Dsgn: 25d
+# TTLds: 1h
+# TTLsig: 1d
+# retire-safety: 2h
+# Iret: 4h
+# IretZ: 26d3h
+# Ipub: 3h
+#
+# Tact(N) = Tnow - Lcsk = now - 186d
+# Tret(N) = now
+# Trem(N) = Tnow + IretZ = now + 26d3h = now + 627h
+# Tpub(N+1) = Tnow - Ipub = now - 3h
+# Tsbm(N+1) = Tret(N)
+# Tact(N+1) = Tret(N)
+# Tret(N+1) = Tnow + Lcsk = now + 186d = now + 186d
+# Trem(N+1) = Tnow + Lcsk + IretZ = now + 186d + 26d3h =
+# = now + 5091h
+TactN="now-186d"
+TretN="now"
+TremN="now+627h"
+TpubN1="now-3h"
+TsbmN1="now"
+TactN1="${TretN}"
+TretN1="now+186d"
+TremN1="now+5091h"
+csktimes="-P ${TactN} -P sync ${TactN} -A ${TactN} -I ${TretN} -D ${TremN}"
+newtimes="-P ${TpubN1} -P sync ${TsbmN1} -A ${TactN1} -I ${TretN1} -D ${TremN1}"
+CSK1=$($KEYGEN -k csk-roll -l policies/autosign.conf $csktimes $zone 2> keygen.out.$zone.1)
+CSK2=$($KEYGEN -k csk-roll -l policies/autosign.conf $newtimes $zone 2> keygen.out.$zone.2)
+$SETTIME -s -g $H -k $O $TactN -r $O $TactN -d $O $TactN -z $O $TactN "$CSK1" > settime.out.$zone.1 2>&1
+$SETTIME -s -g $O -k $R $TpubN1 -r $R $TpubN1 -d $H $TpubN1 -z $H $TpubN1 "$CSK2" > settime.out.$zone.2 2>&1
+# Set key rollover relationship.
+key_successor $CSK1 $CSK2
+# Sign zone.
+cat template.db.in "${CSK1}.key" "${CSK2}.key" > "$infile"
+private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$CSK1" >> "$infile"
+private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$CSK2" >> "$infile"
+cp $infile $zonefile
+$SIGNER -S -z -x -s now-1h -e now+30d -o $zone -O raw -f "${zonefile}.signed" $infile > signer.out.$zone.1 2>&1
+
+# Step 4:
+# Some time later all the ZRRSIG records should be from the new CSK, and the
+# DS should be swapped. The ZRRSIG records are all replaced after IretZ
+# (which is 26d3h). The DS is swapped after Iret (which is 4h).
+# In other words, the DS is swapped before all zone signatures are replaced.
+setup step4.csk-roll.autosign
+# According to RFC 7583:
+# Trem(N) = Tret(N) - Iret + IretZ
+# Tnow = Tsbm(N+1) + Iret
+#
+# Lcsk: 186d
+# Iret: 4h
+# IretZ: 26d3h
+#
+# Tact(N) = Tnow - Iret - Lcsk = now - 4h - 186d = now - 4468h
+# Tret(N) = Tnow - Iret = now - 4h = now - 4h
+# Trem(N) = Tnow - Iret + IretZ = now - 4h + 26d3h
+# = now + 623h
+# Tpub(N+1) = Tnow - Iret - IpubC = now - 4h - 3h = now - 7h
+# Tsbm(N+1) = Tret(N)
+# Tact(N+1) = Tret(N)
+# Tret(N+1) = Tnow - Iret + Lcsk = now - 4h + 186d = now + 4460h
+# Trem(N+1) = Tnow - Iret + Lcsk + IretZ = now - 4h + 186d + 26d3h
+# = now + 5087h
+TactN="now-4468h"
+TretN="now-4h"
+TremN="now+623h"
+TpubN1="now-7h"
+TsbmN1="${TretN}"
+TactN1="${TretN}"
+TretN1="now+4460h"
+TremN1="now+5087h"
+csktimes="-P ${TactN} -P sync ${TactN} -A ${TactN} -I ${TretN} -D ${TremN}"
+newtimes="-P ${TpubN1} -P sync ${TsbmN1} -A ${TactN1} -I ${TretN1} -D ${TremN1}"
+CSK1=$($KEYGEN -k csk-roll -l policies/autosign.conf $csktimes $zone 2> keygen.out.$zone.1)
+CSK2=$($KEYGEN -k csk-roll -l policies/autosign.conf $newtimes $zone 2> keygen.out.$zone.2)
+$SETTIME -s -g $H -k $O $TactN -r $O $TactN -d $U $TsbmN1 -z $U $TsbmN1 -D ds $TsbmN1 "$CSK1" > settime.out.$zone.1 2>&1
+$SETTIME -s -g $O -k $O $TsbmN1 -r $O $TsbmN1 -d $R $TsbmN1 -z $R $TsbmN1 -P ds $TsbmN1 "$CSK2" > settime.out.$zone.2 2>&1
+# Set key rollover relationship.
+key_successor $CSK1 $CSK2
+# Sign zone.
+cat template.db.in "${CSK1}.key" "${CSK2}.key" > "$infile"
+private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$CSK1" >> "$infile"
+private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$CSK2" >> "$infile"
+cp $infile $zonefile
+$SIGNER -S -z -x -s now-1h -e now+30d -o $zone -O raw -f "${zonefile}.signed" $infile > signer.out.$zone.1 2>&1
+
+# Step 5:
+# After the DS is swapped in step 4, also the KRRSIG records can be removed.
+# At this time these have all become hidden.
+setup step5.csk-roll.autosign
+# Subtract DNSKEY TTL plus zone propagation delay from all the times (2h).
+# Tact(N) = now - 4468h - 2h = now - 4470h
+# Tret(N) = now - 4h - 2h = now - 6h
+# Trem(N) = now + 623h - 2h = now + 621h
+# Tpub(N+1) = now - 7h - 2h = now - 9h
+# Tsbm(N+1) = Tret(N)
+# Tact(N+1) = Tret(N)
+# Tret(N+1) = now + 4460h - 2h = now + 4458h
+# Trem(N+1) = now + 5087h - 2h = now + 5085h
+TactN="now-4470h"
+TretN="now-6h"
+TremN="now+621h"
+TpubN1="now-9h"
+TsbmN1="${TretN}"
+TactN1="${TretN}"
+TretN1="now+4458h"
+TremN1="now+5085h"
+csktimes="-P ${TactN} -P sync ${TactN} -A ${TactN} -I ${TretN} -D ${TremN}"
+newtimes="-P ${TpubN1} -P sync ${TsbmN1} -A ${TactN1} -I ${TretN1} -D ${TremN1}"
+CSK1=$($KEYGEN -k csk-roll -l policies/autosign.conf $csktimes $zone 2> keygen.out.$zone.1)
+CSK2=$($KEYGEN -k csk-roll -l policies/autosign.conf $newtimes $zone 2> keygen.out.$zone.2)
+$SETTIME -s -g $H -k $O $TactN -r $U now-2h -d $H now-2h -z $U $TactN1 "$CSK1" > settime.out.$zone.1 2>&1
+$SETTIME -s -g $O -k $O $TsbmN1 -r $O $TsbmN1 -d $O now-2h -z $R $TactN1 "$CSK2" > settime.out.$zone.2 2>&1
+# Set key rollover relationship.
+key_successor $CSK1 $CSK2
+# Sign zone.
+cat template.db.in "${CSK1}.key" "${CSK2}.key" > "$infile"
+private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$CSK1" >> "$infile"
+private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$CSK2" >> "$infile"
+cp $infile $zonefile
+$SIGNER -S -z -x -s now-1h -e now+30d -o $zone -O raw -f "${zonefile}.signed" $infile > signer.out.$zone.1 2>&1
+
+# Step 6:
+# After the retire interval has passed the predecessor DNSKEY can be
+# removed from the zone.
+setup step6.csk-roll.autosign
+# According to RFC 7583:
+# Trem(N) = Tret(N) + IretZ
+# Tret(N) = Tact(N) + Lcsk
+#
+# Lcsk: 186d
+# Iret: 4h
+# IretZ: 26d3h
+#
+# Tact(N) = Tnow - IretZ - Lcsk = now - 627h - 186d
+# = now - 627h - 4464h = now - 5091h
+# Tret(N) = Tnow - IretZ = now - 627h
+# Trem(N) = Tnow
+# Tpub(N+1) = Tnow - IretZ - Ipub = now - 627h - 3h = now - 630h
+# Tsbm(N+1) = Tret(N)
+# Tact(N+1) = Tret(N)
+# Tret(N+1) = Tnow - IretZ + Lcsk = now - 627h + 186d = now + 3837h
+# Trem(N+1) = Tnow + Lcsk = now + 186d
+TactN="now-5091h"
+TretN="now-627h"
+TremN="now"
+TpubN1="now-630h"
+TsbmN1="${TretN}"
+TactN1="${TretN}"
+TretN1="now+3837h"
+TremN1="now+186d"
+csktimes="-P ${TactN} -P sync ${TactN} -A ${TactN} -I ${TretN} -D ${TremN}"
+newtimes="-P ${TpubN1} -P sync ${TsbmN1} -A ${TactN1} -I ${TretN1} -D ${TremN1}"
+CSK1=$($KEYGEN -k csk-roll -l policies/autosign.conf $csktimes $zone 2> keygen.out.$zone.1)
+CSK2=$($KEYGEN -k csk-roll -l policies/autosign.conf $newtimes $zone 2> keygen.out.$zone.2)
+$SETTIME -s -g $H -k $O $TactN -r $H $TremN -d $H $TremN -z $U $TsbmN1 "$CSK1" > settime.out.$zone.1 2>&1
+$SETTIME -s -g $O -k $O $TsbmN1 -r $O $TsbmN1 -d $O $TremN -z $R $TsbmN1 "$CSK2" > settime.out.$zone.2 2>&1
+# Set key rollover relationship.
+key_successor $CSK1 $CSK2
+# Sign zone.
+cat template.db.in "${CSK1}.key" "${CSK2}.key" > "$infile"
+private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$CSK1" >> "$infile"
+private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$CSK2" >> "$infile"
+cp $infile $zonefile
+$SIGNER -S -z -x -s now-1h -e now+30d -o $zone -O raw -f "${zonefile}.signed" $infile > signer.out.$zone.1 2>&1
+
+# Step 7:
+# Some time later the predecessor DNSKEY enters the HIDDEN state.
+setup step7.csk-roll.autosign
+# Subtract DNSKEY TTL plus zone propagation delay from all the times (2h).
+# Tact(N) = now - 5091h - 2h = now - 5093h
+# Tret(N) = now - 627h - 2h = now - 629h
+# Trem(N) = now - 2h
+# Tpub(N+1) = now - 630h - 2h = now - 632h
+# Tsbm(N+1) = Tret(N)
+# Tact(N+1) = Tret(N)
+# Tret(N+1) = now + 3837h - 2h = now + 3835h
+# Trem(N+1) = now + 186d - 2h = now + 4462h
+TactN="now-5093h"
+TretN="now-629h"
+TremN="now-2h"
+TpubN1="now-632h"
+TsbmN1="${TretN}"
+TactN1="${TretN}"
+TretN1="now+3835h"
+TremN1="now+4462h"
+csktimes="-P ${TactN} -P sync ${TactN} -A ${TactN} -I ${TretN} -D ${TremN}"
+newtimes="-P ${TpubN1} -P sync ${TsbmN1} -A ${TactN1} -I ${TretN1} -D ${TremN1}"
+CSK1=$($KEYGEN -k csk-roll -l policies/autosign.conf $csktimes $zone 2> keygen.out.$zone.1)
+CSK2=$($KEYGEN -k csk-roll -l policies/autosign.conf $newtimes $zone 2> keygen.out.$zone.2)
+$SETTIME -s -g $H -k $U $TremN -r $H $TremN -d $H $TremN -z $H $TactN1 "$CSK1" > settime.out.$zone.1 2>&1
+$SETTIME -s -g $O -k $O $TsbmN1 -r $O $TsbmN1 -d $O $TactN1 -z $O $TactN1 "$CSK2" > settime.out.$zone.2 2>&1
+# Set key rollover relationship.
+key_successor $CSK1 $CSK2
+# Sign zone.
+cat template.db.in "${CSK1}.key" "${CSK2}.key" > "$infile"
+private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$CSK1" >> "$infile"
+private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$CSK2" >> "$infile"
+cp $infile $zonefile
+$SIGNER -S -z -x -s now-1h -e now+30d -o $zone -O raw -f "${zonefile}.signed" $infile > signer.out.$zone.1 2>&1
+
+# Step 8:
+# The predecessor DNSKEY can be purged.
+setup step8.csk-roll.autosign
+# Subtract purge-keys interval from all the times (1h).
+# Tact(N) = now - 5093h - 1h = now - 5094h
+# Tret(N) = now - 629h - 1h = now - 630h
+# Trem(N) = now - 2h - 1h = now - 3h
+# Tpub(N+1) = now - 632h - 1h = now - 633h
+# Tsbm(N+1) = Tret(N)
+# Tact(N+1) = Tret(N)
+# Tret(N+1) = now + 3835h - 1h = now + 3834h
+# Trem(N+1) = now + 4462h - 1h = now + 4461h
+TactN="now-5094h"
+TretN="now-630h"
+TremN="now-3h"
+TpubN1="now-633h"
+TsbmN1="${TretN}"
+TactN1="${TretN}"
+TretN1="now+3834h"
+TremN1="now+4461h"
+csktimes="-P ${TactN} -P sync ${TactN} -A ${TactN} -I ${TretN} -D ${TremN}"
+newtimes="-P ${TpubN1} -P sync ${TsbmN1} -A ${TactN1} -I ${TretN1} -D ${TremN1}"
+CSK1=$($KEYGEN -k csk-roll -l policies/autosign.conf $csktimes $zone 2> keygen.out.$zone.1)
+CSK2=$($KEYGEN -k csk-roll -l policies/autosign.conf $newtimes $zone 2> keygen.out.$zone.2)
+$SETTIME -s -g $H -k $H $TremN -r $H $TremN -d $H $TremN -z $H $TactN1 "$CSK1" > settime.out.$zone.1 2>&1
+$SETTIME -s -g $O -k $O $TsbmN1 -r $O $TsbmN1 -d $O $TactN1 -z $O $TactN1 "$CSK2" > settime.out.$zone.2 2>&1
+# Set key rollover relationship.
+key_successor $CSK1 $CSK2
+# Sign zone.
+cat template.db.in "${CSK1}.key" "${CSK2}.key" > "$infile"
+private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$CSK1" >> "$infile"
+private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$CSK2" >> "$infile"
+cp $infile $zonefile
+$SIGNER -S -z -x -s now-1h -e now+30d -o $zone -O raw -f "${zonefile}.signed" $infile > signer.out.$zone.1 2>&1
+
+#
+# The zones at csk-roll2.autosign represent the various steps of a CSK rollover
+# (which is essentially a ZSK Pre-Publication / KSK Double-KSK rollover).
+# This scenario differs from the above one because the zone signatures (ZRRSIG)
+# are replaced with the new key sooner than the DS is swapped.
+#
+
+# Step 1:
+# Introduce the first key. This will immediately be active.
+setup step1.csk-roll2.autosign
+TactN="now"
+csktimes="-P ${TactN} -P sync ${TactN} -A ${TactN}"
+CSK=$($KEYGEN -k csk-roll2 -l policies/autosign.conf $csktimes $zone 2> keygen.out.$zone.1)
+$SETTIME -s -g $O -k $O $TactN -r $O $TactN -d $O $TactN -z $O $TactN "$CSK" > settime.out.$zone.1 2>&1
+cat template.db.in "${CSK}.key" > "$infile"
+private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$CSK" >> "$infile"
+cp $infile $zonefile
+$SIGNER -S -z -x -s now-1h -e now+30d -o $zone -O raw -f "${zonefile}.signed" $infile > signer.out.$zone.1 2>&1
+
+# Step 2:
+# It is time to introduce the new CSK.
+setup step2.csk-roll2.autosign
+# According to RFC 7583:
+# KSK: Tpub(N+1) <= Tact(N) + Lksk - IpubC
+# ZSK: Tpub(N+1) <= Tact(N) + Lzsk - Ipub
+# IpubC = DprpC + TTLkey (+publish-safety)
+# Ipub = IpubC
+# Lcsk = Lksk = Lzsk
+#
+# Lcsk: 6mo (186d, 4464h)
+# Dreg: N/A
+# DprpC: 1h
+# TTLkey: 1h
+# publish-safety: 1h
+# Ipub: 3h
+#
+# Tact(N) = Tnow - Lcsk + Ipub = now - 186d + 3h
+# = now - 4464h + 3h = now - 4461h
+TactN="now-4461h"
+csktimes="-P ${TactN} -P sync ${TactN} -A ${TactN}"
+CSK=$($KEYGEN -k csk-roll2 -l policies/autosign.conf $csktimes $zone 2> keygen.out.$zone.1)
+$SETTIME -s -g $O -k $O $TactN -r $O $TactN -d $O $TactN -z $O $TactN "$CSK" > settime.out.$zone.1 2>&1
+cat template.db.in "${CSK}.key" > "$infile"
+private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$CSK" >> "$infile"
+cp $infile $zonefile
+$SIGNER -S -z -x -s now-1h -e now+30d -o $zone -O raw -f "${zonefile}.signed" $infile > signer.out.$zone.1 2>&1
+
+# Step 3:
+# It is time to submit the DS and to roll signatures.
+setup step3.csk-roll2.autosign
+# According to RFC 7583:
+#
+# Tsbm(N+1) >= Trdy(N+1)
+# KSK: Tact(N+1) = Tsbm(N+1)
+# ZSK: Tact(N+1) = Tpub(N+1) + Ipub = Tsbm(N+1)
+# KSK: Iret = DprpP + TTLds (+retire-safety)
+# ZSK: IretZ = Dsgn + Dprp + TTLsig (+retire-safety)
+#
+# Lcsk: 186d
+# Dprp: 1h
+# DprpP: 1w
+# Dreg: N/A
+# Dsgn: 12h
+# TTLds: 1h
+# TTLsig: 1d
+# retire-safety: 1h
+# Iret: 170h
+# IretZ: 38h
+# Ipub: 3h
+#
+# Tact(N) = Tnow - Lcsk = now - 186d
+# Tret(N) = now
+# Trem(N) = Tnow + Iret = now + 170h
+# Tpub(N+1) = Tnow - Ipub = now - 3h
+# Tsbm(N+1) = Tret(N)
+# Tact(N+1) = Tret(N)
+# Tret(N+1) = Tnow + Lcsk = now + 186d
+# Trem(N+1) = Tnow + Lcsk + Iret = now + 186d + 170h =
+# = now + 4464h + 170h = now + 4634h
+TactN="now-186d"
+TretN="now"
+TremN="now+170h"
+TpubN1="now-3h"
+TsbmN1="${TretN}"
+TactN1="${TretN}"
+TretN1="now+186d"
+TremN1="now+4634h"
+csktimes="-P ${TactN} -P sync ${TactN} -A ${TactN} -I ${TretN} -D ${TremN}"
+newtimes="-P ${TpubN1} -P sync ${TsbmN1} -A ${TactN1} -I ${TretN1} -D ${TremN1}"
+CSK1=$($KEYGEN -k csk-roll2 -l policies/autosign.conf $csktimes $zone 2> keygen.out.$zone.1)
+CSK2=$($KEYGEN -k csk-roll2 -l policies/autosign.conf $newtimes $zone 2> keygen.out.$zone.2)
+$SETTIME -s -g $H -k $O $TactN -r $O $TactN -d $O $TactN -z $O $TactN "$CSK1" > settime.out.$zone.1 2>&1
+$SETTIME -s -g $O -k $R $TpubN1 -r $R $TpubN1 -d $H $TpubN1 -z $H $TpubN1 "$CSK2" > settime.out.$zone.2 2>&1
+# Set key rollover relationship.
+key_successor $CSK1 $CSK2
+# Sign zone.
+cat template.db.in "${CSK1}.key" "${CSK2}.key" > "$infile"
+private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$CSK1" >> "$infile"
+private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$CSK2" >> "$infile"
+cp $infile $zonefile
+$SIGNER -S -z -x -s now-1h -e now+30d -o $zone -O raw -f "${zonefile}.signed" $infile > signer.out.$zone.1 2>&1
+
+# Step 4:
+# Some time later all the ZRRSIG records should be from the new CSK, and the
+# DS should be swapped. The ZRRSIG records are all replaced after IretZ (38h).
+# The DS is swapped after Dreg + Iret (1w3h). In other words, the zone
+# signatures are replaced before the DS is swapped.
+setup step4.csk-roll2.autosign
+# According to RFC 7583:
+# Trem(N) = Tret(N) + IretZ
+#
+# Lcsk: 186d
+# Dreg: N/A
+# Iret: 170h
+# IretZ: 38h
+#
+# Tact(N) = Tnow - IretZ = Lcsk = now - 38h - 186d
+# = now - 38h - 4464h = now - 4502h
+# Tret(N) = Tnow - IretZ = now - 38h
+# Trem(N) = Tnow - IretZ + Iret = now - 38h + 170h = now + 132h
+# Tpub(N+1) = Tnow - IretZ - IpubC = now - 38h - 3h = now - 41h
+# Tsbm(N+1) = Tret(N)
+# Tact(N+1) = Tret(N)
+# Tret(N+1) = Tnow - IretZ + Lcsk = now - 38h + 186d
+# = now + 4426h
+# Trem(N+1) = Tnow - IretZ + Lcsk + Iret
+# = now + 4426h + 3h = now + 4429h
+TactN="now-4502h"
+TretN="now-38h"
+TremN="now+132h"
+TpubN1="now-41h"
+TsbmN1="${TretN}"
+TactN1="${TretN}"
+TretN1="now+4426h"
+TremN1="now+4429h"
+csktimes="-P ${TactN} -P sync ${TactN} -A ${TactN} -I ${TretN} -D ${TremN}"
+newtimes="-P ${TpubN1} -P sync ${TsbmN1} -A ${TactN1} -I ${TretN1} -D ${TremN1}"
+CSK1=$($KEYGEN -k csk-roll2 -l policies/autosign.conf $csktimes $zone 2> keygen.out.$zone.1)
+CSK2=$($KEYGEN -k csk-roll2 -l policies/autosign.conf $newtimes $zone 2> keygen.out.$zone.2)
+$SETTIME -s -g $H -k $O $TactN -r $O $TactN -z $U $TretN -d $U $TsbmN1 -D ds $TsbmN1 "$CSK1" > settime.out.$zone.1 2>&1
+$SETTIME -s -g $O -k $O $TsbmN1 -r $O $TsbmN1 -z $R $TactN1 -d $R $TsbmN1 -P ds $TsbmN1 "$CSK2" > settime.out.$zone.2 2>&1
+# Set key rollover relationship.
+key_successor $CSK1 $CSK2
+# Sign zone.
+cat template.db.in "${CSK1}.key" "${CSK2}.key" > "$infile"
+private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$CSK1" >> "$infile"
+private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$CSK2" >> "$infile"
+cp $infile $zonefile
+$SIGNER -S -z -x -s now-1h -e now+30d -o $zone -O raw -f "${zonefile}.signed" $infile > signer.out.$zone.1 2>&1
+
+# Step 5:
+# Some time later the DS can be swapped and the old DNSKEY can be removed from
+# the zone.
+setup step5.csk-roll2.autosign
+# Subtract Iret (170h) - IretZ (38h) = 132h.
+#
+# Tact(N) = now - 4502h - 132h = now - 4634h
+# Tret(N) = now - 38h - 132h = now - 170h
+# Trem(N) = now + 132h - 132h = now
+# Tpub(N+1) = now - 41h - 132h = now - 173h
+# Tsbm(N+1) = Tret(N)
+# Tact(N+1) = Tret(N)
+# Tret(N+1) = now + 4426h - 132h = now + 4294h
+# Trem(N+1) = now + 4492h - 132h = now + 4360h
+TactN="now-4634h"
+TretN="now-170h"
+TremN="now"
+TpubN1="now-173h"
+TsbmN1="${TretN}"
+TactN1="${TretN}"
+TretN1="now+4294h"
+TremN1="now+4360h"
+csktimes="-P ${TactN} -P sync ${TactN} -A ${TactN} -I ${TretN} -D ${TremN}"
+newtimes="-P ${TpubN1} -P sync ${TsbmN1} -A ${TactN1} -I ${TretN1} -D ${TremN1}"
+CSK1=$($KEYGEN -k csk-roll2 -l policies/autosign.conf $csktimes $zone 2> keygen.out.$zone.1)
+CSK2=$($KEYGEN -k csk-roll2 -l policies/autosign.conf $newtimes $zone 2> keygen.out.$zone.2)
+$SETTIME -s -g $H -k $O $TactN -r $O $TactN -z $H now-133h -d $U $TsbmN1 -D ds $TsbmN1 "$CSK1" > settime.out.$zone.1 2>&1
+$SETTIME -s -g $O -k $O $TsbmN1 -r $O $TsbmN1 -z $O now-133h -d $R $TsbmN1 -P ds $TsbmN1 "$CSK2" > settime.out.$zone.2 2>&1
+# Set key rollover relationship.
+key_successor $CSK1 $CSK2
+# Sign zone.
+cat template.db.in "${CSK1}.key" "${CSK2}.key" > "$infile"
+private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$CSK1" >> "$infile"
+private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$CSK2" >> "$infile"
+cp $infile $zonefile
+$SIGNER -S -z -x -s now-1h -e now+30d -o $zone -O raw -f "${zonefile}.signed" $infile > signer.out.$zone.1 2>&1
+
+# Step 6:
+# Some time later the predecessor DNSKEY enters the HIDDEN state.
+setup step6.csk-roll2.autosign
+# Subtract DNSKEY TTL plus zone propagation delay (2h).
+#
+# Tact(N) = now - 4634h - 2h = now - 4636h
+# Tret(N) = now - 170h - 2h = now - 172h
+# Trem(N) = now - 2h
+# Tpub(N+1) = now - 173h - 2h = now - 175h
+# Tsbm(N+1) = Tret(N)
+# Tact(N+1) = Tret(N)
+# Tret(N+1) = now + 4294h - 2h = now + 4292h
+# Trem(N+1) = now + 4360h - 2h = now + 4358h
+TactN="now-4636h"
+TretN="now-172h"
+TremN="now-2h"
+TpubN1="now-175h"
+TsbmN1="${TretN}"
+TactN1="${TretN}"
+TretN1="now+4292h"
+TremN1="now+4358h"
+csktimes="-P ${TactN} -P sync ${TactN} -A ${TactN} -I ${TretN} -D ${TremN}"
+newtimes="-P ${TpubN1} -P sync ${TsbmN1} -A ${TactN1} -I ${TretN1} -D ${TremN1}"
+CSK1=$($KEYGEN -k csk-roll2 -l policies/autosign.conf $csktimes $zone 2> keygen.out.$zone.1)
+CSK2=$($KEYGEN -k csk-roll2 -l policies/autosign.conf $newtimes $zone 2> keygen.out.$zone.2)
+$SETTIME -s -g $H -k $U $TremN -r $U $TremN -d $H $TremN -z $H now-135h "$CSK1" > settime.out.$zone.1 2>&1
+$SETTIME -s -g $O -k $O $TsbmN1 -r $O $TsbmN1 -d $O $TremN -z $O now-135h "$CSK2" > settime.out.$zone.2 2>&1
+# Set key rollover relationship.
+key_successor $CSK1 $CSK2
+# Sign zone.
+cat template.db.in "${CSK1}.key" "${CSK2}.key" > "$infile"
+private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$CSK1" >> "$infile"
+private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$CSK2" >> "$infile"
+cp $infile $zonefile
+$SIGNER -S -z -x -s now-1h -e now+30d -o $zone -O raw -f "${zonefile}.signed" $infile > signer.out.$zone.1 2>&1
+
+# Step 7:
+# The predecessor DNSKEY can be purged, but purge-keys is disabled.
+setup step7.csk-roll2.autosign
+# Subtract 90 days (default, 2160h) from all the times.
+# Tact(N) = now - 4636h - 2160h = now - 6796h
+# Tret(N) = now - 172h - 2160h = now - 2332h
+# Trem(N) = now - 2h - 2160h = now - 2162h
+# Tpub(N+1) = now - 175h - 2160h = now - 2335h
+# Tsbm(N+1) = Tret(N)
+# Tact(N+1) = Tret(N)
+# Tret(N+1) = now + 4294h - 2160h = now + 2134h
+# Trem(N+1) = now + 4360h - 2160h = now + 2200h
+TactN="now-6796h"
+TretN="now-2332h"
+TremN="now-2162h"
+TpubN1="now-2335h"
+TsbmN1="${TretN}"
+TactN1="${TretN}"
+TretN1="now+2134h"
+TremN1="now+2200h"
+csktimes="-P ${TactN} -P sync ${TactN} -A ${TactN} -I ${TretN} -D ${TremN}"
+newtimes="-P ${TpubN1} -P sync ${TsbmN1} -A ${TactN1} -I ${TretN1} -D ${TremN1}"
+CSK1=$($KEYGEN -k csk-roll2 -l policies/autosign.conf $csktimes $zone 2> keygen.out.$zone.1)
+CSK2=$($KEYGEN -k csk-roll2 -l policies/autosign.conf $newtimes $zone 2> keygen.out.$zone.2)
+$SETTIME -s -g $H -k $U $TremN -r $U $TremN -d $H $TremN -z $H now-135h "$CSK1" > settime.out.$zone.1 2>&1
+$SETTIME -s -g $O -k $O $TsbmN1 -r $O $TsbmN1 -d $O $TremN -z $O now-135h "$CSK2" > settime.out.$zone.2 2>&1
+# Set key rollover relationship.
+key_successor $CSK1 $CSK2
+# Sign zone.
+cat template.db.in "${CSK1}.key" "${CSK2}.key" > "$infile"
+private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$CSK1" >> "$infile"
+private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$CSK2" >> "$infile"
+cp $infile $zonefile
+$SIGNER -S -z -x -s now-1h -e now+30d -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.
+TactN="now-60d"
+TretN="now"
+TremN="now+50h"
+TpubN1="now-27h"
+TsbmN1="now"
+TactN1="${TretN}"
+TretN1="now+60d"
+TremN1="now+1490h"
+ksktimes="-P ${TactN} -A ${TactN} -P sync ${TactN} -I ${TretN} -D ${TremN}"
+newtimes="-P ${TpubN1} -A ${TactN1} -P sync ${TsbmN1} -I ${TretN1} -D ${TremN1}"
+zsktimes="-P ${TactN} -A ${TactN}"
+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 -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/kasp/ns3/template.db.in b/bin/tests/system/kasp/ns3/template.db.in
new file mode 100644
index 0000000..010b05b
--- /dev/null
+++ b/bin/tests/system/kasp/ns3/template.db.in
@@ -0,0 +1,27 @@
+; 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/kasp/ns3/template2.db.in b/bin/tests/system/kasp/ns3/template2.db.in
new file mode 100644
index 0000000..7b94ace
--- /dev/null
+++ b/bin/tests/system/kasp/ns3/template2.db.in
@@ -0,0 +1,27 @@
+; 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. . (
+ 2 ; 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.11
+b A 10.0.0.22
+c A 10.0.0.33
+d A 10.0.0.44
diff --git a/bin/tests/system/kasp/ns4/example1.db.in b/bin/tests/system/kasp/ns4/example1.db.in
new file mode 100644
index 0000000..c9e537f
--- /dev/null
+++ b/bin/tests/system/kasp/ns4/example1.db.in
@@ -0,0 +1,24 @@
+; 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 "view1"
diff --git a/bin/tests/system/kasp/ns4/example2.db.in b/bin/tests/system/kasp/ns4/example2.db.in
new file mode 100644
index 0000000..c1f16a2
--- /dev/null
+++ b/bin/tests/system/kasp/ns4/example2.db.in
@@ -0,0 +1,24 @@
+; 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 "view2"
diff --git a/bin/tests/system/kasp/ns4/named.conf.in b/bin/tests/system/kasp/ns4/named.conf.in
new file mode 100644
index 0000000..459ea73
--- /dev/null
+++ b/bin/tests/system/kasp/ns4/named.conf.in
@@ -0,0 +1,177 @@
+/*
+ * 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
+
+key rndc_key {
+ secret "1234abcd8765";
+ algorithm @DEFAULT_HMAC@;
+};
+
+controls {
+ inet 10.53.0.4 port @CONTROLPORT@ allow { any; } keys { rndc_key; };
+};
+
+key "sha1" {
+ algorithm "hmac-sha1";
+ secret "FrSt77yPTFx6hTs4i2tKLB9LmE0=";
+};
+
+key "sha224" {
+ algorithm "hmac-sha224";
+ secret "hXfwwwiag2QGqblopofai9NuW28q/1rH4CaTnA==";
+};
+
+key "sha256" {
+ algorithm "hmac-sha256";
+ secret "R16NojROxtxH/xbDl//ehDsHm5DjWTQ2YXV+hGC2iBY=";
+};
+
+key "keyforview1" {
+ algorithm @DEFAULT_HMAC@;
+ secret "YPfMoAk6h+3iN8MDRQC004iSNHY=";
+};
+
+key "keyforview2" {
+ algorithm @DEFAULT_HMAC@;
+ secret "4xILSZQnuO1UKubXHkYUsvBRPu8=";
+};
+
+key "keyforview3" {
+ algorithm @DEFAULT_HMAC@;
+ secret "C1Azf+gGPMmxrUg/WQINP6eV9Y0=";
+};
+
+dnssec-policy "test" {
+ keys {
+ csk key-directory lifetime 0 algorithm 14;
+ };
+};
+
+options {
+ query-source address 10.53.0.4;
+ port @PORT@;
+ pid-file "named.pid";
+ listen-on { 10.53.0.4; };
+ listen-on-v6 { none; };
+ recursion no;
+ dnssec-policy "test";
+ dnssec-validation no;
+};
+
+view "inherit" {
+ match-clients { key "sha1"; };
+
+ /* Inherit dnssec-policy 'test' */
+ zone "inherit.inherit.signed" {
+ type primary;
+ file "inherit.inherit.signed.db";
+ inline-signing yes;
+ };
+
+ /* Override dnssec-policy */
+ zone "override.inherit.signed" {
+ type primary;
+ file "override.inherit.signed.db";
+ inline-signing yes;
+ dnssec-policy "default";
+ };
+
+ /* Unset dnssec-policy */
+ zone "none.inherit.signed" {
+ type primary;
+ file "none.inherit.signed.db";
+ dnssec-policy "none";
+ };
+};
+
+view "override" {
+ match-clients { key "sha224"; };
+ dnssec-policy "default";
+
+ /* Inherit dnssec-policy 'test' */
+ zone "inherit.override.signed" {
+ type primary;
+ file "inherit.override.signed.db";
+ inline-signing yes;
+ };
+
+ /* Override dnssec-policy */
+ zone "override.override.signed" {
+ type primary;
+ file "override.override.signed.db";
+ inline-signing yes;
+ dnssec-policy "test";
+ };
+
+ /* Unset dnssec-policy */
+ zone "none.override.signed" {
+ type primary;
+ file "none.override.signed.db";
+ dnssec-policy "none";
+ };
+};
+
+view "none" {
+ match-clients { key "sha256"; };
+ dnssec-policy "none";
+
+ /* Inherit dnssec-policy 'none' */
+ zone "inherit.none.signed" {
+ type primary;
+ file "inherit.none.signed.db";
+ };
+
+ /* Override dnssec-policy */
+ zone "override.none.signed" {
+ type primary;
+ file "override.none.signed.db";
+ inline-signing yes;
+ dnssec-policy "test";
+ };
+
+ /* Unset dnssec-policy */
+ zone "none.none.signed" {
+ type primary;
+ file "none.none.signed.db";
+ dnssec-policy "none";
+ };
+};
+
+view "example1" {
+ match-clients { key "keyforview1"; };
+
+ allow-update { any; };
+
+ zone "example.net" {
+ type primary;
+ file "example1.db";
+ };
+};
+
+view "example2" {
+ match-clients { key "keyforview2"; };
+
+ zone "example.net" {
+ type primary;
+ file "example2.db";
+ inline-signing yes;
+ };
+};
+
+view "example3" {
+ match-clients { key "keyforview3"; };
+ zone "example.net" {
+ in-view example2;
+ };
+};
diff --git a/bin/tests/system/kasp/ns4/setup.sh b/bin/tests/system/kasp/ns4/setup.sh
new file mode 100644
index 0000000..61b049d
--- /dev/null
+++ b/bin/tests/system/kasp/ns4/setup.sh
@@ -0,0 +1,33 @@
+#!/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"
+
+#
+# Set up zones that potentially will be initially signed.
+#
+for zn in inherit.inherit override.inherit none.inherit \
+ inherit.override override.override none.override \
+ inherit.none override.none none.none
+do
+ zone="$zn.signed"
+ echo_i "setting up zone: $zone"
+ zonefile="${zone}.db"
+ cp template.db.in $zonefile
+done
+
+cp example1.db.in example1.db
+cp example2.db.in example2.db
diff --git a/bin/tests/system/kasp/ns4/template.db.in b/bin/tests/system/kasp/ns4/template.db.in
new file mode 100644
index 0000000..0f72e9c
--- /dev/null
+++ b/bin/tests/system/kasp/ns4/template.db.in
@@ -0,0 +1,27 @@
+; 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
+
+a A 10.0.0.1
+b A 10.0.0.2
+c A 10.0.0.3
+
diff --git a/bin/tests/system/kasp/ns5/named.conf.in b/bin/tests/system/kasp/ns5/named.conf.in
new file mode 100644
index 0000000..44855b9
--- /dev/null
+++ b/bin/tests/system/kasp/ns5/named.conf.in
@@ -0,0 +1,133 @@
+/*
+ * 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.
+ */
+
+// NS5
+
+key rndc_key {
+ secret "1234abcd8765";
+ algorithm @DEFAULT_HMAC@;
+};
+
+controls {
+ inet 10.53.0.5 port @CONTROLPORT@ allow { any; } keys { rndc_key; };
+};
+
+key "sha1" {
+ algorithm "hmac-sha1";
+ secret "FrSt77yPTFx6hTs4i2tKLB9LmE0=";
+};
+
+key "sha224" {
+ algorithm "hmac-sha224";
+ secret "hXfwwwiag2QGqblopofai9NuW28q/1rH4CaTnA==";
+};
+
+key "sha256" {
+ algorithm "hmac-sha256";
+ secret "R16NojROxtxH/xbDl//ehDsHm5DjWTQ2YXV+hGC2iBY=";
+};
+
+dnssec-policy "test" {
+ keys {
+ csk key-directory lifetime 0 algorithm 14;
+ };
+};
+
+options {
+ query-source address 10.53.0.5;
+ port @PORT@;
+ pid-file "named.pid";
+ listen-on { 10.53.0.5; };
+ listen-on-v6 { none; };
+ recursion no;
+ dnssec-policy "none";
+ dnssec-validation no;
+};
+
+view "inherit" {
+ match-clients { key "sha1"; };
+
+ /* Inherit dnssec-policy 'none' */
+ zone "inherit.inherit.unsigned" {
+ type primary;
+ file "inherit.inherit.unsigned.db";
+ };
+
+ /* Override dnssec-policy */
+ zone "override.inherit.unsigned" {
+ type primary;
+ file "override.inherit.unsigned.db";
+ inline-signing yes;
+ dnssec-policy "default";
+ };
+
+ /* Unset dnssec-policy */
+ zone "none.inherit.unsigned" {
+ type primary;
+ file "none.inherit.unsigned.db";
+ dnssec-policy "none";
+ };
+};
+
+view "override" {
+ match-clients { key "sha224"; };
+ dnssec-policy "default";
+
+ /* Inherit dnssec-policy 'default' */
+ zone "inherit.override.unsigned" {
+ type primary;
+ file "inherit.override.unsigned.db";
+ inline-signing yes;
+ };
+
+ /* Override dnssec-policy */
+ zone "override.override.unsigned" {
+ type primary;
+ file "override.override.unsigned.db";
+ inline-signing yes;
+ dnssec-policy "test";
+ };
+
+ /* Unset dnssec-policy */
+ zone "none.override.unsigned" {
+ type primary;
+ file "none.override.unsigned.db";
+ dnssec-policy "none";
+ };
+};
+
+view "none" {
+ match-clients { key "sha256"; };
+ dnssec-policy "none";
+
+ /* Inherit dnssec-policy 'none' */
+ zone "inherit.none.unsigned" {
+ type primary;
+ file "inherit.none.unsigned.db";
+ };
+
+ /* Override dnssec-policy */
+ zone "override.none.unsigned" {
+ type primary;
+ file "override.none.unsigned.db";
+ inline-signing yes;
+ dnssec-policy "test";
+ };
+
+ /* Unset dnssec-policy */
+ zone "none.none.unsigned" {
+ type primary;
+ file "none.none.unsigned.db";
+ dnssec-policy "none";
+ };
+};
diff --git a/bin/tests/system/kasp/ns5/setup.sh b/bin/tests/system/kasp/ns5/setup.sh
new file mode 100644
index 0000000..59c7a41
--- /dev/null
+++ b/bin/tests/system/kasp/ns5/setup.sh
@@ -0,0 +1,30 @@
+#!/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 "ns5/setup.sh"
+
+#
+# Set up zones that potentially will be initially signed.
+#
+for zn in inherit.inherit override.inherit none.inherit \
+ inherit.override override.override none.override \
+ inherit.none override.none none.none
+do
+ zone="$zn.unsigned"
+ echo_i "setting up zone: $zone"
+ zonefile="${zone}.db"
+ cp template.db.in $zonefile
+done
diff --git a/bin/tests/system/kasp/ns5/template.db.in b/bin/tests/system/kasp/ns5/template.db.in
new file mode 100644
index 0000000..6cb07a4
--- /dev/null
+++ b/bin/tests/system/kasp/ns5/template.db.in
@@ -0,0 +1,27 @@
+; 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 ns5
+ns5 A 10.53.0.5
+
+a A 10.0.0.1
+b A 10.0.0.2
+c A 10.0.0.3
+
diff --git a/bin/tests/system/kasp/ns6/example.db.in b/bin/tests/system/kasp/ns6/example.db.in
new file mode 100644
index 0000000..d6b912c
--- /dev/null
+++ b/bin/tests/system/kasp/ns6/example.db.in
@@ -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 ns6
+ns6 A 10.53.0.6
+
+a A 10.0.0.1
+b A 10.0.0.2
+c A 10.0.0.3
diff --git a/bin/tests/system/kasp/ns6/example2.db.in b/bin/tests/system/kasp/ns6/example2.db.in
new file mode 100644
index 0000000..46aed9b
--- /dev/null
+++ b/bin/tests/system/kasp/ns6/example2.db.in
@@ -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. . (
+ 2 ; serial
+ 20 ; refresh (20 seconds)
+ 20 ; retry (20 seconds)
+ 1814400 ; expire (3 weeks)
+ 3600 ; minimum (1 hour)
+ )
+
+ NS ns6
+ns6 A 10.53.0.6
+
+a A 10.0.0.1
+b A 10.0.0.2
+c A 10.0.0.3
diff --git a/bin/tests/system/kasp/ns6/example3.db.in b/bin/tests/system/kasp/ns6/example3.db.in
new file mode 100644
index 0000000..ccbd96a
--- /dev/null
+++ b/bin/tests/system/kasp/ns6/example3.db.in
@@ -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 400
+@ IN SOA mname1. . (
+ 3 ; serial
+ 20 ; refresh (20 seconds)
+ 20 ; retry (20 seconds)
+ 1814400 ; expire (3 weeks)
+ 3600 ; minimum (1 hour)
+ )
+
+ NS ns6
+ns6 A 10.53.0.6
+
+a A 10.0.0.1
+b A 10.0.0.2
+c A 10.0.0.3
diff --git a/bin/tests/system/kasp/ns6/named.conf.in b/bin/tests/system/kasp/ns6/named.conf.in
new file mode 100644
index 0000000..c339c44
--- /dev/null
+++ b/bin/tests/system/kasp/ns6/named.conf.in
@@ -0,0 +1,98 @@
+/*
+ * 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.
+ */
+
+// NS6
+
+include "policies/kasp.conf";
+include "policies/csk1.conf";
+
+options {
+ query-source address 10.53.0.6;
+ notify-source 10.53.0.6;
+ transfer-source 10.53.0.6;
+ port @PORT@;
+ pid-file "named.pid";
+ listen-on { 10.53.0.6; };
+ 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.6 port @CONTROLPORT@ allow { any; } keys { rndc_key; };
+};
+
+/* This zone switch from dynamic to inline-signing. */
+zone "dynamic2inline.kasp" {
+ type primary;
+ file "dynamic2inline.kasp.db";
+ allow-update { any; };
+ dnssec-policy "default";
+};
+
+/* These zones are going insecure. */
+zone "step1.going-insecure.kasp" {
+ type primary;
+ file "step1.going-insecure.kasp.db";
+ inline-signing yes;
+ dnssec-policy "unsigning";
+};
+
+zone "step1.going-insecure-dynamic.kasp" {
+ type primary;
+ file "step1.going-insecure-dynamic.kasp.db";
+ dnssec-policy "unsigning";
+ allow-update { any; };
+};
+
+zone "step1.going-straight-to-none.kasp" {
+ type primary;
+ file "step1.going-straight-to-none.kasp.db";
+ inline-signing yes;
+ dnssec-policy "default";
+};
+
+/* These are alorithm rollover test zones. */
+zone "step1.algorithm-roll.kasp" {
+ type primary;
+ file "step1.algorithm-roll.kasp.db";
+ inline-signing yes;
+ dnssec-policy "rsasha256";
+};
+
+zone "step1.csk-algorithm-roll.kasp" {
+ type primary;
+ file "step1.csk-algorithm-roll.kasp.db";
+ inline-signing yes;
+ dnssec-policy "csk-algoroll";
+};
+
+dnssec-policy "modified" {
+ keys {
+ csk lifetime unlimited algorithm rsasha256 2048;
+ };
+};
+
+zone example {
+ type primary;
+ file "example.db";
+ inline-signing yes;
+ dnssec-policy modified;
+};
diff --git a/bin/tests/system/kasp/ns6/named2.conf.in b/bin/tests/system/kasp/ns6/named2.conf.in
new file mode 100644
index 0000000..4d48fd9
--- /dev/null
+++ b/bin/tests/system/kasp/ns6/named2.conf.in
@@ -0,0 +1,186 @@
+/*
+ * 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.
+ */
+
+// NS6
+
+include "policies/kasp.conf";
+include "policies/csk2.conf";
+
+options {
+ query-source address 10.53.0.6;
+ notify-source 10.53.0.6;
+ transfer-source 10.53.0.6;
+ port @PORT@;
+ pid-file "named.pid";
+ listen-on { 10.53.0.6; };
+ 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.6 port @CONTROLPORT@ allow { any; } keys { rndc_key; };
+};
+
+/* This zone switch from dynamic to inline-signing. */
+zone "dynamic2inline.kasp" {
+ type primary;
+ file "dynamic2inline.kasp.db";
+ allow-update { any; };
+ inline-signing yes;
+ dnssec-policy "default";
+};
+
+/* Zones for testing going insecure. */
+zone "step1.going-insecure.kasp" {
+ type primary;
+ file "step1.going-insecure.kasp.db";
+ inline-signing yes;
+ dnssec-policy "insecure";
+};
+
+zone "step2.going-insecure.kasp" {
+ type primary;
+ file "step2.going-insecure.kasp.db";
+ inline-signing yes;
+ dnssec-policy "insecure";
+};
+
+zone "step1.going-insecure-dynamic.kasp" {
+ type primary;
+ file "step1.going-insecure-dynamic.kasp.db";
+ dnssec-policy "insecure";
+ allow-update { any; };
+};
+
+zone "step2.going-insecure-dynamic.kasp" {
+ type primary;
+ file "step2.going-insecure-dynamic.kasp.db";
+ dnssec-policy "insecure";
+ allow-update { any; };
+};
+
+zone "step1.going-straight-to-none.kasp" {
+ type primary;
+ file "step1.going-straight-to-none.kasp.db";
+ dnssec-policy "none";
+};
+
+/*
+ * Zones for testing KSK/ZSK algorithm roll.
+ */
+zone "step1.algorithm-roll.kasp" {
+ type primary;
+ file "step1.algorithm-roll.kasp.db";
+ inline-signing yes;
+ dnssec-policy "ecdsa256";
+};
+
+zone "step2.algorithm-roll.kasp" {
+ type primary;
+ file "step2.algorithm-roll.kasp.db";
+ inline-signing yes;
+ dnssec-policy "ecdsa256";
+};
+
+zone "step3.algorithm-roll.kasp" {
+ type primary;
+ file "step3.algorithm-roll.kasp.db";
+ inline-signing yes;
+ dnssec-policy "ecdsa256";
+};
+
+zone "step4.algorithm-roll.kasp" {
+ type primary;
+ file "step4.algorithm-roll.kasp.db";
+ inline-signing yes;
+ dnssec-policy "ecdsa256";
+};
+
+zone "step5.algorithm-roll.kasp" {
+ type primary;
+ file "step5.algorithm-roll.kasp.db";
+ inline-signing yes;
+ dnssec-policy "ecdsa256";
+};
+
+zone "step6.algorithm-roll.kasp" {
+ type primary;
+ file "step6.algorithm-roll.kasp.db";
+ inline-signing yes;
+ dnssec-policy "ecdsa256";
+};
+
+/*
+ * Zones for testing CSK algorithm roll.
+ */
+zone "step1.csk-algorithm-roll.kasp" {
+ type primary;
+ file "step1.csk-algorithm-roll.kasp.db";
+ inline-signing yes;
+ dnssec-policy "csk-algoroll";
+};
+
+zone "step2.csk-algorithm-roll.kasp" {
+ type primary;
+ file "step2.csk-algorithm-roll.kasp.db";
+ inline-signing yes;
+ dnssec-policy "csk-algoroll";
+};
+
+zone "step3.csk-algorithm-roll.kasp" {
+ type primary;
+ file "step3.csk-algorithm-roll.kasp.db";
+ inline-signing yes;
+ dnssec-policy "csk-algoroll";
+};
+
+zone "step4.csk-algorithm-roll.kasp" {
+ type primary;
+ file "step4.csk-algorithm-roll.kasp.db";
+ inline-signing yes;
+ dnssec-policy "csk-algoroll";
+};
+
+zone "step5.csk-algorithm-roll.kasp" {
+ type primary;
+ file "step5.csk-algorithm-roll.kasp.db";
+ inline-signing yes;
+ dnssec-policy "csk-algoroll";
+};
+
+zone "step6.csk-algorithm-roll.kasp" {
+ type primary;
+ file "step6.csk-algorithm-roll.kasp.db";
+ inline-signing yes;
+ dnssec-policy "csk-algoroll";
+};
+
+dnssec-policy "modified" {
+ keys {
+ csk lifetime unlimited algorithm rsasha256 2048;
+ };
+};
+
+zone example {
+ type primary;
+ file "example.db";
+ inline-signing yes;
+ dnssec-policy modified;
+};
diff --git a/bin/tests/system/kasp/ns6/policies/csk1.conf.in b/bin/tests/system/kasp/ns6/policies/csk1.conf.in
new file mode 100644
index 0000000..a5ff042
--- /dev/null
+++ b/bin/tests/system/kasp/ns6/policies/csk1.conf.in
@@ -0,0 +1,30 @@
+/*
+ * 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 "csk-algoroll" {
+ signatures-refresh P5D;
+ signatures-validity 30d;
+ signatures-validity-dnskey 30d;
+
+ keys {
+ csk lifetime unlimited algorithm rsasha256;
+ };
+
+ dnskey-ttl 1h;
+ publish-safety PT1H;
+ retire-safety 2h;
+ zone-propagation-delay 3600;
+ max-zone-ttl 6h;
+ parent-propagation-delay pt1h;
+ parent-ds-ttl 7200;
+};
diff --git a/bin/tests/system/kasp/ns6/policies/csk2.conf.in b/bin/tests/system/kasp/ns6/policies/csk2.conf.in
new file mode 100644
index 0000000..6d290c3
--- /dev/null
+++ b/bin/tests/system/kasp/ns6/policies/csk2.conf.in
@@ -0,0 +1,30 @@
+/*
+ * 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 "csk-algoroll" {
+ signatures-refresh P5D;
+ signatures-validity 30d;
+ signatures-validity-dnskey 30d;
+
+ keys {
+ csk lifetime unlimited algorithm @DEFAULT_ALGORITHM@;
+ };
+
+ dnskey-ttl 1h;
+ publish-safety PT1H;
+ retire-safety 2h;
+ zone-propagation-delay 3600;
+ max-zone-ttl 6h;
+ parent-propagation-delay pt1h;
+ parent-ds-ttl 7200;
+};
diff --git a/bin/tests/system/kasp/ns6/policies/kasp-fips.conf.in b/bin/tests/system/kasp/ns6/policies/kasp-fips.conf.in
new file mode 100644
index 0000000..810b91d
--- /dev/null
+++ b/bin/tests/system/kasp/ns6/policies/kasp-fips.conf.in
@@ -0,0 +1,63 @@
+/*
+ * 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 "unsigning" {
+ dnskey-ttl 7200;
+
+ keys {
+ ksk key-directory lifetime unlimited algorithm @DEFAULT_ALGORITHM@;
+ zsk key-directory lifetime P60D algorithm @DEFAULT_ALGORITHM@;
+ };
+};
+
+dnssec-policy "nsec3" {
+ nsec3param iterations 0 optout no salt-length 0;
+};
+
+dnssec-policy "rsasha256" {
+ signatures-refresh P5D;
+ signatures-validity 30d;
+ signatures-validity-dnskey 30d;
+
+ keys {
+ ksk lifetime unlimited algorithm rsasha256;
+ zsk lifetime unlimited algorithm rsasha256;
+ };
+
+ dnskey-ttl 1h;
+ publish-safety PT1H;
+ retire-safety 2h;
+ zone-propagation-delay 3600;
+ max-zone-ttl 6h;
+ parent-propagation-delay pt1h;
+ parent-ds-ttl 7200;
+};
+
+dnssec-policy "ecdsa256" {
+ signatures-refresh P5D;
+ signatures-validity 30d;
+ signatures-validity-dnskey 30d;
+
+ keys {
+ ksk lifetime unlimited algorithm ecdsa256;
+ zsk lifetime unlimited algorithm ecdsa256;
+ };
+
+ dnskey-ttl 1h;
+ publish-safety PT1H;
+ retire-safety 2h;
+ zone-propagation-delay 3600;
+ max-zone-ttl 6h;
+ parent-propagation-delay pt1h;
+ parent-ds-ttl 7200;
+};
diff --git a/bin/tests/system/kasp/ns6/policies/kasp.conf.in b/bin/tests/system/kasp/ns6/policies/kasp.conf.in
new file mode 100644
index 0000000..d634b76
--- /dev/null
+++ b/bin/tests/system/kasp/ns6/policies/kasp.conf.in
@@ -0,0 +1,33 @@
+/*
+ * 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 "policies/kasp-fips.conf";
+
+dnssec-policy "rsasha1" {
+ signatures-refresh P5D;
+ signatures-validity 30d;
+ signatures-validity-dnskey 30d;
+
+ keys {
+ ksk lifetime unlimited algorithm rsasha1;
+ zsk lifetime unlimited algorithm rsasha1;
+ };
+
+ dnskey-ttl 1h;
+ publish-safety PT1H;
+ retire-safety 2h;
+ zone-propagation-delay 3600;
+ max-zone-ttl 6h;
+ parent-propagation-delay pt1h;
+ parent-ds-ttl 7200;
+};
diff --git a/bin/tests/system/kasp/ns6/setup.sh b/bin/tests/system/kasp/ns6/setup.sh
new file mode 100644
index 0000000..6764f1b
--- /dev/null
+++ b/bin/tests/system/kasp/ns6/setup.sh
@@ -0,0 +1,409 @@
+#!/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 "ns6/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"
+
+# The child zones (step1, step2) beneath these zones represent the various
+# steps of unsigning a zone.
+for zn in going-insecure.kasp going-insecure-dynamic.kasp
+do
+ # Step 1:
+ # Set up a zone with dnssec-policy that is going insecure.
+ setup step1.$zn
+ echo "$zone" >> zones
+ T="now-10d"
+ ksktimes="-P $T -A $T -P sync $T"
+ zsktimes="-P $T -A $T"
+ 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"
+ 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
+
+ # Step 2:
+ # Set up a zone with dnssec-policy that is going insecure. Don't add
+ # this zone to the zones file, because this zone is no longer expected
+ # to be fully signed.
+ setup step2.$zn
+ # The DS was withdrawn from the parent zone 26 hours ago.
+ Trem="now-26h"
+ ksktimes="-P $T -A $T -P sync $T"
+ zsktimes="-P $T -A $T"
+ 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)
+ $SETTIME -s -g $H -k $O $T -r $O $T -d $U $Trem -D ds $Trem "$KSK" > settime.out.$zone.1 2>&1
+ $SETTIME -s -g $H -k $O $T -z $O $T "$ZSK" > settime.out.$zone.2 2>&1
+ # Fake lifetime of old algorithm keys.
+ echo "Lifetime: 0" >> "${KSK}.state"
+ echo "Lifetime: 5184000" >> "${ZSK}.state"
+ 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"
+ 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
+done
+
+# This zone is going straight to "none" policy. This is undefined behavior.
+setup step1.going-straight-to-none.kasp
+echo "$zone" >> zones
+TactN="now"
+csktimes="-P ${TactN} -A ${TactN} -P sync ${TactN}"
+CSK=$($KEYGEN -k default $csktimes $zone 2> keygen.out.$zone.1)
+$SETTIME -s -g $O -k $O $TactN -z $O $TactN -r $O $TactN -d $O $TactN "$CSK" > settime.out.$zone.1 2>&1
+cat template.db.in "${CSK}.key" > "$infile"
+private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$CSK" >> "$infile"
+cp $infile $zonefile
+$SIGNER -S -z -x -s now-1h -e now+2w -o $zone -O raw -f "${zonefile}.signed" $infile > signer.out.$zone.1 2>&1
+
+#
+# The zones at algorithm-roll.kasp represent the various steps of a ZSK/KSK
+# algorithm rollover.
+#
+
+# Step 1:
+# Introduce the first key. This will immediately be active.
+setup step1.algorithm-roll.kasp
+echo "$zone" >> zones
+TactN="now"
+ksktimes="-P ${TactN} -A ${TactN} -P sync ${TactN}"
+zsktimes="-P ${TactN} -A ${TactN}"
+KSK=$($KEYGEN -a RSASHA256 -L 3600 -f KSK $ksktimes $zone 2> keygen.out.$zone.1)
+ZSK=$($KEYGEN -a RSASHA256 -L 3600 $zsktimes $zone 2> keygen.out.$zone.2)
+$SETTIME -s -g $O -k $O $TactN -r $O $TactN -d $O $TactN "$KSK" > settime.out.$zone.1 2>&1
+$SETTIME -s -g $O -k $O $TactN -z $O $TactN "$ZSK" > settime.out.$zone.2 2>&1
+cat template.db.in "${KSK}.key" "${ZSK}.key" > "$infile"
+private_type_record $zone 8 "$KSK" >> "$infile"
+private_type_record $zone 8 "$ZSK" >> "$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
+
+# Step 2:
+# After the publication interval has passed the DNSKEY is OMNIPRESENT.
+setup step2.algorithm-roll.kasp
+# The time passed since the new algorithm keys have been introduced is 3 hours.
+TactN="now-3h"
+TpubN1="now-3h"
+# Tsbm(N+1) = TpubN1 + Ipub = now + TTLsig + Dprp + publish-safety =
+# now - 3h + 6h + 1h + 1h = now + 5h
+TsbmN1="now+5h"
+ksk1times="-P ${TactN} -A ${TactN} -P sync ${TactN} -I now"
+zsk1times="-P ${TactN} -A ${TactN} -I now"
+ksk2times="-P ${TpubN1} -A ${TpubN1} -P sync ${TsbmN1}"
+zsk2times="-P ${TpubN1} -A ${TpubN1}"
+KSK1=$($KEYGEN -a RSASHA256 -L 3600 -f KSK $ksk1times $zone 2> keygen.out.$zone.1)
+ZSK1=$($KEYGEN -a RSASHA256 -L 3600 $zsk1times $zone 2> keygen.out.$zone.2)
+KSK2=$($KEYGEN -a $DEFAULT_ALGORITHM -L 3600 -f KSK $ksk2times $zone 2> keygen.out.$zone.3)
+ZSK2=$($KEYGEN -a $DEFAULT_ALGORITHM -L 3600 $zsk2times $zone 2> keygen.out.$zone.4)
+$SETTIME -s -g $H -k $O $TactN -r $O $TactN -d $O $TactN "$KSK1" > settime.out.$zone.1 2>&1
+$SETTIME -s -g $H -k $O $TactN -z $O $TactN "$ZSK1" > settime.out.$zone.2 2>&1
+$SETTIME -s -g $O -k $R $TpubN1 -r $R $TpubN1 -d $H $TpubN1 "$KSK2" > settime.out.$zone.3 2>&1
+$SETTIME -s -g $O -k $R $TpubN1 -z $R $TpubN1 "$ZSK2" > settime.out.$zone.4 2>&1
+# Fake lifetime of old algorithm keys.
+echo "Lifetime: 0" >> "${KSK1}.state"
+echo "Lifetime: 0" >> "${ZSK1}.state"
+cat template.db.in "${KSK1}.key" "${ZSK1}.key" "${KSK2}.key" "${ZSK2}.key" > "$infile"
+private_type_record $zone 8 "$KSK1" >> "$infile"
+private_type_record $zone 8 "$ZSK1" >> "$infile"
+private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$KSK2" >> "$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
+
+# Step 3:
+# The zone signatures are also OMNIPRESENT.
+setup step3.algorithm-roll.kasp
+# The time passed since the new algorithm keys have been introduced is 9 hours.
+TactN="now-9h"
+TretN="now-6h"
+TpubN1="now-9h"
+TsbmN1="now-1h"
+ksk1times="-P ${TactN} -A ${TactN} -P sync ${TactN} -I ${TretN}"
+zsk1times="-P ${TactN} -A ${TactN} -I ${TretN}"
+ksk2times="-P ${TpubN1} -A ${TpubN1} -P sync ${TsbmN1}"
+zsk2times="-P ${TpubN1} -A ${TpubN1}"
+KSK1=$($KEYGEN -a RSASHA256 -L 3600 -f KSK $ksk1times $zone 2> keygen.out.$zone.1)
+ZSK1=$($KEYGEN -a RSASHA256 -L 3600 $zsk1times $zone 2> keygen.out.$zone.2)
+KSK2=$($KEYGEN -a $DEFAULT_ALGORITHM -L 3600 -f KSK $ksk2times $zone 2> keygen.out.$zone.3)
+ZSK2=$($KEYGEN -a $DEFAULT_ALGORITHM -L 3600 $zsk2times $zone 2> keygen.out.$zone.4)
+$SETTIME -s -g $H -k $O $TactN -r $O $TactN -d $O $TactN "$KSK1" > settime.out.$zone.1 2>&1
+$SETTIME -s -g $H -k $O $TactN -z $O $TactN "$ZSK1" > settime.out.$zone.2 2>&1
+$SETTIME -s -g $O -k $O $TpubN1 -r $O $TpubN1 -d $H $TpubN1 "$KSK2" > settime.out.$zone.3 2>&1
+$SETTIME -s -g $O -k $O $TpubN1 -z $R $TpubN1 "$ZSK2" > settime.out.$zone.4 2>&1
+# Fake lifetime of old algorithm keys.
+echo "Lifetime: 0" >> "${KSK1}.state"
+echo "Lifetime: 0" >> "${ZSK1}.state"
+cat template.db.in "${KSK1}.key" "${ZSK1}.key" "${KSK2}.key" "${ZSK2}.key" > "$infile"
+private_type_record $zone 8 "$KSK1" >> "$infile"
+private_type_record $zone 8 "$ZSK1" >> "$infile"
+private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$KSK2" >> "$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
+
+# Step 4:
+# The DS is swapped and can become OMNIPRESENT.
+setup step4.algorithm-roll.kasp
+# The time passed since the DS has been swapped is 29 hours.
+TactN="now-38h"
+TretN="now-35h"
+TpubN1="now-38h"
+TsbmN1="now-30h"
+TactN1="now-29h"
+ksk1times="-P ${TactN} -A ${TactN} -P sync ${TactN} -I ${TretN}"
+zsk1times="-P ${TactN} -A ${TactN} -I ${TretN}"
+ksk2times="-P ${TpubN1} -A ${TpubN1} -P sync ${TsbmN1}"
+zsk2times="-P ${TpubN1} -A ${TpubN1}"
+KSK1=$($KEYGEN -a RSASHA256 -L 3600 -f KSK $ksk1times $zone 2> keygen.out.$zone.1)
+ZSK1=$($KEYGEN -a RSASHA256 -L 3600 $zsk1times $zone 2> keygen.out.$zone.2)
+KSK2=$($KEYGEN -a $DEFAULT_ALGORITHM -L 3600 -f KSK $ksk2times $zone 2> keygen.out.$zone.3)
+ZSK2=$($KEYGEN -a $DEFAULT_ALGORITHM -L 3600 $zsk2times $zone 2> keygen.out.$zone.4)
+$SETTIME -s -g $H -k $O $TactN -r $O $TactN -d $U $TactN1 -D ds $TactN1 "$KSK1" > settime.out.$zone.1 2>&1
+$SETTIME -s -g $H -k $O $TactN -z $O $TactN "$ZSK1" > settime.out.$zone.2 2>&1
+$SETTIME -s -g $O -k $O $TpubN1 -r $O $TpubN1 -d $R $TactN1 -P ds $TactN1 "$KSK2" > settime.out.$zone.3 2>&1
+$SETTIME -s -g $O -k $O $TpubN1 -z $R $TpubN1 "$ZSK2" > settime.out.$zone.4 2>&1
+# Fake lifetime of old algorithm keys.
+echo "Lifetime: 0" >> "${KSK1}.state"
+echo "Lifetime: 0" >> "${ZSK1}.state"
+cat template.db.in "${KSK1}.key" "${ZSK1}.key" "${KSK2}.key" "${ZSK2}.key" > "$infile"
+private_type_record $zone 8 "$KSK1" >> "$infile"
+private_type_record $zone 8 "$ZSK1" >> "$infile"
+private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$KSK2" >> "$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
+
+# Step 5:
+# The DNSKEY is removed long enough to be HIDDEN.
+setup step5.algorithm-roll.kasp
+# The time passed since the DNSKEY has been removed is 2 hours.
+TactN="now-40h"
+TretN="now-37h"
+TremN="now-2h"
+TpubN1="now-40h"
+TsbmN1="now-32h"
+TactN1="now-31h"
+ksk1times="-P ${TactN} -A ${TactN} -P sync ${TactN} -I ${TretN}"
+zsk1times="-P ${TactN} -A ${TactN} -I ${TretN}"
+ksk2times="-P ${TpubN1} -A ${TpubN1} -P sync ${TsbmN1}"
+zsk2times="-P ${TpubN1} -A ${TpubN1}"
+KSK1=$($KEYGEN -a RSASHA256 -L 3600 -f KSK $ksk1times $zone 2> keygen.out.$zone.1)
+ZSK1=$($KEYGEN -a RSASHA256 -L 3600 $zsk1times $zone 2> keygen.out.$zone.2)
+KSK2=$($KEYGEN -a $DEFAULT_ALGORITHM -L 3600 -f KSK $ksk2times $zone 2> keygen.out.$zone.3)
+ZSK2=$($KEYGEN -a $DEFAULT_ALGORITHM -L 3600 $zsk2times $zone 2> keygen.out.$zone.4)
+$SETTIME -s -g $H -k $U $TremN -r $U $TremN -d $H $TactN1 "$KSK1" > settime.out.$zone.1 2>&1
+$SETTIME -s -g $H -k $U $TremN -z $U $TremN "$ZSK1" > settime.out.$zone.2 2>&1
+$SETTIME -s -g $O -k $O $TpubN1 -r $O $TpubN1 -d $O $TactN1 "$KSK2" > settime.out.$zone.3 2>&1
+$SETTIME -s -g $O -k $O $TpubN1 -z $R $TpubN1 "$ZSK2" > settime.out.$zone.4 2>&1
+# Fake lifetime of old algorithm keys.
+echo "Lifetime: 0" >> "${KSK1}.state"
+echo "Lifetime: 0" >> "${ZSK1}.state"
+cat template.db.in "${KSK1}.key" "${ZSK1}.key" "${KSK2}.key" "${ZSK2}.key" > "$infile"
+private_type_record $zone 8 "$KSK1" >> "$infile"
+private_type_record $zone 8 "$ZSK1" >> "$infile"
+private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$KSK2" >> "$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
+
+# Step 6:
+# The RRSIGs have been removed long enough to be HIDDEN.
+setup step6.algorithm-roll.kasp
+# Additional time passed: 7h.
+TactN="now-47h"
+TretN="now-44h"
+TremN="now-7h"
+TpubN1="now-47h"
+TsbmN1="now-39h"
+TactN1="now-38h"
+TdeaN="now-9h"
+ksk1times="-P ${TactN} -A ${TactN} -P sync ${TactN} -I ${TretN}"
+zsk1times="-P ${TactN} -A ${TactN} -I ${TretN}"
+ksk2times="-P ${TpubN1} -A ${TpubN1} -P sync ${TsbmN1}"
+zsk2times="-P ${TpubN1} -A ${TpubN1}"
+KSK1=$($KEYGEN -a RSASHA256 -L 3600 -f KSK $ksk1times $zone 2> keygen.out.$zone.1)
+ZSK1=$($KEYGEN -a RSASHA256 -L 3600 $zsk1times $zone 2> keygen.out.$zone.2)
+KSK2=$($KEYGEN -a $DEFAULT_ALGORITHM -L 3600 -f KSK $ksk2times $zone 2> keygen.out.$zone.3)
+ZSK2=$($KEYGEN -a $DEFAULT_ALGORITHM -L 3600 $zsk2times $zone 2> keygen.out.$zone.4)
+$SETTIME -s -g $H -k $H $TremN -r $U $TdeaN -d $H $TactN1 "$KSK1" > settime.out.$zone.1 2>&1
+$SETTIME -s -g $H -k $H $TremN -z $U $TdeaN "$ZSK1" > settime.out.$zone.2 2>&1
+$SETTIME -s -g $O -k $O $TpubN1 -r $O $TpubN1 -d $O $TactN1 "$KSK2" > settime.out.$zone.3 2>&1
+$SETTIME -s -g $O -k $O $TpubN1 -z $R $TpubN1 "$ZSK2" > settime.out.$zone.4 2>&1
+# Fake lifetime of old algorithm keys.
+echo "Lifetime: 0" >> "${KSK1}.state"
+echo "Lifetime: 0" >> "${ZSK1}.state"
+cat template.db.in "${KSK1}.key" "${ZSK1}.key" "${KSK2}.key" "${ZSK2}.key" > "$infile"
+private_type_record $zone 8 "$KSK1" >> "$infile"
+private_type_record $zone 8 "$ZSK1" >> "$infile"
+private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$KSK2" >> "$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
+
+#
+# The zones at csk-algorithm-roll.kasp represent the various steps of a CSK
+# algorithm rollover.
+#
+
+# Step 1:
+# Introduce the first key. This will immediately be active.
+setup step1.csk-algorithm-roll.kasp
+echo "$zone" >> zones
+TactN="now"
+csktimes="-P ${TactN} -P sync ${TactN} -A ${TactN}"
+CSK=$($KEYGEN -k csk-algoroll -l policies/csk1.conf $csktimes $zone 2> keygen.out.$zone.1)
+$SETTIME -s -g $O -k $O $TactN -r $O $TactN -z $O $TactN -d $O $TactN "$CSK" > settime.out.$zone.1 2>&1
+cat template.db.in "${CSK}.key" > "$infile"
+private_type_record $zone 5 "$CSK" >> "$infile"
+cp $infile $zonefile
+$SIGNER -S -x -z -s now-1h -e now+2w -o $zone -O raw -f "${zonefile}.signed" $infile > signer.out.$zone.1 2>&1
+
+# Step 2:
+# After the publication interval has passed the DNSKEY is OMNIPRESENT.
+setup step2.csk-algorithm-roll.kasp
+# The time passed since the new algorithm keys have been introduced is 3 hours.
+TactN="now-3h"
+TpubN1="now-3h"
+csktimes="-P ${TactN} -A ${TactN} -P sync ${TactN} -I now"
+newtimes="-P ${TpubN1} -A ${TpubN1}"
+CSK1=$($KEYGEN -k csk-algoroll -l policies/csk1.conf $csktimes $zone 2> keygen.out.$zone.1)
+CSK2=$($KEYGEN -k csk-algoroll -l policies/csk2.conf $newtimes $zone 2> keygen.out.$zone.2)
+$SETTIME -s -g $H -k $O $TactN -r $O $TactN -z $O $TactN -d $O $TactN "$CSK1" > settime.out.$zone.1 2>&1
+$SETTIME -s -g $O -k $R $TpubN1 -r $R $TpubN1 -z $R $TpubN1 -d $H $TpubN1 "$CSK2" > settime.out.$zone.2 2>&1
+# Fake lifetime of old algorithm keys.
+echo "Lifetime: 0" >> "${CSK1}.state"
+cat template.db.in "${CSK1}.key" "${CSK2}.key" > "$infile"
+private_type_record $zone 5 "$CSK1" >> "$infile"
+private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$CSK2" >> "$infile"
+cp $infile $zonefile
+$SIGNER -S -x -z -s now-1h -e now+2w -o $zone -O raw -f "${zonefile}.signed" $infile > signer.out.$zone.1 2>&1
+
+# Step 3:
+# The zone signatures are also OMNIPRESENT.
+setup step3.csk-algorithm-roll.kasp
+# The time passed since the new algorithm keys have been introduced is 9 hours.
+TactN="now-9h"
+TretN="now-6h"
+TpubN1="now-9h"
+TactN1="now-6h"
+csktimes="-P ${TactN} -A ${TactN} -P sync ${TactN} -I ${TretN}"
+newtimes="-P ${TpubN1} -A ${TpubN1}"
+CSK1=$($KEYGEN -k csk-algoroll -l policies/csk1.conf $csktimes $zone 2> keygen.out.$zone.1)
+CSK2=$($KEYGEN -k csk-algoroll -l policies/csk2.conf $newtimes $zone 2> keygen.out.$zone.2)
+$SETTIME -s -g $H -k $O $TactN -r $O $TactN -z $O $TactN -d $O $TactN "$CSK1" > settime.out.$zone.1 2>&1
+$SETTIME -s -g $O -k $O $TactN1 -r $O $TactN1 -z $R $TpubN1 -d $H $TpubN1 "$CSK2" > settime.out.$zone.2 2>&1
+# Fake lifetime of old algorithm keys.
+echo "Lifetime: 0" >> "${CSK1}.state"
+cat template.db.in "${CSK1}.key" "${CSK2}.key" > "$infile"
+private_type_record $zone 5 "$CSK1" >> "$infile"
+private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$CSK2" >> "$infile"
+cp $infile $zonefile
+$SIGNER -S -x -z -s now-1h -e now+2w -o $zone -O raw -f "${zonefile}.signed" $infile > signer.out.$zone.1 2>&1
+
+# Step 4:
+# The DS is swapped and can become OMNIPRESENT.
+setup step4.csk-algorithm-roll.kasp
+# The time passed since the DS has been swapped is 29 hours.
+TactN="now-38h"
+TretN="now-35h"
+TpubN1="now-38h"
+TactN1="now-35h"
+TsubN1="now-29h"
+csktimes="-P ${TactN} -A ${TactN} -P sync ${TactN} -I ${TretN}"
+newtimes="-P ${TpubN1} -A ${TpubN1}"
+CSK1=$($KEYGEN -k csk-algoroll -l policies/csk1.conf $csktimes $zone 2> keygen.out.$zone.1)
+CSK2=$($KEYGEN -k csk-algoroll -l policies/csk2.conf $newtimes $zone 2> keygen.out.$zone.2)
+$SETTIME -s -g $H -k $O $TactN -r $O $TactN -z $O $TactN -d $U $TactN1 -D ds $TactN1 "$CSK1" > settime.out.$zone.1 2>&1
+$SETTIME -s -g $O -k $O $TactN1 -r $O $TactN1 -z $O $TsubN1 -d $R $TsubN1 -P ds $TsubN1 "$CSK2" > settime.out.$zone.2 2>&1
+# Fake lifetime of old algorithm keys.
+echo "Lifetime: 0" >> "${CSK1}.state"
+cat template.db.in "${CSK1}.key" "${CSK2}.key" > "$infile"
+private_type_record $zone 5 "$CSK1" >> "$infile"
+private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$CSK2" >> "$infile"
+cp $infile $zonefile
+$SIGNER -S -x -z -s now-1h -e now+2w -o $zone -O raw -f "${zonefile}.signed" $infile > signer.out.$zone.1 2>&1
+
+# Step 5:
+# The DNSKEY is removed long enough to be HIDDEN.
+setup step5.csk-algorithm-roll.kasp
+# The time passed since the DNSKEY has been removed is 2 hours.
+TactN="now-40h"
+TretN="now-37h"
+TremN="now-2h"
+TpubN1="now-40h"
+TactN1="now-37h"
+TsubN1="now-31h"
+csktimes="-P ${TactN} -A ${TactN} -P sync ${TactN} -I ${TretN}"
+newtimes="-P ${TpubN1} -A ${TpubN1}"
+CSK1=$($KEYGEN -k csk-algoroll -l policies/csk1.conf $csktimes $zone 2> keygen.out.$zone.1)
+CSK2=$($KEYGEN -k csk-algoroll -l policies/csk2.conf $newtimes $zone 2> keygen.out.$zone.2)
+$SETTIME -s -g $H -k $U $TremN -r $U $TremN -z $U $TremN -d $H $TremN "$CSK1" > settime.out.$zone.1 2>&1
+$SETTIME -s -g $O -k $O $TactN1 -r $O $TactN1 -z $O $TsubN1 -d $O $TremN "$CSK2" > settime.out.$zone.2 2>&1
+# Fake lifetime of old algorithm keys.
+echo "Lifetime: 0" >> "${CSK1}.state"
+cat template.db.in "${CSK1}.key" "${CSK2}.key" > "$infile"
+private_type_record $zone 5 "$CSK1" >> "$infile"
+private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$CSK2" >> "$infile"
+cp $infile $zonefile
+$SIGNER -S -x -z -s now-1h -e now+2w -o $zone -O raw -f "${zonefile}.signed" $infile > signer.out.$zone.1 2>&1
+
+# Step 6:
+# The RRSIGs have been removed long enough to be HIDDEN.
+setup step6.csk-algorithm-roll.kasp
+# Additional time passed: 7h.
+TactN="now-47h"
+TretN="now-44h"
+TdeaN="now-9h"
+TremN="now-7h"
+TpubN1="now-47h"
+TactN1="now-44h"
+TsubN1="now-38h"
+csktimes="-P ${TactN} -A ${TactN} -P sync ${TactN} -I ${TretN}"
+newtimes="-P ${TpubN1} -A ${TpubN1}"
+CSK1=$($KEYGEN -k csk-algoroll -l policies/csk1.conf $csktimes $zone 2> keygen.out.$zone.1)
+CSK2=$($KEYGEN -k csk-algoroll -l policies/csk2.conf $newtimes $zone 2> keygen.out.$zone.2)
+$SETTIME -s -g $H -k $H $TremN -r $U $TdeaN -z $U $TdeaN -d $H $TactN1 "$CSK1" > settime.out.$zone.1 2>&1
+$SETTIME -s -g $O -k $O $TactN1 -r $O $TactN1 -z $O $TsubN1 -d $O $TactN1 "$CSK2" > settime.out.$zone.2 2>&1
+# Fake lifetime of old algorithm keys.
+echo "Lifetime: 0" >> "${CSK1}.state"
+cat template.db.in "${CSK1}.key" "${CSK2}.key" > "$infile"
+private_type_record $zone 5 "$CSK1" >> "$infile"
+private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$CSK2" >> "$infile"
+cp $infile $zonefile
+$SIGNER -S -x -z -s now-1h -e now+2w -o $zone -O raw -f "${zonefile}.signed" $infile > signer.out.$zone.1 2>&1
+
+#
+# Reload testing
+#
+echo "example" >> zones
+cp example.db.in example.db
+
+setup "dynamic2inline.kasp"
+cp template.db.in $zonefile
diff --git a/bin/tests/system/kasp/ns6/template.db.in b/bin/tests/system/kasp/ns6/template.db.in
new file mode 100644
index 0000000..f1d8b94
--- /dev/null
+++ b/bin/tests/system/kasp/ns6/template.db.in
@@ -0,0 +1,27 @@
+; 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 ns6
+ns6 A 10.53.0.6
+
+a A 10.0.0.1
+b A 10.0.0.2
+c A 10.0.0.3
+
diff --git a/bin/tests/system/kasp/setup.sh b/bin/tests/system/kasp/setup.sh
new file mode 100644
index 0000000..67cfa92
--- /dev/null
+++ b/bin/tests/system/kasp/setup.sh
@@ -0,0 +1,80 @@
+#!/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
+
+$SHELL clean.sh
+
+mkdir keys
+
+copy_setports ns2/named.conf.in ns2/named.conf
+if ! $SHELL ../testcrypto.sh -q RSASHA1
+then
+ copy_setports ns3/named-fips.conf.in ns3/named.conf
+else
+ copy_setports ns3/named-fips.conf.in ns3/named-fips.conf
+ copy_setports ns3/named.conf.in ns3/named.conf
+fi
+copy_setports ns4/named.conf.in ns4/named.conf
+copy_setports ns5/named.conf.in ns5/named.conf
+copy_setports ns6/named.conf.in ns6/named.conf
+
+if $SHELL ../testcrypto.sh ed25519; then
+ echo "yes" > ed25519-supported.file
+fi
+
+if $SHELL ../testcrypto.sh ed448; then
+ echo "yes" > ed448-supported.file
+fi
+
+copy_setports ns3/policies/autosign.conf.in ns3/policies/autosign.conf
+copy_setports ns3/policies/kasp-fips.conf.in ns3/policies/kasp-fips.conf
+copy_setports ns3/policies/kasp.conf.in ns3/policies/kasp.conf
+if ! $SHELL ../testcrypto.sh -q RSASHA1
+then
+ cp ns3/policies/kasp-fips.conf ns3/policies/kasp.conf
+fi
+
+copy_setports ns6/policies/csk1.conf.in ns6/policies/csk1.conf
+copy_setports ns6/policies/csk2.conf.in ns6/policies/csk2.conf
+copy_setports ns6/policies/kasp-fips.conf.in ns6/policies/kasp-fips.conf
+copy_setports ns6/policies/kasp.conf.in ns6/policies/kasp.conf
+if ! $SHELL ../testcrypto.sh -q RSASHA1
+then
+ cp ns6/policies/kasp-fips.conf ns6/policies/kasp.conf
+fi
+
+# Setup zones
+(
+ cd ns2
+ $SHELL setup.sh
+)
+(
+ cd ns3
+ $SHELL setup.sh
+)
+(
+ cd ns4
+ $SHELL setup.sh
+)
+(
+ cd ns5
+ $SHELL setup.sh
+)
+(
+ cd ns6
+ $SHELL setup.sh
+)
diff --git a/bin/tests/system/kasp/tests.sh b/bin/tests/system/kasp/tests.sh
new file mode 100644
index 0000000..ddbbd32
--- /dev/null
+++ b/bin/tests/system/kasp/tests.sh
@@ -0,0 +1,4883 @@
+#!/bin/sh
+
+# 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.
+
+set -e
+
+# shellcheck source=conf.sh
+. ../conf.sh
+# shellcheck source=kasp.sh
+. ../kasp.sh
+
+start_time="$(TZ=UTC date +%s)"
+status=0
+n=0
+
+###############################################################################
+# Utilities #
+###############################################################################
+
+# Call dig with default options.
+dig_with_opts() {
+
+ if [ -n "$TSIG" ]; then
+ "$DIG" +tcp +noadd +nosea +nostat +nocmd +dnssec -p "$PORT" -y "$TSIG" "$@"
+ else
+ "$DIG" +tcp +noadd +nosea +nostat +nocmd +dnssec -p "$PORT" "$@"
+ fi
+}
+
+# RNDC.
+rndccmd() {
+ "$RNDC" -c ../common/rndc.conf -p "$CONTROLPORT" -s "$@"
+}
+
+# Log error and increment failure rate.
+log_error() {
+ echo_i "error: $1"
+ ret=$((ret+1))
+}
+
+# Default next key event threshold. May be extended by wait periods.
+next_key_event_threshold=100
+
+###############################################################################
+# Tests #
+###############################################################################
+
+#
+# dnssec-keygen
+#
+set_zone "kasp"
+set_policy "kasp" "4" "200"
+set_server "keys" "10.53.0.1"
+
+n=$((n+1))
+echo_i "check that 'dnssec-keygen -k' (configured policy) creates valid files ($n)"
+ret=0
+$KEYGEN -K keys -k "$POLICY" -l kasp.conf "$ZONE" > "keygen.out.$POLICY.test$n" 2>/dev/null || ret=1
+lines=$(wc -l < "keygen.out.$POLICY.test$n")
+test "$lines" -eq $NUM_KEYS || log_error "wrong number of keys created for policy kasp: $lines"
+# Temporarily don't log errors because we are searching multiple files.
+disable_logerror
+
+# Key properties.
+set_keyrole "KEY1" "csk"
+set_keylifetime "KEY1" "31536000"
+set_keyalgorithm "KEY1" "13" "ECDSAP256SHA256" "256"
+set_keysigning "KEY1" "yes"
+set_zonesigning "KEY1" "yes"
+
+set_keyrole "KEY2" "ksk"
+set_keylifetime "KEY2" "31536000"
+set_keyalgorithm "KEY2" "8" "RSASHA256" "2048"
+set_keysigning "KEY2" "yes"
+set_zonesigning "KEY2" "no"
+
+set_keyrole "KEY3" "zsk"
+set_keylifetime "KEY3" "2592000"
+set_keyalgorithm "KEY3" "8" "RSASHA256" "2048"
+set_keysigning "KEY3" "no"
+set_zonesigning "KEY3" "yes"
+
+set_keyrole "KEY4" "zsk"
+set_keylifetime "KEY4" "16070400"
+set_keyalgorithm "KEY4" "8" "RSASHA256" "3072"
+set_keysigning "KEY4" "no"
+set_zonesigning "KEY4" "yes"
+
+lines=$(get_keyids "$DIR" "$ZONE" | wc -l)
+test "$lines" -eq $NUM_KEYS || log_error "bad number of key ids"
+
+ids=$(get_keyids "$DIR" "$ZONE")
+for id in $ids; do
+ # There are four key files with the same algorithm.
+ # Check them until a match is found.
+ ret=0 && check_key "KEY1" "$id"
+ test "$ret" -eq 0 && continue
+
+ ret=0 && check_key "KEY2" "$id"
+ test "$ret" -eq 0 && continue
+
+ ret=0 && check_key "KEY3" "$id"
+ test "$ret" -eq 0 && continue
+
+ ret=0 && check_key "KEY4" "$id"
+
+ # If ret is still non-zero, non of the files matched.
+ test "$ret" -eq 0 || echo_i "failed"
+ status=$((status+ret))
+done
+# Turn error logs on again.
+enable_logerror
+
+n=$((n+1))
+echo_i "check that 'dnssec-keygen -k' (default policy) creates valid files ($n)"
+ret=0
+set_zone "kasp"
+set_policy "default" "1" "3600"
+set_server "." "10.53.0.1"
+# Key properties.
+set_keyrole "KEY1" "csk"
+set_keylifetime "KEY1" "0"
+set_keyalgorithm "KEY1" "13" "ECDSAP256SHA256" "256"
+set_keysigning "KEY1" "yes"
+set_zonesigning "KEY1" "yes"
+
+key_clear "KEY2"
+key_clear "KEY3"
+key_clear "KEY4"
+
+$KEYGEN -G -k "$POLICY" "$ZONE" > "keygen.out.$POLICY.test$n" 2>/dev/null || ret=1
+lines=$(wc -l < "keygen.out.$POLICY.test$n")
+test "$lines" -eq $NUM_KEYS || log_error "wrong number of keys created for policy default: $lines"
+ids=$(get_keyids "$DIR" "$ZONE")
+for id in $ids; do
+ check_key "KEY1" "$id"
+ test "$ret" -eq 0 && key_save KEY1
+ check_keytimes
+done
+test "$ret" -eq 0 || echo_i "failed"
+status=$((status+ret))
+
+#
+# dnssec-settime
+#
+
+# These test builds upon the latest created key with dnssec-keygen and uses the
+# environment variables BASE_FILE, KEY_FILE, PRIVATE_FILE and STATE_FILE.
+CMP_FILE="${BASE_FILE}.cmp"
+n=$((n+1))
+echo_i "check that 'dnssec-settime' by default does not edit key state file ($n)"
+ret=0
+cp "$STATE_FILE" "$CMP_FILE"
+$SETTIME -P +3600 "$BASE_FILE" > /dev/null || log_error "settime failed"
+grep "; Publish: " "$KEY_FILE" > /dev/null || log_error "mismatch published in $KEY_FILE"
+grep "Publish: " "$PRIVATE_FILE" > /dev/null || log_error "mismatch published in $PRIVATE_FILE"
+diff "$CMP_FILE" "$STATE_FILE" || log_error "unexpected file change in $STATE_FILE"
+test "$ret" -eq 0 || echo_i "failed"
+status=$((status+ret))
+
+n=$((n+1))
+echo_i "check that 'dnssec-settime -s' also sets publish time metadata and states in key state file ($n)"
+ret=0
+cp "$STATE_FILE" "$CMP_FILE"
+now=$(date +%Y%m%d%H%M%S)
+$SETTIME -s -P "$now" -g "omnipresent" -k "rumoured" "$now" -z "omnipresent" "$now" -r "rumoured" "$now" -d "hidden" "$now" "$BASE_FILE" > /dev/null || log_error "settime failed"
+set_keystate "KEY1" "GOAL" "omnipresent"
+set_keystate "KEY1" "STATE_DNSKEY" "rumoured"
+set_keystate "KEY1" "STATE_KRRSIG" "rumoured"
+set_keystate "KEY1" "STATE_ZRRSIG" "omnipresent"
+set_keystate "KEY1" "STATE_DS" "hidden"
+check_key "KEY1" "$id"
+test "$ret" -eq 0 && key_save KEY1
+set_keytime "KEY1" "PUBLISHED" "${now}"
+check_keytimes
+test "$ret" -eq 0 || echo_i "failed"
+status=$((status+ret))
+
+n=$((n+1))
+echo_i "check that 'dnssec-settime -s' also unsets publish time metadata and states in key state file ($n)"
+ret=0
+cp "$STATE_FILE" "$CMP_FILE"
+$SETTIME -s -P "none" -g "none" -k "none" "$now" -z "none" "$now" -r "none" "$now" -d "none" "$now" "$BASE_FILE" > /dev/null || log_error "settime failed"
+set_keystate "KEY1" "GOAL" "none"
+set_keystate "KEY1" "STATE_DNSKEY" "none"
+set_keystate "KEY1" "STATE_KRRSIG" "none"
+set_keystate "KEY1" "STATE_ZRRSIG" "none"
+set_keystate "KEY1" "STATE_DS" "none"
+check_key "KEY1" "$id"
+test "$ret" -eq 0 && key_save KEY1
+set_keytime "KEY1" "PUBLISHED" "none"
+check_keytimes
+test "$ret" -eq 0 || echo_i "failed"
+status=$((status+ret))
+
+n=$((n+1))
+echo_i "check that 'dnssec-settime -s' also sets active time metadata and states in key state file (uppercase) ($n)"
+ret=0
+cp "$STATE_FILE" "$CMP_FILE"
+now=$(date +%Y%m%d%H%M%S)
+$SETTIME -s -A "$now" -g "HIDDEN" -k "UNRETENTIVE" "$now" -z "UNRETENTIVE" "$now" -r "OMNIPRESENT" "$now" -d "OMNIPRESENT" "$now" "$BASE_FILE" > /dev/null || log_error "settime failed"
+set_keystate "KEY1" "GOAL" "hidden"
+set_keystate "KEY1" "STATE_DNSKEY" "unretentive"
+set_keystate "KEY1" "STATE_KRRSIG" "omnipresent"
+set_keystate "KEY1" "STATE_ZRRSIG" "unretentive"
+set_keystate "KEY1" "STATE_DS" "omnipresent"
+check_key "KEY1" "$id"
+test "$ret" -eq 0 && key_save KEY1
+set_keytime "KEY1" "ACTIVE" "${now}"
+check_keytimes
+test "$ret" -eq 0 || echo_i "failed"
+status=$((status+ret))
+
+#
+# named
+#
+
+# The NSEC record at the apex of the zone and its RRSIG records are
+# added as part of the last step in signing a zone. We wait for the
+# NSEC records to appear before proceeding with a counter to prevent
+# infinite loops if there is an error.
+n=$((n+1))
+echo_i "waiting for kasp signing changes to take effect ($n)"
+
+_wait_for_done_apexnsec() {
+ while read -r zone
+ do
+ dig_with_opts "$zone" @10.53.0.3 nsec > "dig.out.ns3.test$n.$zone" || return 1
+ grep "NS SOA" "dig.out.ns3.test$n.$zone" > /dev/null || return 1
+ grep "$zone\..*IN.*RRSIG" "dig.out.ns3.test$n.$zone" > /dev/null || return 1
+ done < ns3/zones
+
+ while read -r zone
+ do
+ dig_with_opts "$zone" @10.53.0.6 nsec > "dig.out.ns6.test$n.$zone" || return 1
+ grep "NS SOA" "dig.out.ns6.test$n.$zone" > /dev/null || return 1
+ grep "$zone\..*IN.*RRSIG" "dig.out.ns6.test$n.$zone" > /dev/null || return 1
+ done < ns6/zones
+
+ return 0
+}
+retry_quiet 30 _wait_for_done_apexnsec || ret=1
+test "$ret" -eq 0 || echo_i "failed"
+status=$((status+ret))
+
+# Test max-zone-ttl rejects zones with too high TTL.
+n=$((n+1))
+echo_i "check that max-zone-ttl rejects zones with too high TTL ($n)"
+ret=0
+set_zone "max-zone-ttl.kasp"
+grep "loading from master file ${ZONE}.db failed: out of range" "ns3/named.run" > /dev/null || ret=1
+test "$ret" -eq 0 || echo_i "failed"
+status=$((status+ret))
+
+#
+# Zone: default.kasp.
+#
+set_keytimes_csk_policy() {
+ # The first key is immediately published and activated.
+ created=$(key_get KEY1 CREATED)
+ set_keytime "KEY1" "PUBLISHED" "${created}"
+ set_keytime "KEY1" "ACTIVE" "${created}"
+ # The DS can be published if the DNSKEY and RRSIG records are
+ # OMNIPRESENT. This happens after max-zone-ttl (1d) plus
+ # publish-safety (1h) plus zone-propagation-delay (300s) =
+ # 86400 + 3600 + 300 = 90300.
+ set_addkeytime "KEY1" "SYNCPUBLISH" "${created}" 90300
+ # Key lifetime is unlimited, so not setting RETIRED and REMOVED.
+}
+
+# Check the zone with default kasp policy has loaded and is signed.
+set_zone "default.kasp"
+set_policy "default" "1" "3600"
+set_server "ns3" "10.53.0.3"
+# Key properties.
+set_keyrole "KEY1" "csk"
+set_keylifetime "KEY1" "0"
+set_keyalgorithm "KEY1" "13" "ECDSAP256SHA256" "256"
+set_keysigning "KEY1" "yes"
+set_zonesigning "KEY1" "yes"
+# DNSKEY, RRSIG (ksk), RRSIG (zsk) are published. DS needs to wait.
+set_keystate "KEY1" "GOAL" "omnipresent"
+set_keystate "KEY1" "STATE_DNSKEY" "rumoured"
+set_keystate "KEY1" "STATE_KRRSIG" "rumoured"
+set_keystate "KEY1" "STATE_ZRRSIG" "rumoured"
+set_keystate "KEY1" "STATE_DS" "hidden"
+
+check_keys
+check_dnssecstatus "$SERVER" "$POLICY" "$ZONE"
+set_keytimes_csk_policy
+check_keytimes
+check_apex
+check_subdomain
+dnssec_verify
+
+# Trigger a keymgr run. Make sure the key files are not touched if there are
+# no modifications to the key metadata.
+n=$((n+1))
+echo_i "make sure key files are untouched if metadata does not change ($n)"
+ret=0
+basefile=$(key_get KEY1 BASEFILE)
+privkey_stat=$(key_get KEY1 PRIVKEY_STAT)
+pubkey_stat=$(key_get KEY1 PUBKEY_STAT)
+state_stat=$(key_get KEY1 STATE_STAT)
+
+nextpart $DIR/named.run > /dev/null
+rndccmd 10.53.0.3 loadkeys "$ZONE" > /dev/null || log_error "rndc loadkeys zone ${ZONE} failed"
+wait_for_log 3 "keymgr: $ZONE done" $DIR/named.run
+privkey_stat2=$(key_stat "${basefile}.private")
+pubkey_stat2=$(key_stat "${basefile}.key")
+state_stat2=$(key_stat "${basefile}.state")
+test "$privkey_stat" = "$privkey_stat2" || log_error "wrong private key file stat (expected $privkey_stat got $privkey_stat2)"
+test "$pubkey_stat" = "$pubkey_stat2" || log_error "wrong public key file stat (expected $pubkey_stat got $pubkey_stat2)"
+test "$state_stat" = "$state_stat2" || log_error "wrong state file stat (expected $state_stat got $state_stat2)"
+test "$ret" -eq 0 || echo_i "failed"
+status=$((status+ret))
+
+n=$((n+1))
+echo_i "again ($n)"
+ret=0
+
+nextpart $DIR/named.run > /dev/null
+rndccmd 10.53.0.3 loadkeys "$ZONE" > /dev/null || log_error "rndc loadkeys zone ${ZONE} failed"
+wait_for_log 3 "keymgr: $ZONE done" $DIR/named.run
+privkey_stat2=$(key_stat "${basefile}.private")
+pubkey_stat2=$(key_stat "${basefile}.key")
+state_stat2=$(key_stat "${basefile}.state")
+test "$privkey_stat" = "$privkey_stat2" || log_error "wrong private key file stat (expected $privkey_stat got $privkey_stat2)"
+test "$pubkey_stat" = "$pubkey_stat2" || log_error "wrong public key file stat (expected $pubkey_stat got $pubkey_stat2)"
+test "$state_stat" = "$state_stat2" || log_error "wrong state file stat (expected $state_stat got $state_stat2)"
+test "$ret" -eq 0 || echo_i "failed"
+status=$((status+ret))
+
+# Update zone.
+n=$((n+1))
+echo_i "modify unsigned zone file and check that new record is signed for zone ${ZONE} ($n)"
+ret=0
+cp "${DIR}/template2.db.in" "${DIR}/${ZONE}.db"
+rndccmd 10.53.0.3 reload "$ZONE" > /dev/null || log_error "rndc reload zone ${ZONE} failed"
+
+update_is_signed() {
+ ip_a=$1
+ ip_d=$2
+
+ if [ "$ip_a" != "-" ]; then
+ dig_with_opts "a.${ZONE}" "@${SERVER}" A > "dig.out.$DIR.test$n.a" || return 1
+ grep "status: NOERROR" "dig.out.$DIR.test$n.a" > /dev/null || return 1
+ grep "a.${ZONE}\..*${DEFAULT_TTL}.*IN.*A.*${ip_a}" "dig.out.$DIR.test$n.a" > /dev/null || return 1
+ lines=$(get_keys_which_signed A "dig.out.$DIR.test$n.a" | wc -l)
+ test "$lines" -eq 1 || return 1
+ get_keys_which_signed A "dig.out.$DIR.test$n.a" | grep "^${KEY_ID}$" > /dev/null || return 1
+ fi
+
+ if [ "$ip_d" != "-" ]; then
+ dig_with_opts "d.${ZONE}" "@${SERVER}" A > "dig.out.$DIR.test$n".d || return 1
+ grep "status: NOERROR" "dig.out.$DIR.test$n".d > /dev/null || return 1
+ grep "d.${ZONE}\..*${DEFAULT_TTL}.*IN.*A.*${ip_d}" "dig.out.$DIR.test$n".d > /dev/null || return 1
+ lines=$(get_keys_which_signed A "dig.out.$DIR.test$n".d | wc -l)
+ test "$lines" -eq 1 || return 1
+ get_keys_which_signed A "dig.out.$DIR.test$n".d | grep "^${KEY_ID}$" > /dev/null || return 1
+ fi
+}
+
+retry_quiet 10 update_is_signed "10.0.0.11" "10.0.0.44" || ret=1
+test "$ret" -eq 0 || echo_i "failed"
+status=$((status+ret))
+
+# Move the private key file, a rekey event should not introduce replacement
+# keys.
+ret=0
+echo_i "test that if private key files are inaccessible this doesn't trigger a rollover ($n)"
+basefile=$(key_get KEY1 BASEFILE)
+mv "${basefile}.private" "${basefile}.offline"
+rndccmd 10.53.0.3 loadkeys "$ZONE" > /dev/null || log_error "rndc loadkeys zone ${ZONE} failed"
+wait_for_log 3 "offline, policy default" $DIR/named.run || ret=1
+mv "${basefile}.offline" "${basefile}.private"
+test "$ret" -eq 0 || echo_i "failed"
+status=$((status+ret))
+
+# Nothing has changed.
+check_keys
+check_dnssecstatus "$SERVER" "$POLICY" "$ZONE"
+set_keytimes_csk_policy
+check_keytimes
+check_apex
+check_subdomain
+dnssec_verify
+
+#
+# Zone: dynamic.kasp
+#
+set_zone "dynamic.kasp"
+set_dynamic
+set_policy "default" "1" "3600"
+set_server "ns3" "10.53.0.3"
+# Key properties, timings and states same as above.
+check_keys
+check_dnssecstatus "$SERVER" "$POLICY" "$ZONE"
+set_keytimes_csk_policy
+check_keytimes
+check_apex
+check_subdomain
+dnssec_verify
+
+# Update zone with nsupdate.
+n=$((n+1))
+echo_i "nsupdate zone and check that new record is signed for zone ${ZONE} ($n)"
+ret=0
+(
+echo zone ${ZONE}
+echo server 10.53.0.3 "$PORT"
+echo update del "a.${ZONE}" 300 A 10.0.0.1
+echo update add "a.${ZONE}" 300 A 10.0.0.101
+echo update add "d.${ZONE}" 300 A 10.0.0.4
+echo send
+) | $NSUPDATE
+
+retry_quiet 10 update_is_signed "10.0.0.101" "10.0.0.4" || ret=1
+test "$ret" -eq 0 || echo_i "failed"
+status=$((status+ret))
+
+# Update zone with nsupdate (reverting the above change).
+n=$((n+1))
+echo_i "nsupdate zone and check that new record is signed for zone ${ZONE} ($n)"
+ret=0
+(
+echo zone ${ZONE}
+echo server 10.53.0.3 "$PORT"
+echo update add "a.${ZONE}" 300 A 10.0.0.1
+echo update del "a.${ZONE}" 300 A 10.0.0.101
+echo update del "d.${ZONE}" 300 A 10.0.0.4
+echo send
+) | $NSUPDATE
+
+retry_quiet 10 update_is_signed "10.0.0.1" "-" || ret=1
+test "$ret" -eq 0 || echo_i "failed"
+status=$((status+ret))
+
+# Update zone with freeze/thaw.
+n=$((n+1))
+echo_i "modify zone file and check that new record is signed for zone ${ZONE} ($n)"
+ret=0
+rndccmd 10.53.0.3 freeze "$ZONE" > /dev/null || log_error "rndc freeze zone ${ZONE} failed"
+sleep 1
+echo "d.${ZONE}. 300 A 10.0.0.44" >> "${DIR}/${ZONE}.db"
+rndccmd 10.53.0.3 thaw "$ZONE" > /dev/null || log_error "rndc thaw zone ${ZONE} failed"
+
+retry_quiet 10 update_is_signed "10.0.0.1" "10.0.0.44" || ret=1
+test "$ret" -eq 0 || echo_i "failed"
+status=$((status+ret))
+
+#
+# Zone: dynamic-inline-signing.kasp
+#
+set_zone "dynamic-inline-signing.kasp"
+set_dynamic
+set_policy "default" "1" "3600"
+set_server "ns3" "10.53.0.3"
+# Key properties, timings and states same as above.
+check_keys
+check_dnssecstatus "$SERVER" "$POLICY" "$ZONE"
+set_keytimes_csk_policy
+check_keytimes
+check_apex
+check_subdomain
+dnssec_verify
+
+# Update zone with freeze/thaw.
+n=$((n+1))
+echo_i "modify unsigned zone file and check that new record is signed for zone ${ZONE} ($n)"
+ret=0
+rndccmd 10.53.0.3 freeze "$ZONE" > /dev/null || log_error "rndc freeze zone ${ZONE} failed"
+sleep 1
+cp "${DIR}/template2.db.in" "${DIR}/${ZONE}.db"
+rndccmd 10.53.0.3 thaw "$ZONE" > /dev/null || log_error "rndc thaw zone ${ZONE} failed"
+
+retry_quiet 10 update_is_signed || ret=1
+test "$ret" -eq 0 || echo_i "failed"
+status=$((status+ret))
+
+#
+# Zone: inline-signing.kasp
+#
+set_zone "inline-signing.kasp"
+set_policy "default" "1" "3600"
+set_server "ns3" "10.53.0.3"
+# Key properties, timings and states same as above.
+check_keys
+check_dnssecstatus "$SERVER" "$POLICY" "$ZONE"
+set_keytimes_csk_policy
+check_keytimes
+check_apex
+check_subdomain
+dnssec_verify
+
+#
+# Zone: checkds-ksk.kasp.
+#
+key_clear "KEY1"
+key_clear "KEY2"
+key_clear "KEY3"
+key_clear "KEY4"
+
+set_zone "checkds-ksk.kasp"
+set_policy "checkds-ksk" "2" "303"
+set_server "ns3" "10.53.0.3"
+# Key properties.
+set_keyrole "KEY1" "ksk"
+set_keylifetime "KEY1" "0"
+set_keyalgorithm "KEY1" "13" "ECDSAP256SHA256" "256"
+set_keysigning "KEY1" "yes"
+set_zonesigning "KEY1" "no"
+
+set_keyrole "KEY2" "zsk"
+set_keylifetime "KEY2" "0"
+set_keyalgorithm "KEY2" "13" "ECDSAP256SHA256" "256"
+set_keysigning "KEY2" "no"
+set_zonesigning "KEY2" "yes"
+# DNSKEY, RRSIG (ksk), RRSIG (zsk) are published. DS needs to wait.
+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
+
+basefile=$(key_get KEY1 BASEFILE)
+
+_wait_for_metadata() {
+ _expr=$1
+ _file=$2
+ grep "$_expr" $_file > /dev/null || return 1
+ return 0
+}
+
+n=$((n+1))
+echo_i "checkds publish correctly sets DSPublish for zone $ZONE ($n)"
+now=$(date +%Y%m%d%H%M%S)
+rndc_checkds "$SERVER" "$DIR" "-" "$now" "published" "$ZONE"
+retry_quiet 3 _wait_for_metadata "DSPublish: $now" "${basefile}.state" || log_error "bad DSPublish in ${basefile}.state"
+# DS State should be forced into RUMOURED.
+set_keystate "KEY1" "STATE_DS" "rumoured"
+check_keys
+test "$ret" -eq 0 || echo_i "failed"
+status=$((status+ret))
+
+n=$((n+1))
+echo_i "checkds withdraw correctly sets DSRemoved for zone $ZONE ($n)"
+now=$(date +%Y%m%d%H%M%S)
+rndc_checkds "$SERVER" "$DIR" "-" "$now" "withdrawn" "$ZONE"
+retry_quiet 3 _wait_for_metadata "DSRemoved: $now" "${basefile}.state" || log_error "bad DSRemoved in ${basefile}.state"
+# DS State should be forced into UNRETENTIVE.
+set_keystate "KEY1" "STATE_DS" "unretentive"
+check_keys
+test "$ret" -eq 0 || echo_i "failed"
+status=$((status+ret))
+
+#
+# Zone: checkds-doubleksk.kasp.
+#
+key_clear "KEY1"
+key_clear "KEY2"
+key_clear "KEY3"
+key_clear "KEY4"
+
+set_zone "checkds-doubleksk.kasp"
+set_policy "checkds-doubleksk" "3" "303"
+set_server "ns3" "10.53.0.3"
+# Key properties.
+set_keyrole "KEY1" "ksk"
+set_keylifetime "KEY1" "0"
+set_keyalgorithm "KEY1" "13" "ECDSAP256SHA256" "256"
+set_keysigning "KEY1" "yes"
+set_zonesigning "KEY1" "no"
+
+set_keyrole "KEY2" "ksk"
+set_keylifetime "KEY2" "0"
+set_keyalgorithm "KEY2" "13" "ECDSAP256SHA256" "256"
+set_keysigning "KEY2" "yes"
+set_zonesigning "KEY2" "no"
+
+set_keyrole "KEY3" "zsk"
+set_keylifetime "KEY3" "0"
+set_keyalgorithm "KEY3" "13" "ECDSAP256SHA256" "256"
+set_keysigning "KEY3" "no"
+set_zonesigning "KEY3" "yes"
+# DNSKEY, RRSIG (ksk), RRSIG (zsk) are published. DS needs to wait.
+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_KRRSIG" "rumoured"
+set_keystate "KEY2" "STATE_DS" "hidden"
+
+set_keystate "KEY3" "GOAL" "omnipresent"
+set_keystate "KEY3" "STATE_DNSKEY" "rumoured"
+set_keystate "KEY3" "STATE_ZRRSIG" "rumoured"
+
+check_keys
+check_dnssecstatus "$SERVER" "$POLICY" "$ZONE"
+check_apex
+check_subdomain
+dnssec_verify
+
+basefile1=$(key_get KEY1 BASEFILE)
+basefile2=$(key_get KEY2 BASEFILE)
+
+n=$((n+1))
+echo_i "checkds published does not set DSPublish for zone $ZONE (multiple KSK) ($n)"
+rndc_checkds "$SERVER" "$DIR" "-" "20200102121314" "published" "$ZONE"
+grep "DSPublish:" "${basefile1}.state" > /dev/null && log_error "DSPublish incorrectly set in ${basefile1}"
+grep "DSPublish:" "${basefile2}.state" > /dev/null && log_error "DSPublish incorrectly set in ${basefile2}"
+test "$ret" -eq 0 || echo_i "failed"
+status=$((status+ret))
+
+n=$((n+1))
+echo_i "checkds withdrawn does not set DSRemoved for zone $ZONE (multiple KSK) ($n)"
+rndc_checkds "$SERVER" "$DIR" "-" "20190102121314" "withdrawn" "$ZONE"
+grep "DSRemoved:" "${basefile1}.state" > /dev/null && log_error "DSRemoved incorrectly set in ${basefile1}"
+grep "DSRemoved:" "${basefile2}.state" > /dev/null && log_error "DSRemoved incorrectly set in ${basefile2}"
+test "$ret" -eq 0 || echo_i "failed"
+status=$((status+ret))
+
+n=$((n+1))
+echo_i "checkds published does not set DSPublish for zone $ZONE (wrong algorithm) ($n)"
+rndccmd "$SERVER" dnssec -checkds -key $(key_get KEY1 ID) -alg 8 "published" "$ZONE" > rndc.dnssec.checkds.out.$ZONE.$n
+grep "DSPublish:" "${basefile1}.state" > /dev/null && log_error "DSPublish incorrectly set in ${basefile1}"
+grep "DSPublish:" "${basefile2}.state" > /dev/null && log_error "DSPublish incorrectly set in ${basefile2}"
+test "$ret" -eq 0 || echo_i "failed"
+status=$((status+ret))
+
+n=$((n+1))
+echo_i "checkds withdrawn does not set DSRemoved for zone $ZONE (wrong algorithm) ($n)"
+rndccmd "$SERVER" dnssec -checkds -key $(key_get KEY1 ID) -alg RSASHA256 "withdrawn" "$ZONE" > rndc.dnssec.checkds.out.$ZONE.$n
+grep "DSRemoved:" "${basefile1}.state" > /dev/null && log_error "DSRemoved incorrectly set in ${basefile1}"
+grep "DSRemoved:" "${basefile2}.state" > /dev/null && log_error "DSRemoved incorrectly set in ${basefile2}"
+test "$ret" -eq 0 || echo_i "failed"
+status=$((status+ret))
+
+n=$((n+1))
+echo_i "checkds published -key correctly sets DSPublish for key $(key_get KEY1 ID) zone $ZONE (multiple KSK) ($n)"
+rndc_checkds "$SERVER" "$DIR" KEY1 "20190102121314" "published" "$ZONE"
+retry_quiet 3 _wait_for_metadata "DSPublish: 20190102121314" "${basefile1}.state" || log_error "bad DSPublish in ${basefile1}.state"
+grep "DSPublish:" "${basefile2}.state" > /dev/null && log_error "DSPublish incorrectly set in ${basefile2}"
+test "$ret" -eq 0 || echo_i "failed"
+status=$((status+ret))
+
+n=$((n+1))
+echo_i "checkds withdrawn -key correctly sets DSRemoved for key $(key_get KEY2 ID) zone $ZONE (multiple KSK) ($n)"
+rndc_checkds "$SERVER" "$DIR" KEY2 "20200102121314" "withdrawn" "$ZONE"
+grep "DSRemoved:" "${basefile1}.state" > /dev/null && log_error "DSPublish incorrectly set in ${basefile1}"
+retry_quiet 3 _wait_for_metadata "DSRemoved: 20200102121314" "${basefile2}.state" || log_error "bad DSRemoved in ${basefile2}.state"
+test "$ret" -eq 0 || echo_i "failed"
+status=$((status+ret))
+
+#
+# Zone: checkds-csk.kasp.
+#
+key_clear "KEY1"
+key_clear "KEY2"
+key_clear "KEY3"
+key_clear "KEY4"
+
+set_zone "checkds-csk.kasp"
+set_policy "checkds-csk" "1" "303"
+set_server "ns3" "10.53.0.3"
+# Key properties.
+set_keyrole "KEY1" "csk"
+set_keylifetime "KEY1" "0"
+set_keyalgorithm "KEY1" "13" "ECDSAP256SHA256" "256"
+set_keysigning "KEY1" "yes"
+set_zonesigning "KEY1" "yes"
+# DNSKEY, RRSIG (ksk), RRSIG (zsk) are published. DS needs to wait.
+set_keystate "KEY1" "GOAL" "omnipresent"
+set_keystate "KEY1" "STATE_DNSKEY" "rumoured"
+set_keystate "KEY1" "STATE_KRRSIG" "rumoured"
+set_keystate "KEY1" "STATE_ZRRSIG" "rumoured"
+set_keystate "KEY1" "STATE_DS" "hidden"
+
+check_keys
+check_dnssecstatus "$SERVER" "$POLICY" "$ZONE"
+check_apex
+check_subdomain
+dnssec_verify
+
+basefile=$(key_get KEY1 BASEFILE)
+
+n=$((n+1))
+echo_i "checkds publish correctly sets DSPublish for zone $ZONE ($n)"
+rndc_checkds "$SERVER" "$DIR" "-" "20190102121314" "published" "$ZONE"
+retry_quiet 3 _wait_for_metadata "DSPublish: 20190102121314" "${basefile}.state" || log_error "bad DSPublish in ${basefile}.state"
+test "$ret" -eq 0 || echo_i "failed"
+status=$((status+ret))
+
+n=$((n+1))
+echo_i "checkds withdraw correctly sets DSRemoved for zone $ZONE ($n)"
+rndc_checkds "$SERVER" "$DIR" "-" "20200102121314" "withdrawn" "$ZONE"
+retry_quiet 3 _wait_for_metadata "DSRemoved: 20200102121314" "${basefile}.state" || log_error "bad DSRemoved in ${basefile}.state"
+test "$ret" -eq 0 || echo_i "failed"
+status=$((status+ret))
+
+# Set keytimes for dnssec-policy with various algorithms.
+# These all use the same time values.
+set_keytimes_algorithm_policy() {
+ # The first KSK is immediately published and activated.
+ created=$(key_get KEY1 CREATED)
+ set_keytime "KEY1" "PUBLISHED" "${created}"
+ set_keytime "KEY1" "ACTIVE" "${created}"
+ # Key was pregenerated.
+ if [ "$1" = "pregenerated" ]; then
+ keyfile=$(key_get KEY1 BASEFILE)
+ grep "; Publish:" "${keyfile}.key" > published.test${n}.key1
+ published=$(awk '{print $3}' < published.test${n}.key1)
+ set_keytime "KEY1" "PUBLISHED" "${published}"
+ set_keytime "KEY1" "ACTIVE" "${published}"
+ fi
+ published=$(key_get KEY1 PUBLISHED)
+
+ # The DS can be published if the DNSKEY and RRSIG records are
+ # OMNIPRESENT. This happens after max-zone-ttl (1d) plus
+ # publish-safety (1h) plus zone-propagation-delay (300s) =
+ # 86400 + 3600 + 300 = 90300.
+ set_addkeytime "KEY1" "SYNCPUBLISH" "${published}" 90300
+ # Key lifetime is 10 years, 315360000 seconds.
+ set_addkeytime "KEY1" "RETIRED" "${published}" 315360000
+ # The key is removed after the retire time plus DS TTL (1d),
+ # parent propagation delay (1h), and retire safety (1h) =
+ # 86400 + 3600 + 3600 = 93600.
+ retired=$(key_get KEY1 RETIRED)
+ set_addkeytime "KEY1" "REMOVED" "${retired}" 93600
+
+ # The first ZSKs are immediately published and activated.
+ created=$(key_get KEY2 CREATED)
+ set_keytime "KEY2" "PUBLISHED" "${created}"
+ set_keytime "KEY2" "ACTIVE" "${created}"
+ # Key was pregenerated.
+ if [ "$1" = "pregenerated" ]; then
+ keyfile=$(key_get KEY2 BASEFILE)
+ grep "; Publish:" "${keyfile}.key" > published.test${n}.key2
+ published=$(awk '{print $3}' < published.test${n}.key2)
+ set_keytime "KEY2" "PUBLISHED" "${published}"
+ set_keytime "KEY2" "ACTIVE" "${published}"
+ fi
+ published=$(key_get KEY2 PUBLISHED)
+
+ # Key lifetime for KSK2 is 5 years, 157680000 seconds.
+ set_addkeytime "KEY2" "RETIRED" "${published}" 157680000
+ # The key is removed after the retire time plus max zone ttl (1d), zone
+ # propagation delay (300s), retire safety (1h), and sign delay
+ # (signature validity minus refresh, 9d) =
+ # 86400 + 300 + 3600 + 777600 = 867900.
+ retired=$(key_get KEY2 RETIRED)
+ set_addkeytime "KEY2" "REMOVED" "${retired}" 867900
+
+ # Second ZSK (KEY3).
+ created=$(key_get KEY3 CREATED)
+ set_keytime "KEY3" "PUBLISHED" "${created}"
+ set_keytime "KEY3" "ACTIVE" "${created}"
+ # Key was pregenerated.
+ if [ "$1" = "pregenerated" ]; then
+ keyfile=$(key_get KEY3 BASEFILE)
+ grep "; Publish:" "${keyfile}.key" > published.test${n}.key3
+ published=$(awk '{print $3}' < published.test${n}.key3)
+ set_keytime "KEY3" "PUBLISHED" "${published}"
+ set_keytime "KEY3" "ACTIVE" "${published}"
+ fi
+ published=$(key_get KEY3 PUBLISHED)
+
+ # Key lifetime for KSK3 is 1 year, 31536000 seconds.
+ set_addkeytime "KEY3" "RETIRED" "${published}" 31536000
+ retired=$(key_get KEY3 RETIRED)
+ set_addkeytime "KEY3" "REMOVED" "${retired}" 867900
+}
+
+#
+# Zone: rsasha1.kasp.
+#
+if $SHELL ../testcrypto.sh -q RSASHA1
+then
+ set_zone "rsasha1.kasp"
+ set_policy "rsasha1" "3" "1234"
+ set_server "ns3" "10.53.0.3"
+ # Key properties.
+ key_clear "KEY1"
+ set_keyrole "KEY1" "ksk"
+ set_keylifetime "KEY1" "315360000"
+ set_keyalgorithm "KEY1" "5" "RSASHA1" "2048"
+ set_keysigning "KEY1" "yes"
+ set_zonesigning "KEY1" "no"
+
+ key_clear "KEY2"
+ set_keyrole "KEY2" "zsk"
+ set_keylifetime "KEY2" "157680000"
+ set_keyalgorithm "KEY2" "5" "RSASHA1" "2048"
+ set_keysigning "KEY2" "no"
+ set_zonesigning "KEY2" "yes"
+
+ key_clear "KEY3"
+ set_keyrole "KEY3" "zsk"
+ set_keylifetime "KEY3" "31536000"
+ set_keyalgorithm "KEY3" "5" "RSASHA1" "2000"
+ set_keysigning "KEY3" "no"
+ set_zonesigning "KEY3" "yes"
+
+ # KSK: DNSKEY, RRSIG (ksk) published. DS needs to wait.
+ # ZSK: DNSKEY, RRSIG (zsk) published.
+ 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"
+
+ set_keystate "KEY3" "GOAL" "omnipresent"
+ set_keystate "KEY3" "STATE_DNSKEY" "rumoured"
+ set_keystate "KEY3" "STATE_ZRRSIG" "rumoured"
+ # Three keys only.
+ key_clear "KEY4"
+
+ check_keys
+ check_dnssecstatus "$SERVER" "$POLICY" "$ZONE"
+ set_keytimes_algorithm_policy
+ check_keytimes
+ check_apex
+ check_subdomain
+ dnssec_verify
+fi
+
+#
+# Zone: unsigned.kasp.
+#
+set_zone "unsigned.kasp"
+set_policy "none" "0" "0"
+set_server "ns3" "10.53.0.3"
+
+key_clear "KEY1"
+key_clear "KEY2"
+key_clear "KEY3"
+key_clear "KEY4"
+
+check_keys
+check_dnssecstatus "$SERVER" "$POLICY" "$ZONE"
+check_apex
+check_subdomain
+# Make sure the zone file is untouched.
+n=$((n+1))
+echo_i "Make sure the zonefile for zone ${ZONE} is not edited ($n)"
+ret=0
+diff "${DIR}/${ZONE}.db.infile" "${DIR}/${ZONE}.db" || ret=1
+test "$ret" -eq 0 || echo_i "failed"
+status=$((status+ret))
+
+#
+# Zone: insecure.kasp.
+#
+set_zone "insecure.kasp"
+set_policy "insecure" "0" "0"
+set_server "ns3" "10.53.0.3"
+
+key_clear "KEY1"
+key_clear "KEY2"
+key_clear "KEY3"
+key_clear "KEY4"
+
+check_keys
+check_dnssecstatus "$SERVER" "$POLICY" "$ZONE"
+check_apex
+check_subdomain
+
+#
+# Zone: unlimited.kasp.
+#
+set_zone "unlimited.kasp"
+set_policy "unlimited" "1" "1234"
+set_server "ns3" "10.53.0.3"
+# Key properties.
+set_keyrole "KEY1" "csk"
+set_keylifetime "KEY1" "0"
+set_keyalgorithm "KEY1" "13" "ECDSAP256SHA256" "256"
+set_keysigning "KEY1" "yes"
+set_zonesigning "KEY1" "yes"
+# DNSKEY, RRSIG (ksk), RRSIG (zsk) are published. DS needs to wait.
+set_keystate "KEY1" "GOAL" "omnipresent"
+set_keystate "KEY1" "STATE_DNSKEY" "rumoured"
+set_keystate "KEY1" "STATE_KRRSIG" "rumoured"
+set_keystate "KEY1" "STATE_ZRRSIG" "rumoured"
+set_keystate "KEY1" "STATE_DS" "hidden"
+
+check_keys
+check_dnssecstatus "$SERVER" "$POLICY" "$ZONE"
+set_keytimes_csk_policy
+check_keytimes
+check_apex
+check_subdomain
+dnssec_verify
+
+#
+# Zone: inherit.kasp.
+#
+set_zone "inherit.kasp"
+set_policy "rsasha256" "3" "1234"
+set_server "ns3" "10.53.0.3"
+
+# Key properties.
+key_clear "KEY1"
+set_keyrole "KEY1" "ksk"
+set_keylifetime "KEY1" "315360000"
+set_keyalgorithm "KEY1" "8" "RSASHA256" "2048"
+set_keysigning "KEY1" "yes"
+set_zonesigning "KEY1" "no"
+
+key_clear "KEY2"
+set_keyrole "KEY2" "zsk"
+set_keylifetime "KEY2" "157680000"
+set_keyalgorithm "KEY2" "8" "RSASHA256" "2048"
+set_keysigning "KEY2" "no"
+set_zonesigning "KEY2" "yes"
+
+key_clear "KEY3"
+set_keyrole "KEY3" "zsk"
+set_keylifetime "KEY3" "31536000"
+set_keyalgorithm "KEY3" "8" "RSASHA256" "3072"
+set_keysigning "KEY3" "no"
+set_zonesigning "KEY3" "yes"
+# KSK: DNSKEY, RRSIG (ksk) published. DS needs to wait.
+# ZSK: DNSKEY, RRSIG (zsk) published.
+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"
+
+set_keystate "KEY3" "GOAL" "omnipresent"
+set_keystate "KEY3" "STATE_DNSKEY" "rumoured"
+set_keystate "KEY3" "STATE_ZRRSIG" "rumoured"
+# Three keys only.
+key_clear "KEY4"
+
+check_keys
+check_dnssecstatus "$SERVER" "$POLICY" "$ZONE"
+set_keytimes_algorithm_policy
+check_keytimes
+check_apex
+check_subdomain
+dnssec_verify
+
+#
+# Zone: dnssec-keygen.kasp.
+#
+set_zone "dnssec-keygen.kasp"
+set_policy "rsasha256" "3" "1234"
+set_server "ns3" "10.53.0.3"
+# Key properties, timings and states same as above.
+
+check_keys
+check_dnssecstatus "$SERVER" "$POLICY" "$ZONE"
+set_keytimes_algorithm_policy
+check_keytimes
+check_apex
+check_subdomain
+dnssec_verify
+
+#
+# Zone: some-keys.kasp.
+#
+set_zone "some-keys.kasp"
+set_policy "rsasha256" "3" "1234"
+set_server "ns3" "10.53.0.3"
+# Key properties, timings and states same as above.
+
+check_keys
+check_dnssecstatus "$SERVER" "$POLICY" "$ZONE"
+set_keytimes_algorithm_policy "pregenerated"
+check_keytimes
+check_apex
+check_subdomain
+dnssec_verify
+
+#
+# Zone: pregenerated.kasp.
+#
+# There are more pregenerated keys than needed, hence the number of keys is
+# six, not three.
+set_zone "pregenerated.kasp"
+set_policy "rsasha256" "6" "1234"
+set_server "ns3" "10.53.0.3"
+# Key properties, timings and states same as above.
+
+check_keys
+check_dnssecstatus "$SERVER" "$POLICY" "$ZONE"
+set_keytimes_algorithm_policy "pregenerated"
+check_keytimes
+check_apex
+check_subdomain
+dnssec_verify
+
+#
+# Zone: rumoured.kasp.
+#
+# There are three keys in rumoured state.
+set_zone "rumoured.kasp"
+set_policy "rsasha256" "3" "1234"
+set_server "ns3" "10.53.0.3"
+# Key properties, timings and states same as above.
+
+check_keys
+check_dnssecstatus "$SERVER" "$POLICY" "$ZONE"
+set_keytimes_algorithm_policy
+# Activation date is a day later.
+set_addkeytime "KEY1" "ACTIVE" $(key_get KEY1 ACTIVE) 86400
+set_addkeytime "KEY1" "RETIRED" $(key_get KEY1 RETIRED) 86400
+set_addkeytime "KEY1" "REMOVED" $(key_get KEY1 REMOVED) 86400
+set_addkeytime "KEY2" "ACTIVE" $(key_get KEY2 ACTIVE) 86400
+set_addkeytime "KEY2" "RETIRED" $(key_get KEY2 RETIRED) 86400
+set_addkeytime "KEY2" "REMOVED" $(key_get KEY2 REMOVED) 86400
+set_addkeytime "KEY3" "ACTIVE" $(key_get KEY3 ACTIVE) 86400
+set_addkeytime "KEY3" "RETIRED" $(key_get KEY3 RETIRED) 86400
+set_addkeytime "KEY3" "REMOVED" $(key_get KEY3 REMOVED) 86400
+check_keytimes
+check_apex
+check_subdomain
+dnssec_verify
+
+#
+# Zone: secondary.kasp.
+#
+set_zone "secondary.kasp"
+set_policy "rsasha256" "3" "1234"
+set_server "ns3" "10.53.0.3"
+# Key properties, timings and states same as above.
+
+check_keys
+check_dnssecstatus "$SERVER" "$POLICY" "$ZONE"
+set_keytimes_algorithm_policy
+check_keytimes
+check_apex
+check_subdomain
+dnssec_verify
+
+# Update zone.
+n=$((n+1))
+echo_i "check that we correctly sign the zone after IXFR for zone ${ZONE} ($n)"
+ret=0
+cp ns2/secondary.kasp.db.in2 ns2/secondary.kasp.db
+rndccmd 10.53.0.2 reload "$ZONE" > /dev/null || log_error "rndc reload zone ${ZONE} failed"
+
+_wait_for_done_subdomains() {
+ ret=0
+ dig_with_opts "a.${ZONE}" "@${SERVER}" A > "dig.out.$DIR.test$n.a" || return 1
+ grep "status: NOERROR" "dig.out.$DIR.test$n.a" > /dev/null || return 1
+ grep "a.${ZONE}\..*${DEFAULT_TTL}.*IN.*A.*10\.0\.0\.11" "dig.out.$DIR.test$n.a" > /dev/null || return 1
+ check_signatures $_qtype "dig.out.$DIR.test$n.a" "ZSK"
+ if [ $ret -gt 0 ]; then return $ret; fi
+
+ dig_with_opts "d.${ZONE}" "@${SERVER}" A > "dig.out.$DIR.test$n.d" || return 1
+ grep "status: NOERROR" "dig.out.$DIR.test$n.d" > /dev/null || return 1
+ grep "d.${ZONE}\..*${DEFAULT_TTL}.*IN.*A.*10\.0\.0\.4" "dig.out.$DIR.test$n.d" > /dev/null || return 1
+ check_signatures $_qtype "dig.out.$DIR.test$n.d" "ZSK"
+ return $ret
+}
+retry_quiet 5 _wait_for_done_subdomains || ret=1
+test "$ret" -eq 0 || echo_i "failed"
+status=$((status+ret))
+
+# TODO: we might want to test:
+# - configuring a zone with too many active keys (should trigger retire).
+# - configuring a zone with keys not matching the policy.
+
+#
+# Zone: rsasha1-nsec3.kasp.
+#
+if $SHELL ../testcrypto.sh -q RSASHA1
+then
+ set_zone "rsasha1-nsec3.kasp"
+ set_policy "rsasha1-nsec3" "3" "1234"
+ set_server "ns3" "10.53.0.3"
+ # Key properties.
+ set_keyalgorithm "KEY1" "7" "NSEC3RSASHA1" "2048"
+ set_keyalgorithm "KEY2" "7" "NSEC3RSASHA1" "2048"
+ set_keyalgorithm "KEY3" "7" "NSEC3RSASHA1" "2000"
+ # Key timings and states same as above.
+
+ check_keys
+ check_dnssecstatus "$SERVER" "$POLICY" "$ZONE"
+ set_keytimes_algorithm_policy
+ check_keytimes
+ check_apex
+ check_subdomain
+ dnssec_verify
+fi
+
+#
+# Zone: rsasha256.kasp.
+#
+set_zone "rsasha256.kasp"
+set_policy "rsasha256" "3" "1234"
+set_server "ns3" "10.53.0.3"
+# Key properties.
+set_keyalgorithm "KEY1" "8" "RSASHA256" "2048"
+set_keyalgorithm "KEY2" "8" "RSASHA256" "2048"
+set_keyalgorithm "KEY3" "8" "RSASHA256" "3072"
+# Key timings and states same as above.
+
+check_keys
+check_dnssecstatus "$SERVER" "$POLICY" "$ZONE"
+set_keytimes_algorithm_policy
+check_keytimes
+check_apex
+check_subdomain
+dnssec_verify
+
+#
+# Zone: rsasha512.kasp.
+#
+set_zone "rsasha512.kasp"
+set_policy "rsasha512" "3" "1234"
+set_server "ns3" "10.53.0.3"
+# Key properties.
+set_keyalgorithm "KEY1" "10" "RSASHA512" "2048"
+set_keyalgorithm "KEY2" "10" "RSASHA512" "2048"
+set_keyalgorithm "KEY3" "10" "RSASHA512" "3072"
+# Key timings and states same as above.
+
+check_keys
+check_dnssecstatus "$SERVER" "$POLICY" "$ZONE"
+set_keytimes_algorithm_policy
+check_keytimes
+check_apex
+check_subdomain
+dnssec_verify
+
+#
+# Zone: ecdsa256.kasp.
+#
+set_zone "ecdsa256.kasp"
+set_policy "ecdsa256" "3" "1234"
+set_server "ns3" "10.53.0.3"
+# Key properties.
+set_keyalgorithm "KEY1" "13" "ECDSAP256SHA256" "256"
+set_keyalgorithm "KEY2" "13" "ECDSAP256SHA256" "256"
+set_keyalgorithm "KEY3" "13" "ECDSAP256SHA256" "256"
+# Key timings and states same as above.
+
+check_keys
+check_dnssecstatus "$SERVER" "$POLICY" "$ZONE"
+set_keytimes_algorithm_policy
+check_keytimes
+check_apex
+check_subdomain
+dnssec_verify
+
+#
+# Zone: ecdsa512.kasp.
+#
+set_zone "ecdsa384.kasp"
+set_policy "ecdsa384" "3" "1234"
+set_server "ns3" "10.53.0.3"
+# Key properties.
+set_keyalgorithm "KEY1" "14" "ECDSAP384SHA384" "384"
+set_keyalgorithm "KEY2" "14" "ECDSAP384SHA384" "384"
+set_keyalgorithm "KEY3" "14" "ECDSAP384SHA384" "384"
+# Key timings and states same as above.
+
+check_keys
+check_dnssecstatus "$SERVER" "$POLICY" "$ZONE"
+set_keytimes_algorithm_policy
+check_keytimes
+check_apex
+check_subdomain
+dnssec_verify
+
+#
+# Zone: ed25519.kasp.
+#
+if [ -f ed25519-supported.file ]; then
+ set_zone "ed25519.kasp"
+ set_policy "ed25519" "3" "1234"
+ set_server "ns3" "10.53.0.3"
+ # Key properties.
+ set_keyalgorithm "KEY1" "15" "ED25519" "256"
+ set_keyalgorithm "KEY2" "15" "ED25519" "256"
+ set_keyalgorithm "KEY3" "15" "ED25519" "256"
+ # Key timings and states same as above.
+
+ check_keys
+ check_dnssecstatus "$SERVER" "$POLICY" "$ZONE"
+ set_keytimes_algorithm_policy
+ check_keytimes
+ check_apex
+ check_subdomain
+ dnssec_verify
+fi
+
+#
+# Zone: ed448.kasp.
+#
+if [ -f ed448-supported.file ]; then
+ set_zone "ed448.kasp"
+ set_policy "ed448" "3" "1234"
+ set_server "ns3" "10.53.0.3"
+ # Key properties.
+ set_keyalgorithm "KEY1" "16" "ED448" "456"
+ set_keyalgorithm "KEY2" "16" "ED448" "456"
+ set_keyalgorithm "KEY3" "16" "ED448" "456"
+ # Key timings and states same as above.
+
+ check_keys
+ check_dnssecstatus "$SERVER" "$POLICY" "$ZONE"
+ set_keytimes_algorithm_policy
+ check_keytimes
+ check_apex
+ check_subdomain
+ dnssec_verify
+fi
+
+# Set key times for 'autosign' policy.
+set_keytimes_autosign_policy() {
+ # The KSK was published six months ago (with settime).
+ created=$(key_get KEY1 CREATED)
+ set_addkeytime "KEY1" "PUBLISHED" "${created}" -15552000
+ set_addkeytime "KEY1" "ACTIVE" "${created}" -15552000
+ set_addkeytime "KEY1" "SYNCPUBLISH" "${created}" -15552000
+ # Key lifetime is 2 years, 63072000 seconds.
+ active=$(key_get KEY1 ACTIVE)
+ set_addkeytime "KEY1" "RETIRED" "${active}" 63072000
+ # The key is removed after the retire time plus DS TTL (1d),
+ # parent propagation delay (1h), retire safety (1h) =
+ # 86400 + 3600 + 3600 = 93600
+ retired=$(key_get KEY1 RETIRED)
+ set_addkeytime "KEY1" "REMOVED" "${retired}" 93600
+
+ # The ZSK was published six months ago (with settime).
+ created=$(key_get KEY2 CREATED)
+ set_addkeytime "KEY2" "PUBLISHED" "${created}" -15552000
+ set_addkeytime "KEY2" "ACTIVE" "${created}" -15552000
+ # Key lifetime for KSK2 is 1 year, 31536000 seconds.
+ active=$(key_get KEY2 ACTIVE)
+ set_addkeytime "KEY2" "RETIRED" "${active}" 31536000
+ # The key is removed after the retire time plus:
+ # TTLsig (RRSIG TTL): 1 day (86400 seconds)
+ # Dprp (propagation delay): 5 minutes (300 seconds)
+ # retire-safety: 1 hour (3600 seconds)
+ # Dsgn (sign delay): 7 days (604800 seconds)
+ # Iret: 695100 seconds.
+ retired=$(key_get KEY2 RETIRED)
+ set_addkeytime "KEY2" "REMOVED" "${retired}" 695100
+}
+
+#
+# Zone: expired-sigs.autosign.
+#
+set_zone "expired-sigs.autosign"
+set_policy "autosign" "2" "300"
+set_server "ns3" "10.53.0.3"
+# Key properties.
+key_clear "KEY1"
+set_keyrole "KEY1" "ksk"
+set_keylifetime "KEY1" "63072000"
+set_keyalgorithm "KEY1" "$DEFAULT_ALGORITHM_NUMBER" "$DEFAULT_ALGORITHM" "$DEFAULT_BITS"
+set_keysigning "KEY1" "yes"
+set_zonesigning "KEY1" "no"
+
+key_clear "KEY2"
+set_keyrole "KEY2" "zsk"
+set_keylifetime "KEY2" "31536000"
+set_keyalgorithm "KEY2" "$DEFAULT_ALGORITHM_NUMBER" "$DEFAULT_ALGORITHM" "$DEFAULT_BITS"
+set_keysigning "KEY2" "no"
+set_zonesigning "KEY2" "yes"
+
+# Both KSK and ZSK stay OMNIPRESENT.
+set_keystate "KEY1" "GOAL" "omnipresent"
+set_keystate "KEY1" "STATE_DNSKEY" "omnipresent"
+set_keystate "KEY1" "STATE_KRRSIG" "omnipresent"
+set_keystate "KEY1" "STATE_DS" "omnipresent"
+
+set_keystate "KEY2" "GOAL" "omnipresent"
+set_keystate "KEY2" "STATE_DNSKEY" "omnipresent"
+set_keystate "KEY2" "STATE_ZRRSIG" "omnipresent"
+# Expect only two keys.
+key_clear "KEY3"
+key_clear "KEY4"
+
+check_keys
+check_dnssecstatus "$SERVER" "$POLICY" "$ZONE"
+set_keytimes_autosign_policy
+check_keytimes
+check_apex
+check_subdomain
+dnssec_verify
+
+# Verify all signatures have been refreshed.
+check_rrsig_refresh() {
+ # Apex.
+ _qtypes="DNSKEY SOA NS NSEC"
+ for _qtype in $_qtypes
+ do
+ n=$((n+1))
+ echo_i "check ${_qtype} rrsig is refreshed correctly for zone ${ZONE} ($n)"
+ ret=0
+ dig_with_opts "$ZONE" "@${SERVER}" "$_qtype" > "dig.out.$DIR.test$n" || log_error "dig ${ZONE} ${_qtype} failed"
+ grep "status: NOERROR" "dig.out.$DIR.test$n" > /dev/null || log_error "mismatch status in DNS response"
+ grep "${ZONE}\..*IN.*RRSIG.*${_qtype}.*${ZONE}" "dig.out.$DIR.test$n" > "rrsig.out.$ZONE.$_qtype" || log_error "missing RRSIG (${_qtype}) record in response"
+ # If this exact RRSIG is also in the zone file it is not refreshed.
+ _rrsig=$(cat "rrsig.out.$ZONE.$_qtype")
+ grep "${_rrsig}" "${DIR}/${ZONE}.db" > /dev/null && log_error "RRSIG (${_qtype}) not refreshed in zone ${ZONE}"
+ test "$ret" -eq 0 || echo_i "failed"
+ status=$((status+ret))
+ done
+
+ # Below apex.
+ _labels="a b c ns3"
+ for _label in $_labels;
+ do
+ _qtypes="A NSEC"
+ for _qtype in $_qtypes
+ do
+ n=$((n+1))
+ echo_i "check ${_label} ${_qtype} rrsig is refreshed correctly for zone ${ZONE} ($n)"
+ ret=0
+ dig_with_opts "${_label}.${ZONE}" "@${SERVER}" "$_qtype" > "dig.out.$DIR.test$n" || log_error "dig ${_label}.${ZONE} ${_qtype} failed"
+ grep "status: NOERROR" "dig.out.$DIR.test$n" > /dev/null || log_error "mismatch status in DNS response"
+ grep "${ZONE}\..*IN.*RRSIG.*${_qtype}.*${ZONE}" "dig.out.$DIR.test$n" > "rrsig.out.$ZONE.$_qtype" || log_error "missing RRSIG (${_qtype}) record in response"
+ _rrsig=$(cat "rrsig.out.$ZONE.$_qtype")
+ grep "${_rrsig}" "${DIR}/${ZONE}.db" > /dev/null && log_error "RRSIG (${_qtype}) not refreshed in zone ${ZONE}"
+ test "$ret" -eq 0 || echo_i "failed"
+ status=$((status+ret))
+ done
+ done
+}
+
+check_rrsig_refresh
+
+#
+# Zone: fresh-sigs.autosign.
+#
+set_zone "fresh-sigs.autosign"
+set_policy "autosign" "2" "300"
+set_server "ns3" "10.53.0.3"
+# Key properties, timings and states same as above.
+
+check_keys
+check_dnssecstatus "$SERVER" "$POLICY" "$ZONE"
+set_keytimes_autosign_policy
+check_keytimes
+check_apex
+check_subdomain
+dnssec_verify
+
+# Verify signature reuse.
+check_rrsig_reuse() {
+ # Apex.
+ _qtypes="NS NSEC"
+ for _qtype in $_qtypes
+ do
+ n=$((n+1))
+ echo_i "check ${_qtype} rrsig is reused correctly for zone ${ZONE} ($n)"
+ ret=0
+ dig_with_opts "$ZONE" "@${SERVER}" "$_qtype" > "dig.out.$DIR.test$n" || log_error "dig ${ZONE} ${_qtype} failed"
+ grep "status: NOERROR" "dig.out.$DIR.test$n" > /dev/null || log_error "mismatch status in DNS response"
+ grep "${ZONE}\..*IN.*RRSIG.*${_qtype}.*${ZONE}" "dig.out.$DIR.test$n" > "rrsig.out.$ZONE.$_qtype" || log_error "missing RRSIG (${_qtype}) record in response"
+ # If this exact RRSIG is also in the signed zone file it is not refreshed.
+ _rrsig=$(awk '{print $5, $6, $7, $8, $9, $10, $11, $12, $13, $14;}' < "rrsig.out.$ZONE.$_qtype")
+ $CHECKZONE -f raw -F text -s full -o zone.out.${ZONE}.test$n "${ZONE}" "${DIR}/${ZONE}.db.signed" > /dev/null
+ grep "${_rrsig}" zone.out.${ZONE}.test$n > /dev/null || log_error "RRSIG (${_qtype}) not reused in zone ${ZONE}"
+ test "$ret" -eq 0 || echo_i "failed"
+ status=$((status+ret))
+ done
+
+ # Below apex.
+ _labels="a b c ns3"
+ for _label in $_labels;
+ do
+ _qtypes="A NSEC"
+ for _qtype in $_qtypes
+ do
+ n=$((n+1))
+ echo_i "check ${_label} ${_qtype} rrsig is reused correctly for zone ${ZONE} ($n)"
+ ret=0
+ dig_with_opts "${_label}.${ZONE}" "@${SERVER}" "$_qtype" > "dig.out.$DIR.test$n" || log_error "dig ${_label}.${ZONE} ${_qtype} failed"
+ grep "status: NOERROR" "dig.out.$DIR.test$n" > /dev/null || log_error "mismatch status in DNS response"
+ grep "${ZONE}\..*IN.*RRSIG.*${_qtype}.*${ZONE}" "dig.out.$DIR.test$n" > "rrsig.out.$ZONE.$_qtype" || log_error "missing RRSIG (${_qtype}) record in response"
+ # If this exact RRSIG is also in the signed zone file it is not refreshed.
+ _rrsig=$(awk '{print $5, $6, $7, $8, $9, $10, $11, $12, $13, $14;}' < "rrsig.out.$ZONE.$_qtype")
+ $CHECKZONE -f raw -F text -s full -o zone.out.${ZONE}.test$n "${ZONE}" "${DIR}/${ZONE}.db.signed" > /dev/null
+ grep "${_rrsig}" zone.out.${ZONE}.test$n > /dev/null || log_error "RRSIG (${_qtype}) not reused in zone ${ZONE}"
+ test "$ret" -eq 0 || echo_i "failed"
+ status=$((status+ret))
+ done
+ done
+}
+
+check_rrsig_reuse
+
+#
+# Zone: unfresh-sigs.autosign.
+#
+set_zone "unfresh-sigs.autosign"
+set_policy "autosign" "2" "300"
+set_server "ns3" "10.53.0.3"
+# Key properties, timings and states same as above.
+
+check_keys
+check_dnssecstatus "$SERVER" "$POLICY" "$ZONE"
+set_keytimes_autosign_policy
+check_keytimes
+check_apex
+check_subdomain
+dnssec_verify
+check_rrsig_refresh
+
+#
+# Zone: ksk-missing.autosign.
+#
+set_zone "ksk-missing.autosign"
+set_policy "autosign" "2" "300"
+set_server "ns3" "10.53.0.3"
+# Key properties, timings and states same as above.
+# Skip checking the private file, because it is missing.
+key_set "KEY1" "PRIVATE" "no"
+
+check_keys
+check_dnssecstatus "$SERVER" "$POLICY" "$ZONE"
+check_apex
+check_subdomain
+dnssec_verify
+
+# Restore the PRIVATE variable.
+key_set "KEY1" "PRIVATE" "yes"
+
+#
+# Zone: zsk-missing.autosign.
+#
+set_zone "zsk-missing.autosign"
+set_policy "autosign" "2" "300"
+set_server "ns3" "10.53.0.3"
+# Key properties, timings and states same as above.
+# Skip checking the private file, because it is missing.
+key_set "KEY2" "PRIVATE" "no"
+
+check_keys
+check_dnssecstatus "$SERVER" "$POLICY" "$ZONE"
+# For the apex, we expect the SOA to be signed with the KSK because the ZSK is
+# offline. Temporary treat KEY1 as a zone signing key too.
+set_keyrole "KEY1" "csk"
+set_zonesigning "KEY1" "yes"
+set_zonesigning "KEY2" "no"
+check_apex
+set_keyrole "KEY1" "ksk"
+set_zonesigning "KEY1" "no"
+set_zonesigning "KEY2" "yes"
+check_subdomain
+dnssec_verify
+
+# Restore the PRIVATE variable.
+key_set "KEY2" "PRIVATE" "yes"
+
+#
+# Zone: zsk-retired.autosign.
+#
+set_zone "zsk-retired.autosign"
+set_policy "autosign" "3" "300"
+set_server "ns3" "10.53.0.3"
+# The third key is not yet expected to be signing.
+set_keyrole "KEY3" "zsk"
+set_keylifetime "KEY3" "31536000"
+set_keyalgorithm "KEY3" "$DEFAULT_ALGORITHM_NUMBER" "$DEFAULT_ALGORITHM" "$DEFAULT_BITS"
+set_keysigning "KEY3" "no"
+set_zonesigning "KEY3" "no"
+# The ZSK goal is set to HIDDEN but records stay OMNIPRESENT until the new ZSK
+# is active.
+set_keystate "KEY2" "GOAL" "hidden"
+set_keystate "KEY2" "STATE_DNSKEY" "omnipresent"
+set_keystate "KEY2" "STATE_ZRRSIG" "omnipresent"
+# A new ZSK should be introduced, so expect a key with goal OMNIPRESENT,
+# the DNSKEY introduced (RUMOURED) and the signatures HIDDEN.
+set_keystate "KEY3" "GOAL" "omnipresent"
+set_keystate "KEY3" "STATE_DNSKEY" "rumoured"
+set_keystate "KEY3" "STATE_ZRRSIG" "hidden"
+
+check_keys
+check_dnssecstatus "$SERVER" "$POLICY" "$ZONE"
+set_keytimes_autosign_policy
+
+# The old ZSK is retired.
+created=$(key_get KEY2 CREATED)
+set_keytime "KEY2" "RETIRED" "${created}"
+set_addkeytime "KEY2" "REMOVED" "${created}" 695100
+# The new ZSK is immediately published.
+created=$(key_get KEY3 CREATED)
+set_keytime "KEY3" "PUBLISHED" "${created}"
+# And becomes active after Ipub:
+# DNSKEY TTL: 300 seconds
+# zone-propagation-delay 5 minutes (300 seconds)
+# publish-safety: 1 hour (3600 seconds)
+# Ipub: 4200 seconds
+published=$(key_get KEY3 PUBLISHED)
+set_addkeytime "KEY3" "ACTIVE" "${published}" 4200
+# Lzsk: 1 year (31536000 seconds)
+active=$(key_get KEY3 ACTIVE)
+set_addkeytime "KEY3" "RETIRED" "${active}" 31536000
+# Iret: 695100 seconds.
+retired=$(key_get KEY3 RETIRED)
+set_addkeytime "KEY3" "REMOVED" "${retired}" 695100
+
+check_keytimes
+check_apex
+check_subdomain
+dnssec_verify
+check_rrsig_refresh
+
+#
+# Zone: legacy-keys.kasp.
+#
+set_zone "legacy-keys.kasp"
+# This zone has two active keys and two old keys left in key directory, so
+# expect 4 key files.
+set_policy "migrate-to-dnssec-policy" "4" "1234"
+set_server "ns3" "10.53.0.3"
+
+# Key properties.
+key_clear "KEY1"
+set_keyrole "KEY1" "ksk"
+set_keylifetime "KEY1" "16070400"
+set_keyalgorithm "KEY1" "8" "RSASHA256" "2048"
+set_keysigning "KEY1" "yes"
+set_zonesigning "KEY1" "no"
+
+key_clear "KEY2"
+set_keyrole "KEY2" "zsk"
+set_keylifetime "KEY2" "16070400"
+set_keyalgorithm "KEY2" "8" "RSASHA256" "2048"
+set_keysigning "KEY2" "no"
+set_zonesigning "KEY2" "yes"
+# KSK: DNSKEY, RRSIG (ksk) published. DS needs to wait.
+# ZSK: DNSKEY, RRSIG (zsk) published.
+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"
+# Two keys only.
+key_clear "KEY3"
+key_clear "KEY4"
+
+check_keys
+check_dnssecstatus "$SERVER" "$POLICY" "$ZONE"
+
+# Make sure the correct legacy keys were used (and not the removed predecessor
+# keys).
+n=$((n+1))
+echo_i "check correct keys were used when migrating zone ${ZONE} to dnssec-policy ($n)"
+ret=0
+kskfile=$(cat ns3/legacy-keys.kasp.ksk)
+basefile=$(key_get KEY1 BASEFILE)
+echo_i "filename: $basefile (expect $kskfile)"
+test "$DIR/$kskfile" = "$basefile" || ret=1
+zskfile=$(cat ns3/legacy-keys.kasp.zsk)
+basefile=$(key_get KEY2 BASEFILE)
+echo_i "filename: $basefile (expect $zskfile)"
+test "$DIR/$zskfile" = "$basefile" || ret=1
+test "$ret" -eq 0 || echo_i "failed"
+status=$((status+ret))
+
+# KSK times.
+created=$(key_get KEY1 CREATED)
+keyfile=$(key_get KEY1 BASEFILE)
+grep "; Publish:" "${keyfile}.key" > published.test${n}.key1
+published=$(awk '{print $3}' < published.test${n}.key1)
+set_keytime "KEY1" "PUBLISHED" "${published}"
+set_keytime "KEY1" "ACTIVE" "${published}"
+published=$(key_get KEY1 PUBLISHED)
+# The DS can be published if the DNSKEY and RRSIG records are OMNIPRESENT.
+# This happens after max-zone-ttl (1d) plus publish-safety (1h) plus
+# zone-propagation-delay (300s) = 86400 + 3600 + 300 = 90300.
+set_addkeytime "KEY1" "SYNCPUBLISH" "${published}" 90300
+# Key lifetime is 6 months, 315360000 seconds.
+set_addkeytime "KEY1" "RETIRED" "${published}" 16070400
+# The key is removed after the retire time plus DS TTL (1d), parent
+# propagation delay (1h), and retire safety (1h) = 86400 + 3600 + 3600 = 93600.
+retired=$(key_get KEY1 RETIRED)
+set_addkeytime "KEY1" "REMOVED" "${retired}" 93600
+
+# ZSK times.
+created=$(key_get KEY2 CREATED)
+keyfile=$(key_get KEY2 BASEFILE)
+grep "; Publish:" "${keyfile}.key" > published.test${n}.key2
+published=$(awk '{print $3}' < published.test${n}.key2)
+set_keytime "KEY2" "PUBLISHED" "${published}"
+set_keytime "KEY2" "ACTIVE" "${published}"
+published=$(key_get KEY2 PUBLISHED)
+# Key lifetime is 6 months, 315360000 seconds.
+set_addkeytime "KEY2" "RETIRED" "${published}" 16070400
+# The key is removed after the retire time plus max zone ttl (1d), zone
+# propagation delay (300s), retire safety (1h), and sign delay (signature
+# validity minus refresh, 9d) = 86400 + 300 + 3600 + 777600 = 867900.
+retired=$(key_get KEY2 RETIRED)
+set_addkeytime "KEY2" "REMOVED" "${retired}" 867900
+
+check_keytimes
+check_apex
+check_subdomain
+dnssec_verify
+
+#
+# Test dnssec-policy inheritance.
+#
+
+# These zones should be unsigned:
+# ns2/unsigned.tld
+# ns4/none.inherit.signed
+# ns4/none.override.signed
+# ns4/inherit.none.signed
+# ns4/none.none.signed
+# ns5/inherit.inherit.unsigned
+# ns5/none.inherit.unsigned
+# ns5/none.override.unsigned
+# ns5/inherit.none.unsigned
+# ns5/none.none.unsigned
+key_clear "KEY1"
+key_clear "KEY2"
+key_clear "KEY3"
+key_clear "KEY4"
+
+set_zone "unsigned.tld"
+set_policy "none" "0" "0"
+set_server "ns2" "10.53.0.2"
+TSIG=""
+check_keys
+check_dnssecstatus "$SERVER" "$POLICY" "$ZONE"
+check_apex
+check_subdomain
+
+set_zone "none.inherit.signed"
+set_policy "none" "0" "0"
+set_server "ns4" "10.53.0.4"
+TSIG="hmac-sha1:sha1:$SHA1"
+check_keys
+check_dnssecstatus "$SERVER" "$POLICY" "$ZONE"
+check_apex
+check_subdomain
+
+set_zone "none.override.signed"
+set_policy "none" "0" "0"
+set_server "ns4" "10.53.0.4"
+TSIG="hmac-sha224:sha224:$SHA224"
+check_keys
+check_dnssecstatus "$SERVER" "$POLICY" "$ZONE"
+check_apex
+check_subdomain
+
+set_zone "inherit.none.signed"
+set_policy "none" "0" "0"
+set_server "ns4" "10.53.0.4"
+TSIG="hmac-sha256:sha256:$SHA256"
+check_keys
+check_dnssecstatus "$SERVER" "$POLICY" "$ZONE"
+check_apex
+check_subdomain
+
+set_zone "none.none.signed"
+set_policy "none" "0" "0"
+set_server "ns4" "10.53.0.4"
+TSIG="hmac-sha256:sha256:$SHA256"
+check_keys
+check_dnssecstatus "$SERVER" "$POLICY" "$ZONE"
+check_apex
+check_subdomain
+
+set_zone "inherit.inherit.unsigned"
+set_policy "none" "0" "0"
+set_server "ns5" "10.53.0.5"
+TSIG="hmac-sha1:sha1:$SHA1"
+check_keys
+check_dnssecstatus "$SERVER" "$POLICY" "$ZONE"
+check_apex
+check_subdomain
+
+set_zone "none.inherit.unsigned"
+set_policy "none" "0" "0"
+set_server "ns5" "10.53.0.5"
+TSIG="hmac-sha1:sha1:$SHA1"
+check_keys
+check_dnssecstatus "$SERVER" "$POLICY" "$ZONE"
+check_apex
+check_subdomain
+
+set_zone "none.override.unsigned"
+set_policy "none" "0" "0"
+set_server "ns5" "10.53.0.5"
+TSIG="hmac-sha224:sha224:$SHA224"
+check_keys
+check_dnssecstatus "$SERVER" "$POLICY" "$ZONE"
+check_apex
+check_subdomain
+
+set_zone "inherit.none.unsigned"
+set_policy "none" "0" "0"
+set_server "ns5" "10.53.0.5"
+TSIG="hmac-sha256:sha256:$SHA256"
+check_keys
+check_dnssecstatus "$SERVER" "$POLICY" "$ZONE"
+check_apex
+check_subdomain
+
+set_zone "none.none.unsigned"
+set_policy "none" "0" "0"
+set_server "ns5" "10.53.0.5"
+TSIG="hmac-sha256:sha256:$SHA256"
+check_keys
+check_dnssecstatus "$SERVER" "$POLICY" "$ZONE"
+check_apex
+check_subdomain
+
+# These zones should be signed with the default policy:
+# ns2/signed.tld
+# ns4/override.inherit.signed
+# ns4/inherit.override.signed
+# ns5/override.inherit.signed
+# ns5/inherit.override.signed
+set_keyrole "KEY1" "csk"
+set_keylifetime "KEY1" "0"
+set_keyalgorithm "KEY1" "13" "ECDSAP256SHA256" "256"
+set_keysigning "KEY1" "yes"
+set_zonesigning "KEY1" "yes"
+
+set_keystate "KEY1" "GOAL" "omnipresent"
+set_keystate "KEY1" "STATE_DNSKEY" "rumoured"
+set_keystate "KEY1" "STATE_KRRSIG" "rumoured"
+set_keystate "KEY1" "STATE_ZRRSIG" "rumoured"
+set_keystate "KEY1" "STATE_DS" "hidden"
+
+set_zone "signed.tld"
+set_policy "default" "1" "3600"
+set_server "ns2" "10.53.0.2"
+TSIG=""
+check_keys
+check_dnssecstatus "$SERVER" "$POLICY" "$ZONE"
+set_keytimes_csk_policy
+check_keytimes
+check_apex
+check_subdomain
+dnssec_verify
+
+set_zone "override.inherit.signed"
+set_policy "default" "1" "3600"
+set_server "ns4" "10.53.0.4"
+TSIG="hmac-sha1:sha1:$SHA1"
+check_keys
+check_dnssecstatus "$SERVER" "$POLICY" "$ZONE"
+set_keytimes_csk_policy
+check_keytimes
+check_apex
+check_subdomain
+dnssec_verify
+
+set_zone "inherit.override.signed"
+set_policy "default" "1" "3600"
+set_server "ns4" "10.53.0.4"
+TSIG="hmac-sha224:sha224:$SHA224"
+check_keys
+check_dnssecstatus "$SERVER" "$POLICY" "$ZONE"
+set_keytimes_csk_policy
+check_keytimes
+check_apex
+check_subdomain
+dnssec_verify
+
+set_zone "override.inherit.unsigned"
+set_policy "default" "1" "3600"
+set_server "ns5" "10.53.0.5"
+TSIG="hmac-sha1:sha1:$SHA1"
+check_keys
+check_dnssecstatus "$SERVER" "$POLICY" "$ZONE"
+set_keytimes_csk_policy
+check_keytimes
+check_apex
+check_subdomain
+dnssec_verify
+
+set_zone "inherit.override.unsigned"
+set_policy "default" "1" "3600"
+set_server "ns5" "10.53.0.5"
+TSIG="hmac-sha224:sha224:$SHA224"
+check_keys
+check_dnssecstatus "$SERVER" "$POLICY" "$ZONE"
+set_keytimes_csk_policy
+check_keytimes
+check_apex
+check_subdomain
+dnssec_verify
+
+# These zones should be signed with the test policy:
+# ns4/inherit.inherit.signed
+# ns4/override.override.signed
+# ns4/override.none.signed
+# ns5/override.override.unsigned
+# ns5/override.none.unsigned
+# ns4/example.net (both views)
+set_keyrole "KEY1" "csk"
+set_keylifetime "KEY1" "0"
+set_keyalgorithm "KEY1" "14" "ECDSAP384SHA384" "384"
+set_keysigning "KEY1" "yes"
+set_zonesigning "KEY1" "yes"
+
+set_zone "inherit.inherit.signed"
+set_policy "test" "1" "3600"
+set_server "ns4" "10.53.0.4"
+TSIG="hmac-sha1:sha1:$SHA1"
+wait_for_nsec
+check_keys
+check_dnssecstatus "$SERVER" "$POLICY" "$ZONE"
+set_keytimes_csk_policy
+check_keytimes
+check_apex
+check_subdomain
+dnssec_verify
+
+set_zone "override.override.signed"
+set_policy "test" "1" "3600"
+set_server "ns4" "10.53.0.4"
+TSIG="hmac-sha224:sha224:$SHA224"
+wait_for_nsec
+check_keys
+check_dnssecstatus "$SERVER" "$POLICY" "$ZONE"
+set_keytimes_csk_policy
+check_keytimes
+check_apex
+check_subdomain
+dnssec_verify
+
+set_zone "override.none.signed"
+set_policy "test" "1" "3600"
+set_server "ns4" "10.53.0.4"
+TSIG="hmac-sha256:sha256:$SHA256"
+wait_for_nsec
+check_keys
+check_dnssecstatus "$SERVER" "$POLICY" "$ZONE"
+set_keytimes_csk_policy
+check_keytimes
+check_apex
+check_subdomain
+dnssec_verify
+
+set_zone "override.override.unsigned"
+set_policy "test" "1" "3600"
+set_server "ns5" "10.53.0.5"
+TSIG="hmac-sha224:sha224:$SHA224"
+wait_for_nsec
+check_keys
+check_dnssecstatus "$SERVER" "$POLICY" "$ZONE"
+set_keytimes_csk_policy
+check_keytimes
+check_apex
+check_subdomain
+dnssec_verify
+
+set_zone "override.none.unsigned"
+set_policy "test" "1" "3600"
+set_server "ns5" "10.53.0.5"
+TSIG="hmac-sha256:sha256:$SHA256"
+wait_for_nsec
+check_keys
+check_dnssecstatus "$SERVER" "$POLICY" "$ZONE"
+set_keytimes_csk_policy
+check_keytimes
+check_apex
+check_subdomain
+dnssec_verify
+
+# Test with views.
+set_zone "example.net"
+set_server "ns4" "10.53.0.4"
+TSIG="$DEFAULT_HMAC:keyforview1:$VIEW1"
+wait_for_nsec
+check_keys
+check_dnssecstatus "$SERVER" "$POLICY" "$ZONE" "example1"
+set_keytimes_csk_policy
+check_keytimes
+check_apex
+dnssec_verify
+# check zonestatus
+n=$((n+1))
+echo_i "check $ZONE (view example1) zonestatus ($n)"
+ret=0
+check_isdynamic "$SERVER" "$ZONE" "example1" || log_error "zone not dynamic"
+check_inlinesigning "$SERVER" "$ZONE" "example1" && log_error "inline-signing enabled, expected disabled"
+test "$ret" -eq 0 || echo_i "failed"
+status=$((status+ret))
+# check subdomain
+n=$((n+1))
+echo_i "check TXT example.net (view example1) rrset is signed correctly ($n)"
+ret=0
+dig_with_opts "view.${ZONE}" "@${SERVER}" TXT > "dig.out.$DIR.test$n.txt" || log_error "dig view.${ZONE} TXT failed"
+grep "status: NOERROR" "dig.out.$DIR.test$n.txt" > /dev/null || log_error "mismatch status in DNS response"
+grep "view.${ZONE}\..*${DEFAULT_TTL}.*IN.*TXT.*view1" "dig.out.$DIR.test$n.txt" > /dev/null || log_error "missing view.${ZONE} TXT record in response"
+check_signatures TXT "dig.out.$DIR.test$n.txt" "ZSK"
+test "$ret" -eq 0 || echo_i "failed"
+status=$((status+ret))
+
+TSIG="$DEFAULT_HMAC:keyforview2:$VIEW2"
+wait_for_nsec
+check_keys
+check_dnssecstatus "$SERVER" "$POLICY" "$ZONE" "example2"
+check_apex
+dnssec_verify
+# check zonestatus
+n=$((n+1))
+echo_i "check $ZONE (view example2) zonestatus ($n)"
+ret=0
+check_isdynamic "$SERVER" "$ZONE" "example2" && log_error "zone dynamic, but not expected"
+check_inlinesigning "$SERVER" "$ZONE" "example2" || log_error "inline-signing disabled, expected enabled"
+test "$ret" -eq 0 || echo_i "failed"
+status=$((status+ret))
+# check subdomain
+n=$((n+1))
+echo_i "check TXT example.net (view example2) rrset is signed correctly ($n)"
+ret=0
+dig_with_opts "view.${ZONE}" "@${SERVER}" TXT > "dig.out.$DIR.test$n.txt" || log_error "dig view.${ZONE} TXT failed"
+grep "status: NOERROR" "dig.out.$DIR.test$n.txt" > /dev/null || log_error "mismatch status in DNS response"
+grep "view.${ZONE}\..*${DEFAULT_TTL}.*IN.*TXT.*view2" "dig.out.$DIR.test$n.txt" > /dev/null || log_error "missing view.${ZONE} TXT record in response"
+check_signatures TXT "dig.out.$DIR.test$n.txt" "ZSK"
+test "$ret" -eq 0 || echo_i "failed"
+status=$((status+ret))
+
+TSIG="$DEFAULT_HMAC:keyforview3:$VIEW3"
+wait_for_nsec
+check_keys
+check_dnssecstatus "$SERVER" "$POLICY" "$ZONE" "example3"
+check_apex
+dnssec_verify
+# check zonestatus
+n=$((n+1))
+echo_i "check $ZONE (view example3) zonestatus ($n)"
+ret=0
+check_isdynamic "$SERVER" "$ZONE" "example3" && log_error "zone dynamic, but not expected"
+check_inlinesigning "$SERVER" "$ZONE" "example3" || log_error "inline-signing disabled, expected enabled"
+test "$ret" -eq 0 || echo_i "failed"
+status=$((status+ret))
+# check subdomain
+n=$((n+1))
+echo_i "check TXT example.net (view example3) rrset is signed correctly ($n)"
+ret=0
+dig_with_opts "view.${ZONE}" "@${SERVER}" TXT > "dig.out.$DIR.test$n.txt" || log_error "dig view.${ZONE} TXT failed"
+grep "status: NOERROR" "dig.out.$DIR.test$n.txt" > /dev/null || log_error "mismatch status in DNS response"
+grep "view.${ZONE}\..*${DEFAULT_TTL}.*IN.*TXT.*view2" "dig.out.$DIR.test$n.txt" > /dev/null || log_error "missing view.${ZONE} TXT record in response"
+check_signatures TXT "dig.out.$DIR.test$n.txt" "ZSK"
+test "$ret" -eq 0 || echo_i "failed"
+status=$((status+ret))
+
+# Clear TSIG.
+TSIG=""
+
+#
+# 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 provider are published.
+zsks_are_published() {
+ 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 3 || 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 "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 || ret=1
+test "$ret" -eq 0 || echo_i "failed"
+status=$((status+ret))
+
+#
+# Testing manual rollover.
+#
+set_zone "manual-rollover.kasp"
+set_policy "manual-rollover" "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"
+# During set up everything was set to OMNIPRESENT.
+set_keystate "KEY1" "GOAL" "omnipresent"
+set_keystate "KEY1" "STATE_DNSKEY" "omnipresent"
+set_keystate "KEY1" "STATE_KRRSIG" "omnipresent"
+set_keystate "KEY1" "STATE_DS" "omnipresent"
+
+set_keystate "KEY2" "GOAL" "omnipresent"
+set_keystate "KEY2" "STATE_DNSKEY" "omnipresent"
+set_keystate "KEY2" "STATE_ZRRSIG" "omnipresent"
+
+check_keys
+check_dnssecstatus "$SERVER" "$POLICY" "$ZONE"
+
+# The first keys were published and activated a day ago.
+created=$(key_get KEY1 CREATED)
+set_addkeytime "KEY1" "PUBLISHED" "${created}" -86400
+set_addkeytime "KEY1" "SYNCPUBLISH" "${created}" -86400
+set_addkeytime "KEY1" "ACTIVE" "${created}" -86400
+created=$(key_get KEY2 CREATED)
+set_addkeytime "KEY2" "PUBLISHED" "${created}" -86400
+set_addkeytime "KEY2" "ACTIVE" "${created}" -86400
+# Key lifetimes are unlimited, so not setting RETIRED and REMOVED.
+check_keytimes
+check_apex
+check_subdomain
+dnssec_verify
+
+# Schedule KSK rollover in six months (15552000 seconds).
+active=$(key_get KEY1 ACTIVE)
+set_addkeytime "KEY1" "RETIRED" "${active}" 15552000
+retired=$(key_get KEY1 RETIRED)
+rndc_rollover "$SERVER" "$DIR" $(key_get KEY1 ID) "${retired}" "$ZONE"
+# Rollover starts in six months, but lifetime is set to six months plus
+# prepublication duration = 15552000 + 7500 = 15559500 seconds.
+set_keylifetime "KEY1" "15559500"
+set_addkeytime "KEY1" "RETIRED" "${active}" 15559500
+retired=$(key_get KEY1 RETIRED)
+# Retire interval of this policy is 26h (93600 seconds).
+set_addkeytime "KEY1" "REMOVED" "${retired}" 93600
+
+check_keys
+check_dnssecstatus "$SERVER" "$POLICY" "$ZONE"
+check_keytimes
+check_apex
+check_subdomain
+dnssec_verify
+
+# Schedule KSK rollover now.
+set_policy "manual-rollover" "3" "3600"
+set_keystate "KEY1" "GOAL" "hidden"
+# This key was activated one day ago, so lifetime is set to 1d plus
+# prepublication duration (7500 seconds) = 93900 seconds.
+set_keylifetime "KEY1" "93900"
+created=$(key_get KEY1 CREATED)
+set_keytime "KEY1" "RETIRED" "${created}"
+rndc_rollover "$SERVER" "$DIR" $(key_get KEY1 ID) "${created}" "$ZONE"
+# New key is introduced.
+set_keyrole "KEY3" "ksk"
+set_keylifetime "KEY3" "0"
+set_keyalgorithm "KEY3" "13" "ECDSAP256SHA256" "256"
+set_keysigning "KEY3" "yes"
+set_zonesigning "KEY3" "no"
+
+set_keystate "KEY3" "GOAL" "omnipresent"
+set_keystate "KEY3" "STATE_DNSKEY" "rumoured"
+set_keystate "KEY3" "STATE_KRRSIG" "rumoured"
+set_keystate "KEY3" "STATE_DS" "hidden"
+
+check_keys
+check_dnssecstatus "$SERVER" "$POLICY" "$ZONE"
+check_apex
+check_subdomain
+dnssec_verify
+
+# Schedule ZSK rollover now.
+set_policy "manual-rollover" "4" "3600"
+set_keystate "KEY2" "GOAL" "hidden"
+# This key was activated one day ago, so lifetime is set to 1d plus
+# prepublication duration (7500 seconds) = 93900 seconds.
+set_keylifetime "KEY2" "93900"
+created=$(key_get KEY2 CREATED)
+set_keytime "KEY2" "RETIRED" "${created}"
+rndc_rollover "$SERVER" "$DIR" $(key_get KEY2 ID) "${created}" "$ZONE"
+# New key is introduced.
+set_keyrole "KEY4" "zsk"
+set_keylifetime "KEY4" "0"
+set_keyalgorithm "KEY4" "13" "ECDSAP256SHA256" "256"
+set_keysigning "KEY4" "no"
+set_zonesigning "KEY4" "no" # not yet, first prepublish DNSKEY.
+
+set_keystate "KEY4" "GOAL" "omnipresent"
+set_keystate "KEY4" "STATE_DNSKEY" "rumoured"
+set_keystate "KEY4" "STATE_ZRRSIG" "hidden"
+
+check_keys
+check_dnssecstatus "$SERVER" "$POLICY" "$ZONE"
+check_apex
+check_subdomain
+dnssec_verify
+
+# Try to schedule a ZSK rollover for an inactive key (should fail).
+n=$((n+1))
+echo_i "check that rndc dnssec -rollover fails if key is inactive ($n)"
+ret=0
+rndccmd "$SERVER" dnssec -rollover -key $(key_get KEY4 ID) "$ZONE" > rndc.dnssec.rollover.out.$ZONE.$n || ret=1
+grep "key is not actively signing" rndc.dnssec.rollover.out.$ZONE.$n > /dev/null || log_error "bad error message"
+test "$ret" -eq 0 || echo_i "failed"
+status=$((status+ret))
+
+#
+# Testing DNSSEC introduction.
+#
+
+#
+# Zone: step1.enable-dnssec.autosign.
+#
+set_zone "step1.enable-dnssec.autosign"
+set_policy "enable-dnssec" "1" "300"
+set_server "ns3" "10.53.0.3"
+# Key properties.
+key_clear "KEY1"
+set_keyrole "KEY1" "csk"
+set_keylifetime "KEY1" "0"
+set_keyalgorithm "KEY1" "$DEFAULT_ALGORITHM_NUMBER" "$DEFAULT_ALGORITHM" "$DEFAULT_BITS"
+set_keysigning "KEY1" "yes"
+set_zonesigning "KEY1" "yes"
+# The DNSKEY and signatures are introduced first, the DS remains hidden.
+set_keystate "KEY1" "GOAL" "omnipresent"
+set_keystate "KEY1" "STATE_DNSKEY" "rumoured"
+set_keystate "KEY1" "STATE_KRRSIG" "rumoured"
+set_keystate "KEY1" "STATE_ZRRSIG" "rumoured"
+set_keystate "KEY1" "STATE_DS" "hidden"
+# This policy lists only one key (CSK).
+key_clear "KEY2"
+key_clear "KEY3"
+key_clear "KEY4"
+
+check_keys
+check_dnssecstatus "$SERVER" "$POLICY" "$ZONE"
+
+# Set expected key times:
+# - The first key is immediately published and activated.
+created=$(key_get KEY1 CREATED)
+set_keytime "KEY1" "PUBLISHED" "${created}"
+set_keytime "KEY1" "ACTIVE" "${created}"
+# - The DS can be published if the DNSKEY and RRSIG records are
+# OMNIPRESENT. This happens after max-zone-ttl (12h) plus
+# publish-safety (5m) plus zone-propagation-delay (5m) =
+# 43200 + 300 + 300 = 43800.
+set_addkeytime "KEY1" "SYNCPUBLISH" "${created}" 43800
+# - Key lifetime is unlimited, so not setting RETIRED and REMOVED.
+
+# Various signing policy checks.
+check_keytimes
+check_apex
+check_subdomain
+dnssec_verify
+
+_check_next_key_event() {
+ _expect=$1
+
+ grep "zone ${ZONE}.*: next key event in .* seconds" "${DIR}/named.run" > "keyevent.out.$ZONE.test$n" || return 1
+
+ # Get the latest next key event.
+ if [ "${DYNAMIC}" = "yes" ]; then
+ _time=$(awk '{print $9}' < "keyevent.out.$ZONE.test$n" | tail -1)
+ else
+ # inline-signing zone adds "(signed)"
+ _time=$(awk '{print $10}' < "keyevent.out.$ZONE.test$n" | tail -1)
+ fi
+
+ # The next key event time must within threshold of the
+ # expected time.
+ _expectmin=$((_expect-next_key_event_threshold))
+ _expectmax=$((_expect+next_key_event_threshold))
+
+ test $_expectmin -le "$_time" || return 1
+ test $_expectmax -ge "$_time" || return 1
+
+ return 0
+}
+
+check_next_key_event() {
+ n=$((n+1))
+ echo_i "check next key event for zone ${ZONE} ($n)"
+ ret=0
+
+ retry_quiet 3 _check_next_key_event $1 || log_error "bad next key event time for zone ${ZONE} (expect ${_expect})"
+ test "$ret" -eq 0 || echo_i "failed"
+ status=$((status+ret))
+
+}
+
+# Next key event is when the DNSKEY RRset becomes OMNIPRESENT: DNSKEY TTL plus
+# publish safety plus the zone propagation delay: 900 seconds.
+check_next_key_event 900
+
+#
+# Zone: step2.enable-dnssec.autosign.
+#
+set_zone "step2.enable-dnssec.autosign"
+set_policy "enable-dnssec" "1" "300"
+set_server "ns3" "10.53.0.3"
+# The DNSKEY is omnipresent, but the zone signatures not yet.
+# Thus, the DS remains hidden.
+set_keystate "KEY1" "STATE_DNSKEY" "omnipresent"
+set_keystate "KEY1" "STATE_KRRSIG" "omnipresent"
+
+# Various signing policy checks.
+check_keys
+check_dnssecstatus "$SERVER" "$POLICY" "$ZONE"
+
+# Set expected key times:
+# - The key was published and activated 900 seconds ago (with settime).
+created=$(key_get KEY1 CREATED)
+set_addkeytime "KEY1" "PUBLISHED" "${created}" -900
+set_addkeytime "KEY1" "ACTIVE" "${created}" -900
+set_addkeytime "KEY1" "SYNCPUBLISH" "${created}" 43800
+
+# Continue signing policy checks.
+check_keytimes
+check_apex
+check_subdomain
+dnssec_verify
+
+# Next key event is when the zone signatures become OMNIPRESENT: max-zone-ttl
+# plus zone propagation delay plus retire safety minus the already elapsed
+# 900 seconds: 12h + 300s + 20m - 900 = 44700 - 900 = 43800 seconds
+check_next_key_event 43800
+
+#
+# Zone: step3.enable-dnssec.autosign.
+#
+set_zone "step3.enable-dnssec.autosign"
+set_policy "enable-dnssec" "1" "300"
+set_server "ns3" "10.53.0.3"
+# All signatures should be omnipresent, so the DS can be submitted.
+set_keystate "KEY1" "STATE_ZRRSIG" "omnipresent"
+set_keystate "KEY1" "STATE_DS" "rumoured"
+
+# Various signing policy checks.
+check_keys
+check_dnssecstatus "$SERVER" "$POLICY" "$ZONE"
+
+# Set expected key times:
+# - The key was published and activated 44700 seconds ago (with settime).
+created=$(key_get KEY1 CREATED)
+set_addkeytime "KEY1" "PUBLISHED" "${created}" -44700
+set_addkeytime "KEY1" "ACTIVE" "${created}" -44700
+set_keytime "KEY1" "SYNCPUBLISH" "${created}"
+
+# Continue signing policy checks.
+check_keytimes
+check_apex
+check_subdomain
+dnssec_verify
+# Check that CDS publication is logged.
+check_cdslog "$DIR" "$ZONE" KEY1
+
+# The DS can be introduced. We ignore any parent registration delay, so set
+# the DS publish time to now.
+rndc_checkds "$SERVER" "$DIR" KEY1 "now" "published" "$ZONE"
+# Next key event is when the DS can move to the OMNIPRESENT state. This occurs
+# when the parent propagation delay have passed, plus the DS TTL and retire
+# safety delay: 1h + 2h + 20m = 3h20m = 12000 seconds
+check_next_key_event 12000
+
+#
+# Zone: step4.enable-dnssec.autosign.
+#
+set_zone "step4.enable-dnssec.autosign"
+set_policy "enable-dnssec" "1" "300"
+set_server "ns3" "10.53.0.3"
+# The DS is omnipresent.
+set_keystate "KEY1" "STATE_DS" "omnipresent"
+
+# Various signing policy checks.
+check_keys
+check_dnssecstatus "$SERVER" "$POLICY" "$ZONE"
+
+# Set expected key times:
+# - The key was published and activated 56700 seconds ago (with settime).
+created=$(key_get KEY1 CREATED)
+set_addkeytime "KEY1" "PUBLISHED" "${created}" -56700
+set_addkeytime "KEY1" "ACTIVE" "${created}" -56700
+set_addkeytime "KEY1" "SYNCPUBLISH" "${created}" -12000
+
+# Continue signing policy checks.
+check_keytimes
+check_apex
+check_subdomain
+dnssec_verify
+
+# Next key event is never, the zone dnssec-policy has been established. So we
+# fall back to the default loadkeys interval.
+check_next_key_event 3600
+
+#
+# Testing ZSK Pre-Publication rollover.
+#
+
+# Policy parameters.
+# Lksk: 2 years (63072000 seconds)
+# Lzsk: 30 days (2592000 seconds)
+# Iret(KSK): DS TTL (1d) + DprpP (1h) + retire-safety (2d)
+# Iret(KSK): 3d1h (262800 seconds)
+# Iret(ZSK): RRSIG TTL (1d) + Dprp (1h) + Dsgn (1w) + retire-safety (2d)
+# Iret(ZSK): 10d1h (867600 seconds)
+Lksk=63072000
+Lzsk=2592000
+IretKSK=262800
+IretZSK=867600
+
+#
+# Zone: step1.zsk-prepub.autosign.
+#
+set_zone "step1.zsk-prepub.autosign"
+set_policy "zsk-prepub" "2" "3600"
+set_server "ns3" "10.53.0.3"
+
+set_retired_removed() {
+ _Lkey=$2
+ _Iret=$3
+
+ _active=$(key_get $1 ACTIVE)
+ set_addkeytime "${1}" "RETIRED" "${_active}" "${_Lkey}"
+ _retired=$(key_get $1 RETIRED)
+ set_addkeytime "${1}" "REMOVED" "${_retired}" "${_Iret}"
+}
+
+rollover_predecessor_keytimes() {
+ _addtime=$1
+
+ _created=$(key_get KEY1 CREATED)
+ set_addkeytime "KEY1" "PUBLISHED" "${_created}" "${_addtime}"
+ set_addkeytime "KEY1" "SYNCPUBLISH" "${_created}" "${_addtime}"
+ set_addkeytime "KEY1" "ACTIVE" "${_created}" "${_addtime}"
+ [ "$Lksk" = 0 ] || set_retired_removed "KEY1" "${Lksk}" "${IretKSK}"
+
+ _created=$(key_get KEY2 CREATED)
+ set_addkeytime "KEY2" "PUBLISHED" "${_created}" "${_addtime}"
+ set_addkeytime "KEY2" "ACTIVE" "${_created}" "${_addtime}"
+ [ "$Lzsk" = 0 ] || set_retired_removed "KEY2" "${Lzsk}" "${IretZSK}"
+}
+
+# Key properties.
+key_clear "KEY1"
+set_keyrole "KEY1" "ksk"
+set_keylifetime "KEY1" "${Lksk}"
+set_keyalgorithm "KEY1" "$DEFAULT_ALGORITHM_NUMBER" "$DEFAULT_ALGORITHM" "$DEFAULT_BITS"
+set_keysigning "KEY1" "yes"
+set_zonesigning "KEY1" "no"
+
+key_clear "KEY2"
+set_keyrole "KEY2" "zsk"
+set_keylifetime "KEY2" "${Lzsk}"
+set_keyalgorithm "KEY2" "$DEFAULT_ALGORITHM_NUMBER" "$DEFAULT_ALGORITHM" "$DEFAULT_BITS"
+set_keysigning "KEY2" "no"
+set_zonesigning "KEY2" "yes"
+# Both KSK (KEY1) and ZSK (KEY2) start in OMNIPRESENT.
+set_keystate "KEY1" "GOAL" "omnipresent"
+set_keystate "KEY1" "STATE_DNSKEY" "omnipresent"
+set_keystate "KEY1" "STATE_KRRSIG" "omnipresent"
+set_keystate "KEY1" "STATE_DS" "omnipresent"
+
+set_keystate "KEY2" "GOAL" "omnipresent"
+set_keystate "KEY2" "STATE_DNSKEY" "omnipresent"
+set_keystate "KEY2" "STATE_ZRRSIG" "omnipresent"
+# Initially only two keys.
+key_clear "KEY3"
+key_clear "KEY4"
+
+# Various signing policy checks.
+check_keys
+check_dnssecstatus "$SERVER" "$POLICY" "$ZONE"
+# These keys are immediately published and activated.
+rollover_predecessor_keytimes 0
+check_keytimes
+check_apex
+check_subdomain
+dnssec_verify
+
+# Next key event is when the successor ZSK needs to be published. That is
+# the ZSK lifetime - prepublication time. The prepublication time is DNSKEY
+# TTL plus publish safety plus the zone propagation delay. For the
+# zsk-prepub policy that means: 30d - 3600s + 1d + 1h = 2498400 seconds.
+check_next_key_event 2498400
+
+#
+# Zone: step2.zsk-prepub.autosign.
+#
+set_zone "step2.zsk-prepub.autosign"
+set_policy "zsk-prepub" "3" "3600"
+set_server "ns3" "10.53.0.3"
+# New ZSK (KEY3) is prepublished, but not yet signing.
+key_clear "KEY3"
+set_keyrole "KEY3" "zsk"
+set_keylifetime "KEY3" "${Lzsk}"
+set_keyalgorithm "KEY3" "$DEFAULT_ALGORITHM_NUMBER" "$DEFAULT_ALGORITHM" "$DEFAULT_BITS"
+set_keysigning "KEY3" "no"
+set_zonesigning "KEY3" "no"
+# Key states.
+set_keystate "KEY2" "GOAL" "hidden"
+set_keystate "KEY3" "GOAL" "omnipresent"
+set_keystate "KEY3" "STATE_DNSKEY" "rumoured"
+set_keystate "KEY3" "STATE_ZRRSIG" "hidden"
+
+# Various signing policy checks.
+check_keys
+check_dnssecstatus "$SERVER" "$POLICY" "$ZONE"
+
+# Set expected key times:
+# - The old keys were activated 694 hours ago (2498400 seconds).
+rollover_predecessor_keytimes -2498400
+# - The new ZSK is published now.
+created=$(key_get KEY3 CREATED)
+set_keytime "KEY3" "PUBLISHED" "${created}"
+# - The new ZSK becomes active when the DNSKEY is OMNIPRESENT.
+# Ipub: TTLkey (1h) + Dprp (1h) + publish-safety (1d)
+# Ipub: 26 hour (93600 seconds).
+IpubZSK=93600
+set_addkeytime "KEY3" "ACTIVE" "${created}" "${IpubZSK}"
+set_retired_removed "KEY3" "${Lzsk}" "${IretZSK}"
+
+# Continue signing policy checks.
+check_keytimes
+check_apex
+check_subdomain
+dnssec_verify
+
+# Next key event is when the successor ZSK becomes OMNIPRESENT. That is the
+# DNSKEY TTL plus the zone propagation delay, plus the publish-safety. For
+# the zsk-prepub policy, this means: 3600s + 1h + 1d = 93600 seconds.
+check_next_key_event 93600
+
+#
+# Zone: step3.zsk-prepub.autosign.
+#
+set_zone "step3.zsk-prepub.autosign"
+set_policy "zsk-prepub" "3" "3600"
+set_server "ns3" "10.53.0.3"
+# ZSK (KEY2) no longer is actively signing, RRSIG state in UNRETENTIVE.
+# New ZSK (KEY3) is now actively signing, RRSIG state in RUMOURED.
+set_zonesigning "KEY2" "no"
+set_keystate "KEY2" "STATE_ZRRSIG" "unretentive"
+set_zonesigning "KEY3" "yes"
+set_keystate "KEY3" "STATE_DNSKEY" "omnipresent"
+set_keystate "KEY3" "STATE_ZRRSIG" "rumoured"
+
+# Various signing policy checks.
+check_keys
+check_dnssecstatus "$SERVER" "$POLICY" "$ZONE"
+
+# Set expected key times:
+# - The old keys are activated 30 days ago (2592000 seconds).
+rollover_predecessor_keytimes -2592000
+# - The new ZSK is published 26 hours ago (93600 seconds).
+created=$(key_get KEY3 CREATED)
+set_addkeytime "KEY3" "PUBLISHED" "${created}" -93600
+set_keytime "KEY3" "ACTIVE" "${created}"
+set_retired_removed "KEY3" "${Lzsk}" "${IretZSK}"
+
+# Continue signing policy checks.
+check_keytimes
+check_apex
+# Subdomain still has good signatures of ZSK (KEY2).
+# Set expected zone signing on for KEY2 and off for KEY3,
+# testing whether signatures which are still valid are being reused.
+set_zonesigning "KEY2" "yes"
+set_zonesigning "KEY3" "no"
+check_subdomain
+# Restore the expected zone signing properties.
+set_zonesigning "KEY2" "no"
+set_zonesigning "KEY3" "yes"
+dnssec_verify
+
+# Next key event is when all the RRSIG records have been replaced with
+# signatures of the new ZSK, in other words when ZRRSIG becomes OMNIPRESENT.
+# That is Dsgn plus the maximum zone TTL plus the zone propagation delay plus
+# retire-safety. For the zsk-prepub policy that means: 1w (because 2w validity
+# and refresh within a week) + 1d + 1h + 2d = 10d1h = 867600 seconds.
+check_next_key_event 867600
+
+#
+# Zone: step4.zsk-prepub.autosign.
+#
+set_zone "step4.zsk-prepub.autosign"
+set_policy "zsk-prepub" "3" "3600"
+set_server "ns3" "10.53.0.3"
+# ZSK (KEY2) DNSKEY is no longer needed.
+# ZSK (KEY3) is now actively signing, RRSIG state in RUMOURED.
+set_keystate "KEY2" "STATE_DNSKEY" "unretentive"
+set_keystate "KEY2" "STATE_ZRRSIG" "hidden"
+set_keystate "KEY3" "STATE_ZRRSIG" "omnipresent"
+
+# Various signing policy checks.
+check_keys
+check_dnssecstatus "$SERVER" "$POLICY" "$ZONE"
+
+# Set expected key times:
+# - The old keys are activated 961 hours ago (3459600 seconds).
+rollover_predecessor_keytimes -3459600
+# - The new ZSK is published 267 hours ago (961200 seconds).
+created=$(key_get KEY3 CREATED)
+set_addkeytime "KEY3" "PUBLISHED" "${created}" -961200
+published=$(key_get KEY3 PUBLISHED)
+set_addkeytime "KEY3" "ACTIVE" "${published}" "${IpubZSK}"
+set_retired_removed "KEY3" "${Lzsk}" "${IretZSK}"
+
+# Continue signing policy checks.
+check_keytimes
+check_apex
+check_subdomain
+dnssec_verify
+
+# Next key event is when the DNSKEY enters the HIDDEN state. This is the
+# DNSKEY TTL plus zone propagation delay. For the zsk-prepub policy this is:
+# 3600s + 1h = 7200s
+check_next_key_event 7200
+
+#
+# Zone: step5.zsk-prepub.autosign.
+#
+set_zone "step5.zsk-prepub.autosign"
+set_policy "zsk-prepub" "3" "3600"
+set_server "ns3" "10.53.0.3"
+# ZSK (KEY2) DNSKEY is now completely HIDDEN and removed.
+set_keystate "KEY2" "STATE_DNSKEY" "hidden"
+
+# Various signing policy checks.
+check_keys
+check_dnssecstatus "$SERVER" "$POLICY" "$ZONE"
+
+# Set expected key times:
+# - The old keys are activated 962 hours ago (3463200 seconds).
+rollover_predecessor_keytimes -3463200
+# - The new ZSK is published 268 hours ago (964800 seconds).
+created=$(key_get KEY3 CREATED)
+set_addkeytime "KEY3" "PUBLISHED" "${created}" -964800
+published=$(key_get KEY3 PUBLISHED)
+set_addkeytime "KEY3" "ACTIVE" "${published}" "${IpubZSK}"
+set_retired_removed "KEY3" "${Lzsk}" "${IretZSK}"
+
+# Continue signing policy checks.
+check_keytimes
+check_apex
+check_subdomain
+dnssec_verify
+
+# Next key event is when the new successor needs to be published. This is the
+# ZSK lifetime minus Iret minus Ipub minus DNSKEY TTL. For the zsk-prepub
+# policy this is: 30d - 867600s - 93600s - 3600s = 1627200 seconds.
+check_next_key_event 1627200
+
+#
+# Zone: step6.zsk-prepub.autosign.
+#
+set_zone "step6.zsk-prepub.autosign"
+set_policy "zsk-prepub" "2" "3600"
+set_server "ns3" "10.53.0.3"
+# ZSK (KEY2) DNSKEY is purged.
+key_clear "KEY2"
+
+# Various signing policy checks.
+check_keys
+check_dnssecstatus "$SERVER" "$POLICY" "$ZONE"
+check_apex
+check_subdomain
+dnssec_verify
+
+#
+# Testing KSK Double-KSK rollover.
+#
+
+# Policy parameters.
+# Lksk: 60 days (16070400 seconds)
+# Lzsk: 1 year (31536000 seconds)
+# Iret(KSK): DS TTL (1h) + DprpP (1h) + retire-safety (2d)
+# Iret(KSK): 50h (180000 seconds)
+# Iret(ZSK): RRSIG TTL (1d) + Dprp (1h) + Dsgn (1w) + retire-safety (2d)
+# Iret(ZSK): 10d1h (867600 seconds)
+Lksk=5184000
+Lzsk=31536000
+IretKSK=180000
+IretZSK=867600
+
+#
+# Zone: step1.ksk-doubleksk.autosign.
+#
+set_zone "step1.ksk-doubleksk.autosign"
+set_policy "ksk-doubleksk" "2" "7200"
+set_server "ns3" "10.53.0.3"
+# Key properties.
+key_clear "KEY1"
+set_keyrole "KEY1" "ksk"
+set_keylifetime "KEY1" "${Lksk}"
+set_keyalgorithm "KEY1" "$DEFAULT_ALGORITHM_NUMBER" "$DEFAULT_ALGORITHM" "$DEFAULT_BITS"
+set_keysigning "KEY1" "yes"
+set_zonesigning "KEY1" "no"
+
+key_clear "KEY2"
+set_keyrole "KEY2" "zsk"
+set_keylifetime "KEY2" "${Lzsk}"
+set_keyalgorithm "KEY2" "$DEFAULT_ALGORITHM_NUMBER" "$DEFAULT_ALGORITHM" "$DEFAULT_BITS"
+set_keysigning "KEY2" "no"
+set_zonesigning "KEY2" "yes"
+# Both KSK (KEY1) and ZSK (KEY2) start in OMNIPRESENT.
+set_keystate "KEY1" "GOAL" "omnipresent"
+set_keystate "KEY1" "STATE_DNSKEY" "omnipresent"
+set_keystate "KEY1" "STATE_KRRSIG" "omnipresent"
+set_keystate "KEY1" "STATE_DS" "omnipresent"
+
+set_keystate "KEY2" "GOAL" "omnipresent"
+set_keystate "KEY2" "STATE_DNSKEY" "omnipresent"
+set_keystate "KEY2" "STATE_ZRRSIG" "omnipresent"
+# Initially only two keys.
+key_clear "KEY3"
+key_clear "KEY4"
+
+# Various signing policy checks.
+check_keys
+check_dnssecstatus "$SERVER" "$POLICY" "$ZONE"
+# These keys are immediately published and activated.
+rollover_predecessor_keytimes 0
+check_keytimes
+check_apex
+check_subdomain
+dnssec_verify
+
+# Next key event is when the successor KSK needs to be published. That is
+# the KSK lifetime - prepublication time. The prepublication time is
+# DNSKEY TTL plus publish safety plus the zone propagation delay.
+# For the ksk-doubleksk policy that means: 60d - (1d3h) = 5086800 seconds.
+check_next_key_event 5086800
+
+#
+# Zone: step2.ksk-doubleksk.autosign.
+#
+set_zone "step2.ksk-doubleksk.autosign"
+set_policy "ksk-doubleksk" "3" "7200"
+set_server "ns3" "10.53.0.3"
+# New KSK (KEY3) is prepublished (and signs DNSKEY RRset).
+key_clear "KEY3"
+set_keyrole "KEY3" "ksk"
+set_keylifetime "KEY3" "${Lksk}"
+set_keyalgorithm "KEY3" "$DEFAULT_ALGORITHM_NUMBER" "$DEFAULT_ALGORITHM" "$DEFAULT_BITS"
+set_keysigning "KEY3" "yes"
+set_zonesigning "KEY3" "no"
+# Key states.
+set_keystate "KEY1" "GOAL" "hidden"
+set_keystate "KEY3" "GOAL" "omnipresent"
+set_keystate "KEY3" "STATE_DNSKEY" "rumoured"
+set_keystate "KEY3" "STATE_KRRSIG" "rumoured"
+set_keystate "KEY3" "STATE_DS" "hidden"
+
+# Various signing policy checks.
+check_keys
+check_dnssecstatus "$SERVER" "$POLICY" "$ZONE"
+
+# Set expected key times:
+# - The old keys were activated 1413 hours ago (5086800 seconds).
+rollover_predecessor_keytimes -5086800
+# - The new KSK is published now.
+created=$(key_get KEY3 CREATED)
+set_keytime "KEY3" "PUBLISHED" "${created}"
+# The new KSK should publish the CDS after the prepublication time.
+# TTLkey: 2h
+# DprpC: 1h
+# publish-safety: 1d
+# IpubC: 27h (97200 seconds)
+IpubC=97200
+set_addkeytime "KEY3" "SYNCPUBLISH" "${created}" "${IpubC}"
+set_addkeytime "KEY3" "ACTIVE" "${created}" "${IpubC}"
+set_retired_removed "KEY3" "${Lksk}" "${IretKSK}"
+
+# Continue signing policy checks.
+check_keytimes
+check_apex
+check_subdomain
+dnssec_verify
+
+# Next key event is when the successor KSK becomes OMNIPRESENT. That is the
+# DNSKEY TTL plus the zone propagation delay, plus the publish-safety. For
+# the ksk-doubleksk policy, this means: 7200s + 1h + 1d = 97200 seconds.
+check_next_key_event 97200
+
+#
+# Zone: step3.ksk-doubleksk.autosign.
+#
+set_zone "step3.ksk-doubleksk.autosign"
+set_policy "ksk-doubleksk" "3" "7200"
+set_server "ns3" "10.53.0.3"
+
+# The DNSKEY RRset has become omnipresent.
+# Check keys before we tell named that we saw the DS has been replaced.
+set_keystate "KEY3" "STATE_DNSKEY" "omnipresent"
+set_keystate "KEY3" "STATE_KRRSIG" "omnipresent"
+# The old DS (KEY1) can be withdrawn and the new DS (KEY3) can be introduced.
+set_keystate "KEY1" "STATE_DS" "unretentive"
+set_keystate "KEY3" "STATE_DS" "rumoured"
+
+# Various signing policy checks.
+check_keys
+check_dnssecstatus "$SERVER" "$POLICY" "$ZONE"
+# Check that CDS publication is logged.
+check_cdslog "$DIR" "$ZONE" KEY3
+
+# Set expected key times:
+# - The old keys were activated 60 days ago (5184000 seconds).
+rollover_predecessor_keytimes -5184000
+# - The new KSK is published 27 hours ago (97200 seconds).
+created=$(key_get KEY3 CREATED)
+set_addkeytime "KEY3" "PUBLISHED" "${created}" -97200
+# - The new KSK CDS is published now.
+set_keytime "KEY3" "SYNCPUBLISH" "${created}"
+syncpub=$(key_get KEY3 SYNCPUBLISH)
+set_keytime "KEY3" "ACTIVE" "${syncpub}"
+set_retired_removed "KEY3" "${Lksk}" "${IretKSK}"
+
+# Continue signing policy checks.
+check_keytimes
+check_apex
+check_subdomain
+dnssec_verify
+
+# We ignore any parent registration delay, so set the DS publish time to now.
+rndc_checkds "$SERVER" "$DIR" KEY1 "now" "withdrawn" "$ZONE"
+rndc_checkds "$SERVER" "$DIR" KEY3 "now" "published" "$ZONE"
+# 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, which is the parent propagation delay plus the DS TTL
+# plus the retire-safety. For the ksk-double-ksk policy this means:
+# 1h + 3600s + 2d = 2d2h = 180000 seconds.
+check_next_key_event 180000
+
+#
+# Zone: step4.ksk-doubleksk.autosign.
+#
+set_zone "step4.ksk-doubleksk.autosign"
+set_policy "ksk-doubleksk" "3" "7200"
+set_server "ns3" "10.53.0.3"
+# KSK (KEY1) DNSKEY can be removed.
+set_keysigning "KEY1" "no"
+set_keystate "KEY1" "STATE_DNSKEY" "unretentive"
+set_keystate "KEY1" "STATE_KRRSIG" "unretentive"
+set_keystate "KEY1" "STATE_DS" "hidden"
+# New KSK (KEY3) DS is now OMNIPRESENT.
+set_keystate "KEY3" "STATE_DS" "omnipresent"
+
+# Various signing policy checks.
+check_keys
+check_dnssecstatus "$SERVER" "$POLICY" "$ZONE"
+
+# Set expected key times:
+# - The old keys were activated 1490 hours ago (5364000 seconds).
+rollover_predecessor_keytimes -5364000
+# - The new KSK is published 77 hours ago (277200 seconds).
+created=$(key_get KEY3 CREATED)
+set_addkeytime "KEY3" "PUBLISHED" "${created}" -277200
+published=$(key_get KEY3 PUBLISHED)
+set_addkeytime "KEY3" "SYNCPUBLISH" "${published}" "${IpubC}"
+syncpub=$(key_get KEY3 SYNCPUBLISH)
+set_keytime "KEY3" "ACTIVE" "${syncpub}"
+set_retired_removed "KEY3" "${Lksk}" "${IretKSK}"
+
+# Continue signing policy checks.
+check_keytimes
+check_apex
+check_subdomain
+dnssec_verify
+
+# Next key event is when the DNSKEY enters the HIDDEN state. This is the
+# DNSKEY TTL plus zone propagation delay. For the ksk-doubleksk policy this is:
+# 7200s + 1h = 10800s
+check_next_key_event 10800
+
+#
+# Zone: step5.ksk-doubleksk.autosign.
+#
+set_zone "step5.ksk-doubleksk.autosign"
+set_policy "ksk-doubleksk" "3" "7200"
+set_server "ns3" "10.53.0.3"
+# KSK (KEY1) DNSKEY is now HIDDEN.
+set_keystate "KEY1" "STATE_DNSKEY" "hidden"
+set_keystate "KEY1" "STATE_KRRSIG" "hidden"
+
+# Various signing policy checks.
+check_keys
+check_dnssecstatus "$SERVER" "$POLICY" "$ZONE"
+
+# Set expected key times:
+# - The old KSK is activated 1492 hours ago (5371200 seconds).
+rollover_predecessor_keytimes -5371200
+# - The new KSK is published 79 hours ago (284400 seconds).
+created=$(key_get KEY3 CREATED)
+set_addkeytime "KEY3" "PUBLISHED" "${created}" -284400
+published=$(key_get KEY3 PUBLISHED)
+set_addkeytime "KEY3" "SYNCPUBLISH" "${published}" "${IpubC}"
+syncpub=$(key_get KEY3 SYNCPUBLISH)
+set_keytime "KEY3" "ACTIVE" "${syncpub}"
+set_retired_removed "KEY3" "${Lksk}" "${IretKSK}"
+
+# Various signing policy checks.
+check_keytimes
+check_apex
+check_subdomain
+dnssec_verify
+
+# Next key event is when the new successor needs to be published. This is the
+# KSK lifetime minus Ipub minus Iret minus DNSKEY TTL. For the
+# ksk-doubleksk this is: 60d - 1d3h - 1d - 2d2h - 2h =
+# 5184000 - 97200 - 180000 - 7200 = 4813200 seconds.
+check_next_key_event 4899600
+
+#
+# Zone: step6.ksk-doubleksk.autosign.
+#
+set_zone "step6.ksk-doubleksk.autosign"
+set_policy "ksk-doubleksk" "2" "7200"
+set_server "ns3" "10.53.0.3"
+# KSK (KEY1) DNSKEY is purged.
+key_clear "KEY1"
+
+# Various signing policy checks.
+check_keys
+check_dnssecstatus "$SERVER" "$POLICY" "$ZONE"
+check_apex
+check_subdomain
+dnssec_verify
+
+#
+# Testing CSK key rollover (1).
+#
+
+# Policy parameters.
+# Lcsk: 186 days (5184000 seconds)
+# Iret(KSK): DS TTL (1h) + DprpP (1h) + retire-safety (2h)
+# Iret(KSK): 4h (14400 seconds)
+# Iret(ZSK): RRSIG TTL (1d) + Dprp (1h) + Dsgn (25d) + retire-safety (2h)
+# Iret(ZSK): 26d3h (2257200 seconds)
+Lcsk=16070400
+IretKSK=14400
+IretZSK=2257200
+IretCSK=$IretZSK
+
+csk_rollover_predecessor_keytimes() {
+ _addtime=$1
+
+ _created=$(key_get KEY1 CREATED)
+ set_addkeytime "KEY1" "PUBLISHED" "${_created}" "${_addtime}"
+ set_addkeytime "KEY1" "SYNCPUBLISH" "${_created}" "${_addtime}"
+ set_addkeytime "KEY1" "ACTIVE" "${_created}" "${_addtime}"
+ [ "$Lcsk" = 0 ] || set_retired_removed "KEY1" "${Lcsk}" "${IretCSK}"
+}
+
+#
+# Zone: step1.csk-roll.autosign.
+#
+set_zone "step1.csk-roll.autosign"
+set_policy "csk-roll" "1" "3600"
+set_server "ns3" "10.53.0.3"
+# Key properties.
+key_clear "KEY1"
+set_keyrole "KEY1" "csk"
+set_keylifetime "KEY1" "${Lcsk}"
+set_keyalgorithm "KEY1" "$DEFAULT_ALGORITHM_NUMBER" "$DEFAULT_ALGORITHM" "$DEFAULT_BITS"
+set_keysigning "KEY1" "yes"
+set_zonesigning "KEY1" "yes"
+# The CSK (KEY1) starts in OMNIPRESENT.
+set_keystate "KEY1" "GOAL" "omnipresent"
+set_keystate "KEY1" "STATE_DNSKEY" "omnipresent"
+set_keystate "KEY1" "STATE_KRRSIG" "omnipresent"
+set_keystate "KEY1" "STATE_ZRRSIG" "omnipresent"
+set_keystate "KEY1" "STATE_DS" "omnipresent"
+# Initially only one key.
+key_clear "KEY2"
+key_clear "KEY3"
+key_clear "KEY4"
+
+# Various signing policy checks.
+check_keys
+check_dnssecstatus "$SERVER" "$POLICY" "$ZONE"
+# This key is immediately published and activated.
+csk_rollover_predecessor_keytimes 0
+check_keytimes
+check_apex
+check_subdomain
+dnssec_verify
+
+# Next key event is when the successor CSK needs to be published.
+# This is Lcsk - Ipub - Dreg.
+# Lcsk: 186d (16070400 seconds)
+# Ipub: 3h (10800 seconds)
+check_next_key_event 16059600
+
+#
+# Zone: step2.csk-roll.autosign.
+#
+set_zone "step2.csk-roll.autosign"
+set_policy "csk-roll" "2" "3600"
+set_server "ns3" "10.53.0.3"
+# New CSK (KEY2) is prepublished (signs DNSKEY RRset, but not yet other RRsets).
+key_clear "KEY2"
+set_keyrole "KEY2" "csk"
+set_keylifetime "KEY2" "16070400"
+set_keyalgorithm "KEY2" "$DEFAULT_ALGORITHM_NUMBER" "$DEFAULT_ALGORITHM" "$DEFAULT_BITS"
+set_keysigning "KEY2" "yes"
+set_zonesigning "KEY2" "no"
+# Key states.
+set_keystate "KEY1" "GOAL" "hidden"
+set_keystate "KEY2" "GOAL" "omnipresent"
+set_keystate "KEY2" "STATE_DNSKEY" "rumoured"
+set_keystate "KEY2" "STATE_KRRSIG" "rumoured"
+set_keystate "KEY2" "STATE_ZRRSIG" "hidden"
+set_keystate "KEY2" "STATE_DS" "hidden"
+
+# Various signing policy checks.
+check_keys
+check_dnssecstatus "$SERVER" "$POLICY" "$ZONE"
+
+# Set expected key times:
+# - This key was activated 4461 hours ago (16059600 seconds).
+csk_rollover_predecessor_keytimes -16059600
+# - The new CSK is published now.
+created=$(key_get KEY2 CREATED)
+set_keytime "KEY2" "PUBLISHED" "${created}"
+# - The new CSK should publish the CDS after the prepublication time.
+# Ipub: 3 hour (10800 seconds)
+Ipub="10800"
+set_addkeytime "KEY2" "SYNCPUBLISH" "${created}" "${Ipub}"
+set_addkeytime "KEY2" "ACTIVE" "${created}" "${Ipub}"
+set_retired_removed "KEY2" "${Lcsk}" "${IretCSK}"
+
+# Continue signing policy checks.
+check_keytimes
+check_apex
+check_subdomain
+dnssec_verify
+
+# Next key event is when the successor CSK becomes OMNIPRESENT. That is the
+# DNSKEY TTL plus the zone propagation delay, plus the publish-safety. For
+# the csk-roll policy, this means 3 hours = 10800 seconds.
+check_next_key_event 10800
+
+#
+# Zone: step3.csk-roll.autosign.
+#
+set_zone "step3.csk-roll.autosign"
+set_policy "csk-roll" "2" "3600"
+set_server "ns3" "10.53.0.3"
+# Swap zone signing role.
+set_zonesigning "KEY1" "no"
+set_zonesigning "KEY2" "yes"
+# CSK (KEY1) will be removed, so moving to UNRETENTIVE.
+set_keystate "KEY1" "STATE_ZRRSIG" "unretentive"
+# New CSK (KEY2) DNSKEY is OMNIPRESENT, so moving ZRRSIG to RUMOURED.
+set_keystate "KEY2" "STATE_DNSKEY" "omnipresent"
+set_keystate "KEY2" "STATE_KRRSIG" "omnipresent"
+set_keystate "KEY2" "STATE_ZRRSIG" "rumoured"
+# The old DS (KEY1) can be withdrawn and the new DS (KEY2) can be introduced.
+set_keystate "KEY1" "STATE_DS" "unretentive"
+set_keystate "KEY2" "STATE_DS" "rumoured"
+
+# Various signing policy checks.
+check_keys
+check_dnssecstatus "$SERVER" "$POLICY" "$ZONE"
+# Check that CDS publication is logged.
+check_cdslog "$DIR" "$ZONE" KEY2
+
+# Set expected key times:
+# - This key was activated 186 days ago (16070400 seconds).
+csk_rollover_predecessor_keytimes -16070400
+# - The new CSK is published three hours ago, CDS must be published now.
+created=$(key_get KEY2 CREATED)
+set_addkeytime "KEY2" "PUBLISHED" "${created}" "-${Ipub}"
+set_keytime "KEY2" "SYNCPUBLISH" "${created}"
+# - Also signatures are being introduced now.
+set_keytime "KEY2" "ACTIVE" "${created}"
+set_retired_removed "KEY2" "${Lcsk}" "${IretCSK}"
+
+# Continue signing policy checks.
+check_keytimes
+check_apex
+# Subdomain still has good signatures of old CSK (KEY1).
+# Set expected zone signing on for KEY1 and off for KEY2,
+# testing whether signatures which are still valid are being reused.
+set_zonesigning "KEY1" "yes"
+set_zonesigning "KEY2" "no"
+check_subdomain
+# Restore the expected zone signing properties.
+set_zonesigning "KEY1" "no"
+set_zonesigning "KEY2" "yes"
+dnssec_verify
+
+# We ignore any parent registration delay, so set the DS publish time to now.
+rndc_checkds "$SERVER" "$DIR" KEY1 "now" "withdrawn" "$ZONE"
+rndc_checkds "$SERVER" "$DIR" KEY2 "now" "published" "$ZONE"
+# 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, which is the parent propagation delay plus the DS TTL
+# plus the retire-safety. For the csk-roll policy this means:
+# 1h + 1h + 2h = 4h = 14400 seconds.
+check_next_key_event 14400
+
+#
+# Zone: step4.csk-roll.autosign.
+#
+set_zone "step4.csk-roll.autosign"
+set_policy "csk-roll" "2" "3600"
+set_server "ns3" "10.53.0.3"
+# The old CSK (KEY1) is no longer signing the DNSKEY RRset.
+set_keysigning "KEY1" "no"
+# The old CSK (KEY1) DS is hidden. We still need to keep the DNSKEY public
+# but can remove the KRRSIG records.
+set_keystate "KEY1" "STATE_KRRSIG" "unretentive"
+set_keystate "KEY1" "STATE_DS" "hidden"
+# The new CSK (KEY2) DS is now OMNIPRESENT.
+set_keystate "KEY2" "STATE_DS" "omnipresent"
+
+# Various signing policy checks.
+check_keys
+check_dnssecstatus "$SERVER" "$POLICY" "$ZONE"
+
+# Set expected key times:
+# - This key was activated 4468 hours ago (16084800 seconds).
+csk_rollover_predecessor_keytimes -16084800
+# - The new CSK started signing 4h ago (14400 seconds).
+created=$(key_get KEY2 CREATED)
+set_addkeytime "KEY2" "ACTIVE" "${created}" -14400
+set_addkeytime "KEY2" "SYNCPUBLISH" "${created}" -14400
+syncpub=$(key_get KEY2 SYNCPUBLISH)
+set_addkeytime "KEY2" "PUBLISHED" "${syncpub}" "-${Ipub}"
+set_retired_removed "KEY2" "${Lcsk}" "${IretCSK}"
+
+# Continue signing policy checks.
+check_keytimes
+check_apex
+check_subdomain
+dnssec_verify
+
+# Next key event is when the KRRSIG enters the HIDDEN state. This is the
+# DNSKEY TTL plus zone propagation delay. For the csk-roll policy this is:
+# 1h + 1h = 7200 seconds.
+check_next_key_event 7200
+
+#
+# Zone: step5.csk-roll.autosign.
+#
+set_zone "step5.csk-roll.autosign"
+set_policy "csk-roll" "2" "3600"
+set_server "ns3" "10.53.0.3"
+# The old CSK (KEY1) KRRSIG records are now all hidden.
+set_keystate "KEY1" "STATE_KRRSIG" "hidden"
+
+# Various signing policy checks.
+check_keys
+check_dnssecstatus "$SERVER" "$POLICY" "$ZONE"
+
+# Set expected key times:
+# - This key was activated 4470 hours ago (16092000 seconds).
+csk_rollover_predecessor_keytimes -16092000
+# - The new CSK started signing 6h ago (21600 seconds).
+created=$(key_get KEY2 CREATED)
+set_addkeytime "KEY2" "ACTIVE" "${created}" -21600
+set_addkeytime "KEY2" "SYNCPUBLISH" "${created}" -21600
+syncpub=$(key_get KEY2 SYNCPUBLISH)
+set_addkeytime "KEY2" "PUBLISHED" "${syncpub}" "-${Ipub}"
+set_retired_removed "KEY2" "${Lcsk}" "${IretCSK}"
+
+# Continue signing policy checks.
+check_keytimes
+check_apex
+check_subdomain
+dnssec_verify
+
+# Next key event is when the DNSKEY can be removed. This is when all ZRRSIG
+# records have been replaced with signatures of the new CSK. We have
+# calculated the interval to be 26d3h of which 4h (Iret(KSK)) plus
+# 2h (DNSKEY TTL + Dprp) have already passed. So next key event is in
+# 26d3h - 4h - 2h = 621h = 2235600 seconds.
+check_next_key_event 2235600
+
+#
+# Zone: step6.csk-roll.autosign.
+#
+set_zone "step6.csk-roll.autosign"
+set_policy "csk-roll" "2" "3600"
+set_server "ns3" "10.53.0.3"
+# The old CSK (KEY1) ZRRSIG records are now all hidden (so the DNSKEY can
+# be removed).
+set_keystate "KEY1" "STATE_DNSKEY" "unretentive"
+set_keystate "KEY1" "STATE_ZRRSIG" "hidden"
+# The new CSK (KEY2) is now fully OMNIPRESENT.
+set_keystate "KEY2" "STATE_ZRRSIG" "omnipresent"
+
+# Various signing policy checks.
+check_keys
+check_dnssecstatus "$SERVER" "$POLICY" "$ZONE"
+
+# Set expected key times
+# - This key was activated 5091 hours ago (18327600 seconds).
+csk_rollover_predecessor_keytimes -18327600
+# - The new CSK is activated 627 hours ago (2257200 seconds).
+created=$(key_get KEY2 CREATED)
+set_addkeytime "KEY2" "ACTIVE" "${created}" -2257200
+set_addkeytime "KEY2" "SYNCPUBLISH" "${created}" -2257200
+syncpub=$(key_get KEY2 SYNCPUBLISH)
+set_addkeytime "KEY2" "PUBLISHED" "${syncpub}" "-${Ipub}"
+set_retired_removed "KEY2" "${Lcsk}" "${IretCSK}"
+
+# Continue signing policy checks.
+check_keytimes
+check_apex
+check_subdomain
+dnssec_verify
+
+# Next key event is when the DNSKEY enters the HIDDEN state. This is the
+# DNSKEY TTL plus zone propagation delay. For the csk-roll policy this is:
+# 1h + 1h = 7200 seconds.
+check_next_key_event 7200
+
+#
+# Zone: step7.csk-roll.autosign.
+#
+set_zone "step7.csk-roll.autosign"
+set_policy "csk-roll" "2" "3600"
+set_server "ns3" "10.53.0.3"
+# The old CSK (KEY1) is now completely HIDDEN.
+set_keystate "KEY1" "STATE_DNSKEY" "hidden"
+
+# Various signing policy checks.
+check_keys
+check_dnssecstatus "$SERVER" "$POLICY" "$ZONE"
+
+# Set expected key times:
+# - This key was activated 5093 hours ago (18334800 seconds).
+csk_rollover_predecessor_keytimes -18334800
+# - The new CSK is activated 629 hours ago (2264400 seconds).
+created=$(key_get KEY2 CREATED)
+set_addkeytime "KEY2" "ACTIVE" "${created}" -2264400
+set_addkeytime "KEY2" "SYNCPUBLISH" "${created}" -2264400
+syncpub=$(key_get KEY2 SYNCPUBLISH)
+set_addkeytime "KEY2" "PUBLISHED" "${syncpub}" "-${Ipub}"
+set_retired_removed "KEY2" "${Lcsk}" "${IretCSK}"
+
+# Continue signing policy checks.
+check_keytimes
+check_apex
+check_subdomain
+dnssec_verify
+
+# Next key event is when the new successor needs to be published.
+# This is the Lcsk, minus time passed since the key started signing,
+# minus the prepublication time.
+# Lcsk: 186d (16070400 seconds)
+# Time passed: 629h (2264400 seconds)
+# Ipub: 3h (10800 seconds)
+check_next_key_event 13795200
+
+#
+# Zone: step8.csk-roll.autosign.
+#
+set_zone "step8.csk-roll.autosign"
+set_policy "csk-roll" "1" "3600"
+set_server "ns3" "10.53.0.3"
+# The old CSK (KEY1) is purged.
+key_clear "KEY1"
+
+# Various signing policy checks.
+check_keys
+check_dnssecstatus "$SERVER" "$POLICY" "$ZONE"
+check_apex
+check_subdomain
+dnssec_verify
+
+#
+# Testing CSK key rollover (2).
+#
+
+# Policy parameters.
+# Lcsk: 186 days (16070400 seconds)
+# Dreg: N/A
+# Iret(KSK): DS TTL (1h) + DprpP (1w) + retire-safety (1h)
+# Iret(KSK): 170h (61200 seconds)
+# Iret(ZSK): RRSIG TTL (1d) + Dprp (1h) + Dsgn (12h) + retire-safety (1h)
+# Iret(ZSK): 38h (136800 seconds)
+Lcsk=16070400
+IretKSK=612000
+IretZSK=136800
+IretCSK=$IretKSK
+
+#
+# Zone: step1.csk-roll2.autosign.
+#
+set_zone "step1.csk-roll2.autosign"
+set_policy "csk-roll2" "1" "3600"
+set_server "ns3" "10.53.0.3"
+# Key properties.
+key_clear "KEY1"
+set_keyrole "KEY1" "csk"
+set_keylifetime "KEY1" "16070400"
+set_keyalgorithm "KEY1" "$DEFAULT_ALGORITHM_NUMBER" "$DEFAULT_ALGORITHM" "$DEFAULT_BITS"
+set_keysigning "KEY1" "yes"
+set_zonesigning "KEY1" "yes"
+# The CSK (KEY1) starts in OMNIPRESENT.
+set_keystate "KEY1" "GOAL" "omnipresent"
+set_keystate "KEY1" "STATE_DNSKEY" "omnipresent"
+set_keystate "KEY1" "STATE_KRRSIG" "omnipresent"
+set_keystate "KEY1" "STATE_ZRRSIG" "omnipresent"
+set_keystate "KEY1" "STATE_DS" "omnipresent"
+# Initially only one key.
+key_clear "KEY2"
+key_clear "KEY3"
+key_clear "KEY4"
+
+# Various signing policy checks.
+check_keys
+check_dnssecstatus "$SERVER" "$POLICY" "$ZONE"
+# This key is immediately published and activated.
+csk_rollover_predecessor_keytimes 0
+check_keytimes
+check_apex
+check_subdomain
+dnssec_verify
+
+# Next key event is when the successor CSK needs to be published.
+# This is Lcsk - Ipub.
+# Lcsk: 186d (16070400 seconds)
+# Ipub: 3h (10800 seconds)
+# Total: 186d3h (16059600 seconds)
+check_next_key_event 16059600
+
+#
+# Zone: step2.csk-roll2.autosign.
+#
+set_zone "step2.csk-roll2.autosign"
+set_policy "csk-roll2" "2" "3600"
+set_server "ns3" "10.53.0.3"
+# New CSK (KEY2) is prepublished (signs DNSKEY RRset, but not yet other RRsets).
+key_clear "KEY2"
+set_keyrole "KEY2" "csk"
+set_keylifetime "KEY2" "16070400"
+set_keyalgorithm "KEY2" "$DEFAULT_ALGORITHM_NUMBER" "$DEFAULT_ALGORITHM" "$DEFAULT_BITS"
+set_keysigning "KEY2" "yes"
+set_zonesigning "KEY2" "no"
+# Key states.
+set_keystate "KEY1" "GOAL" "hidden"
+set_keystate "KEY2" "GOAL" "omnipresent"
+set_keystate "KEY2" "STATE_DNSKEY" "rumoured"
+set_keystate "KEY2" "STATE_KRRSIG" "rumoured"
+set_keystate "KEY2" "STATE_ZRRSIG" "hidden"
+set_keystate "KEY2" "STATE_DS" "hidden"
+
+# Various signing policy checks.
+check_keys
+check_dnssecstatus "$SERVER" "$POLICY" "$ZONE"
+
+# Set expected key times:
+# - This key was activated 4461 hours ago (16059600 seconds).
+csk_rollover_predecessor_keytimes -16059600
+# - The new CSK is published now.
+created=$(key_get KEY2 CREATED)
+set_keytime "KEY2" "PUBLISHED" "${created}"
+# - The new CSK should publish the CDS after the prepublication time.
+# - Ipub: 3 hour (10800 seconds)
+Ipub="10800"
+set_addkeytime "KEY2" "SYNCPUBLISH" "${created}" "${Ipub}"
+set_addkeytime "KEY2" "ACTIVE" "${created}" "${Ipub}"
+set_retired_removed "KEY2" "${Lcsk}" "${IretCSK}"
+
+# Continue signing policy checks.
+check_apex
+check_subdomain
+dnssec_verify
+
+# Next key event is when the successor CSK becomes OMNIPRESENT. That is the
+# DNSKEY TTL plus the zone propagation delay, plus the publish-safety. For
+# the csk-roll2 policy, this means 3h hours = 10800 seconds.
+check_next_key_event 10800
+
+#
+# Zone: step3.csk-roll2.autosign.
+#
+set_zone "step3.csk-roll2.autosign"
+set_policy "csk-roll2" "2" "3600"
+set_server "ns3" "10.53.0.3"
+# CSK (KEY1) can be removed, so move to UNRETENTIVE.
+set_zonesigning "KEY1" "no"
+set_keystate "KEY1" "STATE_ZRRSIG" "unretentive"
+# New CSK (KEY2) DNSKEY is OMNIPRESENT, so move ZRRSIG to RUMOURED state.
+set_zonesigning "KEY2" "yes"
+set_keystate "KEY2" "STATE_DNSKEY" "omnipresent"
+set_keystate "KEY2" "STATE_KRRSIG" "omnipresent"
+set_keystate "KEY2" "STATE_ZRRSIG" "rumoured"
+# The old DS (KEY1) can be withdrawn and the new DS (KEY2) can be introduced.
+set_keystate "KEY1" "STATE_DS" "unretentive"
+set_keystate "KEY2" "STATE_DS" "rumoured"
+
+# Various signing policy checks.
+check_keys
+check_dnssecstatus "$SERVER" "$POLICY" "$ZONE"
+# Check that CDS publication is logged.
+check_cdslog "$DIR" "$ZONE" KEY2
+
+# Set expected key times:
+# - This key was activated 186 days ago (16070400 seconds).
+csk_rollover_predecessor_keytimes -16070400
+# - The new CSK is published three hours ago, CDS must be published now.
+created=$(key_get KEY2 CREATED)
+set_addkeytime "KEY2" "PUBLISHED" "${created}" "-${Ipub}"
+set_keytime "KEY2" "SYNCPUBLISH" "${created}"
+# - Also signatures are being introduced now.
+set_keytime "KEY2" "ACTIVE" "${created}"
+set_retired_removed "KEY2" "${Lcsk}" "${IretCSK}"
+
+# Continue signing policy checks.
+check_keytimes
+check_apex
+# Subdomain still has good signatures of old CSK (KEY1).
+# Set expected zone signing on for KEY1 and off for KEY2,
+# testing whether signatures which are still valid are being reused.
+set_zonesigning "KEY1" "yes"
+set_zonesigning "KEY2" "no"
+check_subdomain
+# Restore the expected zone signing properties.
+set_zonesigning "KEY1" "no"
+set_zonesigning "KEY2" "yes"
+dnssec_verify
+
+# We ignore any parent registration delay, so set the DS publish time to now.
+rndc_checkds "$SERVER" "$DIR" KEY1 "now" "withdrawn" "$ZONE"
+rndc_checkds "$SERVER" "$DIR" KEY2 "now" "published" "$ZONE"
+# Next key event is when the predecessor ZRRSIG records have been replaced
+# with that of the successor and enough time has passed such that the all
+# validators that have such signed RRsets in cache only know about the
+# successor signatures. This is the retire interval: Dsgn plus the
+# maximum zone TTL plus the zone propagation delay plus retire-safety. For the
+# csk-roll2 policy that means: 12h (because 1d validity and refresh within
+# 12 hours) + 1d + 1h + 1h = 38h = 136800 seconds. Prevent intermittent false
+# positives on slow platforms by subtracting the number of seconds which
+# passed between key creation and invoking 'rndc dnssec -checkds'.
+now="$(TZ=UTC date +%s)"
+time_passed=$((now-start_time))
+next_time=$((136800-time_passed))
+check_next_key_event $next_time
+
+#
+# Zone: step4.csk-roll2.autosign.
+#
+set_zone "step4.csk-roll2.autosign"
+set_policy "csk-roll2" "2" "3600"
+set_server "ns3" "10.53.0.3"
+# The old CSK (KEY1) ZRRSIG is now HIDDEN.
+set_keystate "KEY1" "STATE_ZRRSIG" "hidden"
+# The new CSK (KEY2) ZRRSIG is now OMNIPRESENT.
+set_keystate "KEY2" "STATE_ZRRSIG" "omnipresent"
+
+# Various signing policy checks.
+check_keys
+check_dnssecstatus "$SERVER" "$POLICY" "$ZONE"
+
+# Set expected key times:
+# - This key was activated 4502 hours ago (16207200 seconds).
+csk_rollover_predecessor_keytimes -16207200
+# - The new CSK was published 41 hours (147600 seconds) ago.
+created=$(key_get KEY2 CREATED)
+set_addkeytime "KEY2" "PUBLISHED" "${created}" -147600
+published=$(key_get KEY2 PUBLISHED)
+set_addkeytime "KEY2" "SYNCPUBLISH" "${published}" "${Ipub}"
+set_addkeytime "KEY2" "ACTIVE" "${published}" "${Ipub}"
+set_retired_removed "KEY2" "${Lcsk}" "${IretCSK}"
+
+# Continue signing policy checks.
+check_keytimes
+check_apex
+check_subdomain
+dnssec_verify
+
+# 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
+# registration delay plus the retire interval, which is the parent
+# propagation delay plus the DS TTL plus the retire-safety. For the
+# csk-roll2 policy this means: 1w + 1h + 1h = 170h = 612000 seconds.
+# However, 136800 seconds have passed already, so 478800 seconds left.
+check_next_key_event 475200
+
+#
+# Zone: step5.csk-roll2.autosign.
+#
+set_zone "step5.csk-roll2.autosign"
+set_policy "csk-roll2" "2" "3600"
+set_server "ns3" "10.53.0.3"
+# The old CSK (KEY1) DNSKEY can be removed.
+set_keysigning "KEY1" "no"
+set_keystate "KEY1" "STATE_DNSKEY" "unretentive"
+set_keystate "KEY1" "STATE_KRRSIG" "unretentive"
+set_keystate "KEY1" "STATE_DS" "hidden"
+# The new CSK (KEY2) is now fully OMNIPRESENT.
+set_keystate "KEY2" "STATE_DS" "omnipresent"
+
+# Various signing policy checks.
+check_keys
+check_dnssecstatus "$SERVER" "$POLICY" "$ZONE"
+
+# Set expected key times:
+# - This key was activated 4634 hours ago (16682400 seconds).
+csk_rollover_predecessor_keytimes -16682400
+# - The new CSK was published 173 hours (622800 seconds) ago.
+created=$(key_get KEY2 CREATED)
+set_addkeytime "KEY2" "PUBLISHED" "${created}" -622800
+published=$(key_get KEY2 PUBLISHED)
+set_addkeytime "KEY2" "SYNCPUBLISH" "${published}" "${Ipub}"
+set_addkeytime "KEY2" "ACTIVE" "${published}" "${Ipub}"
+set_retired_removed "KEY2" "${Lcsk}" "${IretCSK}"
+
+# Continue signing policy checks.
+check_keytimes
+check_apex
+check_subdomain
+dnssec_verify
+
+# Next key event is when the DNSKEY enters the HIDDEN state. This is the
+# DNSKEY TTL plus zone propagation delay. For the csk-roll policy this is:
+# 1h + 1h = 7200 seconds.
+check_next_key_event 7200
+
+#
+# Zone: step6.csk-roll2.autosign.
+#
+set_zone "step6.csk-roll2.autosign"
+set_policy "csk-roll2" "2" "3600"
+set_server "ns3" "10.53.0.3"
+# The old CSK (KEY1) is now completely HIDDEN.
+set_keystate "KEY1" "STATE_DNSKEY" "hidden"
+set_keystate "KEY1" "STATE_KRRSIG" "hidden"
+
+# Various signing policy checks.
+check_keys
+check_dnssecstatus "$SERVER" "$POLICY" "$ZONE"
+
+# Set expected key times:
+# - This key was activated 4636 hours ago (16689600 seconds).
+csk_rollover_predecessor_keytimes -16689600
+# - The new CSK was published 175 hours (630000 seconds) ago.
+created=$(key_get KEY2 CREATED)
+set_addkeytime "KEY2" "PUBLISHED" "${created}" -630000
+published=$(key_get KEY2 PUBLISHED)
+set_addkeytime "KEY2" "SYNCPUBLISH" "${published}" "${Ipub}"
+set_addkeytime "KEY2" "ACTIVE" "${published}" "${Ipub}"
+set_retired_removed "KEY2" "${Lcsk}" "${IretCSK}"
+
+# Continue signing policy checks.
+check_keytimes
+check_apex
+check_subdomain
+dnssec_verify
+
+# Next key event is when the new successor needs to be published.
+# This is the Lcsk, minus time passed since the key was published.
+# Lcsk: 186d (16070400 seconds)
+# Time passed: 175h (630000 seconds)
+check_next_key_event 15440400
+
+#
+# Zone: step7.csk-roll2.autosign.
+#
+set_zone "step7.csk-roll2.autosign"
+set_policy "csk-roll2" "2" "3600"
+set_server "ns3" "10.53.0.3"
+# The old CSK (KEY1) could have been purged, but purge-keys is disabled.
+
+# Various signing policy checks.
+check_keys
+check_dnssecstatus "$SERVER" "$POLICY" "$ZONE"
+check_apex
+check_subdomain
+dnssec_verify
+
+#
+# Test #2375: Scheduled rollovers are happening faster than they can finish
+#
+set_zone "three-is-a-crowd.kasp"
+set_policy "ksk-doubleksk" "3" "7200"
+set_server "ns3" "10.53.0.3"
+CDNSKEY="no"
+# These are the same time values as calculated for ksk-doubleksk.
+Lksk=5184000
+Lzsk=31536000
+IretKSK=180000
+IretZSK=867600
+# KSK (KEY1) is outgoing.
+key_clear "KEY1"
+set_keyrole "KEY1" "ksk"
+set_keylifetime "KEY1" "${Lksk}"
+set_keyalgorithm "KEY1" "$DEFAULT_ALGORITHM_NUMBER" "$DEFAULT_ALGORITHM" "$DEFAULT_BITS"
+set_keysigning "KEY1" "yes"
+set_zonesigning "KEY1" "yes"
+set_keystate "KEY1" "GOAL" "hidden"
+set_keystate "KEY1" "STATE_DNSKEY" "omnipresent"
+set_keystate "KEY1" "STATE_KRRSIG" "omnipresent"
+set_keystate "KEY1" "STATE_DS" "unretentive"
+# KSK (KEY2) is incoming.
+key_clear "KEY2"
+set_keyrole "KEY2" "ksk"
+set_keylifetime "KEY2" "${Lksk}"
+set_keyalgorithm "KEY2" "$DEFAULT_ALGORITHM_NUMBER" "$DEFAULT_ALGORITHM" "$DEFAULT_BITS"
+set_keysigning "KEY2" "yes"
+set_zonesigning "KEY2" "no"
+set_keystate "KEY2" "GOAL" "omnipresent"
+set_keystate "KEY2" "STATE_DNSKEY" "omnipresent"
+set_keystate "KEY2" "STATE_KRRSIG" "omnipresent"
+set_keystate "KEY2" "STATE_DS" "rumoured"
+# We will introduce the third KSK shortly.
+key_clear "KEY3"
+# ZSK (KEY4).
+key_clear "KEY4"
+set_keyrole "KEY4" "zsk"
+set_keylifetime "KEY4" "${Lzsk}"
+set_keyalgorithm "KEY4" "$DEFAULT_ALGORITHM_NUMBER" "$DEFAULT_ALGORITHM" "$DEFAULT_BITS"
+set_keysigning "KEY4" "no"
+set_zonesigning "KEY4" "yes"
+set_keystate "KEY4" "GOAL" "omnipresent"
+set_keystate "KEY4" "STATE_DNSKEY" "omnipresent"
+set_keystate "KEY4" "STATE_ZRRSIG" "omnipresent"
+# Run preliminary tests.
+check_keys
+check_dnssecstatus "$SERVER" "$POLICY" "$ZONE"
+check_apex
+check_subdomain
+dnssec_verify
+# Roll over KEY2.
+# Set expected key lifetime, which is DNSKEY TTL plus the zone propagation delay,
+# plus the publish-safety: 7200s + 1h + 1d = 97200 seconds.
+set_keylifetime "KEY2" "97200"
+created=$(key_get KEY2 CREATED)
+rndc_rollover "$SERVER" "$DIR" $(key_get KEY2 ID) "${created}" "$ZONE"
+# Update expected number of keys and key states.
+set_keystate "KEY2" "GOAL" "hidden"
+set_policy "ksk-doubleksk" "4" "7200"
+CDNSKEY="no"
+# New KSK (KEY3) is introduced.
+set_keyrole "KEY3" "ksk"
+set_keylifetime "KEY3" "${Lksk}"
+set_keyalgorithm "KEY3" "$DEFAULT_ALGORITHM_NUMBER" "$DEFAULT_ALGORITHM" "$DEFAULT_BITS"
+set_keysigning "KEY3" "yes"
+set_zonesigning "KEY3" "no"
+set_keystate "KEY3" "GOAL" "omnipresent"
+set_keystate "KEY3" "STATE_DNSKEY" "rumoured"
+set_keystate "KEY3" "STATE_KRRSIG" "rumoured"
+set_keystate "KEY3" "STATE_DS" "hidden"
+# Run tests again. We now expect four keys (3x KSK, 1x ZSK).
+check_keys
+check_dnssecstatus "$SERVER" "$POLICY" "$ZONE"
+check_apex
+check_subdomain
+dnssec_verify
+
+# Test dynamic zones that switch to inline-signing.
+set_zone "dynamic2inline.kasp"
+set_policy "default" "1" "3600"
+set_server "ns6" "10.53.0.6"
+# Key properties.
+key_clear "KEY1"
+set_keyrole "KEY1" "csk"
+set_keylifetime "KEY1" "0"
+set_keyalgorithm "KEY1" "13" "ECDSAP256SHA256" "256"
+set_keysigning "KEY1" "yes"
+set_zonesigning "KEY1" "yes"
+key_clear "KEY2"
+key_clear "KEY3"
+key_clear "KEY4"
+
+# The CSK is rumoured.
+set_keystate "KEY1" "GOAL" "omnipresent"
+set_keystate "KEY1" "STATE_DNSKEY" "rumoured"
+set_keystate "KEY1" "STATE_KRRSIG" "rumoured"
+set_keystate "KEY1" "STATE_ZRRSIG" "rumoured"
+set_keystate "KEY1" "STATE_DS" "hidden"
+# Various signing policy checks.
+check_keys
+check_dnssecstatus "$SERVER" "$POLICY" "$ZONE"
+check_apex
+check_subdomain
+dnssec_verify
+
+#
+# Testing algorithm rollover.
+#
+Lksk=0
+Lzsk=0
+IretKSK=0
+IretZSK=0
+
+#
+# Zone: step1.algorithm-roll.kasp
+#
+set_zone "step1.algorithm-roll.kasp"
+set_policy "rsasha256" "2" "3600"
+set_server "ns6" "10.53.0.6"
+# Key properties.
+key_clear "KEY1"
+set_keyrole "KEY1" "ksk"
+set_keylifetime "KEY1" "0"
+set_keyalgorithm "KEY1" "8" "RSASHA256" "2048"
+set_keysigning "KEY1" "yes"
+set_zonesigning "KEY1" "no"
+
+key_clear "KEY2"
+set_keyrole "KEY2" "zsk"
+set_keylifetime "KEY2" "0"
+set_keyalgorithm "KEY2" "8" "RSASHA256" "2048"
+set_keysigning "KEY2" "no"
+set_zonesigning "KEY2" "yes"
+key_clear "KEY3"
+key_clear "KEY4"
+
+# The KSK (KEY1) and ZSK (KEY2) start in OMNIPRESENT.
+set_keystate "KEY1" "GOAL" "omnipresent"
+set_keystate "KEY1" "STATE_DNSKEY" "omnipresent"
+set_keystate "KEY1" "STATE_KRRSIG" "omnipresent"
+set_keystate "KEY1" "STATE_DS" "omnipresent"
+
+set_keystate "KEY2" "GOAL" "omnipresent"
+set_keystate "KEY2" "STATE_DNSKEY" "omnipresent"
+set_keystate "KEY2" "STATE_ZRRSIG" "omnipresent"
+
+# Various signing policy checks.
+check_keys
+check_dnssecstatus "$SERVER" "$POLICY" "$ZONE"
+# These keys are immediately published and activated.
+rollover_predecessor_keytimes 0
+check_keytimes
+check_apex
+check_subdomain
+dnssec_verify
+
+# Next key event is when the successor keys need to be published.
+# Since the lifetime of the keys are unlimited, so default to loadkeys
+# interval.
+check_next_key_event 3600
+
+#
+# Zone: step1.csk-algorithm-roll.kasp
+#
+set_zone "step1.csk-algorithm-roll.kasp"
+set_policy "csk-algoroll" "1" "3600"
+set_server "ns6" "10.53.0.6"
+# Key properties.
+key_clear "KEY1"
+set_keyrole "KEY1" "csk"
+set_keylifetime "KEY1" "0"
+set_keyalgorithm "KEY1" "8" "RSASHA256" "2048"
+set_keysigning "KEY1" "yes"
+set_zonesigning "KEY1" "yes"
+key_clear "KEY2"
+key_clear "KEY3"
+key_clear "KEY4"
+# The CSK (KEY1) starts in OMNIPRESENT.
+set_keystate "KEY1" "GOAL" "omnipresent"
+set_keystate "KEY1" "STATE_DNSKEY" "omnipresent"
+set_keystate "KEY1" "STATE_KRRSIG" "omnipresent"
+set_keystate "KEY1" "STATE_ZRRSIG" "omnipresent"
+set_keystate "KEY1" "STATE_DS" "omnipresent"
+
+# Various signing policy checks.
+check_keys
+check_dnssecstatus "$SERVER" "$POLICY" "$ZONE"
+# This key is immediately published and activated.
+Lcsk=0
+IretCSK=0
+csk_rollover_predecessor_keytimes 0
+check_keytimes
+check_apex
+check_subdomain
+dnssec_verify
+
+# Next key event is when the successor keys need to be published.
+# Since the lifetime of the keys are unlimited, so default to loadkeys
+# interval.
+check_next_key_event 3600
+
+#
+# Testing going insecure.
+#
+
+#
+# Zone step1.going-insecure.kasp
+#
+set_zone "step1.going-insecure.kasp"
+set_policy "unsigning" "2" "7200"
+set_server "ns6" "10.53.0.6"
+
+# Policy parameters.
+# Lksk: 0
+# Lzsk: 60 days (5184000 seconds)
+# Iret(KSK): DS TTL (1d) + DprpP (1h) + retire-safety (1h)
+# Iret(KSK): 1d2h (93600 seconds)
+# Iret(ZSK): RRSIG TTL (1d) + Dprp (5m) + Dsgn (9d) + retire-safety (1h)
+# Iret(ZSK): 10d1h5m (867900 seconds)
+Lksk=0
+Lzsk=5184000
+IretKSK=93600
+IretZSK=867900
+
+init_migration_insecure() {
+ key_clear "KEY1"
+ set_keyrole "KEY1" "ksk"
+ set_keylifetime "KEY1" "${Lksk}"
+ set_keyalgorithm "KEY1" "$DEFAULT_ALGORITHM_NUMBER" "$DEFAULT_ALGORITHM" "$DEFAULT_BITS"
+ set_keysigning "KEY1" "yes"
+ set_zonesigning "KEY1" "no"
+
+ set_keystate "KEY1" "GOAL" "omnipresent"
+ set_keystate "KEY1" "STATE_DNSKEY" "omnipresent"
+ set_keystate "KEY1" "STATE_KRRSIG" "omnipresent"
+ set_keystate "KEY1" "STATE_DS" "omnipresent"
+
+ key_clear "KEY2"
+ set_keyrole "KEY2" "zsk"
+ set_keylifetime "KEY2" "${Lzsk}"
+ set_keyalgorithm "KEY2" "$DEFAULT_ALGORITHM_NUMBER" "$DEFAULT_ALGORITHM" "$DEFAULT_BITS"
+ set_keysigning "KEY2" "no"
+ set_zonesigning "KEY2" "yes"
+
+ set_keystate "KEY2" "GOAL" "omnipresent"
+ set_keystate "KEY2" "STATE_DNSKEY" "omnipresent"
+ set_keystate "KEY2" "STATE_ZRRSIG" "omnipresent"
+
+ key_clear "KEY3"
+ key_clear "KEY4"
+}
+init_migration_insecure
+
+# Various signing policy checks.
+check_keys
+check_dnssecstatus "$SERVER" "$POLICY" "$ZONE"
+
+# We have set the timing metadata to now - 10 days (864000 seconds).
+rollover_predecessor_keytimes -864000
+check_keytimes
+check_apex
+check_subdomain
+dnssec_verify
+
+#
+# Zone step1.going-insecure-dynamic.kasp
+#
+
+set_zone "step1.going-insecure-dynamic.kasp"
+set_dynamic
+set_policy "unsigning" "2" "7200"
+set_server "ns6" "10.53.0.6"
+init_migration_insecure
+
+# Various signing policy checks.
+check_keys
+check_dnssecstatus "$SERVER" "$POLICY" "$ZONE"
+
+# We have set the timing metadata to now - 10 days (864000 seconds).
+rollover_predecessor_keytimes -864000
+check_keytimes
+check_apex
+check_subdomain
+dnssec_verify
+
+#
+# Zone step1.going-straight-to-none.kasp
+#
+set_zone "step1.going-straight-to-none.kasp"
+set_policy "default" "1" "3600"
+set_server "ns6" "10.53.0.6"
+# Key properties.
+set_keyrole "KEY1" "csk"
+set_keylifetime "KEY1" "0"
+set_keyalgorithm "KEY1" "13" "ECDSAP256SHA256" "256"
+set_keysigning "KEY1" "yes"
+set_zonesigning "KEY1" "yes"
+# DNSKEY, RRSIG (ksk), RRSIG (zsk) are published. DS needs to wait.
+set_keystate "KEY1" "GOAL" "omnipresent"
+set_keystate "KEY1" "STATE_DNSKEY" "omnipresent"
+set_keystate "KEY1" "STATE_KRRSIG" "omnipresent"
+set_keystate "KEY1" "STATE_ZRRSIG" "omnipresent"
+set_keystate "KEY1" "STATE_DS" "omnipresent"
+# This policy only has one key.
+key_clear "KEY2"
+key_clear "KEY3"
+key_clear "KEY4"
+
+check_keys
+check_dnssecstatus "$SERVER" "$POLICY" "$ZONE"
+
+# The first key is immediately published and activated.
+created=$(key_get KEY1 CREATED)
+set_keytime "KEY1" "PUBLISHED" "${created}"
+set_keytime "KEY1" "ACTIVE" "${created}"
+set_keytime "KEY1" "SYNCPUBLISH" "${created}"
+# Key lifetime is unlimited, so not setting RETIRED and REMOVED.
+check_keytimes
+
+check_apex
+check_subdomain
+dnssec_verify
+
+# Reconfig dnssec-policy (triggering algorithm roll and other dnssec-policy
+# changes).
+echo_i "reconfig dnssec-policy to trigger algorithm rollover"
+copy_setports ns6/named2.conf.in ns6/named.conf
+rndc_reconfig ns6 10.53.0.6
+
+# Calculate time passed to correctly check for next key events.
+now="$(TZ=UTC date +%s)"
+time_passed=$((now-start_time))
+echo_i "${time_passed} seconds passed between start of tests and reconfig"
+
+# Wait until we have seen "zone_rekey done:" message for this key.
+_wait_for_done_signing() {
+ _zone=$1
+
+ _ksk=$(key_get $2 KSK)
+ _zsk=$(key_get $2 ZSK)
+ if [ "$_ksk" = "yes" ]; then
+ _role="KSK"
+ _expect_type=EXPECT_KRRSIG
+ elif [ "$_zsk" = "yes" ]; then
+ _role="ZSK"
+ _expect_type=EXPECT_ZRRSIG
+ fi
+
+ if [ "$(key_get ${2} $_expect_type)" = "yes" ] && [ "$(key_get $2 $_role)" = "yes" ]; then
+ _keyid=$(key_get $2 ID)
+ _keyalg=$(key_get $2 ALG_STR)
+ echo_i "wait for zone ${_zone} is done signing with $2 ${_zone}/${_keyalg}/${_keyid}"
+ grep "zone_rekey done: key ${_keyid}/${_keyalg}" "${DIR}/named.run" > /dev/null || return 1
+ fi
+
+ return 0
+}
+
+wait_for_done_signing() {
+ n=$((n+1))
+ echo_i "wait for zone ${ZONE} is done signing ($n)"
+ ret=0
+
+ retry_quiet 30 _wait_for_done_signing ${ZONE} KEY1 || ret=1
+ retry_quiet 30 _wait_for_done_signing ${ZONE} KEY2 || ret=1
+ retry_quiet 30 _wait_for_done_signing ${ZONE} KEY3 || ret=1
+ retry_quiet 30 _wait_for_done_signing ${ZONE} KEY4 || ret=1
+
+ test "$ret" -eq 0 || echo_i "failed"
+ status=$((status+ret))
+}
+
+# Test dynamic zones that switch to inline-signing.
+set_zone "dynamic2inline.kasp"
+set_policy "default" "1" "3600"
+set_server "ns6" "10.53.0.6"
+# Key properties.
+key_clear "KEY1"
+set_keyrole "KEY1" "csk"
+set_keylifetime "KEY1" "0"
+set_keyalgorithm "KEY1" "13" "ECDSAP256SHA256" "256"
+set_keysigning "KEY1" "yes"
+set_zonesigning "KEY1" "yes"
+key_clear "KEY2"
+key_clear "KEY3"
+key_clear "KEY4"
+
+# The CSK is rumoured.
+set_keystate "KEY1" "GOAL" "omnipresent"
+set_keystate "KEY1" "STATE_DNSKEY" "rumoured"
+set_keystate "KEY1" "STATE_KRRSIG" "rumoured"
+set_keystate "KEY1" "STATE_ZRRSIG" "rumoured"
+set_keystate "KEY1" "STATE_DS" "hidden"
+# Various signing policy checks.
+check_keys
+check_dnssecstatus "$SERVER" "$POLICY" "$ZONE"
+check_apex
+check_subdomain
+dnssec_verify
+
+#
+# Testing going insecure.
+#
+
+#
+# Zone: step1.going-insecure.kasp
+#
+set_zone "step1.going-insecure.kasp"
+set_policy "insecure" "2" "7200"
+set_server "ns6" "10.53.0.6"
+# Expect a CDS/CDNSKEY Delete Record.
+set_cdsdelete
+
+# Key goal states should be HIDDEN.
+init_migration_insecure
+set_keystate "KEY1" "GOAL" "hidden"
+set_keystate "KEY2" "GOAL" "hidden"
+# The DS may be removed if we are going insecure.
+set_keystate "KEY1" "STATE_DS" "unretentive"
+
+# Various signing policy checks.
+check_keys
+wait_for_done_signing
+check_dnssecstatus "$SERVER" "$POLICY" "$ZONE"
+check_apex
+check_subdomain
+dnssec_verify
+
+# Tell named that the DS has been removed.
+rndc_checkds "$SERVER" "$DIR" "KEY1" "now" "withdrawn" "$ZONE"
+wait_for_done_signing
+check_dnssecstatus "$SERVER" "$POLICY" "$ZONE"
+check_apex
+check_subdomain
+dnssec_verify
+
+# Next key event is when the DS becomes HIDDEN. This happens after the
+# parent propagation delay, retire safety delay, and DS TTL:
+# 1h + 1h + 1d = 26h = 93600 seconds.
+check_next_key_event 93600
+
+#
+# Zone: step2.going-insecure.kasp
+#
+set_zone "step2.going-insecure.kasp"
+set_policy "insecure" "2" "7200"
+set_server "ns6" "10.53.0.6"
+
+# The DS is long enough removed from the zone to be considered HIDDEN.
+# This means the DNSKEY and the KSK signatures can be removed.
+set_keystate "KEY1" "STATE_DS" "hidden"
+set_keystate "KEY1" "STATE_DNSKEY" "unretentive"
+set_keystate "KEY1" "STATE_KRRSIG" "unretentive"
+set_keysigning "KEY1" "no"
+
+set_keystate "KEY2" "STATE_DNSKEY" "unretentive"
+set_keystate "KEY2" "STATE_ZRRSIG" "unretentive"
+set_zonesigning "KEY2" "no"
+
+# Various signing policy checks.
+check_keys
+check_dnssecstatus "$SERVER" "$POLICY" "$ZONE"
+check_apex
+check_subdomain
+
+# Next key event is when the DNSKEY becomes HIDDEN. This happens after the
+# propagation delay, plus DNSKEY TTL:
+# 5m + 2h = 125m = 7500 seconds.
+check_next_key_event 7500
+
+#
+# Zone: step1.going-insecure-dynamic.kasp
+#
+set_zone "step1.going-insecure-dynamic.kasp"
+set_dynamic
+set_policy "insecure" "2" "7200"
+set_server "ns6" "10.53.0.6"
+# Expect a CDS/CDNSKEY Delete Record.
+set_cdsdelete
+
+# Key goal states should be HIDDEN.
+init_migration_insecure
+set_keystate "KEY1" "GOAL" "hidden"
+set_keystate "KEY2" "GOAL" "hidden"
+# The DS may be removed if we are going insecure.
+set_keystate "KEY1" "STATE_DS" "unretentive"
+
+# Various signing policy checks.
+check_keys
+wait_for_done_signing
+check_dnssecstatus "$SERVER" "$POLICY" "$ZONE"
+check_apex
+check_subdomain
+dnssec_verify
+
+# Tell named that the DS has been removed.
+rndc_checkds "$SERVER" "$DIR" "KEY1" "now" "withdrawn" "$ZONE"
+wait_for_done_signing
+check_dnssecstatus "$SERVER" "$POLICY" "$ZONE"
+check_apex
+check_subdomain
+dnssec_verify
+
+# Next key event is when the DS becomes HIDDEN. This happens after the
+# parent propagation delay, retire safety delay, and DS TTL:
+# 1h + 1h + 1d = 26h = 93600 seconds.
+check_next_key_event 93600
+
+#
+# Zone: step2.going-insecure-dynamic.kasp
+#
+set_zone "step2.going-insecure-dynamic.kasp"
+set_dynamic
+set_policy "insecure" "2" "7200"
+set_server "ns6" "10.53.0.6"
+
+# The DS is long enough removed from the zone to be considered HIDDEN.
+# This means the DNSKEY and the KSK signatures can be removed.
+set_keystate "KEY1" "STATE_DS" "hidden"
+set_keystate "KEY1" "STATE_DNSKEY" "unretentive"
+set_keystate "KEY1" "STATE_KRRSIG" "unretentive"
+set_keysigning "KEY1" "no"
+
+set_keystate "KEY2" "STATE_DNSKEY" "unretentive"
+set_keystate "KEY2" "STATE_ZRRSIG" "unretentive"
+set_zonesigning "KEY2" "no"
+
+# Various signing policy checks.
+check_keys
+check_dnssecstatus "$SERVER" "$POLICY" "$ZONE"
+check_apex
+check_subdomain
+
+# Next key event is when the DNSKEY becomes HIDDEN. This happens after the
+# propagation delay, plus DNSKEY TTL:
+# 5m + 2h = 125m = 7500 seconds.
+check_next_key_event 7500
+
+#
+# Zone: step1.going-straight-to-none.kasp
+#
+set_zone "step1.going-straight-to-none.kasp"
+set_policy "none" "1" "3600"
+set_server "ns6" "10.53.0.6"
+
+# The zone will go bogus after signatures expire, but remains validly signed for now.
+
+# Key properties.
+set_keyrole "KEY1" "csk"
+set_keylifetime "KEY1" "0"
+set_keyalgorithm "KEY1" "13" "ECDSAP256SHA256" "256"
+set_keysigning "KEY1" "yes"
+set_zonesigning "KEY1" "yes"
+# DNSKEY, RRSIG (ksk), RRSIG (zsk) are published. DS needs to wait.
+set_keystate "KEY1" "GOAL" "omnipresent"
+set_keystate "KEY1" "STATE_DNSKEY" "omnipresent"
+set_keystate "KEY1" "STATE_KRRSIG" "omnipresent"
+set_keystate "KEY1" "STATE_ZRRSIG" "omnipresent"
+set_keystate "KEY1" "STATE_DS" "omnipresent"
+# This policy only has one key.
+key_clear "KEY2"
+key_clear "KEY3"
+key_clear "KEY4"
+
+# Various signing policy checks.
+check_keys
+check_dnssecstatus "$SERVER" "$POLICY" "$ZONE"
+dnssec_verify
+
+#
+# Testing KSK/ZSK algorithm rollover.
+#
+
+# Policy parameters.
+# Lksk: unlimited
+# Lzsk: unlimited
+Lksk=0
+Lzsk=0
+
+#
+# Zone: step1.algorithm-roll.kasp
+#
+set_zone "step1.algorithm-roll.kasp"
+set_policy "ecdsa256" "4" "3600"
+set_server "ns6" "10.53.0.6"
+# Old RSASHA1 keys.
+key_clear "KEY1"
+set_keyrole "KEY1" "ksk"
+set_keylifetime "KEY1" "0"
+set_keyalgorithm "KEY1" "8" "RSASHA256" "2048"
+set_keysigning "KEY1" "yes"
+set_zonesigning "KEY1" "no"
+
+key_clear "KEY2"
+set_keyrole "KEY2" "zsk"
+set_keylifetime "KEY2" "0"
+set_keyalgorithm "KEY2" "8" "RSASHA256" "2048"
+set_keysigning "KEY2" "no"
+set_zonesigning "KEY2" "yes"
+# New ECDSAP256SHA256 keys.
+key_clear "KEY3"
+set_keyrole "KEY3" "ksk"
+set_keylifetime "KEY3" "0"
+set_keyalgorithm "KEY3" "13" "ECDSAP256SHA256" "256"
+set_keysigning "KEY3" "yes"
+set_zonesigning "KEY3" "no"
+
+key_clear "KEY4"
+set_keyrole "KEY4" "zsk"
+set_keylifetime "KEY4" "0"
+set_keyalgorithm "KEY4" "13" "ECDSAP256SHA256" "256"
+set_keysigning "KEY4" "no"
+set_zonesigning "KEY4" "yes"
+# The RSAHSHA1 keys are outroducing.
+set_keystate "KEY1" "GOAL" "hidden"
+set_keystate "KEY1" "STATE_DNSKEY" "omnipresent"
+set_keystate "KEY1" "STATE_KRRSIG" "omnipresent"
+set_keystate "KEY1" "STATE_DS" "omnipresent"
+set_keystate "KEY2" "GOAL" "hidden"
+set_keystate "KEY2" "STATE_DNSKEY" "omnipresent"
+set_keystate "KEY2" "STATE_ZRRSIG" "omnipresent"
+# The ECDSAP256SHA256 keys are introducing.
+set_keystate "KEY3" "GOAL" "omnipresent"
+set_keystate "KEY3" "STATE_DNSKEY" "rumoured"
+set_keystate "KEY3" "STATE_KRRSIG" "rumoured"
+set_keystate "KEY3" "STATE_DS" "hidden"
+set_keystate "KEY4" "GOAL" "omnipresent"
+set_keystate "KEY4" "STATE_DNSKEY" "rumoured"
+set_keystate "KEY4" "STATE_ZRRSIG" "rumoured"
+
+# Various signing policy checks.
+check_keys
+wait_for_done_signing
+check_dnssecstatus "$SERVER" "$POLICY" "$ZONE"
+
+# Set expected key times:
+# - The old keys are published and activated.
+rollover_predecessor_keytimes 0
+# - KSK must be retired since it no longer matches the policy.
+keyfile=$(key_get KEY1 BASEFILE)
+grep "; Inactive:" "${keyfile}.key" > retired.test${n}.ksk
+retired=$(awk '{print $3}' < retired.test${n}.ksk)
+set_keytime "KEY1" "RETIRED" "${retired}"
+# - The key is removed after the retire interval:
+# IretKSK = TTLds + DprpP + retire-safety
+# TTLds: 2h (7200 seconds)
+# DprpP: 1h (3600 seconds)
+# retire-safety: 2h (7200 seconds)
+# IretKSK: 5h (18000 seconds)
+IretKSK=18000
+set_addkeytime "KEY1" "REMOVED" "${retired}" "${IretKSK}"
+# - ZSK must be retired since it no longer matches the policy.
+keyfile=$(key_get KEY2 BASEFILE)
+grep "; Inactive:" "${keyfile}.key" > retired.test${n}.zsk
+retired=$(awk '{print $3}' < retired.test${n}.zsk)
+set_keytime "KEY2" "RETIRED" "${retired}"
+# - The key is removed after the retire interval:
+# IretZSK = TTLsig + Dprp + Dsgn + retire-safety
+# TTLsig: 6h (21600 seconds)
+# Dprp: 1h (3600 seconds)
+# Dsgn: 25d (2160000 seconds)
+# retire-safety: 2h (7200 seconds)
+# IretZSK: 25d9h (2192400 seconds)
+IretZSK=2192400
+set_addkeytime "KEY2" "REMOVED" "${retired}" "${IretZSK}"
+# - The new KSK is published and activated.
+created=$(key_get KEY3 CREATED)
+set_keytime "KEY3" "PUBLISHED" "${created}"
+set_keytime "KEY3" "ACTIVE" "${created}"
+# - It takes TTLsig + Dprp + publish-safety hours to propagate the zone.
+# TTLsig: 6h (39600 seconds)
+# Dprp: 1h (3600 seconds)
+# publish-safety: 1h (3600 seconds)
+# Ipub: 8h (28800 seconds)
+Ipub=28800
+set_addkeytime "KEY3" "SYNCPUBLISH" "${created}" "${Ipub}"
+# - The new ZSK is published and activated.
+created=$(key_get KEY4 CREATED)
+set_keytime "KEY4" "PUBLISHED" "${created}"
+set_keytime "KEY4" "ACTIVE" "${created}"
+
+# Continue signing policy checks.
+check_keytimes
+check_apex
+check_subdomain
+dnssec_verify
+
+# Next key event is when the ecdsa256 keys have been propagated.
+# This is the DNSKEY TTL plus publish safety plus zone propagation delay:
+# 3 times an hour: 10800 seconds.
+check_next_key_event 10800
+
+#
+# Zone: step2.algorithm-roll.kasp
+#
+set_zone "step2.algorithm-roll.kasp"
+set_policy "ecdsa256" "4" "3600"
+set_server "ns6" "10.53.0.6"
+# The RSAHSHA1 keys are outroducing, but need to stay present until the new
+# algorithm chain of trust has been established. Thus the properties, timings
+# and states of the KEY1 and KEY2 are the same as above.
+
+# The ECDSAP256SHA256 keys are introducing. The DNSKEY RRset is omnipresent,
+# but the zone signatures are not.
+set_keystate "KEY3" "STATE_DNSKEY" "omnipresent"
+set_keystate "KEY3" "STATE_KRRSIG" "omnipresent"
+set_keystate "KEY4" "STATE_DNSKEY" "omnipresent"
+
+# Various signing policy checks.
+check_keys
+wait_for_done_signing
+check_dnssecstatus "$SERVER" "$POLICY" "$ZONE"
+
+# Set expected key times:
+# - The old keys were activated three hours ago (10800 seconds).
+rollover_predecessor_keytimes -10800
+# - KSK must be retired since it no longer matches the policy.
+created=$(key_get KEY1 CREATED)
+set_keytime "KEY1" "RETIRED" "${created}"
+set_addkeytime "KEY1" "REMOVED" "${created}" "${IretKSK}"
+# - ZSK must be retired since it no longer matches the policy.
+created=$(key_get KEY2 CREATED)
+set_keytime "KEY2" "RETIRED" "${created}"
+set_addkeytime "KEY2" "REMOVED" "${created}" "${IretZSK}"
+# - The new keys are published 3 hours ago.
+created=$(key_get KEY3 CREATED)
+set_addkeytime "KEY3" "PUBLISHED" "${created}" -10800
+set_addkeytime "KEY3" "ACTIVE" "${created}" -10800
+published=$(key_get KEY3 PUBLISHED)
+set_addkeytime "KEY3" "SYNCPUBLISH" "${published}" "${Ipub}"
+
+created=$(key_get KEY4 CREATED)
+set_addkeytime "KEY4" "PUBLISHED" "${created}" -10800
+set_addkeytime "KEY4" "ACTIVE" "${created}" -10800
+
+# Continue signing policy checks.
+check_keytimes
+check_apex
+check_subdomain
+dnssec_verify
+
+# Next key event is when all zone signatures are signed with the new
+# algorithm. This is the max-zone-ttl plus zone propagation delay
+# plus retire safety: 6h + 1h + 2h. But three hours have already passed
+# (the time it took to make the DNSKEY omnipresent), so the next event
+# should be scheduled in 6 hour: 21600 seconds. Prevent intermittent
+# false positives on slow platforms by subtracting the number of seconds
+# which passed between key creation and invoking 'rndc reconfig'.
+next_time=$((21600-time_passed))
+check_next_key_event $next_time
+
+#
+# Zone: step3.algorithm-roll.kasp
+#
+set_zone "step3.algorithm-roll.kasp"
+set_policy "ecdsa256" "4" "3600"
+set_server "ns6" "10.53.0.6"
+# The ECDSAP256SHA256 keys are introducing.
+set_keystate "KEY4" "STATE_ZRRSIG" "omnipresent"
+# The DS can be swapped.
+set_keystate "KEY1" "STATE_DS" "unretentive"
+set_keystate "KEY3" "STATE_DS" "rumoured"
+
+# Various signing policy checks.
+check_keys
+wait_for_done_signing
+check_dnssecstatus "$SERVER" "$POLICY" "$ZONE"
+# Check that CDS publication is logged.
+check_cdslog "$DIR" "$ZONE" KEY3
+
+# Set expected key times:
+# - The old keys were activated 9 hours ago (32400 seconds).
+rollover_predecessor_keytimes -32400
+# - And retired 6 hours ago (21600 seconds).
+created=$(key_get KEY1 CREATED)
+set_addkeytime "KEY1" "RETIRED" "${created}" -21600
+retired=$(key_get KEY1 RETIRED)
+set_addkeytime "KEY1" "REMOVED" "${retired}" "${IretKSK}"
+
+created=$(key_get KEY2 CREATED)
+set_addkeytime "KEY2" "RETIRED" "${created}" -21600
+retired=$(key_get KEY2 RETIRED)
+set_addkeytime "KEY2" "REMOVED" "${retired}" "${IretZSK}"
+# - The new keys are published 9 hours ago.
+created=$(key_get KEY3 CREATED)
+set_addkeytime "KEY3" "PUBLISHED" "${created}" -32400
+set_addkeytime "KEY3" "ACTIVE" "${created}" -32400
+published=$(key_get KEY3 PUBLISHED)
+set_addkeytime "KEY3" "SYNCPUBLISH" "${published}" ${Ipub}
+
+created=$(key_get KEY4 CREATED)
+set_addkeytime "KEY4" "PUBLISHED" "${created}" -32400
+set_addkeytime "KEY4" "ACTIVE" "${created}" -32400
+
+# Continue signing policy checks.
+check_keytimes
+check_apex
+check_subdomain
+dnssec_verify
+
+# Tell named we "saw" the parent swap the DS and see if the next key event is
+# scheduled at the correct time.
+rndc_checkds "$SERVER" "$DIR" KEY1 "now" "withdrawn" "$ZONE"
+rndc_checkds "$SERVER" "$DIR" KEY3 "now" "published" "$ZONE"
+# Next key event is when the DS becomes OMNIPRESENT. This happens after the
+# parent propagation delay, retire safety delay, and DS TTL:
+# 1h + 2h + 2h = 5h = 18000 seconds.
+check_next_key_event 18000
+
+#
+# Zone: step4.algorithm-roll.kasp
+#
+set_zone "step4.algorithm-roll.kasp"
+set_policy "ecdsa256" "4" "3600"
+set_server "ns6" "10.53.0.6"
+# The old DS is HIDDEN, we can remove the old algorithm DNSKEY/RRSIG records.
+set_keysigning "KEY1" "no"
+set_keystate "KEY1" "STATE_DNSKEY" "unretentive"
+set_keystate "KEY1" "STATE_KRRSIG" "unretentive"
+set_keystate "KEY1" "STATE_DS" "hidden"
+
+set_zonesigning "KEY2" "no"
+set_keystate "KEY2" "GOAL" "hidden"
+set_keystate "KEY2" "STATE_DNSKEY" "unretentive"
+set_keystate "KEY2" "STATE_ZRRSIG" "unretentive"
+# The ECDSAP256SHA256 DS is now OMNIPRESENT.
+set_keystate "KEY3" "STATE_DS" "omnipresent"
+
+# Various signing policy checks.
+check_keys
+wait_for_done_signing
+check_dnssecstatus "$SERVER" "$POLICY" "$ZONE"
+
+# Set expected key times:
+# - The old keys were activated 38 hours ago (136800 seconds).
+rollover_predecessor_keytimes -136800
+# - And retired 35 hours ago (126000 seconds).
+created=$(key_get KEY1 CREATED)
+set_addkeytime "KEY1" "RETIRED" "${created}" -126000
+retired=$(key_get KEY1 RETIRED)
+set_addkeytime "KEY1" "REMOVED" "${retired}" "${IretKSK}"
+
+created=$(key_get KEY2 CREATED)
+set_addkeytime "KEY2" "RETIRED" "${created}" -126000
+retired=$(key_get KEY2 RETIRED)
+set_addkeytime "KEY2" "REMOVED" "${retired}" "${IretZSK}"
+
+# - The new keys are published 38 hours ago.
+created=$(key_get KEY3 CREATED)
+set_addkeytime "KEY3" "PUBLISHED" "${created}" -136800
+set_addkeytime "KEY3" "ACTIVE" "${created}" -136800
+published=$(key_get KEY3 PUBLISHED)
+set_addkeytime "KEY3" "SYNCPUBLISH" "${published}" ${Ipub}
+
+created=$(key_get KEY4 CREATED)
+set_addkeytime "KEY4" "PUBLISHED" "${created}" -136800
+set_addkeytime "KEY4" "ACTIVE" "${created}" -136800
+
+# Continue signing policy checks.
+check_keytimes
+check_apex
+check_subdomain
+dnssec_verify
+
+# Next key event is when the old DNSKEY becomes HIDDEN. This happens after the
+# DNSKEY TTL plus zone propagation delay (2h).
+check_next_key_event 7200
+
+#
+# Zone: step5.algorithm-roll.kasp
+#
+set_zone "step5.algorithm-roll.kasp"
+set_policy "ecdsa256" "4" "3600"
+set_server "ns6" "10.53.0.6"
+# The DNSKEY becomes HIDDEN.
+set_keystate "KEY1" "STATE_DNSKEY" "hidden"
+set_keystate "KEY1" "STATE_KRRSIG" "hidden"
+set_keystate "KEY2" "STATE_DNSKEY" "hidden"
+
+# Various signing policy checks.
+check_keys
+wait_for_done_signing
+check_dnssecstatus "$SERVER" "$POLICY" "$ZONE"
+
+# Set expected key times:
+# - The old keys were activated 40 hours ago (144000 seconds)
+rollover_predecessor_keytimes -144000
+# - And retired 37 hours ago (133200 seconds).
+created=$(key_get KEY1 CREATED)
+set_addkeytime "KEY1" "RETIRED" "${created}" -133200
+retired=$(key_get KEY1 RETIRED)
+set_addkeytime "KEY1" "REMOVED" "${retired}" "${IretKSK}"
+
+created=$(key_get KEY2 CREATED)
+set_addkeytime "KEY2" "RETIRED" "${created}" -133200
+retired=$(key_get KEY2 RETIRED)
+set_addkeytime "KEY2" "REMOVED" "${retired}" "${IretZSK}"
+
+# The new keys are published 40 hours ago.
+created=$(key_get KEY3 CREATED)
+set_addkeytime "KEY3" "PUBLISHED" "${created}" -144000
+set_addkeytime "KEY3" "ACTIVE" "${created}" -144000
+published=$(key_get KEY3 PUBLISHED)
+set_addkeytime "KEY3" "SYNCPUBLISH" "${published}" ${Ipub}
+
+created=$(key_get KEY4 CREATED)
+set_addkeytime "KEY4" "PUBLISHED" "${created}" -144000
+set_addkeytime "KEY4" "ACTIVE" "${created}" -144000
+
+# Continue signing policy checks.
+check_keytimes
+check_apex
+check_subdomain
+dnssec_verify
+
+# Next key event is when the RSASHA1 signatures become HIDDEN. This happens
+# after the max-zone-ttl plus zone propagation delay plus retire safety
+# (6h + 1h + 2h) minus the time already passed since the UNRETENTIVE state has
+# been reached (2h): 9h - 2h = 7h = 25200 seconds. Prevent intermittent
+# false positives on slow platforms by subtracting the number of seconds
+# which passed between key creation and invoking 'rndc reconfig'.
+next_time=$((25200-time_passed))
+check_next_key_event $next_time
+
+#
+# Zone: step6.algorithm-roll.kasp
+#
+set_zone "step6.algorithm-roll.kasp"
+set_policy "ecdsa256" "4" "3600"
+set_server "ns6" "10.53.0.6"
+# The old zone signatures (KEY2) should now also be HIDDEN.
+set_keystate "KEY2" "STATE_ZRRSIG" "hidden"
+
+# Various signing policy checks.
+check_keys
+wait_for_done_signing
+check_dnssecstatus "$SERVER" "$POLICY" "$ZONE"
+
+# Set expected key times:
+# - The old keys were activated 47 hours ago (169200 seconds)
+rollover_predecessor_keytimes -169200
+# - And retired 44 hours ago (158400 seconds).
+created=$(key_get KEY1 CREATED)
+set_addkeytime "KEY1" "RETIRED" "${created}" -158400
+retired=$(key_get KEY1 RETIRED)
+set_addkeytime "KEY1" "REMOVED" "${retired}" "${IretKSK}"
+
+created=$(key_get KEY2 CREATED)
+set_addkeytime "KEY2" "RETIRED" "${created}" -158400
+retired=$(key_get KEY2 RETIRED)
+set_addkeytime "KEY2" "REMOVED" "${retired}" "${IretZSK}"
+
+# The new keys are published 47 hours ago.
+created=$(key_get KEY3 CREATED)
+set_addkeytime "KEY3" "PUBLISHED" "${created}" -169200
+set_addkeytime "KEY3" "ACTIVE" "${created}" -169200
+published=$(key_get KEY3 PUBLISHED)
+set_addkeytime "KEY3" "SYNCPUBLISH" "${published}" ${Ipub}
+
+created=$(key_get KEY4 CREATED)
+set_addkeytime "KEY4" "PUBLISHED" "${created}" -169200
+set_addkeytime "KEY4" "ACTIVE" "${created}" -169200
+
+# Continue signing policy checks.
+check_keytimes
+check_apex
+check_subdomain
+dnssec_verify
+
+# Next key event is never since we established the policy and the keys have
+# an unlimited lifetime. Fallback to the default loadkeys interval.
+check_next_key_event 3600
+
+#
+# Testing CSK algorithm rollover.
+#
+
+# Policy parameters.
+# Lcsk: unlimited
+Lcksk=0
+
+#
+# Zone: step1.csk-algorithm-roll.kasp
+#
+set_zone "step1.csk-algorithm-roll.kasp"
+set_policy "csk-algoroll" "2" "3600"
+set_server "ns6" "10.53.0.6"
+# Old RSASHA1 key.
+key_clear "KEY1"
+set_keyrole "KEY1" "csk"
+set_keylifetime "KEY1" "0"
+set_keyalgorithm "KEY1" "8" "RSASHA256" "2048"
+set_keysigning "KEY1" "yes"
+set_zonesigning "KEY1" "yes"
+# New ECDSAP256SHA256 key.
+key_clear "KEY2"
+set_keyrole "KEY2" "csk"
+set_keylifetime "KEY2" "0"
+set_keyalgorithm "KEY2" "$DEFAULT_ALGORITHM_NUMBER" "$DEFAULT_ALGORITHM" "$DEFAULT_BITS"
+set_keysigning "KEY2" "yes"
+set_zonesigning "KEY2" "yes"
+key_clear "KEY3"
+key_clear "KEY4"
+# The RSAHSHA1 key is outroducing.
+set_keystate "KEY1" "GOAL" "hidden"
+set_keystate "KEY1" "STATE_DNSKEY" "omnipresent"
+set_keystate "KEY1" "STATE_KRRSIG" "omnipresent"
+set_keystate "KEY1" "STATE_ZRRSIG" "omnipresent"
+set_keystate "KEY1" "STATE_DS" "omnipresent"
+# The ECDSAP256SHA256 key is introducing.
+set_keystate "KEY2" "GOAL" "omnipresent"
+set_keystate "KEY2" "STATE_DNSKEY" "rumoured"
+set_keystate "KEY2" "STATE_KRRSIG" "rumoured"
+set_keystate "KEY2" "STATE_ZRRSIG" "rumoured"
+set_keystate "KEY2" "STATE_DS" "hidden"
+
+# Various signing policy checks.
+check_keys
+wait_for_done_signing
+check_dnssecstatus "$SERVER" "$POLICY" "$ZONE"
+
+# Set expected key times:
+# - CSK must be retired since it no longer matches the policy.
+csk_rollover_predecessor_keytimes 0
+keyfile=$(key_get KEY1 BASEFILE)
+grep "; Inactive:" "${keyfile}.key" > retired.test${n}.ksk
+retired=$(awk '{print $3}' < retired.test${n}.ksk)
+set_keytime "KEY1" "RETIRED" "${retired}"
+# - The key is removed after the retire interval:
+# IretZSK = TTLsig + Dprp + Dsgn + retire-safety
+# TTLsig: 6h (21600 seconds)
+# Dprp: 1h (3600 seconds)
+# Dsgn: 25d (2160000 seconds)
+# retire-safety: 2h (7200 seconds)
+# IretZSK: 25d9h (2192400 seconds)
+IretCSK=2192400
+set_addkeytime "KEY1" "REMOVED" "${retired}" "${IretCSK}"
+# - The new CSK is published and activated.
+created=$(key_get KEY2 CREATED)
+set_keytime "KEY2" "PUBLISHED" "${created}"
+set_keytime "KEY2" "ACTIVE" "${created}"
+# - It takes TTLsig + Dprp + publish-safety hours to propagate the zone.
+# TTLsig: 6h (39600 seconds)
+# Dprp: 1h (3600 seconds)
+# publish-safety: 1h (3600 seconds)
+# Ipub: 8h (28800 seconds)
+Ipub=28800
+set_addkeytime "KEY2" "SYNCPUBLISH" "${created}" "${Ipub}"
+
+# Continue signing policy checks.
+check_keytimes
+check_apex
+check_subdomain
+dnssec_verify
+
+# Next key event is when the new key has been propagated.
+# This is the DNSKEY TTL plus publish safety plus zone propagation delay:
+# 3 times an hour: 10800 seconds.
+check_next_key_event 10800
+
+#
+# Zone: step2.csk-algorithm-roll.kasp
+#
+set_zone "step2.csk-algorithm-roll.kasp"
+set_policy "csk-algoroll" "2" "3600"
+set_server "ns6" "10.53.0.6"
+# The RSAHSHA1 key is outroducing, but need to stay present until the new
+# algorithm chain of trust has been established. Thus the properties, timings
+# and states of KEY1 is the same as above.
+#
+# The ECDSAP256SHA256 keys are introducing. The DNSKEY RRset is omnipresent,
+# but the zone signatures are not.
+set_keystate "KEY2" "STATE_DNSKEY" "omnipresent"
+set_keystate "KEY2" "STATE_KRRSIG" "omnipresent"
+
+# Various signing policy checks.
+check_keys
+wait_for_done_signing
+check_dnssecstatus "$SERVER" "$POLICY" "$ZONE"
+
+# Set expected key times:
+# - The old key was activated three hours ago (10800 seconds).
+csk_rollover_predecessor_keytimes -10800
+# - CSK must be retired since it no longer matches the policy.
+created=$(key_get KEY1 CREATED)
+set_keytime "KEY1" "RETIRED" "${created}"
+set_addkeytime "KEY1" "REMOVED" "${created}" "${IretCSK}"
+# - The new key was published 3 hours ago.
+created=$(key_get KEY2 CREATED)
+set_addkeytime "KEY2" "PUBLISHED" "${created}" -10800
+set_addkeytime "KEY2" "ACTIVE" "${created}" -10800
+published=$(key_get KEY2 PUBLISHED)
+set_addkeytime "KEY2" "SYNCPUBLISH" "${published}" "${Ipub}"
+
+# Continue signing policy checks.
+check_keytimes
+check_apex
+check_subdomain
+dnssec_verify
+
+# Next key event is when all zone signatures are signed with the new
+# algorithm. This is the max-zone-ttl plus zone propagation delay
+# plus retire safety: 6h + 1h + 2h. But three hours have already passed
+# (the time it took to make the DNSKEY omnipresent), so the next event
+# should be scheduled in 6 hour: 21600 seconds. Prevent intermittent
+# false positives on slow platforms by subtracting the number of seconds
+# which passed between key creation and invoking 'rndc reconfig'.
+next_time=$((21600-time_passed))
+check_next_key_event $next_time
+
+#
+# Zone: step3.csk-algorithm-roll.kasp
+#
+set_zone "step3.csk-algorithm-roll.kasp"
+set_policy "csk-algoroll" "2" "3600"
+set_server "ns6" "10.53.0.6"
+# The RSAHSHA1 key is outroducing, and it is time to swap the DS.
+# The ECDSAP256SHA256 key is introducing. The DNSKEY RRset and all signatures
+# are now omnipresent, so the DS can be introduced.
+set_keystate "KEY2" "STATE_ZRRSIG" "omnipresent"
+# The old DS (KEY1) can be withdrawn and the new DS (KEY2) can be introduced.
+set_keystate "KEY1" "STATE_DS" "unretentive"
+set_keystate "KEY2" "STATE_DS" "rumoured"
+
+# Various signing policy checks.
+check_keys
+wait_for_done_signing
+check_dnssecstatus "$SERVER" "$POLICY" "$ZONE"
+# Check that CDS publication is logged.
+check_cdslog "$DIR" "$ZONE" KEY2
+
+# Set expected key times:
+# - The old key was activated 9 hours ago (32400 seconds).
+csk_rollover_predecessor_keytimes -32400
+# - And was retired 6 hours ago (21600 seconds).
+created=$(key_get KEY1 CREATED)
+set_addkeytime "KEY1" "RETIRED" "${created}" -21600
+retired=$(key_get KEY1 RETIRED)
+set_addkeytime "KEY1" "REMOVED" "${retired}" "${IretCSK}"
+# - The new key was published 9 hours ago.
+created=$(key_get KEY2 CREATED)
+set_addkeytime "KEY2" "PUBLISHED" "${created}" -32400
+set_addkeytime "KEY2" "ACTIVE" "${created}" -32400
+published=$(key_get KEY2 PUBLISHED)
+set_addkeytime "KEY2" "SYNCPUBLISH" "${published}" "${Ipub}"
+
+# Continue signing policy checks.
+check_keytimes
+check_apex
+check_subdomain
+dnssec_verify
+
+# We ignore any parent registration delay, so set the DS publish time to now.
+rndc_checkds "$SERVER" "$DIR" KEY1 "now" "withdrawn" "$ZONE"
+rndc_checkds "$SERVER" "$DIR" KEY2 "now" "published" "$ZONE"
+# Next key event is when the DS becomes OMNIPRESENT. This happens after the
+# parent propagation delay, retire safety delay, and DS TTL:
+# 1h + 2h + 2h = 5h = 18000 seconds.
+check_next_key_event 18000
+
+#
+# Zone: step4.csk-algorithm-roll.kasp
+#
+set_zone "step4.csk-algorithm-roll.kasp"
+set_policy "csk-algoroll" "2" "3600"
+set_server "ns6" "10.53.0.6"
+# The old DS is HIDDEN, we can remove the old algorithm DNSKEY/RRSIG records.
+set_keysigning "KEY1" "no"
+set_zonesigning "KEY1" "no"
+set_keystate "KEY1" "STATE_DNSKEY" "unretentive"
+set_keystate "KEY1" "STATE_KRRSIG" "unretentive"
+set_keystate "KEY1" "STATE_ZRRSIG" "unretentive"
+set_keystate "KEY1" "STATE_DS" "hidden"
+# The ECDSAP256SHA256 DS is now OMNIPRESENT.
+set_keystate "KEY2" "STATE_DS" "omnipresent"
+
+# Various signing policy checks.
+check_keys
+wait_for_done_signing
+check_dnssecstatus "$SERVER" "$POLICY" "$ZONE"
+
+# Set expected key times:
+# - The old key was activated 38 hours ago (136800 seconds)
+csk_rollover_predecessor_keytimes -136800
+# - And retired 35 hours ago (126000 seconds).
+created=$(key_get KEY1 CREATED)
+set_addkeytime "KEY1" "RETIRED" "${created}" -126000
+retired=$(key_get KEY1 RETIRED)
+set_addkeytime "KEY1" "REMOVED" "${retired}" "${IretCSK}"
+# - The new key was published 38 hours ago.
+created=$(key_get KEY2 CREATED)
+set_addkeytime "KEY2" "PUBLISHED" "${created}" -136800
+set_addkeytime "KEY2" "ACTIVE" "${created}" -136800
+published=$(key_get KEY2 PUBLISHED)
+set_addkeytime "KEY2" "SYNCPUBLISH" "${published}" ${Ipub}
+
+# Continue signing policy checks.
+check_keytimes
+check_apex
+check_subdomain
+dnssec_verify
+
+# Next key event is when the old DNSKEY becomes HIDDEN. This happens after the
+# DNSKEY TTL plus zone propagation delay (2h).
+check_next_key_event 7200
+
+#
+# Zone: step5.csk-algorithm-roll.kasp
+#
+set_zone "step5.csk-algorithm-roll.kasp"
+set_policy "csk-algoroll" "2" "3600"
+set_server "ns6" "10.53.0.6"
+# The DNSKEY becomes HIDDEN.
+set_keystate "KEY1" "STATE_DNSKEY" "hidden"
+set_keystate "KEY1" "STATE_KRRSIG" "hidden"
+
+# Various signing policy checks.
+check_keys
+wait_for_done_signing
+check_dnssecstatus "$SERVER" "$POLICY" "$ZONE"
+
+# Set expected key times:
+# - The old key was activated 40 hours ago (144000 seconds)
+csk_rollover_predecessor_keytimes -144000
+# - And retired 37 hours ago (133200 seconds).
+created=$(key_get KEY1 CREATED)
+set_addkeytime "KEY1" "RETIRED" "${created}" -133200
+retired=$(key_get KEY1 RETIRED)
+set_addkeytime "KEY1" "REMOVED" "${retired}" "${IretCSK}"
+# - The new key was published 40 hours ago.
+created=$(key_get KEY2 CREATED)
+set_addkeytime "KEY2" "PUBLISHED" "${created}" -144000
+set_addkeytime "KEY2" "ACTIVE" "${created}" -144000
+published=$(key_get KEY2 PUBLISHED)
+set_addkeytime "KEY2" "SYNCPUBLISH" "${published}" ${Ipub}
+
+# Continue signing policy checks.
+check_keytimes
+check_apex
+check_subdomain
+dnssec_verify
+
+# Next key event is when the RSASHA1 signatures become HIDDEN. This happens
+# after the max-zone-ttl plus zone propagation delay plus retire safety
+# (6h + 1h + 2h) minus the time already passed since the UNRETENTIVE state has
+# been reached (2h): 9h - 2h = 7h = 25200 seconds. Prevent intermittent
+# false positives on slow platforms by subtracting the number of seconds
+# which passed between key creation and invoking 'rndc reconfig'.
+next_time=$((25200-time_passed))
+check_next_key_event $next_time
+
+#
+# Zone: step6.csk-algorithm-roll.kasp
+#
+set_zone "step6.csk-algorithm-roll.kasp"
+set_policy "csk-algoroll" "2" "3600"
+set_server "ns6" "10.53.0.6"
+# The zone signatures should now also be HIDDEN.
+set_keystate "KEY1" "STATE_ZRRSIG" "hidden"
+
+# Various signing policy checks.
+check_keys
+wait_for_done_signing
+check_dnssecstatus "$SERVER" "$POLICY" "$ZONE"
+
+# Set expected key times:
+# - The old keys were activated 47 hours ago (169200 seconds)
+csk_rollover_predecessor_keytimes -169200
+# - And retired 44 hours ago (158400 seconds).
+created=$(key_get KEY1 CREATED)
+set_addkeytime "KEY1" "RETIRED" "${created}" -158400
+retired=$(key_get KEY1 RETIRED)
+set_addkeytime "KEY1" "REMOVED" "${retired}" "${IretCSK}"
+# - The new key was published 47 hours ago.
+created=$(key_get KEY2 CREATED)
+set_addkeytime "KEY2" "PUBLISHED" "${created}" -169200
+set_addkeytime "KEY2" "ACTIVE" "${created}" -169200
+published=$(key_get KEY2 PUBLISHED)
+set_addkeytime "KEY2" "SYNCPUBLISH" "${published}" ${Ipub}
+
+# Continue signing policy checks.
+check_keytimes
+check_apex
+check_subdomain
+dnssec_verify
+
+# Next key event is never since we established the policy and the keys have
+# an unlimited lifetime. Fallback to the default loadkeys interval.
+check_next_key_event 3600
+
+_check_soa_ttl() {
+ dig_with_opts @10.53.0.6 example SOA > dig.out.ns6.test$n.soa2 || return 1
+ soa1=$(awk '$4 == "SOA" { print $7 }' dig.out.ns6.test$n.soa1)
+ soa2=$(awk '$4 == "SOA" { print $7 }' dig.out.ns6.test$n.soa2)
+ ttl1=$(awk '$4 == "SOA" { print $2 }' dig.out.ns6.test$n.soa1)
+ ttl2=$(awk '$4 == "SOA" { print $2 }' dig.out.ns6.test$n.soa2)
+ test ${soa1:-1000} -lt ${soa2:-0} || return 1
+ test ${ttl1:-0} -eq $1 || return 1
+ test ${ttl2:-0} -eq $2 || return 1
+}
+
+n=$((n+1))
+echo_i "Check that 'rndc reload' of just the serial updates the signed instance ($n)"
+TSIG=
+ret=0
+dig_with_opts @10.53.0.6 example SOA > dig.out.ns6.test$n.soa1 || ret=1
+cp ns6/example2.db.in ns6/example.db || ret=1
+nextpart ns6/named.run > /dev/null
+rndccmd 10.53.0.6 reload || ret=1
+wait_for_log 3 "all zones loaded" ns6/named.run
+# Check that the SOA SERIAL increases and check the TTLs (should be 300 as
+# defined in ns6/example2.db.in).
+retry_quiet 10 _check_soa_ttl 300 300 || ret=1
+test "$ret" -eq 0 || echo_i "failed"
+status=$((status+ret))
+
+n=$((n+1))
+echo_i "Check that restart with zone changes and deleted journal works ($n)"
+TSIG=
+ret=0
+dig_with_opts @10.53.0.6 example SOA > dig.out.ns6.test$n.soa1 || ret=1
+stop_server --use-rndc --port ${CONTROLPORT} ns6
+# TTL of all records change from 300 to 400
+cp ns6/example3.db.in ns6/example.db || ret=1
+rm ns6/example.db.jnl
+nextpart ns6/named.run > /dev/null
+start_server --noclean --restart --port ${PORT} ns6
+wait_for_log 3 "all zones loaded" ns6/named.run
+# Check that the SOA SERIAL increases and check the TTLs (should be changed
+# from 300 to 400 as defined in ns6/example3.db.in).
+retry_quiet 10 _check_soa_ttl 300 400 || ret=1
+test "$ret" -eq 0 || echo_i "failed"
+status=$((status+ret))
+
+echo_i "exit status: $status"
+[ $status -eq 0 ] || exit 1
diff --git a/bin/tests/system/kasp/tests_sh_kasp.py b/bin/tests/system/kasp/tests_sh_kasp.py
new file mode 100644
index 0000000..d01125d
--- /dev/null
+++ b/bin/tests/system/kasp/tests_sh_kasp.py
@@ -0,0 +1,14 @@
+# 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.
+
+
+def test_kasp(run_tests_sh):
+ run_tests_sh()