Merge branch 'kasp-test-algoroll' into 'master'

Test dnssec-policy algorithm rollover, fix some bugs

Closes #1626, #1625, and #1624

See merge request isc-projects/bind9!3086
This commit is contained in:
Matthijs Mekking 2020-03-06 15:16:19 +00:00
commit a1849cea53
18 changed files with 1317 additions and 97 deletions

17
CHANGES
View file

@ -1,3 +1,20 @@
5365. [bug] Algorithm rollover was stuck on submitting DS
because keymgr thought it would move to an invalid
state. Fixed by when checking the current key,
check it against the desired state, not the existing
state. [GL #1626]
5364. [bug] Algorithm rollover waited too long before introducing
zone signatures. It waited to make sure all signatures
were resigned, but when introducing a new algorithm,
all signatures are resigned immediately. Only
add the sign delay if there is a predecessor key.
[GL #1625]
5363. [bug] When changing a dnssec-policy, existing keys with
properties that no longer match were not being retired.
[GL #1624]
5362. [func] Limit the size of IXFR responses so that AXFR will
be used instead if it would be smaller. This is
controlled by the "max-ixfr-ratio" option, which

View file

@ -11,3 +11,5 @@ 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.

View file

@ -22,5 +22,4 @@ 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
# NS3 specific
rm -f ns3/zones ns3/*.db.infile
rm -f ns*/zones* ns*/*.db.infile

View file

@ -202,6 +202,30 @@ zone "zsk-retired.autosign" {
dnssec-policy "autosign";
};
/*
* Zones for testing enabling DNSSEC.
*/
zone "step1.enable-dnssec.autosign" {
type master;
file "step1.enable-dnssec.autosign.db";
dnssec-policy "enable-dnssec";
};
zone "step2.enable-dnssec.autosign" {
type master;
file "step2.enable-dnssec.autosign.db";
dnssec-policy "enable-dnssec";
};
zone "step3.enable-dnssec.autosign" {
type master;
file "step3.enable-dnssec.autosign.db";
dnssec-policy "enable-dnssec";
};
zone "step4.enable-dnssec.autosign" {
type master;
file "step4.enable-dnssec.autosign.db";
dnssec-policy "enable-dnssec";
};
/*
* Zones for testing ZSK Pre-Publication steps.
*/
@ -259,11 +283,6 @@ zone "step5.ksk-doubleksk.autosign" {
file "step5.ksk-doubleksk.autosign.db";
dnssec-policy "ksk-doubleksk";
};
zone "step6.ksk-doubleksk.autosign" {
type master;
file "step6.ksk-doubleksk.autosign.db";
dnssec-policy "ksk-doubleksk";
};
/*
* Zones for testing CSK rollover steps.

View file

@ -23,6 +23,27 @@ dnssec-policy "autosign" {
};
};
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-registration-delay P1D;
parent-ds-ttl 2h;
keys {
csk lifetime unlimited algorithm 13;
};
};
dnssec-policy "zsk-prepub" {
signatures-refresh P1W;

View file

@ -149,6 +149,53 @@ private_type_record $zone 13 "$ZSK" >> "$infile"
$SIGNER -PS -x -s now-2w -e now-1mi -o $zone -O full -f $zonefile $infile > signer.out.$zone.1 2>&1
$SETTIME -s -I now -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
CSK=$($KEYGEN -k enable-dnssec -l policies/autosign.conf $zone 2> keygen.out.$zone.1)
TpubN="now-900s"
$SETTIME -s -P $TpubN -A $TpubN -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 13 "$CSK" >> "$infile"
$SIGNER -S -z -x -s now-1h -e now+30d -o $zone -O full -f $zonefile $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
CSK=$($KEYGEN -k enable-dnssec -l policies/autosign.conf $zone 2> keygen.out.$zone.1)
TpubN="now-44700s"
TactN="now-43800s"
$SETTIME -s -P $TpubN -A $TpubN -g $O -k $O $TactN -r $O $TactN -d $H $TpubN -z $R $TpubN "$CSK" > settime.out.$zone.1 2>&1
cat template.db.in "${CSK}.key" > "$infile"
private_type_record $zone 13 "$CSK" >> "$infile"
$SIGNER -S -z -x -s now-1h -e now+30d -o $zone -O full -f $zonefile $infile > signer.out.$zone.1 2>&1
setup step3.enable-dnssec.autosign
# Step 4:
# The DS has been submitted long enough ago to become OMNIPRESENT.
# Add 27 hour plus retire safety of 20 minutes (98400 seconds) to the times.
setup step4.enable-dnssec.autosign
CSK=$($KEYGEN -k enable-dnssec -l policies/autosign.conf $zone 2> keygen.out.$zone.1)
TpubN="now-143100s"
TactN="now-142200s"
TomnN="now-98400s"
$SETTIME -s -P $TpubN -A $TpubN -g $O -k $O $TactN -r $O $TactN -d $R $TomnN -z $O $TomnN "$CSK" > settime.out.$zone.1 2>&1
cat template.db.in "${CSK}.key" > "$infile"
private_type_record $zone 13 "$CSK" >> "$infile"
$SIGNER -S -z -x -s now-1h -e now+30d -o $zone -O full -f $zonefile $infile > signer.out.$zone.1 2>&1
setup step3.enable-dnssec.autosign
#
# The zones at zsk-prepub.autosign represent the various steps of a ZSK
# Pre-Publication rollover.

View file

@ -0,0 +1,48 @@
/*
* Copyright (C) Internet Systems Consortium, Inc. ("ISC")
*
* 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 http://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 rndc_key {
secret "1234abcd8765";
algorithm hmac-sha256;
};
controls {
inet 10.53.0.6 port @CONTROLPORT@ allow { any; } keys { rndc_key; };
};
zone "step1.algorithm-roll.kasp" {
type master;
file "step1.algorithm-roll.kasp.db";
dnssec-policy "rsasha1";
};
zone "step1.csk-algorithm-roll.kasp" {
type master;
file "step1.csk-algorithm-roll.kasp.db";
dnssec-policy "csk-algoroll";
};

View file

@ -0,0 +1,111 @@
/*
* Copyright (C) Internet Systems Consortium, Inc. ("ISC")
*
* 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 http://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;
};
key rndc_key {
secret "1234abcd8765";
algorithm hmac-sha256;
};
controls {
inet 10.53.0.6 port @CONTROLPORT@ allow { any; } keys { rndc_key; };
};
zone "step1.algorithm-roll.kasp" {
type master;
file "step1.algorithm-roll.kasp.db";
dnssec-policy "ecdsa256";
};
zone "step2.algorithm-roll.kasp" {
type master;
file "step2.algorithm-roll.kasp.db";
dnssec-policy "ecdsa256";
};
zone "step3.algorithm-roll.kasp" {
type master;
file "step3.algorithm-roll.kasp.db";
dnssec-policy "ecdsa256";
};
zone "step4.algorithm-roll.kasp" {
type master;
file "step4.algorithm-roll.kasp.db";
dnssec-policy "ecdsa256";
};
zone "step5.algorithm-roll.kasp" {
type master;
file "step5.algorithm-roll.kasp.db";
dnssec-policy "ecdsa256";
};
zone "step6.algorithm-roll.kasp" {
type master;
file "step6.algorithm-roll.kasp.db";
dnssec-policy "ecdsa256";
};
/*
* Zones for testing CSK algorithm roll.
*/
zone "step1.csk-algorithm-roll.kasp" {
type master;
file "step1.csk-algorithm-roll.kasp.db";
dnssec-policy "csk-algoroll";
};
zone "step2.csk-algorithm-roll.kasp" {
type master;
file "step2.csk-algorithm-roll.kasp.db";
dnssec-policy "csk-algoroll";
};
zone "step3.csk-algorithm-roll.kasp" {
type master;
file "step3.csk-algorithm-roll.kasp.db";
dnssec-policy "csk-algoroll";
};
zone "step4.csk-algorithm-roll.kasp" {
type master;
file "step4.csk-algorithm-roll.kasp.db";
dnssec-policy "csk-algoroll";
};
zone "step5.csk-algorithm-roll.kasp" {
type master;
file "step5.csk-algorithm-roll.kasp.db";
dnssec-policy "csk-algoroll";
};
zone "step6.csk-algorithm-roll.kasp" {
type master;
file "step6.csk-algorithm-roll.kasp.db";
dnssec-policy "csk-algoroll";
};

View file

@ -0,0 +1,29 @@
/*
* Copyright (C) Internet Systems Consortium, Inc. ("ISC")
*
* 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 http://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 rsasha1;
};
dnskey-ttl 1h;
publish-safety PT1H;
retire-safety 2h;
zone-propagation-delay 3600;
max-zone-ttl 6h;
parent-registration-delay 1d;
parent-propagation-delay pt1h;
parent-ds-ttl 7200;
};

View file

@ -0,0 +1,29 @@
/*
* Copyright (C) Internet Systems Consortium, Inc. ("ISC")
*
* 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 http://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 13;
};
dnskey-ttl 1h;
publish-safety PT1H;
retire-safety 2h;
zone-propagation-delay 3600;
max-zone-ttl 6h;
parent-registration-delay 1d;
parent-propagation-delay pt1h;
parent-ds-ttl 7200;
};

View file

@ -0,0 +1,50 @@
/*
* Copyright (C) Internet Systems Consortium, Inc. ("ISC")
*
* 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 http://mozilla.org/MPL/2.0/.
*
* See the COPYRIGHT file distributed with this work for additional
* information regarding copyright ownership.
*/
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-registration-delay 1d;
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-registration-delay 1d;
parent-propagation-delay pt1h;
parent-ds-ttl 7200;
};

View file

@ -0,0 +1,295 @@
#!/bin/sh -e
#
# Copyright (C) Internet Systems Consortium, Inc. ("ISC")
#
# 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 http://mozilla.org/MPL/2.0/.
#
# See the COPYRIGHT file distributed with this work for additional
# information regarding copyright ownership.
# shellcheck source=conf.sh
. "$SYSTEMTESTTOP/conf.sh"
echo_i "ns6/setup.sh"
setup() {
zone="$1"
echo_i "setting up zone: $zone"
zonefile="${zone}.db"
infile="${zone}.db.infile"
echo "$zone" >> zones.2
}
private_type_record() {
_zone=$1
_algorithm=$2
_keyfile=$3
_id=$(keyfile_to_key_id "$_keyfile")
printf "%s. 0 IN TYPE65534 %s 5 %02x%04x0000\n" "$_zone" "\\#" "$_algorithm" "$_id"
}
# Make lines shorter by storing key states in environment variables.
H="HIDDEN"
R="RUMOURED"
O="OMNIPRESENT"
U="UNRETENTIVE"
#
# 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
KSK=$($KEYGEN -a RSASHA1 -f KSK -L 3600 $zone 2> keygen.out.$zone.1)
ZSK=$($KEYGEN -a RSASHA1 -L 3600 $zone 2> keygen.out.$zone.2)
TactN="now"
$SETTIME -s -P $TactN -A $TactN -g $O -k $O $TactN -r $O $TactN -d $O $TactN "$KSK" > settime.out.$zone.1 2>&1
$SETTIME -s -P $TactN -A $TactN -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 5 "$KSK" >> "$infile"
private_type_record $zone 5 "$ZSK" >> "$infile"
$SIGNER -S -x -s now-1h -e now+2w -o $zone -O full -f $zonefile $infile > signer.out.$zone.1 2>&1
# Step 2:
# After the publication interval has passed the DNSKEY is OMNIPRESENT.
setup step2.algorithm-roll.kasp
KSK1=$($KEYGEN -a RSASHA1 -f KSK -L 3600 $zone 2> keygen.out.$zone.1)
ZSK1=$($KEYGEN -a RSASHA1 -L 3600 $zone 2> keygen.out.$zone.2)
KSK2=$($KEYGEN -a ECDSAP256SHA256 -f KSK -L 3600 $zone 2> keygen.out.$zone.1)
ZSK2=$($KEYGEN -a ECDSAP256SHA256 -L 3600 $zone 2> keygen.out.$zone.2)
# The time passed since the new algorithm keys have been introduced is 3 hours.
TactN="now-3h"
TpubN1="now-3h"
TactN1="now+6h"
$SETTIME -s -P $TactN -A $TactN -I now -g $H -k $O $TactN -r $O $TactN -d $O $TactN "$KSK1" > settime.out.$zone.1 2>&1
$SETTIME -s -P $TactN -A $TactN -I now -g $H -k $O $TactN -z $O $TactN "$ZSK1" > settime.out.$zone.2 2>&1
$SETTIME -s -P $TpubN1 -A $TpubN1 -g $O -k $R $TpubN1 -r $R $TpubN1 -d $H $TpubN1 "$KSK2" > settime.out.$zone.1 2>&1
$SETTIME -s -P $TpubN1 -A $TactN1 -g $O -k $R $TpubN1 -z $R $TpubN1 "$ZSK2" > settime.out.$zone.2 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 5 "$KSK1" >> "$infile"
private_type_record $zone 5 "$ZSK1" >> "$infile"
private_type_record $zone 13 "$KSK2" >> "$infile"
private_type_record $zone 13 "$ZSK2" >> "$infile"
$SIGNER -S -x -s now-1h -e now+2w -o $zone -O full -f $zonefile $infile > signer.out.$zone.1 2>&1
# Step 3:
# The zone signatures are also OMNIPRESENT.
setup step3.algorithm-roll.kasp
KSK1=$($KEYGEN -a RSASHA1 -f KSK -L 3600 $zone 2> keygen.out.$zone.1)
ZSK1=$($KEYGEN -a RSASHA1 -L 3600 $zone 2> keygen.out.$zone.2)
KSK2=$($KEYGEN -a ECDSAP256SHA256 -f KSK -L 3600 $zone 2> keygen.out.$zone.1)
ZSK2=$($KEYGEN -a ECDSAP256SHA256 -L 3600 $zone 2> keygen.out.$zone.2)
# The time passed since the new algorithm keys have been introduced is 9 hours.
TactN="now-9h"
TpubN1="now-9h"
TactN1="now"
$SETTIME -s -P $TactN -A $TactN -I now -g $H -k $O $TactN -r $O $TactN -d $O $TactN "$KSK1" > settime.out.$zone.1 2>&1
$SETTIME -s -P $TactN -A $TactN -I now -g $H -k $O $TactN -z $O $TactN "$ZSK1" > settime.out.$zone.2 2>&1
$SETTIME -s -P $TpubN1 -A $TactN1 -g $O -k $O $TpubN1 -r $O $TpubN1 -d $H $TpubN1 "$KSK2" > settime.out.$zone.1 2>&1
$SETTIME -s -P $TpubN1 -A $TactN1 -g $O -k $O $TpubN1 -z $R $TpubN1 "$ZSK2" > settime.out.$zone.2 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 5 "$KSK1" >> "$infile"
private_type_record $zone 5 "$ZSK1" >> "$infile"
private_type_record $zone 13 "$KSK2" >> "$infile"
private_type_record $zone 13 "$ZSK2" >> "$infile"
$SIGNER -S -x -s now-1h -e now+2w -o $zone -O full -f $zonefile $infile > signer.out.$zone.1 2>&1
# Step 4:
# The DS is swapped and can become OMNIPRESENT.
setup step4.algorithm-roll.kasp
KSK1=$($KEYGEN -a RSASHA1 -f KSK -L 3600 $zone 2> keygen.out.$zone.1)
ZSK1=$($KEYGEN -a RSASHA1 -L 3600 $zone 2> keygen.out.$zone.2)
KSK2=$($KEYGEN -a ECDSAP256SHA256 -f KSK -L 3600 $zone 2> keygen.out.$zone.1)
ZSK2=$($KEYGEN -a ECDSAP256SHA256 -L 3600 $zone 2> keygen.out.$zone.2)
# The time passed since the DS has been swapped is 29 hours.
TactN="now-38h"
TpubN1="now-38h"
TactN1="now-29h"
$SETTIME -s -P $TactN -A $TactN -I now -g $H -k $O $TactN -r $O $TactN -d $U $TactN1 "$KSK1" > settime.out.$zone.1 2>&1
$SETTIME -s -P $TactN -A $TactN -I now -g $H -k $O $TactN -z $O $TactN "$ZSK1" > settime.out.$zone.2 2>&1
$SETTIME -s -P $TpubN1 -A $TactN1 -g $O -k $O $TpubN1 -r $O $TpubN1 -d $R $TactN1 "$KSK2" > settime.out.$zone.1 2>&1
$SETTIME -s -P $TpubN1 -A $TactN1 -g $O -k $O $TpubN1 -z $R $TpubN1 "$ZSK2" > settime.out.$zone.2 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 5 "$KSK1" >> "$infile"
private_type_record $zone 5 "$ZSK1" >> "$infile"
private_type_record $zone 13 "$KSK2" >> "$infile"
private_type_record $zone 13 "$ZSK2" >> "$infile"
$SIGNER -S -x -s now-1h -e now+2w -o $zone -O full -f $zonefile $infile > signer.out.$zone.1 2>&1
# Step 5:
# The DNSKEY is removed long enough to be HIDDEN.
setup step5.algorithm-roll.kasp
KSK1=$($KEYGEN -a RSASHA1 -f KSK -L 3600 $zone 2> keygen.out.$zone.1)
ZSK1=$($KEYGEN -a RSASHA1 -L 3600 $zone 2> keygen.out.$zone.2)
KSK2=$($KEYGEN -a ECDSAP256SHA256 -f KSK -L 3600 $zone 2> keygen.out.$zone.1)
ZSK2=$($KEYGEN -a ECDSAP256SHA256 -L 3600 $zone 2> keygen.out.$zone.2)
# The time passed since the DNSKEY has been removed is 2 hours.
TactN="now-40h"
TpubN1="now-40h"
TactN1="now-31h"
TremN="now-2h"
$SETTIME -s -P $TactN -A $TactN -I now -g $H -k $U $TremN -r $U $TremN -d $H $TremN "$KSK1" > settime.out.$zone.1 2>&1
$SETTIME -s -P $TactN -A $TactN -I now -g $H -k $U $TremN -z $U $TremN "$ZSK1" > settime.out.$zone.2 2>&1
$SETTIME -s -P $TpubN1 -A $TactN1 -g $O -k $O $TpubN1 -r $O $TpubN1 -d $O $TremN "$KSK2" > settime.out.$zone.1 2>&1
$SETTIME -s -P $TpubN1 -A $TactN1 -g $O -k $O $TpubN1 -z $R $TpubN1 "$ZSK2" > settime.out.$zone.2 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 5 "$KSK1" >> "$infile"
private_type_record $zone 5 "$ZSK1" >> "$infile"
private_type_record $zone 13 "$KSK2" >> "$infile"
private_type_record $zone 13 "$ZSK2" >> "$infile"
$SIGNER -S -x -s now-1h -e now+2w -o $zone -O full -f $zonefile $infile > signer.out.$zone.1 2>&1
# Step 6:
# The RRSIGs have been removed long enough to be HIDDEN.
setup step6.algorithm-roll.kasp
KSK1=$($KEYGEN -a RSASHA1 -f KSK -L 3600 $zone 2> keygen.out.$zone.1)
ZSK1=$($KEYGEN -a RSASHA1 -L 3600 $zone 2> keygen.out.$zone.2)
KSK2=$($KEYGEN -a ECDSAP256SHA256 -f KSK -L 3600 $zone 2> keygen.out.$zone.1)
ZSK2=$($KEYGEN -a ECDSAP256SHA256 -L 3600 $zone 2> keygen.out.$zone.2)
# Additional time passed: 7h.
TactN="now-47h"
TpubN1="now-47h"
TactN1="now-38h"
TremN="now-9h"
$SETTIME -s -P $TactN -A $TactN -I now -g $H -k $U $TremN -r $U $TremN -d $H $TremN "$KSK1" > settime.out.$zone.1 2>&1
$SETTIME -s -P $TactN -A $TactN -I now -g $H -k $U $TremN -z $U $TremN "$ZSK1" > settime.out.$zone.2 2>&1
$SETTIME -s -P $TpubN1 -A $TactN1 -g $O -k $O $TpubN1 -r $O $TpubN1 -d $O $TremN "$KSK2" > settime.out.$zone.1 2>&1
$SETTIME -s -P $TpubN1 -A $TactN1 -g $O -k $O $TpubN1 -z $R $TpubN1 "$ZSK2" > settime.out.$zone.2 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 5 "$KSK1" >> "$infile"
private_type_record $zone 5 "$ZSK1" >> "$infile"
private_type_record $zone 13 "$KSK2" >> "$infile"
private_type_record $zone 13 "$ZSK2" >> "$infile"
$SIGNER -S -x -s now-1h -e now+2w -o $zone -O full -f $zonefile $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
CSK=$($KEYGEN -k csk-algoroll -l policies/csk1.conf $zone 2> keygen.out.$zone.1)
TactN="now"
$SETTIME -s -P $TactN -A $TactN -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"
$SIGNER -S -x -z -s now-1h -e now+2w -o $zone -O full -f $zonefile $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
CSK1=$($KEYGEN -k csk-algoroll -l policies/csk1.conf $zone 2> keygen.out.$zone.1)
CSK2=$($KEYGEN -k csk-algoroll -l policies/csk2.conf $zone 2> keygen.out.$zone.1)
# The time passed since the new algorithm keys have been introduced is 3 hours.
TactN="now-3h"
TpubN1="now-3h"
$SETTIME -s -P $TactN -A $TactN -I now -g $H -k $O $TactN -r $O $TactN -z $O $TactN -d $O $TactN "$CSK1" > settime.out.$zone.1 2>&1
$SETTIME -s -P $TpubN1 -A $TpubN1 -g $O -k $R $TpubN1 -r $R $TpubN1 -z $R $TpubN1 -d $H $TpubN1 "$CSK2" > settime.out.$zone.1 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 13 "$CSK2" >> "$infile"
$SIGNER -S -x -z -s now-1h -e now+2w -o $zone -O full -f $zonefile $infile > signer.out.$zone.1 2>&1
# Step 3:
# The zone signatures are also OMNIPRESENT.
setup step3.csk-algorithm-roll.kasp
CSK1=$($KEYGEN -k csk-algoroll -l policies/csk1.conf $zone 2> keygen.out.$zone.1)
CSK2=$($KEYGEN -k csk-algoroll -l policies/csk2.conf $zone 2> keygen.out.$zone.1)
# The time passed since the new algorithm keys have been introduced is 9 hours.
TactN="now-9h"
TpubN1="now-9h"
TactN1="now-6h"
$SETTIME -s -P $TactN -A $TactN -I now -g $H -k $O $TactN -r $O $TactN -z $O $TactN -d $O $TactN "$CSK1" > settime.out.$zone.1 2>&1
$SETTIME -s -P $TpubN1 -A $TpubN1 -g $O -k $O $TactN1 -r $O $TactN1 -z $R $TpubN1 -d $H $TpubN1 "$CSK2" > settime.out.$zone.1 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 13 "$CSK2" >> "$infile"
$SIGNER -S -x -z -s now-1h -e now+2w -o $zone -O full -f $zonefile $infile > signer.out.$zone.1 2>&1
# Step 4:
# The DS is swapped and can become OMNIPRESENT.
setup step4.csk-algorithm-roll.kasp
CSK1=$($KEYGEN -k csk-algoroll -l policies/csk1.conf $zone 2> keygen.out.$zone.1)
CSK2=$($KEYGEN -k csk-algoroll -l policies/csk2.conf $zone 2> keygen.out.$zone.1)
# The time passed since the DS has been swapped is 29 hours.
TactN="now-38h"
TpubN1="now-38h"
TactN1="now-35h"
TsubN1="now-29h"
$SETTIME -s -P $TactN -A $TactN -I now -g $H -k $O $TactN -r $O $TactN -z $O $TactN -d $U $TactN1 "$CSK1" > settime.out.$zone.1 2>&1
$SETTIME -s -P $TpubN1 -A $TpubN1 -g $O -k $O $TactN1 -r $O $TactN1 -z $O $TsubN1 -d $R $TsubN1 "$CSK2" > settime.out.$zone.1 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 13 "$CSK2" >> "$infile"
$SIGNER -S -x -z -s now-1h -e now+2w -o $zone -O full -f $zonefile $infile > signer.out.$zone.1 2>&1
# Step 5:
# The DNSKEY is removed long enough to be HIDDEN.
setup step5.csk-algorithm-roll.kasp
CSK1=$($KEYGEN -k csk-algoroll -l policies/csk1.conf $zone 2> keygen.out.$zone.1)
CSK2=$($KEYGEN -k csk-algoroll -l policies/csk2.conf $zone 2> keygen.out.$zone.1)
# The time passed since the DNSKEY has been removed is 2 hours.
TactN="now-40h"
TpubN1="now-40h"
TactN1="now-37h"
TsubN1="now-31h"
TremN="now-2h"
$SETTIME -s -P $TactN -A $TactN -I now -g $H -k $U $TremN -r $U $TremN -z $U $TremN -d $H $TremN "$CSK1" > settime.out.$zone.1 2>&1
$SETTIME -s -P $TpubN1 -A $TpubN1 -g $O -k $O $TactN1 -r $O $TactN1 -z $O $TsubN1 -d $O $TremN "$CSK2" > settime.out.$zone.1 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 13 "$CSK2" >> "$infile"
$SIGNER -S -x -z -s now-1h -e now+2w -o $zone -O full -f $zonefile $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
CSK1=$($KEYGEN -k csk-algoroll -l policies/csk1.conf $zone 2> keygen.out.$zone.1)
CSK2=$($KEYGEN -k csk-algoroll -l policies/csk2.conf $zone 2> keygen.out.$zone.1)
# Additional time passed: 7h.
TactN="now-47h"
TpubN1="now-47h"
TactN1="now-44h"
TsubN1="now-38h"
TremN="now-9h"
$SETTIME -s -P $TactN -A $TactN -I now -g $H -k $U $TremN -r $U $TremN -z $U $TremN -d $H $TremN "$CSK1" > settime.out.$zone.1 2>&1
$SETTIME -s -P $TpubN1 -A $TpubN1 -g $O -k $O $TactN1 -r $O $TactN1 -z $O $TsubN1 -d $O $TremN "$CSK2" > settime.out.$zone.1 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 13 "$CSK2" >> "$infile"
$SIGNER -S -x -z -s now-1h -e now+2w -o $zone -O full -f $zonefile $infile > signer.out.$zone.1 2>&1

View file

@ -0,0 +1,25 @@
; Copyright (C) Internet Systems Consortium, Inc. ("ISC")
;
; 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 http://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

View file

@ -22,6 +22,7 @@ copy_setports ns2/named.conf.in ns2/named.conf
copy_setports ns3/named.conf.in ns3/named.conf
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
# Setup zones
(
@ -40,3 +41,7 @@ copy_setports ns5/named.conf.in ns5/named.conf
cd ns5
$SHELL setup.sh
)
(
cd ns6
$SHELL setup.sh
)

View file

@ -94,6 +94,8 @@ key_clear() {
}
# Start clear.
# There can be at most 4 keys at the same time during a rollover:
# 2x KSK, 2x ZSK
key_clear "KEY1"
key_clear "KEY2"
key_clear "KEY3"
@ -125,18 +127,13 @@ get_keys_which_signed() {
awk -v qt="$_qtype" '$4 == "RRSIG" && $5 == qt {print $11}' < "$_output"
}
# Get the key ids from key files for zone $2 in directory $1
# that matches algorithm $3.
# Get the key ids from key files for zone $2 in directory $1.
get_keyids() {
_dir=$1
_zone=$2
_algorithm=$(printf "%03d" "$3")
_start="K${_zone}.+${_algorithm}+"
_end=".key"
_regex="K${_zone}.+*+*.key"
if [ "$_algorithm" -ne 0 ]; then
find "${_dir}" -mindepth 1 -maxdepth 1 -name "${_start}*${_end}" | sed "s,$_dir/K${_zone}.+${_algorithm}+\([0-9]\{5\}\)${_end},\1,"
fi
find "${_dir}" -mindepth 1 -maxdepth 1 -name "${_regex}" | sed "s,$_dir/K${_zone}.+\([0-9]\{3\}\)+\([0-9]\{5\}\).key,\2,"
}
# By default log errors and don't quit immediately.
@ -289,6 +286,12 @@ check_key() {
STATE_FILE="${BASE_FILE}.state"
KEY_ID="${_key_id}"
# Check file existence.
[ -s "$KEY_FILE" ] || ret=1
[ -s "$PRIVATE_FILE" ] || ret=1
[ -s "$STATE_FILE" ] || ret=1
[ "$ret" -eq 0 ] || return
test $_log -eq 1 && echo_i "check key $BASE_FILE"
# Check the public key file.
@ -415,7 +418,7 @@ key_unused() {
_zone=$ZONE
_key_idpad=$1
_key_id=$(echo "$_key_idpad" | sed 's/^0\{0,4\}//')
_alg_num=$(key_get KEY1 ALG_NUM)
_alg_num=$2
_alg_numpad=$(printf "%03d" "$_alg_num")
BASE_FILE="${_dir}/K${_zone}.+${_alg_numpad}+${_key_idpad}"
@ -426,6 +429,12 @@ key_unused() {
test $_log -eq 1 && echo_i "key unused $KEY_ID?"
# Check file existence.
[ -s "$KEY_FILE" ] || ret=1
[ -s "$PRIVATE_FILE" ] || ret=1
[ -s "$STATE_FILE" ] || ret=1
[ "$ret" -eq 0 ] || return
# Check timing metadata.
grep "; Publish:" "$KEY_FILE" > /dev/null && log_error "unexpected publish comment in $KEY_FILE"
grep "Publish:" "$PRIVATE_FILE" > /dev/null && log_error "unexpected publish in $PRIVATE_FILE"
@ -456,6 +465,9 @@ dnssec_verify()
status=$((status+ret))
}
# Default next key event threshold. May be extended by wait periods.
next_key_event_threshold=100
###############################################################################
# Tests #
###############################################################################
@ -473,32 +485,29 @@ lines=$(wc -l < "keygen.out.$POLICY.test$n")
test "$lines" -eq 4 || log_error "wrong number of keys created for policy kasp: $lines"
# Temporarily don't log errors because we are searching multiple files.
_log=0
# Check one algorithm.
key_properties "KEY1" "csk" "31536000" "13" "ECDSAP256SHA256" "256" "yes" "yes"
key_timings "KEY1" "none" "none" "none" "none" "none"
key_states "KEY1" "none" "none" "none" "none" "none"
ids=$(get_keyids "$DIR" "$ZONE" "$(key_get KEY1 ALG_NUM)")
for id in $ids; do
check_key "KEY1" "$id"
done
test "$ret" -eq 0 || echo_i "failed"
status=$((status+ret))
# Check the other algorithm.
key_properties "KEY1" "ksk" "31536000" "8" "RSASHA256" "2048" "no" "yes"
key_timings "KEY1" "none" "none" "none" "none" "none"
key_states "KEY1" "none" "none" "none" "none" "none"
key_properties "KEY2" "zsk" "2592000" "8" "RSASHA256" "1024" "yes" "no"
key_properties "KEY2" "ksk" "31536000" "8" "RSASHA256" "2048" "no" "yes"
key_timings "KEY2" "none" "none" "none" "none" "none"
key_states "KEY2" "none" "none" "none" "none" "none"
key_properties "KEY3" "zsk" "16070400" "8" "RSASHA256" "2000" "yes" "no"
key_properties "KEY3" "zsk" "2592000" "8" "RSASHA256" "1024" "yes" "no"
key_timings "KEY3" "none" "none" "none" "none" "none"
key_states "KEY3" "none" "none" "none" "none" "none"
ids=$(get_keyids "$DIR" "$ZONE" "$(key_get KEY1 ALG_NUM)")
key_properties "KEY4" "zsk" "16070400" "8" "RSASHA256" "2000" "yes" "no"
key_timings "KEY4" "none" "none" "none" "none" "none"
key_states "KEY4" "none" "none" "none" "none" "none"
lines=$(get_keyids "$DIR" "$ZONE" | wc -l)
test "$lines" -eq 4 || log_error "bad number of key ids"
ids=$(get_keyids "$DIR" "$ZONE")
for id in $ids; do
# There are three key files with the same algorithm.
# 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
@ -507,6 +516,9 @@ for id in $ids; do
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"
@ -525,7 +537,7 @@ key_states "KEY1" "none" "none" "none" "none" "none"
$KEYGEN -k "$POLICY" "$ZONE" > "keygen.out.$POLICY.test$n" 2>/dev/null || ret=1
lines=$(wc -l < "keygen.out.default.test$n")
test "$lines" -eq 1 || log_error "wrong number of keys created for policy default: $lines"
ids=$(get_keyids "$DIR" "$ZONE" "$(key_get KEY1 ALG_NUM)")
ids=$(get_keyids "$DIR" "$ZONE")
for id in $ids; do
check_key "KEY1" "$id"
done
@ -542,7 +554,7 @@ key_states "KEY1" "none" "none" "none" "none" "none"
$KEYGEN -k "$POLICY" "$ZONE" > "keygen.out.$POLICY.test$n" 2>/dev/null || ret=1
lines=$(wc -l < "keygen.out.$POLICY.test$n")
test "$lines" -eq 1 || log_error "wrong number of keys created for policy default: $lines"
ids=$(get_keyids "$DIR" "$ZONE" "$(key_get KEY1 ALG_NUM)")
ids=$(get_keyids "$DIR" "$ZONE")
for id in $ids; do
check_key "KEY1" "$id"
done
@ -602,7 +614,6 @@ check_key "KEY1" "$id"
test "$ret" -eq 0 || echo_i "failed"
status=$((status+ret))
#
# named
#
@ -624,6 +635,14 @@ do
grep "NS SOA" "dig.out.ns3.test$n.$zone" > /dev/null || ret=1
grep "$zone\..*IN.*RRSIG" "dig.out.ns3.test$n.$zone" > /dev/null || ret=1
done < ns3/zones
while read -r zone
do
dig_with_opts "$zone" @10.53.0.6 nsec > "dig.out.ns6.test$n.$zone" || ret=1
grep "NS SOA" "dig.out.ns6.test$n.$zone" > /dev/null || ret=1
grep "$zone\..*IN.*RRSIG" "dig.out.ns6.test$n.$zone" > /dev/null || ret=1
done < ns6/zones
i=$((i+1))
if [ $ret = 0 ]; then break; fi
echo_i "waiting ... ($i)"
@ -632,6 +651,8 @@ done
test "$ret" -eq 0 || echo_i "failed"
status=$((status+ret))
next_key_event_threshold=$((next_key_event_threshold+i))
#
# Zone: default.kasp.
#
@ -647,7 +668,7 @@ key_states "KEY1" "omnipresent" "rumoured" "rumoured" "rumoured" "hidden"
n=$((n+1))
echo_i "check key is created for zone ${ZONE} ($n)"
ret=0
ids=$(get_keyids "$DIR" "$ZONE" "$(key_get KEY1 ALG_NUM)")
ids=$(get_keyids "$DIR" "$ZONE")
for id in $ids; do
check_key "KEY1" "$id"
done
@ -664,7 +685,7 @@ echo_i "check ${qtype} rrset is signed 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}\..*${DNSKEY_TTL}.*IN.*${qtype}.*257.*.3.*${KEY1__ALG_NUM}" "dig.out.$DIR.test$n" > /dev/null || log_error "missing ${qtype} record in response"
grep "${ZONE}\..*${DNSKEY_TTL}.*IN.*${qtype}.*257.*.3.*$(key_get KEY1 ALG_NUM)" "dig.out.$DIR.test$n" > /dev/null || log_error "missing ${qtype} record in response"
lines=$(get_keys_which_signed $qtype "dig.out.$DIR.test$n" | wc -l)
test "$lines" -eq 1 || log_error "bad number ($lines) of RRSIG records in DNS response"
get_keys_which_signed $qtype "dig.out.$DIR.test$n" | grep "^${KEY_ID}$" > /dev/null || log_error "${qtype} RRset not signed with key ${KEY_ID}"
@ -737,29 +758,24 @@ key_timings "KEY3" "published" "active" "retired" "none" "none"
key_states "KEY1" "omnipresent" "rumoured" "none" "rumoured" "hidden"
key_states "KEY2" "omnipresent" "rumoured" "rumoured" "none" "none"
key_states "KEY3" "omnipresent" "rumoured" "rumoured" "none" "none"
key_clear "KEY4"
# Check keys for a configured zone. This verifies:
# 1. The right number of keys exist in the key pool ($1).
# 2. The right number of keys is active (always expect three keys).
# The algorithm expected is set with $2 (string) and $3 (number), and the
# expected sizes for the keys are set with $4 (ksk), $5 and $6 (zsk).
# A size set to 0 means the corresponding key (KEY1, KEY2 or KEY3) is not
# expected.
# 2. The right number of keys is active. Checks KEY1, KEY2, KEY3, and KEY4.
#
# It is expected that KEY1, KEY2 and KEY3 arrays are set correctly. Found key
# identifiers are stored in the right key array.
# It is expected that KEY1, KEY2, KEY3, and KEY4 arrays are set correctly.
# Found key identifiers are stored in the right key array.
check_keys()
{
n=$((n+1))
echo_i "check keys are created for zone ${ZONE} ($n)"
ret=0
_key_algnum=$(key_get KEY1 ALG_NUM)
n=$((n+1))
echo_i "check number of keys with algorithm ${_key_algnum} for zone ${ZONE} in dir ${DIR} ($n)"
echo_i "check number of keys for zone ${ZONE} in dir ${DIR} ($n)"
ret=0
_numkeys=$(get_keyids "$DIR" "$ZONE" "$_key_algnum" | wc -l)
_numkeys=$(get_keyids "$DIR" "$ZONE" | wc -l)
test "$_numkeys" -eq "$NUM_KEYS" || log_error "bad number ($_numkeys) of key files for zone $ZONE (expected $NUM_KEYS)"
test "$ret" -eq 0 || echo_i "failed"
status=$((status+ret))
@ -771,9 +787,10 @@ check_keys()
key_set KEY1 ID "no"
key_set KEY2 ID "no"
key_set KEY3 ID "no"
key_set KEY4 ID "no"
# Check key files.
_ids=$(get_keyids "$DIR" "$ZONE" "$_key_algnum")
_ids=$(get_keyids "$DIR" "$ZONE")
for _id in $_ids; do
# There are three key files with the same algorithm.
# Check them until a match is found.
@ -794,9 +811,14 @@ check_keys()
check_key "KEY3" "$_id"
test "$ret" -eq 0 && key_set KEY3 ID "$KEY_ID" && continue
fi
if [ "no" = "$(key_get KEY4 ID)" ] && [ "$(key_get KEY4 EXPECT)" = "yes" ]; then
ret=0
check_key "KEY4" "$_id"
test "$ret" -eq 0 && key_set KEY4 ID "$KEY_ID" && continue
fi
# This may be an unused key.
ret=0 && key_unused "$_id"
# This may be an unused key. Assume algorithm of KEY1.
ret=0 && key_unused "$_id" "$(key_get KEY1 ALG_NUM)"
test "$ret" -eq 0 && continue
# If ret is still non-zero, non of the files matched.
@ -817,6 +839,9 @@ check_keys()
if [ "$(key_get KEY3 EXPECT)" = "yes" ]; then
test "no" = "$(key_get KEY3 ID)" && log_error "No KEY3 found for zone ${ZONE}"
fi
if [ "$(key_get KEY4 EXPECT)" = "yes" ]; then
test "no" = "$(key_get KEY4 ID)" && log_error "No KEY4 found for zone ${ZONE}"
fi
test "$ret" -eq 0 || echo_i "failed"
status=$((status+ret))
}
@ -851,6 +876,12 @@ check_signatures() {
elif [ "$(key_get KEY3 EXPECT)" = "yes" ]; then
get_keys_which_signed "$_qtype" "$_file" | grep "^$(key_get KEY3 ID)$" > /dev/null && log_error "${_qtype} RRset signed unexpectedly with key $(key_get KEY3 ID)"
fi
if [ "$(key_get KEY4 "$_expect_type")" = "yes" ] && [ "$(key_get KEY4 "$_role")" = "yes" ]; then
get_keys_which_signed "$_qtype" "$_file" | grep "^$(key_get KEY4 ID)$" > /dev/null || log_error "${_qtype} RRset not signed with key $(key_get KEY4 ID)"
elif [ "$(key_get KEY4 EXPECT)" = "yes" ]; then
get_keys_which_signed "$_qtype" "$_file" | grep "^$(key_get KEY4 ID)$" > /dev/null && log_error "${_qtype} RRset signed unexpectedly with key $(key_get KEY4 ID)"
fi
}
response_has_cds_for_key() (
@ -858,7 +889,7 @@ response_has_cds_for_key() (
-v ttl="${DNSKEY_TTL}" \
-v qtype="CDS" \
-v keyid="$(key_get "${1}" ID)" \
-v keyalg="${_key_algnum}" \
-v keyalg="$(key_get "${1}" ALG_NUM)" \
-v hashalg="2" \
'BEGIN { ret=1; }
$1 == zone && $2 == ttl && $4 == qtype && $5 == keyid && $6 == keyalg && $7 == hashalg { ret=0; exit; }
@ -871,7 +902,7 @@ response_has_cdnskey_for_key() (
-v ttl="${DNSKEY_TTL}" \
-v qtype="CDNSKEY" \
-v flags="257" \
-v keyalg="${_key_algnum}" \
-v keyalg="$(key_get "${1}" ALG_NUM)" \
'BEGIN { ret=1; }
$1 == zone && $2 == ttl && $4 == qtype && $5 == flags && $7 == keyalg { ret=0; exit; }
END { exit ret; }' \
@ -881,8 +912,6 @@ response_has_cdnskey_for_key() (
# Test CDS and CDNSKEY publication.
check_cds() {
_key_algnum="$(key_get KEY1 ALG_NUM)"
n=$((n+1))
echo_i "check CDS and CDNSKEY rrset are signed correctly for zone ${ZONE} ($n)"
ret=0
@ -932,6 +961,19 @@ check_cds() {
# so let's skip this check for now.
fi
if [ "$(key_get KEY4 STATE_DS)" = "rumoured" ] || [ "$(key_get KEY4 STATE_DS)" = "omnipresent" ]; then
response_has_cds_for_key KEY4 "dig.out.$DIR.test$n.cds" || log_error "missing CDS record in response for key $(key_get KEY4 ID)"
check_signatures "CDS" "dig.out.$DIR.test$n.cds" "KSK"
response_has_cdnskey_for_key KEY4 "dig.out.$DIR.test$n.cdnskey" || log_error "missing CDNSKEY record in response for key $(key_get KEY4 ID)"
check_signatures "CDNSKEY" "dig.out.$DIR.test$n.cdnskey" "KSK"
elif [ "$(key_get KEY4 EXPECT)" = "yes" ]; then
response_has_cds_for_key KEY4 "dig.out.$DIR.test$n.cds" && log_error "unexpected CDS record in response for key $(key_get KEY4 ID)"
# KEY4 should not have an associated CDNSKEY, but there may be
# one for another key. Since the CDNSKEY has no field for key
# id, it is hard to check what key the CDNSKEY may belong to
# so let's skip this check for now.
fi
test "$ret" -eq 0 || echo_i "failed"
status=$((status+ret))
}
@ -939,38 +981,45 @@ check_cds() {
# Test the apex of a configured zone. This checks that the SOA and DNSKEY
# RRsets are signed correctly and with the appropriate keys.
check_apex() {
# Test DNSKEY query.
_qtype="DNSKEY"
_key_algnum="$(key_get KEY1 ALG_NUM)"
n=$((n+1))
echo_i "check ${_qtype} rrset is signed 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"
if [ "$(key_get KEY1 STATE_DNSKEY)" = "rumoured" ] || [ "$(key_get KEY1 STATE_DNSKEY)" = "omnipresent" ]; then
grep "${ZONE}\..*${DNSKEY_TTL}.*IN.*${_qtype}.*257.*.3.*${_key_algnum}" "dig.out.$DIR.test$n" > /dev/null || log_error "missing ${_qtype} record in response for key $(key_get KEY1 ID)"
grep "${ZONE}\..*${DNSKEY_TTL}.*IN.*${_qtype}.*257.*.3.*$(key_get KEY1 ALG_NUM)" "dig.out.$DIR.test$n" > /dev/null || log_error "missing ${_qtype} record in response for key $(key_get KEY1 ID)"
check_signatures $_qtype "dig.out.$DIR.test$n" "KSK"
numkeys=$((numkeys+1))
elif [ "$(key_get KEY1 EXPECT)" = "yes" ]; then
grep "${ZONE}\.*${DNSKEY_TTL}.*IN.*${_qtype}.*257.*.3.*${_key_algnum}" "dig.out.$DIR.test$n" > /dev/null && log_error "unexpected ${_qtype} record in response for key $(key_get KEY1 ID)"
grep "${ZONE}\.*${DNSKEY_TTL}.*IN.*${_qtype}.*257.*.3.*$(key_get KEY1 ALG_NUM)" "dig.out.$DIR.test$n" > /dev/null && log_error "unexpected ${_qtype} record in response for key $(key_get KEY1 ID)"
fi
if [ "$(key_get KEY2 STATE_DNSKEY)" = "rumoured" ] || [ "$(key_get KEY2 STATE_DNSKEY)" = "omnipresent" ]; then
grep "${ZONE}\..*${DNSKEY_TTL}.*IN.*${_qtype}.*257.*.3.*${_key_algnum}" "dig.out.$DIR.test$n" > /dev/null || log_error "missing ${_qtype} record in response for key $(key_get KEY2 ID)"
grep "${ZONE}\..*${DNSKEY_TTL}.*IN.*${_qtype}.*257.*.3.*$(key_get KEY2 ALG_NUM)" "dig.out.$DIR.test$n" > /dev/null || log_error "missing ${_qtype} record in response for key $(key_get KEY2 ID)"
check_signatures $_qtype "dig.out.$DIR.test$n" "KSK"
numkeys=$((numkeys+1))
elif [ "$(key_get KEY2 EXPECT)" = "yes" ]; then
grep "${ZONE}\.*${DNSKEY_TTL}.*IN.*${_qtype}.*257.*.3.*${_key_algnum}" "dig.out.$DIR.test$n" > /dev/null && log_error "unexpected ${_qtype} record in response for key $(key_get KEY2 ID)"
grep "${ZONE}\.*${DNSKEY_TTL}.*IN.*${_qtype}.*257.*.3.*$(key_get KEY2 ALG_NUM)" "dig.out.$DIR.test$n" > /dev/null && log_error "unexpected ${_qtype} record in response for key $(key_get KEY2 ID)"
fi
if [ "$(key_get KEY3 STATE_DNSKEY)" = "rumoured" ] || [ "$(key_get KEY3 STATE_DNSKEY)" = "omnipresent" ]; then
grep "${ZONE}\..*${DNSKEY_TTL}.*IN.*${_qtype}.*257.*.3.*${_key_algnum}" "dig.out.$DIR.test$n" > /dev/null || log_error "missing ${_qtype} record in response for key $(key_get KEY3 ID)"
grep "${ZONE}\..*${DNSKEY_TTL}.*IN.*${_qtype}.*257.*.3.*$(key_get KEY3 ALG_NUM)" "dig.out.$DIR.test$n" > /dev/null || log_error "missing ${_qtype} record in response for key $(key_get KEY3 ID)"
check_signatures $_qtype "dig.out.$DIR.test$n" "KSK"
numkeys=$((numkeys+1))
elif [ "$(key_get KEY3 EXPECT)" = "yes" ]; then
grep "${ZONE}\..*${DNSKEY_TTL}.*IN.*${_qtype}.*257.*.3.*${_key_algnum}" "dig.out.$DIR.test$n" > /dev/null && log_error "unexpected ${_qtype} record in response for key $(key_get KEY3 ID)"
grep "${ZONE}\..*${DNSKEY_TTL}.*IN.*${_qtype}.*257.*.3.*$(key_get KEY3 ALG_NUM)" "dig.out.$DIR.test$n" > /dev/null && log_error "unexpected ${_qtype} record in response for key $(key_get KEY3 ID)"
fi
if [ "$(key_get KEY4 STATE_DNSKEY)" = "rumoured" ] || [ "$(key_get KEY4 STATE_DNSKEY)" = "omnipresent" ]; then
grep "${ZONE}\..*${DNSKEY_TTL}.*IN.*${_qtype}.*257.*.3.*$(key_get KEY4 ALG_NUM)" "dig.out.$DIR.test$n" > /dev/null || log_error "missing ${_qtype} record in response for key $(key_get KEY4 ID)"
check_signatures $_qtype "dig.out.$DIR.test$n" "KSK"
numkeys=$((numkeys+1))
elif [ "$(key_get KEY4 EXPECT)" = "yes" ]; then
grep "${ZONE}\..*${DNSKEY_TTL}.*IN.*${_qtype}.*257.*.3.*$(key_get KEY4 ALG_NUM)" "dig.out.$DIR.test$n" > /dev/null && log_error "unexpected ${_qtype} record in response for key $(key_get KEY4 ID)"
fi
lines=$(get_keys_which_signed $_qtype "dig.out.$DIR.test$n" | wc -l)
@ -1022,6 +1071,7 @@ zone_properties "ns3" "unsigned.kasp" "none" "0" "0" "10.53.0.3"
key_clear "KEY1"
key_clear "KEY2"
key_clear "KEY3"
key_clear "KEY4"
check_keys
check_apex
check_subdomain
@ -1033,6 +1083,7 @@ zone_properties "ns3" "unlimited.kasp" "unlimited" "1234" "1" "10.53.0.3"
key_properties "KEY1" "csk" "0" "13" "ECDSAP256SHA256" "256" "yes" "yes"
key_clear "KEY2"
key_clear "KEY3"
key_clear "KEY4"
# The first key is immediately published and activated.
key_timings "KEY1" "published" "active" "none" "none" "none"
# DNSKEY, RRSIG (ksk), RRSIG (zsk) are published. DS needs to wait.
@ -1059,6 +1110,7 @@ key_timings "KEY3" "published" "active" "retired" "none" "none"
key_states "KEY1" "omnipresent" "rumoured" "none" "rumoured" "hidden"
key_states "KEY2" "omnipresent" "rumoured" "rumoured" "none" "none"
key_states "KEY3" "omnipresent" "rumoured" "rumoured" "none" "none"
key_clear "KEY4"
check_keys
check_apex
check_subdomain
@ -1243,6 +1295,7 @@ key_states "KEY2" "omnipresent" "omnipresent" "omnipresent" "none" "none"
key_timings "KEY2" "published" "active" "retired" "none" "none"
# Expect only two keys.
key_clear "KEY3"
key_clear "KEY4"
check_keys
check_apex
@ -1553,6 +1606,99 @@ dnssec_verify
# Clear TSIG.
TSIG=""
#
# Testing DNSSEC introduction.
#
#
# Zone: step1.enable-dnssec.autosign.
#
zone_properties "ns3" "step1.enable-dnssec.autosign" "enable-dnssec" "300" "1" "10.53.0.3"
# The DNSKEY and signatures are introduced first, the DS remains hidden.
key_properties "KEY1" "csk" "0" "13" "ECDSAP256SHA256" "256" "yes" "yes"
key_timings "KEY1" "published" "active" "none" "none" "none"
key_states "KEY1" "omnipresent" "rumoured" "rumoured" "rumoured" "hidden"
key_clear "KEY2"
key_clear "KEY3"
check_keys
check_apex
check_subdomain
dnssec_verify
check_next_key_event() {
_expect=$1
n=$((n+1))
echo_i "check next key event for zone ${ZONE} ($n)"
ret=0
grep "zone ${ZONE}.*: next key event in .* seconds" "${DIR}/named.run" > "keyevent.out.$ZONE.test$n" || log_error "no next key event for zone ${ZONE}"
# Get the latest next key event.
_time=$(awk '{print $10}' < "keyevent.out.$ZONE.test$n" | tail -1)
# 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" || log_error "bad next key event time ${_time} for zone ${ZONE} (expect ${_expect})"
test $_expectmax -ge "$_time" || log_error "bad next key event time ${_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.
#
zone_properties "ns3" "step2.enable-dnssec.autosign" "enable-dnssec" "300" "1" "10.53.0.3"
# The DNSKEY and signatures are introduced first, the DS remains hidden.
key_states "KEY1" "omnipresent" "omnipresent" "rumoured" "omnipresent" "hidden"
check_keys
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.
#
zone_properties "ns3" "step3.enable-dnssec.autosign" "enable-dnssec" "300" "1" "10.53.0.3"
# The DS can be introduced.
key_states "KEY1" "omnipresent" "omnipresent" "omnipresent" "omnipresent" "rumoured"
check_keys
check_apex
check_subdomain
dnssec_verify
# Next key event is when the DS can move to the OMNIPRESENT state. This occurs
# when the parent registration and propagation delay have passed, plus the
# DS TTL and retire safety delay: 1d + 1h + 2h + 20m = 27h20m = 98400 seconds
check_next_key_event 98400
#
# Zone: step4.enable-dnssec.autosign.
#
zone_properties "ns3" "step4.enable-dnssec.autosign" "enable-dnssec" "300" "1" "10.53.0.3"
# The DS is omnipresent.
key_states "KEY1" "omnipresent" "omnipresent" "omnipresent" "omnipresent" "omnipresent"
check_keys
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.
#
@ -1575,33 +1721,12 @@ check_apex
check_subdomain
dnssec_verify
check_next_key_event() {
_expect=$1
n=$((n+1))
echo_i "check next key event for zone ${ZONE} ($n)"
ret=0
grep "zone ${ZONE}.*: next key event in .* seconds" "${DIR}/named.run" > "keyevent.out.$ZONE.test$n" || log_error "no next key event for zone ${ZONE}"
_time=$(awk '{print $10}' < "keyevent.out.$ZONE.test$n")
# The next key event time must within 60 seconds of the
# expected time.
_expectmin=$((_expect-60))
_expectmax=$((_expect+60))
test $_expectmin -le "$_time" || log_error "bad next key event time ${_time} for zone ${ZONE} (expect ${_expect})"
test $_expectmax -ge "$_time" || log_error "bad next key event time ${_time} for zone ${ZONE} (expect ${_expect})"
test "$ret" -eq 0 || echo_i "failed"
status=$((status+ret))
}
# 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.
#
@ -1961,7 +2086,7 @@ dnssec_verify
check_next_key_event 13708800
#
# Testing CSK key rollover (1).
# Testing CSK key rollover (2).
#
#
@ -2098,5 +2223,347 @@ dnssec_verify
# Next key event is when the new successor needs to be published.
check_next_key_event 14684400
#
# Testing algorithm rollover.
#
#
# Zone: step1.algorithm-roll.kasp
#
zone_properties "ns6" "step1.algorithm-roll.kasp" "rsasha1" "3600" "2" "10.53.0.6"
# The KSK (KEY1) and ZSK (KEY2) start in OMNIPRESENT.
key_properties "KEY1" "ksk" "0" "5" "RSASHA1" "2048" "no" "yes"
key_timings "KEY1" "published" "active" "none" "none" "none"
key_states "KEY1" "omnipresent" "omnipresent" "none" "omnipresent" "omnipresent"
key_properties "KEY2" "zsk" "0" "5" "RSASHA1" "2048" "yes" "no"
key_timings "KEY2" "published" "active" "none" "none" "none"
key_states "KEY2" "omnipresent" "omnipresent" "omnipresent" "none" "none"
key_clear "KEY3"
key_clear "KEY4"
check_keys
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
#
zone_properties "ns6" "step1.csk-algorithm-roll.kasp" "csk-algoroll" "3600" "1" "10.53.0.6"
# The CSK (KEY1) starta in OMNIPRESENT.
key_properties "KEY1" "csk" "0" "5" "RSASHA1" "2048" "yes" "yes"
key_timings "KEY1" "published" "active" "none" "none" "none"
key_states "KEY1" "omnipresent" "omnipresent" "omnipresent" "omnipresent" "omnipresent"
key_clear "KEY2"
key_clear "KEY3"
key_clear "KEY4"
check_keys
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
# Reconfig dnssec-policy (triggering algorithm roll).
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
# 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 a error.
#
n=$((n+1))
echo_i "waiting for reconfig signing changes to take effect ($n)"
i=0
while [ $i -lt 30 ]
do
ret=0
while read -r zone
do
dig_with_opts "$zone" @10.53.0.6 nsec > "dig.out.ns6.test$n.$zone" || ret=1
grep "NS SOA" "dig.out.ns6.test$n.$zone" > /dev/null || ret=1
grep "$zone\..*IN.*RRSIG" "dig.out.ns6.test$n.$zone" > /dev/null || ret=1
done < ns6/zones.2
i=$((i+1))
if [ $ret = 0 ]; then break; fi
echo_i "waiting ... ($i)"
sleep 1
done
test "$ret" -eq 0 || echo_i "failed"
status=$((status+ret))
next_key_event_threshold=$((next_key_event_threshold+i))
#
# Testing KSK/ZSK algorithm rollover.
#
#
# Zone: step1.algorithm-roll.kasp
#
zone_properties "ns6" "step1.algorithm-roll.kasp" "ecdsa256" "3600" "4" "10.53.0.6"
# The RSAHSHA1 keys are outroducing.
key_properties "KEY1" "ksk" "0" "5" "RSASHA1" "2048" "no" "yes"
key_timings "KEY1" "published" "active" "retired" "none" "none"
key_states "KEY1" "hidden" "omnipresent" "none" "omnipresent" "omnipresent"
key_properties "KEY2" "zsk" "0" "5" "RSASHA1" "2048" "yes" "no"
key_timings "KEY2" "published" "active" "retired" "none" "none"
key_states "KEY2" "hidden" "omnipresent" "omnipresent" "none" "none"
# The ECDSAP256SHA256 keys are introducing.
key_properties "KEY3" "ksk" "0" "13" "ECDSAP256SHA256" "256" "no" "yes"
key_timings "KEY3" "published" "active" "none" "none" "none"
key_states "KEY3" "omnipresent" "rumoured" "none" "rumoured" "hidden"
key_properties "KEY4" "zsk" "0" "13" "ECDSAP256SHA256" "256" "yes" "no"
key_timings "KEY4" "published" "active" "none" "none" "none"
key_states "KEY4" "omnipresent" "rumoured" "rumoured" "none" "none"
check_keys
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
#
zone_properties "ns6" "step2.algorithm-roll.kasp" "ecdsa256" "3600" "4" "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.
key_states "KEY3" "omnipresent" "omnipresent" "none" "omnipresent" "hidden"
key_states "KEY4" "omnipresent" "omnipresent" "rumoured" "none" "none"
check_keys
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.
check_next_key_event 21600
#
# Zone: step3.algorithm-roll.kasp
#
zone_properties "ns6" "step3.algorithm-roll.kasp" "ecdsa256" "3600" "4" "10.53.0.6"
# The RSAHSHA1 keys are outroducing, and it is time to swap the DS.
key_states "KEY1" "hidden" "omnipresent" "none" "omnipresent" "unretentive"
# The ECDSAP256SHA256 keys are introducing. The DNSKEY RRset and all signatures
# are now omnipresent, so the DS can be introduced.
key_states "KEY3" "omnipresent" "omnipresent" "none" "omnipresent" "rumoured"
key_states "KEY4" "omnipresent" "omnipresent" "omnipresent" "none" "none"
check_keys
check_apex
check_subdomain
dnssec_verify
# Next key event is when the DS becomes OMNIPRESENT. This happens after the
# parent registration delay, parent propagation delay, retire safety delay,
# and DS TTL: 24h + 1h + 2h + 2h = 29h = 104400 seconds.
check_next_key_event 104400
#
# Zone: step4.algorithm-roll.kasp
#
zone_properties "ns6" "step4.algorithm-roll.kasp" "ecdsa256" "3600" "4" "10.53.0.6"
# The old DS is HIDDEN, we can remove the old algorithm DNSKEY/RRSIG records.
key_properties "KEY1" "ksk" "0" "5" "RSASHA1" "2048" "no" "no"
key_states "KEY1" "hidden" "unretentive" "none" "unretentive" "hidden"
key_properties "KEY2" "zsk" "0" "5" "RSASHA1" "2048" "no" "no"
key_states "KEY2" "hidden" "unretentive" "unretentive" "none" "none"
# The ECDSAP256SHA256 DS is now OMNIPRESENT.
key_states "KEY3" "omnipresent" "omnipresent" "none" "omnipresent" "omnipresent"
check_keys
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
#
zone_properties "ns6" "step5.algorithm-roll.kasp" "ecdsa256" "3600" "4" "10.53.0.6"
# The DNSKEY becomes HIDDEN.
key_states "KEY1" "hidden" "hidden" "none" "hidden" "hidden"
key_states "KEY2" "hidden" "hidden" "unretentive" "none" "none"
check_keys
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
check_next_key_event 25200
#
# Zone: step6.algorithm-roll.kasp
#
zone_properties "ns6" "step6.algorithm-roll.kasp" "ecdsa256" "3600" "4" "10.53.0.6"
# The zone signatures should now also be HIDDEN.
key_states "KEY2" "hidden" "hidden" "hidden" "none" "none"
check_keys
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.
#
#
# Zone: step1.csk-algorithm-roll.kasp
#
zone_properties "ns6" "step1.csk-algorithm-roll.kasp" "csk-algoroll" "3600" "2" "10.53.0.6"
# The RSAHSHA1 key is outroducing.
key_properties "KEY1" "csk" "0" "5" "RSASHA1" "2048" "yes" "yes"
key_timings "KEY1" "published" "active" "retired" "none" "none"
key_states "KEY1" "hidden" "omnipresent" "omnipresent" "omnipresent" "omnipresent"
# The ECDSAP256SHA256 key is introducing.
key_properties "KEY2" "csk" "0" "13" "ECDSAP256SHA256" "256" "yes" "yes"
key_timings "KEY2" "published" "active" "none" "none" "none"
key_states "KEY2" "omnipresent" "rumoured" "rumoured" "rumoured" "hidden"
key_clear "KEY3"
key_clear "KEY4"
check_keys
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
#
zone_properties "ns6" "step2.csk-algorithm-roll.kasp" "csk-algoroll" "3600" "2" "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.
key_states "KEY2" "omnipresent" "omnipresent" "rumoured" "omnipresent" "hidden"
check_keys
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.
check_next_key_event 21600
#
# Zone: step3.csk-algorithm-roll.kasp
#
zone_properties "ns6" "step3.csk-algorithm-roll.kasp" "csk-algoroll" "3600" "2" "10.53.0.6"
# The RSAHSHA1 key is outroducing, and it is time to swap the DS.
key_states "KEY1" "hidden" "omnipresent" "omnipresent" "omnipresent" "unretentive"
# The ECDSAP256SHA256 key is introducing. The DNSKEY RRset and all signatures
# are now omnipresent, so the DS can be introduced.
key_states "KEY2" "omnipresent" "omnipresent" "omnipresent" "omnipresent" "rumoured"
check_keys
check_apex
check_subdomain
dnssec_verify
# Next key event is when the DS becomes OMNIPRESENT. This happens after the
# parent registration delay, parent propagation delay, retire safety delay,
# and DS TTL: 24h + 1h + 2h + 2h = 29h = 104400 seconds.
check_next_key_event 104400
#
# Zone: step4.csk-algorithm-roll.kasp
#
zone_properties "ns6" "step4.csk-algorithm-roll.kasp" "csk-algoroll" "3600" "2" "10.53.0.6"
# The old DS is HIDDEN, we can remove the old algorithm DNSKEY/RRSIG records.
key_properties "KEY1" "csk" "0" "5" "RSASHA1" "2048" "no" "no"
key_states "KEY1" "hidden" "unretentive" "unretentive" "unretentive" "hidden"
# The ECDSAP256SHA256 DS is now OMNIPRESENT.
key_states "KEY2" "omnipresent" "omnipresent" "omnipresent" "omnipresent" "omnipresent"
check_keys
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
#
zone_properties "ns6" "step5.csk-algorithm-roll.kasp" "csk-algoroll" "3600" "2" "10.53.0.6"
# The DNSKEY becomes HIDDEN.
key_states "KEY1" "hidden" "hidden" "unretentive" "hidden" "hidden"
check_keys
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
check_next_key_event 25200
#
# Zone: step6.csk-algorithm-roll.kasp
#
zone_properties "ns6" "step6.csk-algorithm-roll.kasp" "csk-algoroll" "3600" "2" "10.53.0.6"
# The zone signatures should now also be HIDDEN.
key_states "KEY1" "hidden" "hidden" "hidden" "hidden" "hidden"
check_keys
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
echo_i "exit status: $status"
[ $status -eq 0 ] || exit 1

View file

@ -546,8 +546,14 @@ keymgr_ds_hidden_or_chained(dns_dnsseckeylist_t *keyring, dns_dnsseckey_t *key,
* chain of trust (can be this key).
*/
dnskey_omnipresent[DST_KEY_DS] = NA;
(void)dst_key_getstate(dkey->key, DST_KEY_DS,
&dnskey_omnipresent[DST_KEY_DS]);
if (next_state != NA &&
dst_key_id(dkey->key) == dst_key_id(key->key)) {
/* Check next state rather than current state. */
dnskey_omnipresent[DST_KEY_DS] = next_state;
} else {
(void)dst_key_getstate(dkey->key, DST_KEY_DS,
&dnskey_omnipresent[DST_KEY_DS]);
}
if (!keymgr_key_exists_with_state(
keyring, key, type, next_state, dnskey_omnipresent,
na, false, match_algorithms))
@ -993,14 +999,22 @@ keymgr_transition_time(dns_dnsseckey_t *key, int type,
* TTLsig is the maximum TTL of all zone RRSIG
* records. This translates to:
*
* Dsgn + zone-propragation-delay + max-zone-ttl.
* Dsgn + zone-propagation-delay + max-zone-ttl.
*
* We will also add the retire-safety interval.
*/
nexttime = lastchange + dns_kasp_signdelay(kasp) +
dns_kasp_zonemaxttl(kasp) +
nexttime = lastchange + dns_kasp_zonemaxttl(kasp) +
dns_kasp_zonepropagationdelay(kasp) +
dns_kasp_retiresafety(kasp);
/*
* Only add the sign delay Dsgn if there is an actual
* predecessor key.
*/
uint32_t pre;
if (dst_key_getnum(key->key, DST_NUM_PREDECESSOR,
&pre) == ISC_R_SUCCESS) {
nexttime += dns_kasp_signdelay(kasp);
}
break;
default:
nexttime = now;
@ -1282,6 +1296,39 @@ dns_keymgr_run(const dns_name_t *origin, dns_rdataclass_t rdclass,
}
}
/* Do we need to remove keys? */
for (dns_dnsseckey_t *dkey = ISC_LIST_HEAD(*keyring); dkey != NULL;
dkey = ISC_LIST_NEXT(dkey, link))
{
bool found_match = false;
/* Make sure this key knows about roles. */
keymgr_key_init_role(dkey);
for (kkey = ISC_LIST_HEAD(dns_kasp_keys(kasp)); kkey != NULL;
kkey = ISC_LIST_NEXT(kkey, link))
{
if (keymgr_dnsseckey_kaspkey_match(dkey, kkey)) {
found_match = true;
dst_key_format(dkey->key, keystr,
sizeof(keystr));
isc_log_write(dns_lctx, DNS_LOGCATEGORY_DNSSEC,
DNS_LOGMODULE_DNSSEC,
ISC_LOG_DEBUG(1),
"keymgr: DNSKEY %s (%s) matches "
"policy %s",
keystr, keymgr_keyrole(dkey->key),
dns_kasp_getname(kasp));
break;
}
}
/* No match, so retire unwanted retire key. */
if (!found_match) {
keymgr_key_retire(dkey, now);
}
}
/* Create keys according to the policy, if come in short. */
for (kkey = ISC_LIST_HEAD(dns_kasp_keys(kasp)); kkey != NULL;
kkey = ISC_LIST_NEXT(kkey, link))
@ -1294,9 +1341,6 @@ dns_keymgr_run(const dns_name_t *origin, dns_rdataclass_t rdclass,
for (dns_dnsseckey_t *dkey = ISC_LIST_HEAD(*keyring);
dkey != NULL; dkey = ISC_LIST_NEXT(dkey, link))
{
/* Make sure this key knows about roles. */
keymgr_key_init_role(dkey);
if (keymgr_dnsseckey_kaspkey_match(dkey, kkey)) {
/* Found a match. */

View file

@ -19657,17 +19657,28 @@ zone_rekey(dns_zone_t *zone) {
/*
* If keymgr provided a next time, use the calculated next rekey time.
*/
if (kasp != NULL && nexttime > 0) {
if (kasp != NULL) {
isc_time_t timenext;
uint32_t nexttime_seconds;
DNS_ZONE_TIME_ADD(&timenow, nexttime - now, &timenext);
/*
* Set the key refresh timer to the next scheduled key event
* or to 'dnssec-loadkeys-interval' seconds in the future
* if no next key event is scheduled (nexttime == 0).
*/
if (nexttime > 0) {
nexttime_seconds = nexttime - now;
} else {
nexttime_seconds = zone->refreshkeyinterval;
}
DNS_ZONE_TIME_ADD(&timenow, nexttime_seconds, &timenext);
zone->refreshkeytime = timenext;
zone_settimer(zone, &timenow);
isc_time_formattimestamp(&zone->refreshkeytime, timebuf, 80);
dnssec_log(zone, ISC_LOG_DEBUG(3),
"next key event in %u seconds: %s", (nexttime - now),
timebuf);
"next key event in %u seconds", nexttime_seconds);
dnssec_log(zone, ISC_LOG_INFO, "next key event: %s", timebuf);
}
/*

View file

@ -697,6 +697,7 @@
./bin/tests/system/kasp/ns3/setup.sh SH 2019,2020
./bin/tests/system/kasp/ns4/setup.sh SH 2019,2020
./bin/tests/system/kasp/ns5/setup.sh SH 2019,2020
./bin/tests/system/kasp/ns6/setup.sh SH 2020
./bin/tests/system/kasp/setup.sh SH 2019,2020
./bin/tests/system/kasp/tests.sh SH 2019,2020
./bin/tests/system/keepalive/clean.sh SH 2017,2018,2019,2020