fix: usr: Make key rollovers more robust

A manual rollover when the zone is in an invalid DNSSEC state causes predecessor keys to be removed too quickly. Additional safeguards to prevent this have been added. DNSSEC records will not be removed from the zone until the underlying state machine has moved back into a valid DNSSEC state.

Closes #5458

Merge branch '5458-safeguard-against-key-rollovers-when-in-invalid-state' into 'main'

See merge request isc-projects/bind9!10813
This commit is contained in:
Matthijs Mekking 2025-12-05 12:07:39 +00:00
commit 42b0046d1e
24 changed files with 344 additions and 200 deletions

View file

@ -31,10 +31,13 @@ setup() {
mkdir inactive
T="now-7d"
keytimes="-P $T -A $T"
setup secure.example
cp $infile $zonefile
ksk=$($KEYGEN -a $DEFAULT_ALGORITHM -3 -q -fk $zone 2>kg.out) || dumpit kg.out
$KEYGEN -a $DEFAULT_ALGORITHM -3 -q $zone >kg.out 2>&1 || dumpit kg.out
ksk=$($KEYGEN -a $DEFAULT_ALGORITHM -3 -q -fk $keytimes $zone 2>kg.out) || dumpit kg.out
$KEYGEN -a $DEFAULT_ALGORITHM -3 -q $keytimes $zone >kg.out 2>&1 || dumpit kg.out
$DSFROMKEY $ksk.key >dsset-${zone}.
#
@ -42,8 +45,8 @@ $DSFROMKEY $ksk.key >dsset-${zone}.
#
setup secure.nsec3.example
cp $infile $zonefile
ksk=$($KEYGEN -q -a $DEFAULT_ALGORITHM -3 -fk $zone 2>kg.out) || dumpit kg.out
$KEYGEN -q -a $DEFAULT_ALGORITHM -3 $zone >kg.out 2>&1 || dumpit kg.out
ksk=$($KEYGEN -q -a $DEFAULT_ALGORITHM -3 -fk $keytimes $zone 2>kg.out) || dumpit kg.out
$KEYGEN -q -a $DEFAULT_ALGORITHM -3 $keytimes $zone >kg.out 2>&1 || dumpit kg.out
$DSFROMKEY $ksk.key >dsset-${zone}.
#
@ -51,8 +54,8 @@ $DSFROMKEY $ksk.key >dsset-${zone}.
#
setup nsec3.nsec3.example
cp $infile $zonefile
ksk=$($KEYGEN -q -a $DEFAULT_ALGORITHM -3 -fk $zone 2>kg.out) || dumpit kg.out
$KEYGEN -q -a $DEFAULT_ALGORITHM -3 $zone >kg.out 2>&1 || dumpit kg.out
ksk=$($KEYGEN -q -a $DEFAULT_ALGORITHM -3 -fk $keytimes $zone 2>kg.out) || dumpit kg.out
$KEYGEN -q -a $DEFAULT_ALGORITHM -3 $keytimes $zone >kg.out 2>&1 || dumpit kg.out
$DSFROMKEY $ksk.key >dsset-${zone}.
#
@ -74,8 +77,8 @@ done
#
setup optout.nsec3.example
cp $infile $zonefile
ksk=$($KEYGEN -q -a $DEFAULT_ALGORITHM -3 -fk $zone 2>kg.out) || dumpit kg.out
$KEYGEN -q -a $DEFAULT_ALGORITHM -3 $zone >kg.out 2>&1 || dumpit kg.out
ksk=$($KEYGEN -q -a $DEFAULT_ALGORITHM -3 -fk $keytimes $zone 2>kg.out) || dumpit kg.out
$KEYGEN -q -a $DEFAULT_ALGORITHM -3 $keytimes $zone >kg.out 2>&1 || dumpit kg.out
$DSFROMKEY $ksk.key >dsset-${zone}.
#
@ -83,8 +86,8 @@ $DSFROMKEY $ksk.key >dsset-${zone}.
#
setup nsec3.example
cat $infile dsset-*.${zone}. >$zonefile
ksk=$($KEYGEN -q -a $DEFAULT_ALGORITHM -3 -fk $zone 2>kg.out) || dumpit kg.out
$KEYGEN -q -a $DEFAULT_ALGORITHM -3 $zone >kg.out 2>&1 || dumpit kg.out
ksk=$($KEYGEN -q -a $DEFAULT_ALGORITHM -3 -fk $keytimes $zone 2>kg.out) || dumpit kg.out
$KEYGEN -q -a $DEFAULT_ALGORITHM -3 $keytimes $zone >kg.out 2>&1 || dumpit kg.out
$DSFROMKEY $ksk.key >dsset-${zone}.
#
@ -92,9 +95,9 @@ $DSFROMKEY $ksk.key >dsset-${zone}.
#
setup autonsec3.example
cat $infile >$zonefile
ksk=$($KEYGEN -G -q -a $DEFAULT_ALGORITHM -3 -fk $zone 2>kg.out) || dumpit kg.out
ksk=$($KEYGEN -q -a $DEFAULT_ALGORITHM -3 -fk $keytimes $zone 2>kg.out) || dumpit kg.out
echo $ksk >../autoksk.key
zsk=$($KEYGEN -G -q -a $DEFAULT_ALGORITHM -3 $zone 2>kg.out) || dumpit kg.out
zsk=$($KEYGEN -q -a $DEFAULT_ALGORITHM -3 $keytimes $zone 2>kg.out) || dumpit kg.out
echo $zsk >../autozsk.key
$DSFROMKEY $ksk.key >dsset-${zone}.
@ -103,8 +106,8 @@ $DSFROMKEY $ksk.key >dsset-${zone}.
#
setup secure.optout.example
cp $infile $zonefile
ksk=$($KEYGEN -q -a $DEFAULT_ALGORITHM -3 -fk $zone 2>kg.out) || dumpit kg.out
$KEYGEN -q -a $DEFAULT_ALGORITHM -3 $zone >kg.out 2>&1 || dumpit kg.out
ksk=$($KEYGEN -q -a $DEFAULT_ALGORITHM -3 -fk $keytimes $zone 2>kg.out) || dumpit kg.out
$KEYGEN -q -a $DEFAULT_ALGORITHM -3 $keytimes $zone >kg.out 2>&1 || dumpit kg.out
$DSFROMKEY $ksk.key >dsset-${zone}.
#
@ -112,8 +115,8 @@ $DSFROMKEY $ksk.key >dsset-${zone}.
#
setup nsec3.optout.example
cp $infile $zonefile
ksk=$($KEYGEN -q -a $DEFAULT_ALGORITHM -3 -fk $zone 2>kg.out) || dumpit kg.out
$KEYGEN -q -a $DEFAULT_ALGORITHM -3 $zone >kg.out 2>&1 || dumpit kg.out
ksk=$($KEYGEN -q -a $DEFAULT_ALGORITHM -3 -fk $keytimes $zone 2>kg.out) || dumpit kg.out
$KEYGEN -q -a $DEFAULT_ALGORITHM -3 $keytimes $zone >kg.out 2>&1 || dumpit kg.out
$DSFROMKEY $ksk.key >dsset-${zone}.
#
@ -121,8 +124,8 @@ $DSFROMKEY $ksk.key >dsset-${zone}.
#
setup optout.optout.example
cp $infile $zonefile
ksk=$($KEYGEN -q -a $DEFAULT_ALGORITHM -3 -fk $zone 2>kg.out) || dumpit kg.out
$KEYGEN -q -a $DEFAULT_ALGORITHM -3 $zone >kg.out 2>&1 || dumpit kg.out
ksk=$($KEYGEN -q -a $DEFAULT_ALGORITHM -3 -fk $keytimes $zone 2>kg.out) || dumpit kg.out
$KEYGEN -q -a $DEFAULT_ALGORITHM -3 $keytimes $zone >kg.out 2>&1 || dumpit kg.out
$DSFROMKEY $ksk.key >dsset-${zone}.
#
@ -130,8 +133,8 @@ $DSFROMKEY $ksk.key >dsset-${zone}.
#
setup optout.example
cat $infile dsset-*.${zone}. >$zonefile
ksk=$($KEYGEN -q -a $DEFAULT_ALGORITHM -3 -fk $zone 2>kg.out) || dumpit kg.out
$KEYGEN -q -a $DEFAULT_ALGORITHM -3 $zone >kg.out 2>&1 || dumpit kg.out
ksk=$($KEYGEN -q -a $DEFAULT_ALGORITHM -3 -fk $keytimes $zone 2>kg.out) || dumpit kg.out
$KEYGEN -q -a $DEFAULT_ALGORITHM -3 $keytimes $zone >kg.out 2>&1 || dumpit kg.out
$DSFROMKEY $ksk.key >dsset-${zone}.
#
@ -139,8 +142,8 @@ $DSFROMKEY $ksk.key >dsset-${zone}.
#
setup rsasha256.example
cp $infile $zonefile
ksk=$($KEYGEN -q -a RSASHA256 -b 2048 -fk $zone 2>kg.out) || dumpit kg.out
$KEYGEN -q -a RSASHA256 -b 2048 $zone >kg.out 2>&1 || dumpit kg.out
ksk=$($KEYGEN -q -a RSASHA256 -b 2048 -fk $keytimes $zone 2>kg.out) || dumpit kg.out
$KEYGEN -q -a RSASHA256 -b 2048 $keytimes $zone >kg.out 2>&1 || dumpit kg.out
$DSFROMKEY $ksk.key >dsset-${zone}.
#
@ -148,8 +151,8 @@ $DSFROMKEY $ksk.key >dsset-${zone}.
#
setup rsasha512.example
cp $infile $zonefile
ksk=$($KEYGEN -q -a RSASHA512 -b 2048 -fk $zone 2>kg.out) || dumpit kg.out
$KEYGEN -q -a RSASHA512 -b 2048 $zone >kg.out 2>&1 || dumpit kg.out
ksk=$($KEYGEN -q -a RSASHA512 -b 2048 -fk $keytimes $zone 2>kg.out) || dumpit kg.out
$KEYGEN -q -a RSASHA512 -b 2048 $keytimes $zone >kg.out 2>&1 || dumpit kg.out
$DSFROMKEY $ksk.key >dsset-${zone}.
#
@ -160,8 +163,8 @@ $DSFROMKEY $ksk.key >dsset-${zone}.
if [ $RSASHA1_SUPPORTED = 1 ]; then
setup nsec-only.example
cp $infile $zonefile
ksk=$($KEYGEN -q -a RSASHA1 -fk $zone 2>kg.out) || dumpit kg.out
$KEYGEN -q -a RSASHA1 $zone >kg.out 2>&1 || dumpit kg.out
ksk=$($KEYGEN -q -a RSASHA1 -fk $keytimes $zone 2>kg.out) || dumpit kg.out
$KEYGEN -q -a RSASHA1 $keytimes $zone >kg.out 2>&1 || dumpit kg.out
$DSFROMKEY $ksk.key >dsset-${zone}.
else
echo_i "skip: nsec-only.example - signing with RSASHA1 not supported"
@ -178,8 +181,8 @@ while [ $count -le 1000 ]; do
echo "label${count} IN TXT label${count}" >>$zonefile
count=$((count + 1))
done
$KEYGEN -q -a $DEFAULT_ALGORITHM -fk $zone >kg.out 2>&1 || dumpit kg.out
$KEYGEN -q -a $DEFAULT_ALGORITHM $zone >kg.out 2>&1 || dumpit kg.out
$KEYGEN -q -a $DEFAULT_ALGORITHM -fk $keytimes $zone >kg.out 2>&1 || dumpit kg.out
$KEYGEN -q -a $DEFAULT_ALGORITHM $keytimes $zone >kg.out 2>&1 || dumpit kg.out
$SIGNER -PS -x -s now-1y -e now-6mo -o $zone -f $zonefile.signed $zonefile >s.out || dumpit s.out
cp $zonefile.signed $zonefile.bak
mv $zonefile.signed $zonefile
@ -188,16 +191,16 @@ mv $zonefile.signed $zonefile
# NSEC3->NSEC transition test zone.
#
setup nsec3-to-nsec.example
$KEYGEN -q -a $DEFAULT_ALGORITHM -fk $zone >kg.out 2>&1 || dumpit kg.out
$KEYGEN -q -a $DEFAULT_ALGORITHM $zone >kg.out 2>&1 || dumpit kg.out
$KEYGEN -q -a $DEFAULT_ALGORITHM -fk $keytimes $zone >kg.out 2>&1 || dumpit kg.out
$KEYGEN -q -a $DEFAULT_ALGORITHM $keytimes $zone >kg.out 2>&1 || dumpit kg.out
$SIGNER -S -3 beef -A -o $zone -f $zonefile $infile >s.out || dumpit s.out
#
# NSEC3->NSEC3 transition test zone.
#
setup nsec3-to-nsec3.example
$KEYGEN -q -a $DEFAULT_ALGORITHM -fk $zone >kg.out 2>&1 || dumpit kg.out
$KEYGEN -q -a $DEFAULT_ALGORITHM $zone >kg.out 2>&1 || dumpit kg.out
$KEYGEN -q -a $DEFAULT_ALGORITHM -fk $keytimes $zone >kg.out 2>&1 || dumpit kg.out
$KEYGEN -q -a $DEFAULT_ALGORITHM $keytimes $zone >kg.out 2>&1 || dumpit kg.out
$SIGNER -S -3 beef -A -o $zone -f $zonefile $infile >s.out || dumpit s.out
#
@ -205,8 +208,8 @@ $SIGNER -S -3 beef -A -o $zone -f $zonefile $infile >s.out || dumpit s.out
#
setup prepub.example
infile="prepub.example.db.in"
$KEYGEN -a $DEFAULT_ALGORITHM -3 -q -fk $zone >kg.out 2>&1 || dumpit kg.out
zsk=$($KEYGEN -a $DEFAULT_ALGORITHM -3 -q $zone 2>kg.out) || dumpit kg.out
$KEYGEN -a $DEFAULT_ALGORITHM -3 -q -fk $keytimes $zone >kg.out 2>&1 || dumpit kg.out
zsk=$($KEYGEN -a $DEFAULT_ALGORITHM -3 -q $keytimes $zone 2>kg.out) || dumpit kg.out
echo $zsk >../prepub.key
$SIGNER -S -3 beef -o $zone -f $zonefile $infile >s.out || dumpit s.out
@ -214,29 +217,29 @@ $SIGNER -S -3 beef -o $zone -f $zonefile $infile >s.out || dumpit s.out
# Key TTL tests.
#
# no default key TTL; DNSKEY should get SOA TTL
# no default key TTL; DNSKEY should get default dnskey-ttl
setup ttl1.example
$KEYGEN -a $DEFAULT_ALGORITHM -3 -q -fk $zone >kg.out 2>&1 || dumpit kg.out
$KEYGEN -a $DEFAULT_ALGORITHM -3 -q $zone >kg.out 2>&1 || dumpit kg.out
$KEYGEN -a $DEFAULT_ALGORITHM -3 -q -fk $keytimes $zone >kg.out 2>&1 || dumpit kg.out
$KEYGEN -a $DEFAULT_ALGORITHM -3 -q $keytimes $zone >kg.out 2>&1 || dumpit kg.out
cp $infile $zonefile
# default key TTL should be used
# default dnskey-ttl should be used
setup ttl2.example
$KEYGEN -a $DEFAULT_ALGORITHM -3 -q -fk -L 60 $zone >kg.out 2>&1 || dumpit kg.out
$KEYGEN -a $DEFAULT_ALGORITHM -3 -q -L 60 $zone >kg.out 2>&1 || dumpit kg.out
$KEYGEN -a $DEFAULT_ALGORITHM -3 -q -fk -L 60 $keytimes $zone >kg.out 2>&1 || dumpit kg.out
$KEYGEN -a $DEFAULT_ALGORITHM -3 -q -L 60 $keytimes $zone >kg.out 2>&1 || dumpit kg.out
cp $infile $zonefile
# mismatched key TTLs, should use shortest
# mismatched key TTLs, should use default dnskey-ttl
setup ttl3.example
$KEYGEN -a $DEFAULT_ALGORITHM -3 -q -fk -L 30 $zone >kg.out 2>&1 || dumpit kg.out
$KEYGEN -a $DEFAULT_ALGORITHM -3 -q -L 60 $zone >kg.out 2>&1 || dumpit kg.out
$KEYGEN -a $DEFAULT_ALGORITHM -3 -q -fk -L 30 $keytimes $zone >kg.out 2>&1 || dumpit kg.out
$KEYGEN -a $DEFAULT_ALGORITHM -3 -q -L 60 $keytimes $zone >kg.out 2>&1 || dumpit kg.out
cp $infile $zonefile
# existing DNSKEY RRset, should retain TTL
# existing DNSKEY RRset, should update to use dnksey-ttl
setup ttl4.example
$KEYGEN -a $DEFAULT_ALGORITHM -3 -q -L 30 -fk $zone >kg.out 2>&1 || dumpit kg.out
cat ${infile} K${zone}.+*.key >$zonefile
$KEYGEN -a $DEFAULT_ALGORITHM -3 -q -L 180 $zone >kg.out 2>&1 || dumpit kg.out
$KEYGEN -a $DEFAULT_ALGORITHM -3 -q -L 30 -fk $keytimes $zone >kg.out 2>&1 || dumpit kg.out
$KEYGEN -a $DEFAULT_ALGORITHM -3 -q -L 30 $keytimes $zone >kg.out 2>&1 || dumpit kg.out
cp $infile $zonefile
#
# A zone with a DNSKEY RRset that is published before it's activated
@ -253,8 +256,8 @@ cp delay.example.db.in delay.example.db
# is missing.
#
setup noksk.example
ksk=$($KEYGEN -q -a $DEFAULT_ALGORITHM -3 -fk $zone 2>kg.out) || dumpit kg.out
zsk=$($KEYGEN -q -a $DEFAULT_ALGORITHM -3 $zone 2>kg.out) || dumpit kg.out
ksk=$($KEYGEN -q -a $DEFAULT_ALGORITHM -3 -fk $keytimes $zone 2>kg.out) || dumpit kg.out
zsk=$($KEYGEN -q -a $DEFAULT_ALGORITHM -3 $keytimes $zone 2>kg.out) || dumpit kg.out
$SIGNER -S -P -s now-1mo -e now-1mi -o $zone -f $zonefile ${zonefile}.in >s.out || dumpit s.out
echo $ksk >../noksk-ksk.key
rm -f ${ksk}.private
@ -264,8 +267,8 @@ rm -f ${ksk}.private
# is missing.
#
setup nozsk.example
ksk=$($KEYGEN -q -a $DEFAULT_ALGORITHM -3 -fk $zone 2>kg.out) || dumpit kg.out
zsk=$($KEYGEN -q -a $DEFAULT_ALGORITHM -3 $zone 2>kg.out) || dumpit kg.out
ksk=$($KEYGEN -q -a $DEFAULT_ALGORITHM -3 -fk $keytimes $zone 2>kg.out) || dumpit kg.out
zsk=$($KEYGEN -q -a $DEFAULT_ALGORITHM -3 $keytimes $zone 2>kg.out) || dumpit kg.out
$SIGNER -S -P -s now-1mo -e now-1mi -o $zone -f $zonefile ${zonefile}.in >s.out || dumpit s.out
echo $ksk >../nozsk-ksk.key
echo $zsk >../nozsk-zsk.key
@ -276,8 +279,8 @@ rm -f ${zsk}.private
# is inactive.
#
setup inaczsk.example
ksk=$($KEYGEN -q -a $DEFAULT_ALGORITHM -3 -fk $zone 2>kg.out) || dumpit kg.out
zsk=$($KEYGEN -q -a $DEFAULT_ALGORITHM -3 $zone 2>kg.out) || dumpit kg.out
ksk=$($KEYGEN -q -a $DEFAULT_ALGORITHM -3 -fk $keytimes $zone 2>kg.out) || dumpit kg.out
zsk=$($KEYGEN -q -a $DEFAULT_ALGORITHM -3 $keytimes $zone 2>kg.out) || dumpit kg.out
$SIGNER -S -P -s now-1mo -e now-1mi -o $zone -f $zonefile ${zonefile}.in >s.out || dumpit s.out
echo $ksk >../inaczsk-ksk.key
echo $zsk >../inaczsk-zsk.key
@ -288,16 +291,16 @@ $SETTIME -I now $zsk >st.out 2>&1 || dumpit st.out
#
setup reconf.example
cp secure.example.db.in $zonefile
$KEYGEN -q -a $DEFAULT_ALGORITHM -3 -fk $zone >kg.out 2>&1 || dumpit kg.out
$KEYGEN -q -a $DEFAULT_ALGORITHM -3 $zone >kg.out 2>&1 || dumpit kg.out
$KEYGEN -q -a $DEFAULT_ALGORITHM -3 -fk $keytimes $zone >kg.out 2>&1 || dumpit kg.out
$KEYGEN -q -a $DEFAULT_ALGORITHM -3 $keytimes $zone >kg.out 2>&1 || dumpit kg.out
#
# A zone which generates CDS and CDNSEY RRsets automatically (with an additional CSK)
#
setup sync.example
cp $infile $zonefile
ksk=$($KEYGEN -a $DEFAULT_ALGORITHM -3 -q -fk -P sync now $zone 2>kg.out) || dumpit kg.out
$KEYGEN -a $DEFAULT_ALGORITHM -3 -q $zone >kg.out 2>&1 || dumpit kg.out
ksk=$($KEYGEN -a $DEFAULT_ALGORITHM -3 -q -fk -P sync now $keytimes $zone 2>kg.out) || dumpit kg.out
$KEYGEN -a $DEFAULT_ALGORITHM -3 -q $keytimes $zone >kg.out 2>&1 || dumpit kg.out
$DSFROMKEY $ksk.key >dsset-${zone}.
echo ns3/$ksk >../sync.key
@ -306,8 +309,8 @@ echo ns3/$ksk >../sync.key
#
setup kskonly.example
cp $infile $zonefile
ksk=$($KEYGEN -a $DEFAULT_ALGORITHM -3 -q -fk -P sync now $zone 2>kg.out) || dumpit kg.out
$KEYGEN -a $DEFAULT_ALGORITHM -3 -q $zone >kg.out 2>&1 || dumpit kg.out
ksk=$($KEYGEN -a $DEFAULT_ALGORITHM -3 -q -fk -P sync now $keytimes $zone 2>kg.out) || dumpit kg.out
$KEYGEN -a $DEFAULT_ALGORITHM -3 -q $keytimes $zone >kg.out 2>&1 || dumpit kg.out
$DSFROMKEY $ksk.key >dsset-${zone}.
#
@ -315,7 +318,7 @@ $DSFROMKEY $ksk.key >dsset-${zone}.
#
setup inaczsk2.example
cp $infile $zonefile
ksk=$($KEYGEN -a $DEFAULT_ALGORITHM -3 -q -fk $zone 2>kg.out) || dumpit kg.out
ksk=$($KEYGEN -a $DEFAULT_ALGORITHM -3 -q -fk $keytimes $zone 2>kg.out) || dumpit kg.out
$KEYGEN -a $DEFAULT_ALGORITHM -3 -q -P now -A now+3600 $zone >kg.out 2>&1 || dumpit kg.out
$DSFROMKEY $ksk.key >dsset-${zone}.
@ -325,19 +328,19 @@ $DSFROMKEY $ksk.key >dsset-${zone}.
#
setup delzsk.example
cp $infile $zonefile
ksk=$($KEYGEN -a $DEFAULT_ALGORITHM -3 -q -fk $zone 2>kg.out) || dumpit kg.out
$KEYGEN -a $DEFAULT_ALGORITHM -3 -q $zone >kg.out 2>&1 || dumpit kg.out
zsk=$($KEYGEN -a $DEFAULT_ALGORITHM -3 -q -I now-1w $zone 2>kg.out) || dumpit kg.out
cat $zsk.key >>$zonefile
mv $zsk.key inactive/
mv $zsk.private inactive/
echo $zsk >../delzsk.key
ksk=$($KEYGEN -a $DEFAULT_ALGORITHM -3 -q -fk -P sync now-7d $keytimes $zone 2>kg.out) || dumpit kg.out
zsk1=$($KEYGEN -a $DEFAULT_ALGORITHM -3 -q $keytimes $zone >kg.out 2>&1) || dumpit kg.out
zsk2=$($KEYGEN -a $DEFAULT_ALGORITHM -3 -q $keytimes -I now-1d $zone 2>kg.out) || dumpit kg.out
cat $ksk.key $zsk2.key >>$zonefile
cp $zsk2.key inactive/
cp $zsk2.private inactive/
echo $zsk2 >../delzsk.key
#
# Check that NSEC3 are correctly signed and returned from below a DNAME
#
setup dname-at-apex-nsec3.example
cp $infile $zonefile
ksk=$($KEYGEN -q -a $DEFAULT_ALGORITHM -3 -fk $zone 2>kg.out) || dumpit kg.out
$KEYGEN -q -a $DEFAULT_ALGORITHM -3 $zone >kg.out 2>&1 || dumpit kg.out
ksk=$($KEYGEN -q -a $DEFAULT_ALGORITHM -3 -fk $keytimes $zone 2>kg.out) || dumpit kg.out
$KEYGEN -q -a $DEFAULT_ALGORITHM -3 $keytimes $zone >kg.out 2>&1 || dumpit kg.out
$DSFROMKEY $ksk.key >dsset-${zone}.

View file

@ -250,14 +250,6 @@ zone "rsasha512.example" {
dnssec-policy rsasha512;
};
zone "nsec-only.example" {
type primary;
file "nsec-only.example.db";
allow-update { any; };
inline-signing no;
dnssec-policy autosign;
};
zone "nsec3-to-nsec.example" {
type primary;
file "nsec3-to-nsec.example.db";
@ -394,4 +386,6 @@ zone "dname-at-apex-nsec3.example" {
dnssec-policy nsec3;
};
include "nsec-only.conf";
include "trusted.conf";

View file

@ -0,0 +1,27 @@
/*
* Copyright (C) Internet Systems Consortium, Inc. ("ISC")
*
* SPDX-License-Identifier: MPL-2.0
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, you can obtain one at https://mozilla.org/MPL/2.0/.
*
* See the COPYRIGHT file distributed with this work for additional
* information regarding copyright ownership.
*/
dnssec-policy "nsec-only" {
keys {
ksk key-directory lifetime unlimited algorithm rsasha1;
zsk key-directory lifetime unlimited algorithm rsasha1;
};
};
zone "nsec-only.example" {
type primary;
file "nsec-only.example.db";
allow-update { any; };
inline-signing no;
dnssec-policy nsec-only;
};

View file

@ -15,6 +15,11 @@
copy_setports ns1/named.conf.in ns1/named.conf
copy_setports ns2/named.conf.in ns2/named.conf
if [ $RSASHA1_SUPPORTED = 1 ]; then
cp ns3/nsec-only.conf.in ns3/nsec-only.conf
else
: >ns3/nsec-only.conf
fi
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

View file

@ -1087,7 +1087,7 @@ ret=0
rekey_calls=$(grep "zone reconf.example.*next key event" ns3/named.run | wc -l)
[ "$rekey_calls" -eq 0 ] || ret=1
# ...then we add dnssec-policy and reconfigure
($RNDCCMD 10.53.0.3 modzone reconf.example '{ type primary; file "reconf.example.db"; allow-update { any; }; dnssec-policy default; };' 2>&1 | sed 's/^/ns3 /' | cat_i) || ret=1
($RNDCCMD 10.53.0.3 modzone reconf.example '{ type primary; file "reconf.example.db"; allow-update { any; }; dnssec-policy autosign; };' 2>&1 | sed 's/^/ns3 /' | cat_i) || ret=1
rndc_reconfig ns3 10.53.0.3
for i in 0 1 2 3 4 5 6 7 8 9; do
lret=0
@ -1256,17 +1256,19 @@ act=$(grep "DNSKEY .* is now active" ns3/named.run | wc -l)
if [ $RSASHA1_SUPPORTED = 1 ]; then
# Include two log lines for nsec-only zone.
[ "$pub" -eq 53 ] || ret=1
[ "$act" -eq 53 ] || ret=1
[ "$act" -eq 54 ] || ret=1
else
[ "$pub" -eq 51 ] || ret=1
[ "$act" -eq 51 ] || ret=1
[ "$act" -eq 52 ] || ret=1
fi
rev=$(grep "DNSKEY .* is now revoked" ns3/named.run | wc -l)
[ "$rev" -eq 0 ] || ret=1
# inaczsk.example
inac=$(grep "DNSKEY .* is now inactive" ns3/named.run | wc -l)
[ "$inac" -eq 0 ] || ret=1
[ "$inac" -eq 1 ] || ret=1
# delzsk.example
del=$(grep "DNSKEY .* is now deleted" ns3/named.run | wc -l)
[ "$del" -eq 3 ] || ret=1
[ "$del" -eq 1 ] || ret=1
n=$((n + 1))
if [ $ret != 0 ]; then echo_i "failed"; fi
status=$((status + ret))

View file

@ -114,6 +114,7 @@ pytestmark = pytest.mark.extra_artifacts(
"ns3/kskonly.example.db.jbk",
"ns3/noksk.example.db",
"ns3/nozsk.example.db",
"ns3/nsec-only.conf",
"ns3/nsec-only.example.db",
"ns3/nsec3-to-nsec.example.db",
"ns3/nsec3-to-nsec3.example.db",

View file

@ -25,7 +25,7 @@ dnssec-policy "rsasha1" {
{% if "rsasha1-to-nsec3.kasp" in zones %}
/*
* This zone starts with NSEC, but will be reconfigured to use NSEC3.
* This should work despite the incompatible RSAHSHA1 algorithm,
* This should work despite the incompatible RSASHA1 algorithm,
* because the DS is still in hidden state.
*/
zone "rsasha1-to-nsec3.kasp" {
@ -51,7 +51,7 @@ zone "rsasha1-to-nsec3-wait.kasp" {
{% if "nsec3-to-rsasha1.kasp" in zones %}
/*
* This zone starts with NSEC3, but will be reconfigured to use NSEC with an
* NSEC only algorithm. This should work despite the incompatible RSAHSHA1
* NSEC only algorithm. This should work despite the incompatible RSASHA1
* algorithm, because the DS is still in hidden state.
*/
zone "nsec3-to-rsasha1.kasp" {

View file

@ -31,24 +31,23 @@ for zn in nsec-to-nsec3 nsec3 nsec3-other nsec3-change nsec3-to-nsec \
done
if [ $RSASHA1_SUPPORTED = 1 ]; then
for zn in rsasha1-to-nsec3 rsasha1-to-nsec3-wait nsec3-to-rsasha1 \
nsec3-to-rsasha1-ds; do
setup "${zn}.kasp"
done
longago="now-1y"
keytimes="-P ${longago} -A ${longago}"
keytimes="-P ${longago} -A ${longago} -P sync ${longago}"
O="omnipresent"
zone="rsasha1-to-nsec3-wait.kasp"
CSK=$($KEYGEN -k "rsasha1" -l named.conf $keytimes $zone 2>keygen.out.$zone)
echo_i "Created key file $CSK"
$SETTIME -s -g $O -k $O $longago -r $O $longago -z $O $longago -d $O $longago "$CSK" >settime.out.$zone 2>&1
for zn in nsec3-to-rsasha1 nsec3-to-rsasha1-ds; do
setup "${zn}.kasp"
CSK=$($KEYGEN -a $DEFAULT_ALGORITHM -L 3600 -f KSK $keytimes $zone 2>keygen.out.$zone)
$SETTIME -s -g $O -k $O $longago -r $O $longago -z $O $longago -d $O $longago "$CSK" >settime.out.$zone 2>&1
cat $CSK.key >>$zonefile
done
zone="nsec3-to-rsasha1-ds.kasp"
CSK=$($KEYGEN -k "default" -l named.conf $keytimes $zone 2>keygen.out.$zone)
echo_i "Created key file $CSK"
$SETTIME -s -g $O -k $O $longago -r $O $longago -z $O $longago -d $O $longago "$CSK" >settime.out.$zone 2>&1
for zn in rsasha1-to-nsec3 rsasha1-to-nsec3-wait; do
setup "${zn}.kasp"
CSK=$($KEYGEN -k "rsasha1" -l named.conf $keytimes $zone 2>keygen.out.$zone)
$SETTIME -s -g $O -k $O $longago -r $O $longago -z $O $longago -d $O $longago "$CSK" >settime.out.$zone 2>&1
cat $CSK.key >>$zonefile
done
else
echo_i "skip: skip rsasha1 zones - signing with RSASHA1 not supported"
fi

View file

@ -81,7 +81,7 @@ def bootstrap():
"zone": "rsasha1-to-nsec3.kasp",
"policy": "rsasha1",
"key-properties": [
f"csk 0 {RSASHA1.number} 2048 goal:omnipresent dnskey:rumoured krrsig:rumoured zrrsig:rumoured ds:hidden",
f"csk 0 {RSASHA1.number} 2048 goal:omnipresent dnskey:omnipresent krrsig:omnipresent zrrsig:omnipresent ds:omnipresent",
],
},
id="rsasha1-to-nsec3.kasp",
@ -162,7 +162,7 @@ def test_nsec_case(ns3, params):
"zone": "nsec3-to-rsasha1.kasp",
"policy": "nsec3",
"key-properties": [
f"csk 0 {ALGORITHM} {SIZE} goal:omnipresent dnskey:rumoured krrsig:rumoured zrrsig:rumoured ds:hidden",
f"csk 0 {ALGORITHM} {SIZE} goal:omnipresent dnskey:omnipresent krrsig:omnipresent zrrsig:omnipresent ds:omnipresent",
],
},
id="nsec3-to-rsasha1.kasp",

View file

@ -92,6 +92,18 @@ def after_servers_start(ns3, templates):
@pytest.mark.parametrize(
"params",
[
pytest.param(
{
"zone": "rsasha1-to-nsec3.kasp",
"policy": "nsec3",
"key-properties": [
f"csk 0 {RSASHA1.number} 2048 goal:hidden dnskey:omnipresent krrsig:omnipresent zrrsig:omnipresent ds:omnipresent",
f"csk 0 {ALGORITHM} {SIZE} goal:omnipresent dnskey:rumoured krrsig:rumoured zrrsig:rumoured ds:hidden",
],
},
id="rsasha1-to-nsec3.kasp",
marks=isctest.mark.with_algorithm("RSASHA1"),
),
pytest.param(
{
"zone": "rsasha1-to-nsec3-wait.kasp",
@ -109,7 +121,7 @@ def after_servers_start(ns3, templates):
"zone": "nsec3-to-rsasha1.kasp",
"policy": "rsasha1",
"key-properties": [
f"csk 0 {ALGORITHM} {SIZE} goal:hidden dnskey:unretentive krrsig:unretentive zrrsig:unretentive ds:hidden",
f"csk 0 {ALGORITHM} {SIZE} goal:hidden dnskey:omnipresent krrsig:omnipresent zrrsig:omnipresent ds:omnipresent",
f"csk 0 {RSASHA1.number} 2048 goal:omnipresent dnskey:rumoured krrsig:rumoured zrrsig:rumoured ds:hidden",
],
},
@ -163,18 +175,6 @@ def test_nsec_case(ns3, params):
},
id="nsec-to-nsec3.kasp",
),
pytest.param(
{
"zone": "rsasha1-to-nsec3.kasp",
"policy": "nsec3",
"key-properties": [
f"csk 0 {RSASHA1.number} 2048 goal:hidden dnskey:unretentive krrsig:unretentive zrrsig:unretentive ds:hidden",
f"csk 0 {ALGORITHM} {SIZE} goal:omnipresent dnskey:rumoured krrsig:rumoured zrrsig:rumoured ds:hidden",
],
},
id="rsasha1-to-nsec3.kasp",
marks=isctest.mark.with_algorithm("RSASHA1"),
),
pytest.param(
{
"zone": "nsec3.kasp",

View file

@ -14,8 +14,11 @@
include "kasp.conf";
include "named.common.conf";
zone "manual-rollover.kasp" {
{% for zone in ['manual-rollover.kasp', 'manual-rollover-zrrsig-rumoured.kasp'] %}
zone "@zone@" {
type primary;
file "manual-rollover.kasp.db";
file "@zone@.db";
dnssec-policy "manual-rollover";
};
{% endfor %}

View file

@ -43,3 +43,17 @@ private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$KSK" >>"$infile"
private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$ZSK" >>"$infile"
cp $infile $zonefile
$SIGNER -PS -x -o $zone -O raw -f "${zonefile}.signed" $infile >signer.out.$zone.1 2>&1
# Zone to test manual rollover.
setup manual-rollover-zrrsig-rumoured.kasp
T2="now-2h"
zsktimes="-P $T2 -A $T2"
KSK=$($KEYGEN -a $DEFAULT_ALGORITHM -L 3600 -f KSK $keytimes $zone 2>keygen.out.$zone.1)
ZSK=$($KEYGEN -a $DEFAULT_ALGORITHM -L 3600 $zsktimes $zone 2>keygen.out.$zone.2)
$SETTIME -s -g $O -d $O $T -k $O $T -r $O $T "$KSK" >settime.out.$zone.1 2>&1
$SETTIME -s -g $O -k $O $T2 -z $R $T2 "$ZSK" >settime.out.$zone.2 2>&1
cat template.db.in "${KSK}.key" "${ZSK}.key" >"$infile"
private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$KSK" >>"$infile"
private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$ZSK" >>"$infile"
cp $infile $zonefile
$SIGNER -PS -x -o $zone -O raw -f "${zonefile}.signed" $infile >signer.out.$zone.1 2>&1

View file

@ -17,21 +17,23 @@ from isctest.kasp import KeyTimingMetadata, Ipub, Iret
from rollover.common import pytestmark # pylint: disable=unused-import
CONFIG = {
"dnskey-ttl": timedelta(hours=1),
"ds-ttl": timedelta(days=1),
"max-zone-ttl": timedelta(days=1),
"parent-propagation-delay": timedelta(hours=1),
"publish-safety": timedelta(hours=1),
"retire-safety": timedelta(hours=1),
"signatures-refresh": timedelta(days=7),
"signatures-validity": timedelta(days=14),
"zone-propagation-delay": timedelta(minutes=5),
}
POLICY = "manual-rollover"
def test_rollover_manual(ns3):
policy = "manual-rollover"
config = {
"dnskey-ttl": timedelta(hours=1),
"ds-ttl": timedelta(days=1),
"max-zone-ttl": timedelta(days=1),
"parent-propagation-delay": timedelta(hours=1),
"publish-safety": timedelta(hours=1),
"retire-safety": timedelta(hours=1),
"signatures-refresh": timedelta(days=7),
"signatures-validity": timedelta(days=14),
"zone-propagation-delay": timedelta(minutes=5),
}
ttl = int(config["dnskey-ttl"].total_seconds())
ttl = int(CONFIG["dnskey-ttl"].total_seconds())
alg = os.environ["DEFAULT_ALGORITHM_NUMBER"]
size = os.environ["DEFAULT_BITS"]
zone = "manual-rollover.kasp"
@ -53,10 +55,10 @@ def test_rollover_manual(ns3):
offset = -timedelta(days=7)
for kp in expected:
kp.set_expected_keytimes(config, offset=offset)
kp.set_expected_keytimes(CONFIG, offset=offset)
isctest.kasp.check_keytimes(keys, expected)
isctest.kasp.check_dnssecstatus(ns3, zone, keys, policy=policy)
isctest.kasp.check_dnssecstatus(ns3, zone, keys, policy=POLICY)
isctest.kasp.check_apex(ns3, zone, ksks, zsks)
isctest.kasp.check_subdomain(ns3, zone, ksks, zsks)
@ -64,9 +66,9 @@ def test_rollover_manual(ns3):
assert len(ksks) == 1
ksk = ksks[0]
startroll = expected[0].timing["Active"] + timedelta(days=30 * 6)
expected[0].timing["Retired"] = startroll + Ipub(config)
expected[0].timing["Retired"] = startroll + Ipub(CONFIG)
expected[0].timing["Removed"] = expected[0].timing["Retired"] + Iret(
config, zsk=False, ksk=True
CONFIG, zsk=False, ksk=True
)
with ns3.watch_log_from_here() as watcher:
@ -76,7 +78,7 @@ def test_rollover_manual(ns3):
isctest.kasp.check_dnssec_verify(ns3, zone)
isctest.kasp.check_keys(zone, keys, expected)
isctest.kasp.check_keytimes(keys, expected)
isctest.kasp.check_dnssecstatus(ns3, zone, keys, policy=policy)
isctest.kasp.check_dnssecstatus(ns3, zone, keys, policy=POLICY)
isctest.kasp.check_apex(ns3, zone, ksks, zsks)
isctest.kasp.check_subdomain(ns3, zone, ksks, zsks)
@ -108,15 +110,15 @@ def test_rollover_manual(ns3):
off = offset
if "Predecessor" in kp.metadata:
off = 0
kp.set_expected_keytimes(config, offset=off)
kp.set_expected_keytimes(CONFIG, offset=off)
expected[0].timing["Retired"] = now + Ipub(config)
expected[0].timing["Retired"] = now + Ipub(CONFIG)
expected[0].timing["Removed"] = expected[0].timing["Retired"] + Iret(
config, zsk=False, ksk=True
CONFIG, zsk=False, ksk=True
)
isctest.kasp.check_keytimes(keys, expected)
isctest.kasp.check_dnssecstatus(ns3, zone, keys, policy=policy)
isctest.kasp.check_dnssecstatus(ns3, zone, keys, policy=POLICY)
isctest.kasp.check_apex(ns3, zone, ksks, zsks)
isctest.kasp.check_subdomain(ns3, zone, ksks, zsks)
@ -153,3 +155,62 @@ def test_rollover_manual(ns3):
zsk = expected[3].key
response = ns3.rndc(f"dnssec -rollover -key {zsk.tag} {zone}")
assert "key is not actively signing" in response
def test_rollover_manual_zrrsig_rumoured(ns3):
ttl = int(CONFIG["dnskey-ttl"].total_seconds())
alg = os.environ["DEFAULT_ALGORITHM_NUMBER"]
size = os.environ["DEFAULT_BITS"]
zone = "manual-rollover-zrrsig-rumoured.kasp"
isctest.kasp.wait_keymgr_done(ns3, zone)
isctest.kasp.check_dnssec_verify(ns3, zone)
koffset = -int(timedelta(days=7).total_seconds())
zoffset = -int(timedelta(hours=2).total_seconds())
key_properties = [
f"ksk unlimited {alg} {size} goal:omnipresent dnskey:omnipresent krrsig:omnipresent ds:omnipresent offset:{koffset}",
f"zsk unlimited {alg} {size} goal:omnipresent dnskey:omnipresent zrrsig:rumoured offset:{zoffset}",
]
expected = isctest.kasp.policy_to_properties(ttl, key_properties)
keys = isctest.kasp.keydir_to_keylist(zone, ns3.identifier)
ksks = [k for k in keys if k.is_ksk()]
zsks = [k for k in keys if not k.is_ksk()]
isctest.kasp.check_keys(zone, keys, expected)
for kp in expected:
kp.set_expected_keytimes(CONFIG)
isctest.kasp.check_keytimes(keys, expected)
isctest.kasp.check_dnssecstatus(ns3, zone, keys, policy=POLICY)
isctest.kasp.check_apex(ns3, zone, ksks, zsks)
isctest.kasp.check_subdomain(ns3, zone, ksks, zsks)
# Schedule ZSK rollover now.
assert len(zsks) == 1
zsk = zsks[0]
now = KeyTimingMetadata.now()
with ns3.watch_log_from_here() as watcher:
ns3.rndc(f"dnssec -rollover -key {zsk.tag} -when {now} {zone}")
watcher.wait_for_line(f"keymgr: {zone} done")
isctest.kasp.check_dnssec_verify(ns3, zone)
key_properties = [
f"ksk unlimited {alg} {size} goal:omnipresent dnskey:omnipresent krrsig:omnipresent ds:omnipresent offset:{koffset}",
# Predecessor DNSKEY must stay until successor ZSK is fully omnipresent.
f"zsk unlimited {alg} {size} goal:hidden dnskey:omnipresent zrrsig:rumoured offset:{zoffset}",
f"zsk unlimited {alg} {size} goal:omnipresent dnskey:rumoured zrrsig:hidden offset:0",
]
expected = isctest.kasp.policy_to_properties(ttl, key_properties)
keys = isctest.kasp.keydir_to_keylist(zone, ns3.identifier)
ksks = [k for k in keys if k.is_ksk()]
zsks = [k for k in keys if not k.is_ksk()]
isctest.kasp.check_keys(zone, keys, expected)
expected[1].metadata["Successor"] = expected[2].key.tag
expected[2].metadata["Predecessor"] = expected[1].key.tag
isctest.kasp.check_keyrelationships(keys, expected)

View file

@ -24,6 +24,7 @@ options {
notify no;
minimal-responses no;
version none; // make statistics independent of the version number
sig-signing-signatures 100;
};
statistics-channels { inet 10.53.0.2 port @EXTRAPORT1@ allow { localhost; }; };

View file

@ -24,6 +24,7 @@ options {
notify no;
minimal-responses no;
version none; // make statistics independent of the version number
sig-signing-signatures 100;
};
statistics-channels { inet 10.53.0.2 port @EXTRAPORT1@ allow { localhost; }; };

View file

@ -16,13 +16,18 @@
set -e
longago="now-1y"
keytimes="-P ${longago} -A ${longago}"
O="omnipresent"
zone=dnssec.
infile=dnssec.db.in
zonefile=dnssec.db.signed
zonefile=dnssec.db
cp $infile $zonefile
ksk=$("$KEYGEN" -q -a "$DEFAULT_ALGORITHM" -L 3600 -b "$DEFAULT_BITS" -f KSK "$zone")
zsk=$("$KEYGEN" -q -a "$DEFAULT_ALGORITHM" -L 3600 -b "$DEFAULT_BITS" "$zone")
# Sign deliberately with a very short expiration date.
"$SIGNER" -P -S -x -O full -e "now"+1s -o "$zone" -f "$zonefile" "$infile" >"signzone.out.$zone" 2>&1
"$SIGNER" -P -S -x -O full -e "now"+1s -o "$zone" "$zonefile" >"signzone.out.$zone" 2>&1
id=$(keyfile_to_key_id "$ksk")
echo "$DEFAULT_ALGORITHM_NUMBER+$id" >dnssec.ksk.id
id=$(keyfile_to_key_id "$zsk")
@ -30,16 +35,22 @@ echo "$DEFAULT_ALGORITHM_NUMBER+$id" >dnssec.zsk.id
zone=manykeys.
infile=manykeys.db.in
zonefile=manykeys.db.signed
ksk8=$("$KEYGEN" -q -a RSASHA256 -L 3600 -b 2048 -f KSK "$zone")
zsk8=$("$KEYGEN" -q -a RSASHA256 -L 3600 -b 2048 "$zone")
zonefile=manykeys.db
cp $infile $zonefile
ksk8=$("$KEYGEN" -q -a RSASHA256 -L 3600 -b 2048 -f KSK $keytimes -P sync $longago "$zone")
zsk8=$("$KEYGEN" -q -a RSASHA256 -L 3600 -b 2048 $keytimes "$zone")
$SETTIME -s -g $O -k $O $longago -r $O $longago -z $O $longago -d $O $longago "$ksk8" >settime.out.$zone 2>&1
$SETTIME -s -g $O -k $O $longago -z $O $longago "$zsk8" >settime.out.$zone 2>&1
cat $ksk8.key $zsk8.key >>$zonefile
ksk13=$("$KEYGEN" -q -a ECDSAP256SHA256 -L 3600 -b 256 -f KSK "$zone")
zsk13=$("$KEYGEN" -q -a ECDSAP256SHA256 -L 3600 -b 256 "$zone")
cat $ksk13.key $zsk13.key >>$zonefile
ksk14=$("$KEYGEN" -q -a ECDSAP384SHA384 -L 3600 -b 384 -f KSK "$zone")
zsk14=$("$KEYGEN" -q -a ECDSAP384SHA384 -L 3600 -b 384 "$zone")
cat $ksk14.key $zsk14.key >>$zonefile
# Sign deliberately with a very short expiration date.
# Disable zone verification (-P) as records may expire before signing is complete
"$SIGNER" -P -S -x -O full -e "now"+1s -o "$zone" -f "$zonefile" "$infile" >"signzone.out.$zone" 2>&1
"$SIGNER" -P -S -x -O full -e "now"+1s -o "$zone" "$zonefile" >"signzone.out.$zone" 2>&1
id=$(keyfile_to_key_id "$ksk8")
echo "8+$id" >manykeys.ksk8.id
id=$(keyfile_to_key_id "$zsk8")

View file

@ -392,22 +392,22 @@ ksk13_id=$(cat ns2/$zone.ksk13.id)
zsk13_id=$(cat ns2/$zone.zsk13.id)
ksk14_id=$(cat ns2/$zone.ksk14.id)
zsk14_id=$(cat ns2/$zone.zsk14.id)
# The dnssec zone has 10 RRsets to sign (including NSEC) with the ZSKs and one
# RRset (DNSKEY) with the KSKs. So starting named with signatures that expire
# almost right away, this should trigger 10 zsk and 1 ksk sign operations per
# key.
# The dnssec zone has 10 RRsets to sign (including NSEC) with the ZSKs and the
# DNSKEY, CDS, and CDNSKEY RRsets with the KSKs. So starting named with
# signatures that expire almost right away, this should trigger 10 zsk and 3
# ksk sign operations per key.
echo "${refresh_prefix} ${zsk8_id}: 10" >zones.expect
echo "${refresh_prefix} ${zsk13_id}: 10" >>zones.expect
echo "${refresh_prefix} ${zsk14_id}: 10" >>zones.expect
echo "${refresh_prefix} ${ksk8_id}: 1" >>zones.expect
echo "${refresh_prefix} ${ksk13_id}: 1" >>zones.expect
echo "${refresh_prefix} ${ksk14_id}: 1" >>zones.expect
echo "${refresh_prefix} ${ksk8_id}: 3" >>zones.expect
echo "${refresh_prefix} ${ksk13_id}: 3" >>zones.expect
echo "${refresh_prefix} ${ksk14_id}: 3" >>zones.expect
echo "${sign_prefix} ${zsk8_id}: 10" >>zones.expect
echo "${sign_prefix} ${zsk13_id}: 10" >>zones.expect
echo "${sign_prefix} ${zsk14_id}: 10" >>zones.expect
echo "${sign_prefix} ${ksk8_id}: 1" >>zones.expect
echo "${sign_prefix} ${ksk13_id}: 1" >>zones.expect
echo "${sign_prefix} ${ksk14_id}: 1" >>zones.expect
echo "${sign_prefix} ${ksk8_id}: 3" >>zones.expect
echo "${sign_prefix} ${ksk13_id}: 3" >>zones.expect
echo "${sign_prefix} ${ksk14_id}: 3" >>zones.expect
cat zones.expect | sort >zones.expect.$n
rm -f zones.expect
# Fetch and check the dnssec sign statistics.
@ -437,15 +437,15 @@ ret=0
echo "${refresh_prefix} ${zsk8_id}: 10" >zones.expect
echo "${refresh_prefix} ${zsk13_id}: 10" >>zones.expect
echo "${refresh_prefix} ${zsk14_id}: 10" >>zones.expect
echo "${refresh_prefix} ${ksk8_id}: 1" >>zones.expect
echo "${refresh_prefix} ${ksk13_id}: 1" >>zones.expect
echo "${refresh_prefix} ${ksk14_id}: 1" >>zones.expect
echo "${refresh_prefix} ${ksk8_id}: 3" >>zones.expect
echo "${refresh_prefix} ${ksk13_id}: 3" >>zones.expect
echo "${refresh_prefix} ${ksk14_id}: 3" >>zones.expect
echo "${sign_prefix} ${zsk8_id}: 13" >>zones.expect
echo "${sign_prefix} ${zsk13_id}: 13" >>zones.expect
echo "${sign_prefix} ${zsk14_id}: 13" >>zones.expect
echo "${sign_prefix} ${ksk8_id}: 1" >>zones.expect
echo "${sign_prefix} ${ksk13_id}: 1" >>zones.expect
echo "${sign_prefix} ${ksk14_id}: 1" >>zones.expect
echo "${sign_prefix} ${ksk8_id}: 3" >>zones.expect
echo "${sign_prefix} ${ksk13_id}: 3" >>zones.expect
echo "${sign_prefix} ${ksk14_id}: 3" >>zones.expect
cat zones.expect | sort >zones.expect.$n
rm -f zones.expect
# Fetch and check the dnssec sign statistics.
@ -466,15 +466,15 @@ n=$((n + 1))
ret=0
copy_setports ns2/named2.conf.in ns2/named.conf
$RNDCCMD 10.53.0.2 reload 2>&1 | sed 's/^/I:ns2 /'
# This should trigger the resign of DNSKEY (+1 ksk), and SOA, NSEC,
# TYPE65534 (+3 zsk). The dnssec-sign statistics for the removed keys should
# be cleared and thus no longer visible. But NSEC and SOA are (mistakenly)
# counted double, one time because of zone_resigninc and one time because of
# zone_nsec3chain. So +5 zsk in total.
# This should trigger the resign of DNSKEY, CDS, and CDNSKEY (+3 ksk),
# and SOA, NSEC, TYPE65534 (+3 zsk). The dnssec-sign statistics for the
# removed keys should be cleared and thus no longer visible. But NSEC and SOA
# are (mistakenly) counted double, one time because of zone_resigninc and one
# time because of zone_nsec3chain. So +5 zsk in total.
echo "${refresh_prefix} ${zsk8_id}: 15" >zones.expect
echo "${refresh_prefix} ${ksk8_id}: 2" >>zones.expect
echo "${refresh_prefix} ${ksk8_id}: 6" >>zones.expect
echo "${sign_prefix} ${zsk8_id}: 18" >>zones.expect
echo "${sign_prefix} ${ksk8_id}: 2" >>zones.expect
echo "${sign_prefix} ${ksk8_id}: 6" >>zones.expect
cat zones.expect | sort >zones.expect.$n
rm -f zones.expect
# Fetch and check the dnssec sign statistics.

View file

@ -31,8 +31,11 @@ pytestmark = [
"ns2/dsset-*",
"ns2/K*",
"ns2/dnssec.db.signed",
"ns2/dnssec.db",
"ns2/dnssec.*.id",
"ns2/manykeys.db",
"ns2/manykeys.*.id",
"ns2/settime.out.*",
"ns2/signzone.out.*",
"ns3/_default.nzd",
"ns3/example-tcp.db",

View file

@ -31,11 +31,15 @@ pytestmark = pytest.mark.extra_artifacts(
"zones*",
"ns2/*.jnl",
"ns2/*.signed",
"ns2/*.db",
"ns2/dsset-*",
"ns2/K*",
"ns2/dnssec.db",
"ns2/dnssec.*.id",
"ns2/manykeys.db",
"ns2/manykeys.*.id",
"ns2/named.stats",
"ns2/settime.out.*",
"ns2/signzone.out.*",
"ns3/_default.nzf*",
"ns3/_default.nzd*",

View file

@ -31,8 +31,11 @@ pytestmark = [
"ns2/*.jnl",
"ns2/*.signed",
"ns2/dsset-*",
"ns2/dnssec.db",
"ns2/dnssec.*.id",
"ns2/manykeys.db",
"ns2/manykeys.*.id",
"ns2/settime.out.*",
"ns2/signzone.out.*",
"ns3/_default.nzd",
"ns3/example-tcp.db",

View file

@ -37,7 +37,7 @@ controls {
dnssec-policy "views" {
keys {
ksk key-directory lifetime unlimited algorithm @DEFAULT_ALGORITHM@;
csk key-directory lifetime unlimited algorithm @DEFAULT_ALGORITHM@;
zsk key-directory lifetime unlimited algorithm @DEFAULT_ALGORITHM@;
};
};

View file

@ -37,7 +37,7 @@ controls {
dnssec-policy "views" {
keys {
ksk key-directory lifetime unlimited algorithm @DEFAULT_ALGORITHM@;
csk key-directory lifetime unlimited algorithm @DEFAULT_ALGORITHM@;
zsk key-directory lifetime unlimited algorithm @DEFAULT_ALGORITHM@;
};
};

View file

@ -137,8 +137,8 @@ ret=0
wait_for_signed() {
"$DIG" -p "${PORT}" @10.53.0.2 -b 10.53.0.2 +dnssec DNSKEY inline >dig.out.internal
"$DIG" -p "${PORT}" @10.53.0.2 -b 10.53.0.5 +dnssec DNSKEY inline >dig.out.external
grep "ANSWER: 4," dig.out.internal >/dev/null || return 1
grep "ANSWER: 4," dig.out.external >/dev/null || return 1
grep "ANSWER: 3," dig.out.internal >/dev/null || return 1
grep "ANSWER: 3," dig.out.external >/dev/null || return 1
return 0
}
retry_quiet 10 wait_for_signed || ret=1

View file

@ -1254,17 +1254,18 @@ keymgr_policy_approval(dns_dnsseckeylist_t *keyring, dns_dnsseckey_t *key,
static bool
keymgr_transition_allowed(dns_dnsseckeylist_t *keyring, dns_dnsseckey_t *key,
int type, dst_key_state_t next_state, uint8_t opts) {
bool rule1a, rule1b, rule2a, rule2b, rule3a, rule3b;
rule1a = keymgr_have_ds(keyring, key, type, NA, opts);
rule1b = keymgr_have_ds(keyring, key, type, next_state, opts);
rule2a = keymgr_have_dnskey(keyring, key, type, NA);
rule2b = keymgr_have_dnskey(keyring, key, type, next_state);
rule3a = keymgr_have_rrsig(keyring, key, type, NA);
rule3b = keymgr_have_rrsig(keyring, key, type, next_state);
/* Debug logging. */
if (isc_log_wouldlog(ISC_LOG_DEBUG(1))) {
bool rule1a, rule1b, rule2a, rule2b, rule3a, rule3b;
char keystr[DST_KEY_FORMATSIZE];
dst_key_format(key->key, keystr, sizeof(keystr));
rule1a = keymgr_have_ds(keyring, key, type, NA, opts);
rule1b = keymgr_have_ds(keyring, key, type, next_state, opts);
rule2a = keymgr_have_dnskey(keyring, key, type, NA);
rule2b = keymgr_have_dnskey(keyring, key, type, next_state);
rule3a = keymgr_have_rrsig(keyring, key, type, NA);
rule3b = keymgr_have_rrsig(keyring, key, type, next_state);
isc_log_write(
DNS_LOGCATEGORY_DNSSEC, DNS_LOGMODULE_DNSSEC,
ISC_LOG_DEBUG(1),
@ -1277,29 +1278,40 @@ keymgr_transition_allowed(dns_dnsseckeylist_t *keyring, dns_dnsseckey_t *key,
rule3a ? "true" : "false", rule3b ? "true" : "false");
}
return
/*
* Rule 1: There must be a DS at all times.
* First check the current situation: if the rule check fails,
* we allow the transition to attempt to move us out of the
* invalid state. If the rule check passes, also check if
* the next state is also still a valid situation.
*/
(!keymgr_have_ds(keyring, key, type, NA, opts) ||
keymgr_have_ds(keyring, key, type, next_state, opts)) &&
/*
* Rule 2: There must be a DNSKEY at all times. Again, first
* check the current situation, then assess the next state.
*/
(!keymgr_have_dnskey(keyring, key, type, NA) ||
keymgr_have_dnskey(keyring, key, type, next_state)) &&
/*
* Rule 3: There must be RRSIG records at all times. Again,
* first check the current situation, then assess the next
* state.
*/
(!keymgr_have_rrsig(keyring, key, type, NA) ||
keymgr_have_rrsig(keyring, key, type, next_state));
/*
* Rule checking:
* First check the current situation: if the rule check fails,
* we allow the transition to attempt to move us out of the
* invalid state. If the rule check passes, also check if
* the next state is also still a valid situation.
*/
char keystr2[DST_KEY_FORMATSIZE];
dst_key_format(key->key, keystr2, sizeof(keystr2));
/*
* Rule 1: There must be a DS at all times.
*/
if (!rule1a && !rule1b && next_state == UNRETENTIVE) {
return false;
}
/*
* Rule 2: There must be a DNSKEY at all times. Again, first
* check the current situation, then assess the next state.
*/
if (!rule2a && !rule2b && next_state == UNRETENTIVE) {
return false;
}
/*
* Rule 3: There must be RRSIG records at all times. Again,
* first check the current situation, then assess the next
* state.
*/
if (!rule3a && !rule3b && next_state == UNRETENTIVE) {
return false;
}
return (!rule1a || rule1b) && (!rule2a || rule2b) &&
(!rule3a || rule3b);
}
/*