--- /dev/null
+../rollover/common.py
\ No newline at end of file
--- /dev/null
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * SPDX-License-Identifier: MPL-2.0
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, you can obtain one at https://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+dnssec-policy "csk-roll1" {
+ signatures-refresh P5D;
+ signatures-validity 30d;
+ signatures-validity-dnskey 30d;
+
+ dnskey-ttl 1h;
+ publish-safety PT1H;
+ retire-safety 2h;
+ purge-keys PT1H;
+
+ cds-digest-types { "sha-384"; }; // use a different digest type for testing purposes
+ 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;
+};
--- /dev/null
+../../rollover/ns3/named.common.conf.j2
\ No newline at end of file
--- /dev/null
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * SPDX-License-Identifier: MPL-2.0
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, you can obtain one at https://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+include "kasp.conf";
+include "named.common.conf";
+
+zone "step1.csk-roll1.autosign" {
+ type primary;
+ file "step1.csk-roll1.autosign.db";
+ dnssec-policy "csk-roll1";
+};
+zone "step2.csk-roll1.autosign" {
+ type primary;
+ file "step2.csk-roll1.autosign.db";
+ dnssec-policy "csk-roll1";
+};
+zone "step3.csk-roll1.autosign" {
+ type primary;
+ file "step3.csk-roll1.autosign.db";
+ dnssec-policy "csk-roll1";
+};
+zone "step4.csk-roll1.autosign" {
+ type primary;
+ file "step4.csk-roll1.autosign.db";
+ dnssec-policy "csk-roll1";
+};
+zone "step5.csk-roll1.autosign" {
+ type primary;
+ file "step5.csk-roll1.autosign.db";
+ dnssec-policy "csk-roll1";
+};
+zone "step6.csk-roll1.autosign" {
+ type primary;
+ file "step6.csk-roll1.autosign.db";
+ dnssec-policy "csk-roll1";
+};
+zone "step7.csk-roll1.autosign" {
+ type primary;
+ file "step7.csk-roll1.autosign.db";
+ dnssec-policy "csk-roll1";
+};
+zone "step8.csk-roll1.autosign" {
+ type primary;
+ file "step8.csk-roll1.autosign.db";
+ dnssec-policy "csk-roll1";
+};
--- /dev/null
+../../rollover/ns3/template.db.in
\ No newline at end of file
--- /dev/null
+#!/bin/sh -e
+
+# Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+#
+# SPDX-License-Identifier: MPL-2.0
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, you can obtain one at https://mozilla.org/MPL/2.0/.
+#
+# See the COPYRIGHT file distributed with this work for additional
+# information regarding copyright ownership.
+
+# shellcheck source=conf.sh
+. ../conf.sh
+
+cd "ns3"
+
+setup() {
+ zone="$1"
+ echo_i "setting up zone: $zone"
+ zonefile="${zone}.db"
+ infile="${zone}.db.infile"
+ echo "$zone" >>zones
+}
+
+# Set in the key state files the Predecessor/Successor fields.
+# Key $1 is the predecessor of key $2.
+key_successor() {
+ id1=$(keyfile_to_key_id "$1")
+ id2=$(keyfile_to_key_id "$2")
+ echo "Predecessor: ${id1}" >>"${2}.state"
+ echo "Successor: ${id2}" >>"${1}.state"
+}
+
+# Make lines shorter by storing key states in environment variables.
+H="HIDDEN"
+R="RUMOURED"
+O="OMNIPRESENT"
+U="UNRETENTIVE"
+
+#
+# The zones at csk-roll1.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-roll1.autosign
+TactN="now-7d"
+keytimes="-P ${TactN} -A ${TactN}"
+CSK=$($KEYGEN -k csk-roll1 -l kasp.conf $keytimes $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 -G "cdnskey,cds:sha-384" -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-roll1.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) = now - Lcsk + Ipub = now - 186d + 3h
+# = now - 4464h + 3h = now - 4461h
+TactN="now-4461h"
+keytimes="-P ${TactN} -A ${TactN}"
+CSK=$($KEYGEN -k csk-roll1 -l kasp.conf $keytimes $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 -G "cdnskey,cds:sha-384" -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-roll1.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
+#
+# Tpub(N) = now - Lcsk = now - 186d
+# Tact(N) = now - Lcsk + Dprp + TTLsig = now - 4439h
+# Tret(N) = now
+# Trem(N) = now + IretZ = now + 26d3h = now + 627h
+# Tpub(N+1) = now - Ipub = now - 3h
+# Tact(N+1) = Tret(N)
+# Tret(N+1) = now + Lcsk = now + 186d = now + 186d
+# Trem(N+1) = now + Lcsk + IretZ = now + 186d + 26d3h =
+# = now + 5091h
+TpubN="now-186d"
+TactN="now-4439h"
+TretN="now"
+TremN="now+627h"
+TpubN1="now-3h"
+TactN1="${TretN}"
+TretN1="now+186d"
+TremN1="now+5091h"
+keytimes="-P ${TpubN} -P sync ${TactN} -A ${TpubN} -I ${TretN} -D ${TremN} -D sync ${TactN1}"
+newtimes="-P ${TpubN1} -P sync ${TactN1} -A ${TactN1} -I ${TretN1} -D ${TremN1}"
+CSK1=$($KEYGEN -k csk-roll1 -l kasp.conf $keytimes $zone 2>keygen.out.$zone.1)
+CSK2=$($KEYGEN -k csk-roll1 -l kasp.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 -G "cdnskey,cds:sha-384" -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-roll1.autosign
+# According to RFC 7583:
+# Trem(N) = Tret(N) - Iret + IretZ
+# now = Tsbm(N+1) + Iret
+#
+# Lcsk: 186d
+# Iret: 4h
+# IretZ: 26d3h
+#
+# Tpub(N) = now - Iret - Lcsk = now - 4h - 186d = now - 4468h
+# Tret(N) = now - Iret = now - 4h = now - 4h
+# Trem(N) = now - Iret + IretZ = now - 4h + 26d3h
+# = now + 623h
+# Tpub(N+1) = now - Iret - IpubC = now - 4h - 3h = now - 7h
+# Tact(N+1) = Tret(N)
+# Tret(N+1) = now - Iret + Lcsk = now - 4h + 186d = now + 4460h
+# Trem(N+1) = now - Iret + Lcsk + IretZ = now - 4h + 186d + 26d3h
+# = now + 5087h
+TpubN="now-4468h"
+TactN="now-4443h"
+TretN="now-4h"
+TremN="now+623h"
+TpubN1="now-7h"
+TactN1="${TretN}"
+TretN1="now+4460h"
+TremN1="now+5087h"
+keytimes="-P ${TpubN} -P sync ${TactN} -A ${TpubN} -I ${TretN} -D ${TremN} -D sync ${TactN1}"
+newtimes="-P ${TpubN1} -P sync ${TactN1} -A ${TactN1} -I ${TretN1} -D ${TremN1}"
+CSK1=$($KEYGEN -k csk-roll1 -l kasp.conf $keytimes $zone 2>keygen.out.$zone.1)
+CSK2=$($KEYGEN -k csk-roll1 -l kasp.conf $newtimes $zone 2>keygen.out.$zone.2)
+$SETTIME -s -g $H -k $O $TactN -r $O $TactN -d $U $TactN1 -z $U $TactN1 -D ds $TactN1 "$CSK1" >settime.out.$zone.1 2>&1
+$SETTIME -s -g $O -k $O $TactN1 -r $O $TactN1 -d $R $TactN1 -z $R $TactN1 -P ds $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 -G "cdnskey,cds:sha-384" -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-roll1.autosign
+# Subtract DNSKEY TTL plus zone propagation delay from all the times (2h).
+TpubN="now-4470h"
+TactN="now-4445h"
+TretN="now-6h"
+TremN="now+621h"
+TpubN1="now-9h"
+TactN1="${TretN}"
+TretN1="now+4458h"
+TremN1="now+5085h"
+keytimes="-P ${TpubN} -P sync ${TactN} -A ${TpubN} -I ${TretN} -D ${TremN} -D sync ${TactN1}"
+newtimes="-P ${TpubN1} -P sync ${TactN1} -A ${TactN1} -I ${TretN1} -D ${TremN1}"
+CSK1=$($KEYGEN -k csk-roll1 -l kasp.conf $keytimes $zone 2>keygen.out.$zone.1)
+CSK2=$($KEYGEN -k csk-roll1 -l kasp.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 $TactN1 -r $O $TactN1 -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 -G "cdnskey,cds:sha-384" -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-roll1.autosign
+# According to RFC 7583:
+# Trem(N) = Tret(N) + IretZ
+# Tret(N) = Tact(N) + Lcsk
+#
+# Lcsk: 186d
+# Iret: 4h
+# IretZ: 26d3h
+#
+# Tpub(N) = now - IretZ - Lcsk = now - 627h - 186d
+# = now - 627h - 4464h = now - 5091h
+# Tact(N) = now - 627h - 186d
+# Tret(N) = now - IretZ = now - 627h
+# Trem(N) = now
+# Tpub(N+1) = now - IretZ - Ipub = now - 627h - 3h = now - 630h
+# Tact(N+1) = Tret(N)
+# Tret(N+1) = now - IretZ + Lcsk = now - 627h + 186d = now + 3837h
+# Trem(N+1) = now + Lcsk = now + 186d
+TpubN="now-5091h"
+TactN="now-5066h"
+TretN="now-627h"
+TremN="now"
+TpubN1="now-630h"
+TactN1="${TretN}"
+TretN1="now+3837h"
+TremN1="now+186d"
+keytimes="-P ${TpubN} -P sync ${TactN} -A ${TpubN} -I ${TretN} -D ${TremN} -D sync ${TactN1}"
+newtimes="-P ${TpubN1} -P sync ${TactN1} -A ${TactN1} -I ${TretN1} -D ${TremN1}"
+CSK1=$($KEYGEN -k csk-roll1 -l kasp.conf $keytimes $zone 2>keygen.out.$zone.1)
+CSK2=$($KEYGEN -k csk-roll1 -l kasp.conf $newtimes $zone 2>keygen.out.$zone.2)
+$SETTIME -s -g $H -k $O $TactN -r $H $TremN -d $H $TremN -z $U $TactN1 "$CSK1" >settime.out.$zone.1 2>&1
+$SETTIME -s -g $O -k $O $TactN1 -r $O $TactN1 -d $O $TremN -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 -G "cdnskey,cds:sha-384" -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-roll1.autosign
+# Subtract DNSKEY TTL plus zone propagation delay from all the times (2h).
+TpubN="now-5093h"
+TactN="now-5068h"
+TretN="now-629h"
+TremN="now-2h"
+TpubN1="now-632h"
+TactN1="${TretN}"
+TretN1="now+3835h"
+TremN1="now+4462h"
+keytimes="-P ${TpubN} -P sync ${TactN} -A ${TpubN} -I ${TretN} -D ${TremN} -D sync ${TactN1}"
+newtimes="-P ${TpubN1} -P sync ${TactN1} -A ${TactN1} -I ${TretN1} -D ${TremN1}"
+CSK1=$($KEYGEN -k csk-roll1 -l kasp.conf $keytimes $zone 2>keygen.out.$zone.1)
+CSK2=$($KEYGEN -k csk-roll1 -l kasp.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 $TactN1 -r $O $TactN1 -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 -G "cdnskey,cds:sha-384" -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-roll1.autosign
+TpubN="now-5094h"
+TactN="now-5069h"
+TretN="now-630h"
+TremN="now-3h"
+TpubN1="now-633h"
+TactN1="${TretN}"
+TretN1="now+3834h"
+TremN1="now+4461h"
+# Subtract purge-keys interval from all the times (1h).
+keytimes="-P ${TpubN} -P sync ${TactN} -A ${TpubN} -I ${TretN} -D ${TremN} -D sync ${TactN1}"
+newtimes="-P ${TpubN1} -P sync ${TactN1} -A ${TactN1} -I ${TretN1} -D ${TremN1}"
+CSK1=$($KEYGEN -k csk-roll1 -l kasp.conf $keytimes $zone 2>keygen.out.$zone.1)
+CSK2=$($KEYGEN -k csk-roll1 -l kasp.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 $TactN1 -r $O $TactN1 -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 -G "cdnskey,cds:sha-384" -s now-1h -e now+30d -o $zone -O raw -f "${zonefile}.signed" $infile >signer.out.$zone.1 2>&1
--- /dev/null
+# Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+#
+# SPDX-License-Identifier: MPL-2.0
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, you can obtain one at https://mozilla.org/MPL/2.0/.
+#
+# See the COPYRIGHT file distributed with this work for additional
+# information regarding copyright ownership.
+
+# pylint: disable=redefined-outer-name,unused-import
+
+from datetime import timedelta
+
+import isctest
+from isctest.kasp import Ipub, Iret
+from common import (
+ pytestmark,
+ alg,
+ size,
+ TIMEDELTA,
+)
+
+
+CDSS = ["CDNSKEY", "CDS (SHA-384)"]
+CONFIG = {
+ "dnskey-ttl": TIMEDELTA["PT1H"],
+ "ds-ttl": TIMEDELTA["PT1H"],
+ "max-zone-ttl": TIMEDELTA["P1D"],
+ "parent-propagation-delay": TIMEDELTA["PT1H"],
+ "publish-safety": TIMEDELTA["PT1H"],
+ "purge-keys": TIMEDELTA["PT1H"],
+ "retire-safety": TIMEDELTA["PT2H"],
+ "signatures-refresh": TIMEDELTA["P5D"],
+ "signatures-validity": TIMEDELTA["P30D"],
+ "zone-propagation-delay": TIMEDELTA["PT1H"],
+}
+POLICY = "csk-roll1"
+CSK_LIFETIME = timedelta(days=31 * 6)
+LIFETIME_POLICY = int(CSK_LIFETIME.total_seconds())
+IPUB = Ipub(CONFIG)
+IRETZSK = Iret(CONFIG)
+IRETKSK = Iret(CONFIG, zsk=False, ksk=True)
+KEYTTLPROP = CONFIG["dnskey-ttl"] + CONFIG["zone-propagation-delay"]
+SIGNDELAY = IRETZSK - IRETKSK - KEYTTLPROP
+OFFSETS = {}
+OFFSETS["step1-p"] = -int(timedelta(days=7).total_seconds())
+OFFSETS["step2-p"] = -int(CSK_LIFETIME.total_seconds() - IPUB.total_seconds())
+OFFSETS["step2-s"] = 0
+OFFSETS["step3-p"] = -int(CSK_LIFETIME.total_seconds())
+OFFSETS["step3-s"] = -int(IPUB.total_seconds())
+OFFSETS["step4-p"] = OFFSETS["step3-p"] - int(IRETKSK.total_seconds())
+OFFSETS["step4-s"] = OFFSETS["step3-s"] - int(IRETKSK.total_seconds())
+OFFSETS["step5-p"] = OFFSETS["step4-p"] - int(KEYTTLPROP.total_seconds())
+OFFSETS["step5-s"] = OFFSETS["step4-s"] - int(KEYTTLPROP.total_seconds())
+OFFSETS["step6-p"] = OFFSETS["step5-p"] - int(SIGNDELAY.total_seconds())
+OFFSETS["step6-s"] = OFFSETS["step5-s"] - int(SIGNDELAY.total_seconds())
+OFFSETS["step7-p"] = OFFSETS["step6-p"] - int(KEYTTLPROP.total_seconds())
+OFFSETS["step7-s"] = OFFSETS["step6-s"] - int(KEYTTLPROP.total_seconds())
+OFFSETS["step8-p"] = OFFSETS["step7-p"] - int(CONFIG["purge-keys"].total_seconds())
+OFFSETS["step8-s"] = OFFSETS["step7-s"] - int(CONFIG["purge-keys"].total_seconds())
+
+
+def test_csk_roll1_step1(alg, size, servers):
+ step = {
+ # Introduce the first key. This will immediately be active.
+ "zone": "step1.csk-roll1.autosign",
+ "cdss": CDSS,
+ "keyprops": [
+ f"csk {LIFETIME_POLICY} {alg} {size} goal:omnipresent dnskey:omnipresent krrsig:omnipresent zrrsig:omnipresent ds:omnipresent offset:{OFFSETS['step1-p']}",
+ ],
+ # Next key event is when the successor CSK needs to be published
+ # minus time already elapsed. This is Lcsk - Ipub + Dreg (we ignore
+ # registration delay).
+ "nextev": CSK_LIFETIME - IPUB - timedelta(days=7),
+ }
+ isctest.kasp.check_rollover_step(servers["ns3"], CONFIG, POLICY, step)
+
+
+def test_csk_roll1_step2(alg, size, servers):
+ step = {
+ # Successor CSK is prepublished (signs DNSKEY RRset, but not yet
+ # other RRsets).
+ # CSK1 goal: omnipresent -> hidden
+ # CSK2 goal: hidden -> omnipresent
+ # CSK2 dnskey: hidden -> rumoured
+ # CSK2 krrsig: hidden -> rumoured
+ "zone": "step2.csk-roll1.autosign",
+ "cdss": CDSS,
+ "keyprops": [
+ f"csk {LIFETIME_POLICY} {alg} {size} goal:hidden dnskey:omnipresent krrsig:omnipresent zrrsig:omnipresent ds:omnipresent offset:{OFFSETS['step2-p']}",
+ f"csk {LIFETIME_POLICY} {alg} {size} goal:omnipresent dnskey:rumoured krrsig:rumoured zrrsig:hidden ds:hidden offset:{OFFSETS['step2-s']}",
+ ],
+ "keyrelationships": [0, 1],
+ # Next key event is when the successor CSK becomes OMNIPRESENT.
+ "nextev": IPUB,
+ }
+ isctest.kasp.check_rollover_step(servers["ns3"], CONFIG, POLICY, step)
+
+
+def test_csk_roll1_step3(alg, size, servers):
+ step = {
+ # Successor CSK becomes omnipresent, meaning we can start signing
+ # the remainder of the zone with the successor CSK, and we can
+ # submit the DS.
+ "zone": "step3.csk-roll1.autosign",
+ "cdss": CDSS,
+ # Predecessor CSK will be removed, so moving to UNRETENTIVE.
+ # CSK1 zrrsig: omnipresent -> unretentive
+ # Successor CSK DNSKEY is OMNIPRESENT, so moving ZRRSIG to RUMOURED.
+ # CSK2 dnskey: rumoured -> omnipresent
+ # CSK2 krrsig: rumoured -> omnipresent
+ # CSK2 zrrsig: hidden -> rumoured
+ # The predecessor DS can be withdrawn and the successor DS can be
+ # introduced.
+ # CSK1 ds: omnipresent -> unretentive
+ # CSK2 ds: hidden -> rumoured
+ "keyprops": [
+ f"csk {LIFETIME_POLICY} {alg} {size} goal:hidden dnskey:omnipresent krrsig:omnipresent zrrsig:unretentive ds:unretentive offset:{OFFSETS['step3-p']}",
+ f"csk {LIFETIME_POLICY} {alg} {size} goal:omnipresent dnskey:omnipresent krrsig:omnipresent zrrsig:rumoured ds:rumoured offset:{OFFSETS['step3-s']}",
+ ],
+ "keyrelationships": [0, 1],
+ # Next key event is when the predecessor DS has been replaced with
+ # the successor DS and enough time has passed such that the all
+ # validators that have this DS RRset cached only know about the
+ # successor DS. This is the the retire interval.
+ "nextev": IRETKSK,
+ # Set 'smooth' to true so expected signatures of subdomain are
+ # from the predecessor ZSK.
+ "smooth": True,
+ }
+ isctest.kasp.check_rollover_step(servers["ns3"], CONFIG, POLICY, step)
+
+
+def test_csk_roll1_step4(alg, size, servers):
+ step = {
+ "zone": "step4.csk-roll1.autosign",
+ "cdss": CDSS,
+ # The predecessor CSK is no longer signing the DNSKEY RRset.
+ # CSK1 krrsig: omnipresent -> unretentive
+ # The predecessor DS is hidden. The successor DS is now omnipresent.
+ # CSK1 ds: unretentive -> hidden
+ # CSK2 ds: rumoured -> omnipresent
+ "keyprops": [
+ f"csk {LIFETIME_POLICY} {alg} {size} goal:hidden dnskey:omnipresent krrsig:unretentive zrrsig:unretentive ds:hidden offset:{OFFSETS['step4-p']}",
+ f"csk {LIFETIME_POLICY} {alg} {size} goal:omnipresent dnskey:omnipresent krrsig:omnipresent zrrsig:rumoured ds:omnipresent offset:{OFFSETS['step4-s']}",
+ ],
+ "keyrelationships": [0, 1],
+ # Next key event is when the KRRSIG enters the HIDDEN state.
+ # This is the DNSKEY TTL plus zone propagation delay.
+ "nextev": KEYTTLPROP,
+ # We already swapped the DS in the previous step, so disable ds-swap.
+ "ds-swap": False,
+ }
+ isctest.kasp.check_rollover_step(servers["ns3"], CONFIG, POLICY, step)
+
+
+def test_csk_roll1_step5(alg, size, servers):
+ step = {
+ "zone": "step5.csk-roll1.autosign",
+ "cdss": CDSS,
+ # The predecessor KRRSIG records are now all hidden.
+ # CSK1 krrsig: unretentive -> hidden
+ "keyprops": [
+ f"csk {LIFETIME_POLICY} {alg} {size} goal:hidden dnskey:omnipresent krrsig:hidden zrrsig:unretentive ds:hidden offset:{OFFSETS['step5-p']}",
+ f"csk {LIFETIME_POLICY} {alg} {size} goal:omnipresent dnskey:omnipresent krrsig:omnipresent zrrsig:rumoured ds:omnipresent offset:{OFFSETS['step5-s']}",
+ ],
+ "keyrelationships": [0, 1],
+ # 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.
+ "nextev": SIGNDELAY,
+ }
+ isctest.kasp.check_rollover_step(servers["ns3"], CONFIG, POLICY, step)
+
+
+def test_csk_roll1_step6(alg, size, servers):
+ step = {
+ "zone": "step6.csk-roll1.autosign",
+ "cdss": CDSS,
+ # The predecessor ZRRSIG records are now all hidden (so the DNSKEY
+ # can be removed).
+ # CSK1 dnskey: omnipresent -> unretentive
+ # CSK1 zrrsig: unretentive -> hidden
+ # CSK2 zrrsig: rumoured -> omnipresent
+ "keyprops": [
+ f"csk {LIFETIME_POLICY} {alg} {size} goal:hidden dnskey:unretentive krrsig:hidden zrrsig:hidden ds:hidden offset:{OFFSETS['step6-p']}",
+ f"csk {LIFETIME_POLICY} {alg} {size} goal:omnipresent dnskey:omnipresent krrsig:omnipresent zrrsig:omnipresent ds:omnipresent offset:{OFFSETS['step6-s']}",
+ ],
+ "keyrelationships": [0, 1],
+ # Next key event is when the DNSKEY enters the HIDDEN state.
+ # This is the DNSKEY TTL plus zone propagation delay.
+ "nextev": KEYTTLPROP,
+ }
+ isctest.kasp.check_rollover_step(servers["ns3"], CONFIG, POLICY, step)
+
+
+def test_csk_roll1_step7(alg, size, servers):
+ step = {
+ "zone": "step7.csk-roll1.autosign",
+ "cdss": CDSS,
+ # The predecessor CSK is now completely HIDDEN.
+ "keyprops": [
+ f"csk {LIFETIME_POLICY} {alg} {size} goal:hidden dnskey:hidden krrsig:hidden zrrsig:hidden ds:hidden offset:{OFFSETS['step7-p']}",
+ f"csk {LIFETIME_POLICY} {alg} {size} goal:omnipresent dnskey:omnipresent krrsig:omnipresent zrrsig:omnipresent ds:omnipresent offset:{OFFSETS['step7-s']}",
+ ],
+ "keyrelationships": [0, 1],
+ # 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.
+ "nextev": CSK_LIFETIME - IRETZSK - IPUB - KEYTTLPROP,
+ }
+ isctest.kasp.check_rollover_step(servers["ns3"], CONFIG, POLICY, step)
+
+
+def test_csk_roll1_step8(alg, size, servers):
+ step = {
+ "zone": "step8.csk-roll1.autosign",
+ "cdss": CDSS,
+ "keyprops": [
+ f"csk {LIFETIME_POLICY} {alg} {size} goal:omnipresent dnskey:omnipresent krrsig:omnipresent zrrsig:omnipresent ds:omnipresent offset:{OFFSETS['step8-s']}",
+ ],
+ "nextev": None,
+ }
+ isctest.kasp.check_rollover_step(servers["ns3"], CONFIG, POLICY, step)
parent-ds-ttl 3600;
parent-propagation-delay PT1H;
};
-
-dnssec-policy "csk-roll1" {
- signatures-refresh P5D;
- signatures-validity 30d;
- signatures-validity-dnskey 30d;
-
- dnskey-ttl 1h;
- publish-safety PT1H;
- retire-safety 2h;
- purge-keys PT1H;
-
- cds-digest-types { "sha-384"; }; // use a different digest type for testing purposes
- 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;
-};
/* Use same policy as KSK rollover test zones. */
dnssec-policy "ksk-doubleksk";
};
-
-/*
- * Zones for testing CSK rollover steps.
- */
-zone "step1.csk-roll1.autosign" {
- type primary;
- file "step1.csk-roll1.autosign.db";
- dnssec-policy "csk-roll1";
-};
-zone "step2.csk-roll1.autosign" {
- type primary;
- file "step2.csk-roll1.autosign.db";
- dnssec-policy "csk-roll1";
-};
-zone "step3.csk-roll1.autosign" {
- type primary;
- file "step3.csk-roll1.autosign.db";
- dnssec-policy "csk-roll1";
-};
-zone "step4.csk-roll1.autosign" {
- type primary;
- file "step4.csk-roll1.autosign.db";
- dnssec-policy "csk-roll1";
-};
-zone "step5.csk-roll1.autosign" {
- type primary;
- file "step5.csk-roll1.autosign.db";
- dnssec-policy "csk-roll1";
-};
-zone "step6.csk-roll1.autosign" {
- type primary;
- file "step6.csk-roll1.autosign.db";
- dnssec-policy "csk-roll1";
-};
-zone "step7.csk-roll1.autosign" {
- type primary;
- file "step7.csk-roll1.autosign.db";
- dnssec-policy "csk-roll1";
-};
-zone "step8.csk-roll1.autosign" {
- type primary;
- file "step8.csk-roll1.autosign.db";
- dnssec-policy "csk-roll1";
-};
private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$ZSK" >>"$infile"
cp $infile $zonefile
$SIGNER -S -x -G "cds:sha-256" -s now-1h -e now+2w -o $zone -O raw -f "${zonefile}.signed" $infile >signer.out.$zone.1 2>&1
-
-#
-# The zones at csk-roll1.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-roll1.autosign
-TactN="now-7d"
-keytimes="-P ${TactN} -A ${TactN}"
-CSK=$($KEYGEN -k csk-roll1 -l kasp.conf $keytimes $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 -G "cdnskey,cds:sha-384" -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-roll1.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) = now - Lcsk + Ipub = now - 186d + 3h
-# = now - 4464h + 3h = now - 4461h
-TactN="now-4461h"
-keytimes="-P ${TactN} -A ${TactN}"
-CSK=$($KEYGEN -k csk-roll1 -l kasp.conf $keytimes $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 -G "cdnskey,cds:sha-384" -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-roll1.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
-#
-# Tpub(N) = now - Lcsk = now - 186d
-# Tact(N) = now - Lcsk + Dprp + TTLsig = now - 4439h
-# Tret(N) = now
-# Trem(N) = now + IretZ = now + 26d3h = now + 627h
-# Tpub(N+1) = now - Ipub = now - 3h
-# Tact(N+1) = Tret(N)
-# Tret(N+1) = now + Lcsk = now + 186d = now + 186d
-# Trem(N+1) = now + Lcsk + IretZ = now + 186d + 26d3h =
-# = now + 5091h
-TpubN="now-186d"
-TactN="now-4439h"
-TretN="now"
-TremN="now+627h"
-TpubN1="now-3h"
-TactN1="${TretN}"
-TretN1="now+186d"
-TremN1="now+5091h"
-keytimes="-P ${TpubN} -P sync ${TactN} -A ${TpubN} -I ${TretN} -D ${TremN} -D sync ${TactN1}"
-newtimes="-P ${TpubN1} -P sync ${TactN1} -A ${TactN1} -I ${TretN1} -D ${TremN1}"
-CSK1=$($KEYGEN -k csk-roll1 -l kasp.conf $keytimes $zone 2>keygen.out.$zone.1)
-CSK2=$($KEYGEN -k csk-roll1 -l kasp.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 -G "cdnskey,cds:sha-384" -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-roll1.autosign
-# According to RFC 7583:
-# Trem(N) = Tret(N) - Iret + IretZ
-# now = Tsbm(N+1) + Iret
-#
-# Lcsk: 186d
-# Iret: 4h
-# IretZ: 26d3h
-#
-# Tpub(N) = now - Iret - Lcsk = now - 4h - 186d = now - 4468h
-# Tret(N) = now - Iret = now - 4h = now - 4h
-# Trem(N) = now - Iret + IretZ = now - 4h + 26d3h
-# = now + 623h
-# Tpub(N+1) = now - Iret - IpubC = now - 4h - 3h = now - 7h
-# Tact(N+1) = Tret(N)
-# Tret(N+1) = now - Iret + Lcsk = now - 4h + 186d = now + 4460h
-# Trem(N+1) = now - Iret + Lcsk + IretZ = now - 4h + 186d + 26d3h
-# = now + 5087h
-TpubN="now-4468h"
-TactN="now-4443h"
-TretN="now-4h"
-TremN="now+623h"
-TpubN1="now-7h"
-TactN1="${TretN}"
-TretN1="now+4460h"
-TremN1="now+5087h"
-keytimes="-P ${TpubN} -P sync ${TactN} -A ${TpubN} -I ${TretN} -D ${TremN} -D sync ${TactN1}"
-newtimes="-P ${TpubN1} -P sync ${TactN1} -A ${TactN1} -I ${TretN1} -D ${TremN1}"
-CSK1=$($KEYGEN -k csk-roll1 -l kasp.conf $keytimes $zone 2>keygen.out.$zone.1)
-CSK2=$($KEYGEN -k csk-roll1 -l kasp.conf $newtimes $zone 2>keygen.out.$zone.2)
-$SETTIME -s -g $H -k $O $TactN -r $O $TactN -d $U $TactN1 -z $U $TactN1 -D ds $TactN1 "$CSK1" >settime.out.$zone.1 2>&1
-$SETTIME -s -g $O -k $O $TactN1 -r $O $TactN1 -d $R $TactN1 -z $R $TactN1 -P ds $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 -G "cdnskey,cds:sha-384" -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-roll1.autosign
-# Subtract DNSKEY TTL plus zone propagation delay from all the times (2h).
-TpubN="now-4470h"
-TactN="now-4445h"
-TretN="now-6h"
-TremN="now+621h"
-TpubN1="now-9h"
-TactN1="${TretN}"
-TretN1="now+4458h"
-TremN1="now+5085h"
-keytimes="-P ${TpubN} -P sync ${TactN} -A ${TpubN} -I ${TretN} -D ${TremN} -D sync ${TactN1}"
-newtimes="-P ${TpubN1} -P sync ${TactN1} -A ${TactN1} -I ${TretN1} -D ${TremN1}"
-CSK1=$($KEYGEN -k csk-roll1 -l kasp.conf $keytimes $zone 2>keygen.out.$zone.1)
-CSK2=$($KEYGEN -k csk-roll1 -l kasp.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 $TactN1 -r $O $TactN1 -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 -G "cdnskey,cds:sha-384" -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-roll1.autosign
-# According to RFC 7583:
-# Trem(N) = Tret(N) + IretZ
-# Tret(N) = Tact(N) + Lcsk
-#
-# Lcsk: 186d
-# Iret: 4h
-# IretZ: 26d3h
-#
-# Tpub(N) = now - IretZ - Lcsk = now - 627h - 186d
-# = now - 627h - 4464h = now - 5091h
-# Tact(N) = now - 627h - 186d
-# Tret(N) = now - IretZ = now - 627h
-# Trem(N) = now
-# Tpub(N+1) = now - IretZ - Ipub = now - 627h - 3h = now - 630h
-# Tact(N+1) = Tret(N)
-# Tret(N+1) = now - IretZ + Lcsk = now - 627h + 186d = now + 3837h
-# Trem(N+1) = now + Lcsk = now + 186d
-TpubN="now-5091h"
-TactN="now-5066h"
-TretN="now-627h"
-TremN="now"
-TpubN1="now-630h"
-TactN1="${TretN}"
-TretN1="now+3837h"
-TremN1="now+186d"
-keytimes="-P ${TpubN} -P sync ${TactN} -A ${TpubN} -I ${TretN} -D ${TremN} -D sync ${TactN1}"
-newtimes="-P ${TpubN1} -P sync ${TactN1} -A ${TactN1} -I ${TretN1} -D ${TremN1}"
-CSK1=$($KEYGEN -k csk-roll1 -l kasp.conf $keytimes $zone 2>keygen.out.$zone.1)
-CSK2=$($KEYGEN -k csk-roll1 -l kasp.conf $newtimes $zone 2>keygen.out.$zone.2)
-$SETTIME -s -g $H -k $O $TactN -r $H $TremN -d $H $TremN -z $U $TactN1 "$CSK1" >settime.out.$zone.1 2>&1
-$SETTIME -s -g $O -k $O $TactN1 -r $O $TactN1 -d $O $TremN -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 -G "cdnskey,cds:sha-384" -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-roll1.autosign
-# Subtract DNSKEY TTL plus zone propagation delay from all the times (2h).
-TpubN="now-5093h"
-TactN="now-5068h"
-TretN="now-629h"
-TremN="now-2h"
-TpubN1="now-632h"
-TactN1="${TretN}"
-TretN1="now+3835h"
-TremN1="now+4462h"
-keytimes="-P ${TpubN} -P sync ${TactN} -A ${TpubN} -I ${TretN} -D ${TremN} -D sync ${TactN1}"
-newtimes="-P ${TpubN1} -P sync ${TactN1} -A ${TactN1} -I ${TretN1} -D ${TremN1}"
-CSK1=$($KEYGEN -k csk-roll1 -l kasp.conf $keytimes $zone 2>keygen.out.$zone.1)
-CSK2=$($KEYGEN -k csk-roll1 -l kasp.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 $TactN1 -r $O $TactN1 -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 -G "cdnskey,cds:sha-384" -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-roll1.autosign
-TpubN="now-5094h"
-TactN="now-5069h"
-TretN="now-630h"
-TremN="now-3h"
-TpubN1="now-633h"
-TactN1="${TretN}"
-TretN1="now+3834h"
-TremN1="now+4461h"
-# Subtract purge-keys interval from all the times (1h).
-keytimes="-P ${TpubN} -P sync ${TactN} -A ${TpubN} -I ${TretN} -D ${TremN} -D sync ${TactN1}"
-newtimes="-P ${TpubN1} -P sync ${TactN1} -A ${TactN1} -I ${TretN1} -D ${TremN1}"
-CSK1=$($KEYGEN -k csk-roll1 -l kasp.conf $keytimes $zone 2>keygen.out.$zone.1)
-CSK2=$($KEYGEN -k csk-roll1 -l kasp.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 $TactN1 -r $O $TactN1 -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 -G "cdnskey,cds:sha-384" -s now-1h -e now+30d -o $zone -O raw -f "${zonefile}.signed" $infile >signer.out.$zone.1 2>&1
isctest.kasp.check_dnssecstatus(server, zone, keys, policy=policy)
isctest.kasp.check_apex(server, zone, ksks, zsks, cdss=cdss)
isctest.kasp.check_subdomain(server, zone, ksks, zsks)
-
-
-def test_rollover_csk_roll1(servers):
- server = servers["ns3"]
- policy = "csk-roll1"
- cdss = ["CDNSKEY", "CDS (SHA-384)"]
- config = {
- "dnskey-ttl": timedelta(hours=1),
- "ds-ttl": timedelta(seconds=3600),
- "max-zone-ttl": timedelta(days=1),
- "parent-propagation-delay": timedelta(hours=1),
- "publish-safety": timedelta(hours=1),
- "purge-keys": timedelta(hours=1),
- "retire-safety": timedelta(hours=2),
- "signatures-refresh": timedelta(days=5),
- "signatures-validity": timedelta(days=30),
- "zone-propagation-delay": timedelta(hours=1),
- }
- alg = os.environ["DEFAULT_ALGORITHM_NUMBER"]
- size = os.environ["DEFAULT_BITS"]
- csk_lifetime = timedelta(days=31 * 6)
- lifetime_policy = int(csk_lifetime.total_seconds())
-
- ipub = Ipub(config)
- iretZSK = Iret(config)
- iretKSK = Iret(config, zsk=False, ksk=True)
- keyttlprop = config["dnskey-ttl"] + config["zone-propagation-delay"]
- signdelay = iretZSK - iretKSK - keyttlprop
- offsets = {}
- offsets["step1-p"] = -int(timedelta(days=7).total_seconds())
- offsets["step2-p"] = -int(csk_lifetime.total_seconds() - ipub.total_seconds())
- offsets["step2-s"] = 0
- offsets["step3-p"] = -int(csk_lifetime.total_seconds())
- offsets["step3-s"] = -int(ipub.total_seconds())
- offsets["step4-p"] = offsets["step3-p"] - int(iretKSK.total_seconds())
- offsets["step4-s"] = offsets["step3-s"] - int(iretKSK.total_seconds())
- offsets["step5-p"] = offsets["step4-p"] - int(keyttlprop.total_seconds())
- offsets["step5-s"] = offsets["step4-s"] - int(keyttlprop.total_seconds())
- offsets["step6-p"] = offsets["step5-p"] - int(signdelay.total_seconds())
- offsets["step6-s"] = offsets["step5-s"] - int(signdelay.total_seconds())
- offsets["step7-p"] = offsets["step6-p"] - int(keyttlprop.total_seconds())
- offsets["step7-s"] = offsets["step6-s"] - int(keyttlprop.total_seconds())
- offsets["step8-p"] = offsets["step7-p"] - int(config["purge-keys"].total_seconds())
- offsets["step8-s"] = offsets["step7-s"] - int(config["purge-keys"].total_seconds())
-
- steps = [
- {
- # Step 1.
- # Introduce the first key. This will immediately be active.
- "zone": "step1.csk-roll1.autosign",
- "cdss": cdss,
- "keyprops": [
- f"csk {lifetime_policy} {alg} {size} goal:omnipresent dnskey:omnipresent krrsig:omnipresent zrrsig:omnipresent ds:omnipresent offset:{offsets['step1-p']}",
- ],
- # Next key event is when the successor CSK needs to be published
- # minus time already elapsed. This is Lcsk - Ipub + Dreg (we ignore
- # registration delay).
- "nextev": csk_lifetime - ipub - timedelta(days=7),
- },
- {
- # Step 2.
- # Successor CSK is prepublished (signs DNSKEY RRset, but not yet
- # other RRsets).
- # CSK1 goal: omnipresent -> hidden
- # CSK2 goal: hidden -> omnipresent
- # CSK2 dnskey: hidden -> rumoured
- # CSK2 krrsig: hidden -> rumoured
- "zone": "step2.csk-roll1.autosign",
- "cdss": cdss,
- "keyprops": [
- f"csk {lifetime_policy} {alg} {size} goal:hidden dnskey:omnipresent krrsig:omnipresent zrrsig:omnipresent ds:omnipresent offset:{offsets['step2-p']}",
- f"csk {lifetime_policy} {alg} {size} goal:omnipresent dnskey:rumoured krrsig:rumoured zrrsig:hidden ds:hidden offset:{offsets['step2-s']}",
- ],
- "keyrelationships": [0, 1],
- # Next key event is when the successor CSK becomes OMNIPRESENT.
- "nextev": ipub,
- },
- {
- # Step 3.
- # Successor CSK becomes omnipresent, meaning we can start signing
- # the remainder of the zone with the successor CSK, and we can
- # submit the DS.
- "zone": "step3.csk-roll1.autosign",
- "cdss": cdss,
- # Predecessor CSK will be removed, so moving to UNRETENTIVE.
- # CSK1 zrrsig: omnipresent -> unretentive
- # Successor CSK DNSKEY is OMNIPRESENT, so moving ZRRSIG to RUMOURED.
- # CSK2 dnskey: rumoured -> omnipresent
- # CSK2 krrsig: rumoured -> omnipresent
- # CSK2 zrrsig: hidden -> rumoured
- # The predecessor DS can be withdrawn and the successor DS can be
- # introduced.
- # CSK1 ds: omnipresent -> unretentive
- # CSK2 ds: hidden -> rumoured
- "keyprops": [
- f"csk {lifetime_policy} {alg} {size} goal:hidden dnskey:omnipresent krrsig:omnipresent zrrsig:unretentive ds:unretentive offset:{offsets['step3-p']}",
- f"csk {lifetime_policy} {alg} {size} goal:omnipresent dnskey:omnipresent krrsig:omnipresent zrrsig:rumoured ds:rumoured offset:{offsets['step3-s']}",
- ],
- "keyrelationships": [0, 1],
- # Next key event is when the predecessor DS has been replaced with
- # the successor DS and enough time has passed such that the all
- # validators that have this DS RRset cached only know about the
- # successor DS. This is the the retire interval.
- "nextev": iretKSK,
- # Set 'smooth' to true so expected signatures of subdomain are
- # from the predecessor ZSK.
- "smooth": True,
- },
- {
- # Step 4.
- "zone": "step4.csk-roll1.autosign",
- "cdss": cdss,
- # The predecessor CSK is no longer signing the DNSKEY RRset.
- # CSK1 krrsig: omnipresent -> unretentive
- # The predecessor DS is hidden. The successor DS is now omnipresent.
- # CSK1 ds: unretentive -> hidden
- # CSK2 ds: rumoured -> omnipresent
- "keyprops": [
- f"csk {lifetime_policy} {alg} {size} goal:hidden dnskey:omnipresent krrsig:unretentive zrrsig:unretentive ds:hidden offset:{offsets['step4-p']}",
- f"csk {lifetime_policy} {alg} {size} goal:omnipresent dnskey:omnipresent krrsig:omnipresent zrrsig:rumoured ds:omnipresent offset:{offsets['step4-s']}",
- ],
- "keyrelationships": [0, 1],
- # Next key event is when the KRRSIG enters the HIDDEN state.
- # This is the DNSKEY TTL plus zone propagation delay.
- "nextev": keyttlprop,
- # We already swapped the DS in the previous step, so disable ds-swap.
- "ds-swap": False,
- },
- {
- # Step 5.
- "zone": "step5.csk-roll1.autosign",
- "cdss": cdss,
- # The predecessor KRRSIG records are now all hidden.
- # CSK1 krrsig: unretentive -> hidden
- "keyprops": [
- f"csk {lifetime_policy} {alg} {size} goal:hidden dnskey:omnipresent krrsig:hidden zrrsig:unretentive ds:hidden offset:{offsets['step5-p']}",
- f"csk {lifetime_policy} {alg} {size} goal:omnipresent dnskey:omnipresent krrsig:omnipresent zrrsig:rumoured ds:omnipresent offset:{offsets['step5-s']}",
- ],
- "keyrelationships": [0, 1],
- # 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.
- "nextev": signdelay,
- },
- {
- # Step 6.
- "zone": "step6.csk-roll1.autosign",
- "cdss": cdss,
- # The predecessor ZRRSIG records are now all hidden (so the DNSKEY
- # can be removed).
- # CSK1 dnskey: omnipresent -> unretentive
- # CSK1 zrrsig: unretentive -> hidden
- # CSK2 zrrsig: rumoured -> omnipresent
- "keyprops": [
- f"csk {lifetime_policy} {alg} {size} goal:hidden dnskey:unretentive krrsig:hidden zrrsig:hidden ds:hidden offset:{offsets['step6-p']}",
- f"csk {lifetime_policy} {alg} {size} goal:omnipresent dnskey:omnipresent krrsig:omnipresent zrrsig:omnipresent ds:omnipresent offset:{offsets['step6-s']}",
- ],
- "keyrelationships": [0, 1],
- # Next key event is when the DNSKEY enters the HIDDEN state.
- # This is the DNSKEY TTL plus zone propagation delay.
- "nextev": keyttlprop,
- },
- {
- # Step 7.
- "zone": "step7.csk-roll1.autosign",
- "cdss": cdss,
- # The predecessor CSK is now completely HIDDEN.
- "keyprops": [
- f"csk {lifetime_policy} {alg} {size} goal:hidden dnskey:hidden krrsig:hidden zrrsig:hidden ds:hidden offset:{offsets['step7-p']}",
- f"csk {lifetime_policy} {alg} {size} goal:omnipresent dnskey:omnipresent krrsig:omnipresent zrrsig:omnipresent ds:omnipresent offset:{offsets['step7-s']}",
- ],
- "keyrelationships": [0, 1],
- # 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.
- "nextev": csk_lifetime - iretZSK - ipub - keyttlprop,
- },
- {
- # Step 8.
- # Predecessor CSK is now purged.
- "zone": "step8.csk-roll1.autosign",
- "cdss": cdss,
- "keyprops": [
- f"csk {lifetime_policy} {alg} {size} goal:omnipresent dnskey:omnipresent krrsig:omnipresent zrrsig:omnipresent ds:omnipresent offset:{offsets['step8-s']}",
- ],
- "nextev": None,
- },
- ]
-
- for step in steps:
- sctest.kasp.check_rollover_step(server, config, policy, step)