2
0
mirror of https://gitlab.isc.org/isc-projects/bind9 synced 2025-08-30 14:07:59 +00:00

[9.20] chg: test: Rewrite kasp system test to pytest (3)

Write python-based tests for the many test cases from the kasp system test with the same pattern.

Backport of MR !10268

Merge branch 'backport-matthijs-pytest-rewrite-kasp-system-test-3-9.20' into 'bind-9.20'

See merge request isc-projects/bind9!10421
This commit is contained in:
Matthijs Mekking
2025-04-23 16:32:45 +00:00
6 changed files with 845 additions and 933 deletions

View File

@@ -16,7 +16,7 @@ from pathlib import Path
import re import re
import subprocess import subprocess
import time import time
from typing import Dict, List, Optional, Union from typing import Dict, List, Optional, Tuple, Union
from datetime import datetime, timedelta, timezone from datetime import datetime, timedelta, timezone
@@ -332,6 +332,55 @@ class Key:
) )
return value return value
def get_signing_state(
self, offline_ksk=False, zsk_missing=False
) -> Tuple[bool, bool]:
"""
This returns the signing state derived from the key states, KRRSIGState
and ZRRSIGState.
If 'offline_ksk' is set to True, we determine the signing state from
the timing metadata. If 'zsigning' is True, ensure the current time is
between the Active and Retired timing metadata.
If 'zsk_missing' is set to True, it means the ZSK private key file is
missing, and the KSK should take over signing the RRset, and the
expected zone signing state (zsigning) is reversed.
"""
# Fetch key timing metadata.
now = KeyTimingMetadata.now()
activate = self.get_timing("Activate")
assert activate is not None # to silence mypy - its implied by line above
inactive = self.get_timing("Inactive", must_exist=False)
active = now >= activate
retired = inactive is not None and inactive <= now
signing = active and not retired
# Fetch key state metadata.
krrsigstate = self.get_metadata("KRRSIGState", must_exist=False)
ksigning = krrsigstate in ["rumoured", "omnipresent"]
zrrsigstate = self.get_metadata("ZRRSIGState", must_exist=False)
zsigning = zrrsigstate in ["rumoured", "omnipresent"]
if ksigning:
assert self.is_ksk()
if zsigning:
assert self.is_zsk()
# If the ZSK private key file is missing, revers the zone signing state.
if zsk_missing:
zsigning = not zsigning
# If testing offline KSK, retrieve the signing state from the key timing
# metadata.
if offline_ksk and signing and self.is_zsk():
assert zsigning
if offline_ksk and signing and self.is_ksk():
ksigning = signing
return ksigning, zsigning
def ttl(self) -> int: def ttl(self) -> int:
with open(self.keyfile, "r", encoding="utf-8") as file: with open(self.keyfile, "r", encoding="utf-8") as file:
for line in file: for line in file:
@@ -772,8 +821,9 @@ def check_dnssecstatus(server, zone, keys, policy=None, view=None):
assert f"key: {key.tag}" in response assert f"key: {key.tag}" in response
def _check_signatures(signatures, covers, fqdn, keys): def _check_signatures(
now = KeyTimingMetadata.now() signatures, covers, fqdn, keys, offline_ksk=False, zsk_missing=False
):
numsigs = 0 numsigs = 0
zrrsig = True zrrsig = True
if covers in [dns.rdatatype.DNSKEY, dns.rdatatype.CDNSKEY, dns.rdatatype.CDS]: if covers in [dns.rdatatype.DNSKEY, dns.rdatatype.CDNSKEY, dns.rdatatype.CDS]:
@@ -781,23 +831,16 @@ def _check_signatures(signatures, covers, fqdn, keys):
krrsig = not zrrsig krrsig = not zrrsig
for key in keys: for key in keys:
activate = key.get_timing("Activate") ksigning, zsigning = key.get_signing_state(
inactive = key.get_timing("Inactive", must_exist=False) offline_ksk=offline_ksk, zsk_missing=zsk_missing
)
active = now >= activate
retired = inactive is not None and inactive <= now
signing = active and not retired
alg = key.get_metadata("Algorithm") alg = key.get_metadata("Algorithm")
rtype = dns.rdatatype.to_text(covers) rtype = dns.rdatatype.to_text(covers)
expect = rf"IN RRSIG {rtype} {alg} (\d) (\d+) (\d+) (\d+) {key.tag} {fqdn}" expect = rf"IN RRSIG {rtype} {alg} (\d) (\d+) (\d+) (\d+) {key.tag} {fqdn}"
if not signing: if zrrsig and zsigning:
for rrsig in signatures:
assert re.search(expect, rrsig) is None
continue
if zrrsig and key.is_zsk():
has_rrsig = False has_rrsig = False
for rrsig in signatures: for rrsig in signatures:
if re.search(expect, rrsig) is not None: if re.search(expect, rrsig) is not None:
@@ -806,11 +849,11 @@ def _check_signatures(signatures, covers, fqdn, keys):
assert has_rrsig, f"Expected signature but not found: {expect}" assert has_rrsig, f"Expected signature but not found: {expect}"
numsigs += 1 numsigs += 1
if zrrsig and not key.is_zsk(): if zrrsig and not zsigning:
for rrsig in signatures: for rrsig in signatures:
assert re.search(expect, rrsig) is None assert re.search(expect, rrsig) is None
if krrsig and key.is_ksk(): if krrsig and ksigning:
has_rrsig = False has_rrsig = False
for rrsig in signatures: for rrsig in signatures:
if re.search(expect, rrsig) is not None: if re.search(expect, rrsig) is not None:
@@ -819,14 +862,16 @@ def _check_signatures(signatures, covers, fqdn, keys):
assert has_rrsig, f"Expected signature but not found: {expect}" assert has_rrsig, f"Expected signature but not found: {expect}"
numsigs += 1 numsigs += 1
if krrsig and not key.is_ksk(): if krrsig and not ksigning:
for rrsig in signatures: for rrsig in signatures:
assert re.search(expect, rrsig) is None assert re.search(expect, rrsig) is None
return numsigs return numsigs
def check_signatures(rrset, covers, fqdn, ksks, zsks): def check_signatures(
rrset, covers, fqdn, ksks, zsks, offline_ksk=False, zsk_missing=False
):
# Check if signatures with covering type are signed with the right keys. # Check if signatures with covering type are signed with the right keys.
# The right keys are the ones that expect a signature and have the # The right keys are the ones that expect a signature and have the
# correct role. # correct role.
@@ -840,8 +885,12 @@ def check_signatures(rrset, covers, fqdn, ksks, zsks):
rrsig = f"{rr.name} {rr.ttl} {rdclass} {rdtype} {rdata}" rrsig = f"{rr.name} {rr.ttl} {rdclass} {rdtype} {rdata}"
signatures.append(rrsig) signatures.append(rrsig)
numsigs += _check_signatures(signatures, covers, fqdn, ksks) numsigs += _check_signatures(
numsigs += _check_signatures(signatures, covers, fqdn, zsks) signatures, covers, fqdn, ksks, offline_ksk=offline_ksk, zsk_missing=zsk_missing
)
numsigs += _check_signatures(
signatures, covers, fqdn, zsks, offline_ksk=offline_ksk, zsk_missing=zsk_missing
)
assert numsigs == len(signatures) assert numsigs == len(signatures)
@@ -965,7 +1014,9 @@ def _query_rrset(server, fqdn, qtype, tsig=None):
return rrs, rrsigs return rrs, rrsigs
def check_apex(server, zone, ksks, zsks, tsig=None): def check_apex(
server, zone, ksks, zsks, offline_ksk=False, zsk_missing=False, tsig=None
):
# Test the apex of a zone. This checks that the SOA and DNSKEY RRsets # Test the apex of a zone. This checks that the SOA and DNSKEY RRsets
# are signed correctly and with the appropriate keys. # are signed correctly and with the appropriate keys.
fqdn = f"{zone}." fqdn = f"{zone}."
@@ -973,30 +1024,44 @@ def check_apex(server, zone, ksks, zsks, tsig=None):
# test dnskey query # test dnskey query
dnskeys, rrsigs = _query_rrset(server, fqdn, dns.rdatatype.DNSKEY, tsig=tsig) dnskeys, rrsigs = _query_rrset(server, fqdn, dns.rdatatype.DNSKEY, tsig=tsig)
check_dnskeys(dnskeys, ksks, zsks) check_dnskeys(dnskeys, ksks, zsks)
check_signatures(rrsigs, dns.rdatatype.DNSKEY, fqdn, ksks, zsks) check_signatures(
rrsigs, dns.rdatatype.DNSKEY, fqdn, ksks, zsks, offline_ksk=offline_ksk
)
# test soa query # test soa query
soa, rrsigs = _query_rrset(server, fqdn, dns.rdatatype.SOA, tsig=tsig) soa, rrsigs = _query_rrset(server, fqdn, dns.rdatatype.SOA, tsig=tsig)
assert len(soa) == 1 assert len(soa) == 1
assert f"{zone}. {DEFAULT_TTL} IN SOA" in soa[0].to_text() assert f"{zone}. {DEFAULT_TTL} IN SOA" in soa[0].to_text()
check_signatures(rrsigs, dns.rdatatype.SOA, fqdn, ksks, zsks) check_signatures(
rrsigs,
dns.rdatatype.SOA,
fqdn,
ksks,
zsks,
offline_ksk=offline_ksk,
zsk_missing=zsk_missing,
)
# test cdnskey query # test cdnskey query
cdnskeys, rrsigs = _query_rrset(server, fqdn, dns.rdatatype.CDNSKEY, tsig=tsig) cdnskeys, rrsigs = _query_rrset(server, fqdn, dns.rdatatype.CDNSKEY, tsig=tsig)
check_dnskeys(cdnskeys, ksks, zsks, cdnskey=True) check_dnskeys(cdnskeys, ksks, zsks, cdnskey=True)
if len(cdnskeys) > 0: if len(cdnskeys) > 0:
assert len(rrsigs) > 0 assert len(rrsigs) > 0
check_signatures(rrsigs, dns.rdatatype.CDNSKEY, fqdn, ksks, zsks) check_signatures(
rrsigs, dns.rdatatype.CDNSKEY, fqdn, ksks, zsks, offline_ksk=offline_ksk
)
# test cds query # test cds query
cds, rrsigs = _query_rrset(server, fqdn, dns.rdatatype.CDS, tsig=tsig) cds, rrsigs = _query_rrset(server, fqdn, dns.rdatatype.CDS, tsig=tsig)
check_cds(cds, ksks) check_cds(cds, ksks)
if len(cds) > 0: if len(cds) > 0:
assert len(rrsigs) > 0 assert len(rrsigs) > 0
check_signatures(rrsigs, dns.rdatatype.CDS, fqdn, ksks, zsks) check_signatures(
rrsigs, dns.rdatatype.CDS, fqdn, ksks, zsks, offline_ksk=offline_ksk
)
def check_subdomain(server, zone, ksks, zsks, tsig=None): def check_subdomain(server, zone, ksks, zsks, offline_ksk=False, tsig=None):
# Test an RRset below the apex and verify it is signed correctly. # Test an RRset below the apex and verify it is signed correctly.
fqdn = f"{zone}." fqdn = f"{zone}."
qname = f"a.{zone}." qname = f"a.{zone}."
@@ -1014,7 +1079,7 @@ def check_subdomain(server, zone, ksks, zsks, tsig=None):
else: else:
assert match in rrset.to_text() assert match in rrset.to_text()
check_signatures(rrsigs, qtype, fqdn, ksks, zsks) check_signatures(rrsigs, qtype, fqdn, ksks, zsks, offline_ksk=offline_ksk)
def verify_update_is_signed(server, fqdn, qname, qtype, rdata, ksks, zsks, tsig=None): def verify_update_is_signed(server, fqdn, qname, qtype, rdata, ksks, zsks, tsig=None):
@@ -1046,6 +1111,98 @@ def verify_update_is_signed(server, fqdn, qname, qtype, rdata, ksks, zsks, tsig=
return True return True
def verify_rrsig_is_refreshed(
server, fqdn, zonefile, qname, qtype, ksks, zsks, tsig=None
):
"""
Verify signature for RRset has been refreshed.
"""
response = _query(server, qname, qtype, tsig=tsig)
if response.rcode() != dns.rcode.NOERROR:
return False
rrtype = dns.rdatatype.to_text(qtype)
match = f"{qname}. {DEFAULT_TTL} IN {rrtype}"
rrsigs = []
for rrset in response.answer:
if rrset.match(
dns.name.from_text(qname), dns.rdataclass.IN, dns.rdatatype.RRSIG, qtype
):
rrsigs.append(rrset)
elif not match in rrset.to_text():
return False
if len(rrsigs) == 0:
return False
tmp_zonefile = f"{zonefile}.tmp"
isctest.run.cmd(
[
os.environ["CHECKZONE"],
"-D",
"-q",
"-o",
tmp_zonefile,
"-f",
"raw",
fqdn,
zonefile,
],
)
zone = dns.zone.from_file(tmp_zonefile, fqdn)
for rrsig in rrsigs:
if isctest.util.zone_contains(zone, rrsig):
return False
# Zone is updated, ready to verify the signatures.
check_signatures(rrsigs, qtype, fqdn, ksks, zsks)
return True
def verify_rrsig_is_reused(server, fqdn, zonefile, qname, qtype, ksks, zsks, tsig=None):
"""
Verify signature for RRset has been reused.
"""
response = _query(server, qname, qtype, tsig=tsig)
assert response.rcode() == dns.rcode.NOERROR
rrtype = dns.rdatatype.to_text(qtype)
match = f"{qname}. {DEFAULT_TTL} IN {rrtype}"
rrsigs = []
for rrset in response.answer:
if rrset.match(
dns.name.from_text(qname), dns.rdataclass.IN, dns.rdatatype.RRSIG, qtype
):
rrsigs.append(rrset)
else:
assert match in rrset.to_text()
tmp_zonefile = f"{zonefile}.tmp"
isctest.run.cmd(
[
os.environ["CHECKZONE"],
"-D",
"-q",
"-o",
tmp_zonefile,
"-f",
"raw",
fqdn,
zonefile,
],
)
zone = dns.zone.from_file(tmp_zonefile, dns.name.from_text(fqdn), relativize=False)
for rrsig in rrsigs:
assert isctest.util.zone_contains(zone, rrsig)
check_signatures(rrsigs, qtype, fqdn, ksks, zsks)
def next_key_event_equals(server, zone, next_event): def next_key_event_equals(server, zone, next_event):
if next_event is None: if next_event is None:
# No next key event check. # No next key event check.
@@ -1140,6 +1297,7 @@ def policy_to_properties(ttl, keys: List[str]) -> List[KeyProperties]:
Then, optional data for specific tests may follow: Then, optional data for specific tests may follow:
- "goal", "dnskey", "krrsig", "zrrsig", "ds", followed by a value, - "goal", "dnskey", "krrsig", "zrrsig", "ds", followed by a value,
sets the given state to the specific value sets the given state to the specific value
- "missing", set if the private key file for this key is not available.
- "offset", an offset for testing key rollover timings - "offset", an offset for testing key rollover timings
""" """
proplist = [] proplist = []
@@ -1190,6 +1348,8 @@ def policy_to_properties(ttl, keys: List[str]) -> List[KeyProperties]:
elif line[i].startswith("offset:"): elif line[i].startswith("offset:"):
keyval = line[i].split(":") keyval = line[i].split(":")
keyprop.properties["offset"] = timedelta(seconds=int(keyval[1])) keyprop.properties["offset"] = timedelta(seconds=int(keyval[1]))
elif line[i] == "missing":
keyprop.properties["private"] = False
else: else:
assert False, f"undefined optional data {line[i]}" assert False, f"undefined optional data {line[i]}"

View File

@@ -56,6 +56,12 @@ def with_tsan(*args): # pylint: disable=unused-argument
return feature_test("--tsan") return feature_test("--tsan")
def with_algorithm(name: str):
key = f"{name}_SUPPORTED"
assert key in os.environ, f"{key} env variable undefined"
return pytest.mark.skipif(os.getenv(key) != "1", reason=f"{name} is not supported")
without_fips = pytest.mark.skipif( without_fips = pytest.mark.skipif(
feature_test("--have-fips-mode"), reason="FIPS support enabled in the build" feature_test("--have-fips-mode"), reason="FIPS support enabled in the build"
) )

View File

@@ -200,13 +200,14 @@ $SETTIME -s -g $O -k $O $T -z $O $T "$ZSK" >settime.out.$zone.2 2>&1
cat template.db.in "${KSK}.key" "${ZSK}.key" >"$infile" cat template.db.in "${KSK}.key" "${ZSK}.key" >"$infile"
$SIGNER -PS -z -x -s now-2w -e now-1mi -o $zone -f "${zonefile}" $infile >signer.out.$zone.1 2>&1 $SIGNER -PS -z -x -s now-2w -e now-1mi -o $zone -f "${zonefile}" $infile >signer.out.$zone.1 2>&1
# Treat the next zones as if they were signed six months ago.
T="now-6mo"
keytimes="-P $T -A $T"
# These signatures are set to expire long in the past, update immediately. # These signatures are set to expire long in the past, update immediately.
setup expired-sigs.autosign setup expired-sigs.autosign
T="now-6mo" KSK=$($KEYGEN -a $DEFAULT_ALGORITHM -L 300 -f KSK $keytimes $zone 2>keygen.out.$zone.1)
ksktimes="-P $T -A $T -P sync $T" ZSK=$($KEYGEN -a $DEFAULT_ALGORITHM -L 300 $keytimes $zone 2>keygen.out.$zone.2)
zsktimes="-P $T -A $T"
KSK=$($KEYGEN -a $DEFAULT_ALGORITHM -L 300 -f KSK $ksktimes $zone 2>keygen.out.$zone.1)
ZSK=$($KEYGEN -a $DEFAULT_ALGORITHM -L 300 $zsktimes $zone 2>keygen.out.$zone.2)
$SETTIME -s -g $O -d $O $T -k $O $T -r $O $T "$KSK" >settime.out.$zone.1 2>&1 $SETTIME -s -g $O -d $O $T -k $O $T -r $O $T "$KSK" >settime.out.$zone.1 2>&1
$SETTIME -s -g $O -k $O $T -z $O $T "$ZSK" >settime.out.$zone.2 2>&1 $SETTIME -s -g $O -k $O $T -z $O $T "$ZSK" >settime.out.$zone.2 2>&1
cat template.db.in "${KSK}.key" "${ZSK}.key" >"$infile" cat template.db.in "${KSK}.key" "${ZSK}.key" >"$infile"
@@ -217,19 +218,18 @@ $SIGNER -PS -x -s now-2mo -e now-1mo -o $zone -O raw -f "${zonefile}.signed" $in
# The DNSKEY's TTLs do not match the policy. # The DNSKEY's TTLs do not match the policy.
setup dnskey-ttl-mismatch.autosign setup dnskey-ttl-mismatch.autosign
KSK=$($KEYGEN -a $DEFAULT_ALGORITHM -L 30 -f KSK $ksktimes $zone 2>keygen.out.$zone.1) KSK=$($KEYGEN -a $DEFAULT_ALGORITHM -L 30 -f KSK $keytimes $zone 2>keygen.out.$zone.1)
ZSK=$($KEYGEN -a $DEFAULT_ALGORITHM -L 30 $zsktimes $zone 2>keygen.out.$zone.2) ZSK=$($KEYGEN -a $DEFAULT_ALGORITHM -L 30 $keytimes $zone 2>keygen.out.$zone.2)
$SETTIME -s -g $O -d $O $T -k $O $T -r $O $T "$KSK" >settime.out.$zone.1 2>&1
$SETTIME -s -g $O -k $O $T -z $O $T "$ZSK " >settime.out.$zone.2 2>&1
cat template.db.in "${KSK}.key" "${ZSK}.key" >"$infile" cat template.db.in "${KSK}.key" "${ZSK}.key" >"$infile"
cp $infile $zonefile cp $infile $zonefile
$SIGNER -PS -x -o $zone -O raw -f "${zonefile}.signed" $infile >signer.out.$zone.1 2>&1 $SIGNER -PS -x -o $zone -O raw -f "${zonefile}.signed" $infile >signer.out.$zone.1 2>&1
# These signatures are still good, and can be reused. # These signatures are still good, and can be reused.
setup fresh-sigs.autosign setup fresh-sigs.autosign
T="now-6mo" KSK=$($KEYGEN -a $DEFAULT_ALGORITHM -L 300 -f KSK $keytimes $zone 2>keygen.out.$zone.1)
ksktimes="-P $T -A $T -P sync $T" ZSK=$($KEYGEN -a $DEFAULT_ALGORITHM -L 300 $keytimes $zone 2>keygen.out.$zone.2)
zsktimes="-P $T -A $T"
KSK=$($KEYGEN -a $DEFAULT_ALGORITHM -L 300 -f KSK $ksktimes $zone 2>keygen.out.$zone.1)
ZSK=$($KEYGEN -a $DEFAULT_ALGORITHM -L 300 $zsktimes $zone 2>keygen.out.$zone.2)
$SETTIME -s -g $O -d $O $T -k $O $T -r $O $T "$KSK" >settime.out.$zone.1 2>&1 $SETTIME -s -g $O -d $O $T -k $O $T -r $O $T "$KSK" >settime.out.$zone.1 2>&1
$SETTIME -s -g $O -k $O $T -z $O $T "$ZSK" >settime.out.$zone.2 2>&1 $SETTIME -s -g $O -k $O $T -z $O $T "$ZSK" >settime.out.$zone.2 2>&1
cat template.db.in "${KSK}.key" "${ZSK}.key" >"$infile" cat template.db.in "${KSK}.key" "${ZSK}.key" >"$infile"
@@ -240,11 +240,8 @@ $SIGNER -S -x -s now-1h -e now+2w -o $zone -O raw -f "${zonefile}.signed" $infil
# These signatures are still good, but not fresh enough, update immediately. # These signatures are still good, but not fresh enough, update immediately.
setup unfresh-sigs.autosign setup unfresh-sigs.autosign
T="now-6mo" KSK=$($KEYGEN -a $DEFAULT_ALGORITHM -L 300 -f KSK $keytimes $zone 2>keygen.out.$zone.1)
ksktimes="-P $T -A $T -P sync $T" ZSK=$($KEYGEN -a $DEFAULT_ALGORITHM -L 300 $keytimes $zone 2>keygen.out.$zone.2)
zsktimes="-P $T -A $T"
KSK=$($KEYGEN -a $DEFAULT_ALGORITHM -L 300 -f KSK $ksktimes $zone 2>keygen.out.$zone.1)
ZSK=$($KEYGEN -a $DEFAULT_ALGORITHM -L 300 $zsktimes $zone 2>keygen.out.$zone.2)
$SETTIME -s -g $O -d $O $T -k $O $T -r $O $T "$KSK" >settime.out.$zone.1 2>&1 $SETTIME -s -g $O -d $O $T -k $O $T -r $O $T "$KSK" >settime.out.$zone.1 2>&1
$SETTIME -s -g $O -k $O $T -z $O $T "$ZSK" >settime.out.$zone.2 2>&1 $SETTIME -s -g $O -k $O $T -z $O $T "$ZSK" >settime.out.$zone.2 2>&1
cat template.db.in "${KSK}.key" "${ZSK}.key" >"$infile" cat template.db.in "${KSK}.key" "${ZSK}.key" >"$infile"
@@ -255,11 +252,13 @@ $SIGNER -S -x -s now-1w -e now+1w -o $zone -O raw -f "${zonefile}.signed" $infil
# These signatures are still good, but the private KSK is missing. # These signatures are still good, but the private KSK is missing.
setup ksk-missing.autosign setup ksk-missing.autosign
T="now-6mo" # KSK file will be gone missing, so we set expected times during setup.
ksktimes="-P $T -A $T -P sync $T" TI="now+550d" # Lifetime of 2 years minus 6 months equals 550 days
zsktimes="-P $T -A $T" TD="now+13226h" # 550 days plus retire time of 1 day 2 hours equals 13226 hours
TS="now-257755mi" # 6 months minus 1 day, 5 minutes equals 257695 minutes
ksktimes="$keytimes -P sync $TS -I $TI -D $TD"
KSK=$($KEYGEN -a $DEFAULT_ALGORITHM -L 300 -f KSK $ksktimes $zone 2>keygen.out.$zone.1) KSK=$($KEYGEN -a $DEFAULT_ALGORITHM -L 300 -f KSK $ksktimes $zone 2>keygen.out.$zone.1)
ZSK=$($KEYGEN -a $DEFAULT_ALGORITHM -L 300 $zsktimes $zone 2>keygen.out.$zone.2) ZSK=$($KEYGEN -a $DEFAULT_ALGORITHM -L 300 $keytimes $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 -d $O $T -k $O $T -r $O $T "$KSK" >settime.out.$zone.1 2>&1
$SETTIME -s -g $O -k $O $T -z $O $T "$ZSK" >settime.out.$zone.2 2>&1 $SETTIME -s -g $O -k $O $T -z $O $T "$ZSK" >settime.out.$zone.2 2>&1
cat template.db.in "${KSK}.key" "${ZSK}.key" >"$infile" cat template.db.in "${KSK}.key" "${ZSK}.key" >"$infile"
@@ -274,10 +273,11 @@ rm -f "${KSK}".private
# These signatures are still good, but the private ZSK is missing. # These signatures are still good, but the private ZSK is missing.
setup zsk-missing.autosign setup zsk-missing.autosign
T="now-6mo" # ZSK file will be gone missing, so we set expected times during setup.
ksktimes="-P $T -A $T -P sync $T" TI="now+185d" # Lifetime of 1 year minus 6 months equals 185 days
zsktimes="-P $T -A $T" TD="now+277985mi" # 185 days plus retire time (sign delay, retire safety, propagation, zone TTL)
KSK=$($KEYGEN -a $DEFAULT_ALGORITHM -L 300 -f KSK $ksktimes $zone 2>keygen.out.$zone.1) zsktimes="$keytimes -I $TI -D $TD"
KSK=$($KEYGEN -a $DEFAULT_ALGORITHM -L 300 -f KSK $keytimes $zone 2>keygen.out.$zone.1)
ZSK=$($KEYGEN -a $DEFAULT_ALGORITHM -L 300 $zsktimes $zone 2>keygen.out.$zone.2) ZSK=$($KEYGEN -a $DEFAULT_ALGORITHM -L 300 $zsktimes $zone 2>keygen.out.$zone.2)
$SETTIME -s -g $O -d $O $T -k $O $T -r $O $T "$KSK" >settime.out.$zone.1 2>&1 $SETTIME -s -g $O -d $O $T -k $O $T -r $O $T "$KSK" >settime.out.$zone.1 2>&1
$SETTIME -s -g $O -k $O $T -z $O $T "$ZSK" >settime.out.$zone.2 2>&1 $SETTIME -s -g $O -k $O $T -z $O $T "$ZSK" >settime.out.$zone.2 2>&1
@@ -294,11 +294,8 @@ rm -f "${ZSK}".private
# These signatures are still good, but the key files will be removed # These signatures are still good, but the key files will be removed
# before a second run of reconfiguring keys. # before a second run of reconfiguring keys.
setup keyfiles-missing.autosign setup keyfiles-missing.autosign
T="now-6mo" KSK=$($KEYGEN -a $DEFAULT_ALGORITHM -L 300 -f KSK $keytimes $zone 2>keygen.out.$zone.1)
ksktimes="-P $T -A $T -P sync $T" ZSK=$($KEYGEN -a $DEFAULT_ALGORITHM -L 300 $keytimes $zone 2>keygen.out.$zone.2)
zsktimes="-P $T -A $T"
KSK=$($KEYGEN -a $DEFAULT_ALGORITHM -L 300 -f KSK $ksktimes $zone 2>keygen.out.$zone.1)
ZSK=$($KEYGEN -a $DEFAULT_ALGORITHM -L 300 $zsktimes $zone 2>keygen.out.$zone.2)
$SETTIME -s -g $O -d $O $T -k $O $T -r $O $T "$KSK" >settime.out.$zone.1 2>&1 $SETTIME -s -g $O -d $O $T -k $O $T -r $O $T "$KSK" >settime.out.$zone.1 2>&1
$SETTIME -s -g $O -k $O $T -z $O $T "$ZSK" >settime.out.$zone.2 2>&1 $SETTIME -s -g $O -k $O $T -z $O $T "$ZSK" >settime.out.$zone.2 2>&1
cat template.db.in "${KSK}.key" "${ZSK}.key" >"$infile" cat template.db.in "${KSK}.key" "${ZSK}.key" >"$infile"
@@ -309,7 +306,6 @@ $SIGNER -S -x -s now-1w -e now+1w -o $zone -O raw -f "${zonefile}.signed" $infil
# These signatures are already expired, and the private ZSK is retired. # These signatures are already expired, and the private ZSK is retired.
setup zsk-retired.autosign setup zsk-retired.autosign
T="now-6mo"
ksktimes="-P $T -A $T -P sync $T" ksktimes="-P $T -A $T -P sync $T"
zsktimes="-P $T -A $T -I now" zsktimes="-P $T -A $T -I now"
KSK=$($KEYGEN -a $DEFAULT_ALGORITHM -L 300 -f KSK $ksktimes $zone 2>keygen.out.$zone.1) KSK=$($KEYGEN -a $DEFAULT_ALGORITHM -L 300 -f KSK $ksktimes $zone 2>keygen.out.$zone.1)

View File

@@ -400,462 +400,10 @@ set_keytimes_algorithm_policy() {
set_addkeytime "KEY3" "REMOVED" "${retired}" 867900 set_addkeytime "KEY3" "REMOVED" "${retired}" 867900
} }
#
# Zone: rsasha1.kasp.
#
if [ $RSASHA1_SUPPORTED = 1 ]; then
set_zone "rsasha1.kasp"
set_policy "rsasha1" "3" "1234"
set_server "ns3" "10.53.0.3"
# Key properties.
key_clear "KEY1"
set_keyrole "KEY1" "ksk"
set_keylifetime "KEY1" "315360000"
set_keyalgorithm "KEY1" "5" "RSASHA1" "2048"
set_keysigning "KEY1" "yes"
set_zonesigning "KEY1" "no"
key_clear "KEY2"
set_keyrole "KEY2" "zsk"
set_keylifetime "KEY2" "157680000"
set_keyalgorithm "KEY2" "5" "RSASHA1" "2048"
set_keysigning "KEY2" "no"
set_zonesigning "KEY2" "yes"
key_clear "KEY3"
set_keyrole "KEY3" "zsk"
set_keylifetime "KEY3" "31536000"
set_keyalgorithm "KEY3" "5" "RSASHA1" "2000"
set_keysigning "KEY3" "no"
set_zonesigning "KEY3" "yes"
# KSK: DNSKEY, RRSIG (ksk) published. DS needs to wait.
# ZSK: DNSKEY, RRSIG (zsk) published.
set_keystate "KEY1" "GOAL" "omnipresent"
set_keystate "KEY1" "STATE_DNSKEY" "rumoured"
set_keystate "KEY1" "STATE_KRRSIG" "rumoured"
set_keystate "KEY1" "STATE_DS" "hidden"
set_keystate "KEY2" "GOAL" "omnipresent"
set_keystate "KEY2" "STATE_DNSKEY" "rumoured"
set_keystate "KEY2" "STATE_ZRRSIG" "rumoured"
set_keystate "KEY3" "GOAL" "omnipresent"
set_keystate "KEY3" "STATE_DNSKEY" "rumoured"
set_keystate "KEY3" "STATE_ZRRSIG" "rumoured"
# Three keys only.
key_clear "KEY4"
check_keys
check_dnssecstatus "$SERVER" "$POLICY" "$ZONE"
set_keytimes_algorithm_policy
check_keytimes
check_apex
check_subdomain
dnssec_verify
fi
#
# Zone: unlimited.kasp.
#
set_zone "unlimited.kasp"
set_policy "unlimited" "1" "1234"
set_server "ns3" "10.53.0.3"
key_clear "KEY1"
key_clear "KEY2"
key_clear "KEY3"
key_clear "KEY4"
# Key properties.
set_keyrole "KEY1" "csk"
set_keylifetime "KEY1" "0"
set_keyalgorithm "KEY1" "13" "ECDSAP256SHA256" "256"
set_keysigning "KEY1" "yes"
set_zonesigning "KEY1" "yes"
# DNSKEY, RRSIG (ksk), RRSIG (zsk) are published. DS needs to wait.
set_keystate "KEY1" "GOAL" "omnipresent"
set_keystate "KEY1" "STATE_DNSKEY" "rumoured"
set_keystate "KEY1" "STATE_KRRSIG" "rumoured"
set_keystate "KEY1" "STATE_ZRRSIG" "rumoured"
set_keystate "KEY1" "STATE_DS" "hidden"
check_keys
check_dnssecstatus "$SERVER" "$POLICY" "$ZONE"
set_keytimes_csk_policy
check_keytimes
check_apex
check_subdomain
dnssec_verify
#
# Zone: keystore.kasp.
#
set_zone "keystore.kasp"
set_policy "keystore" "2" "303"
set_server "ns3" "10.53.0.3"
# Key properties.
key_clear "KEY1"
set_keyrole "KEY1" "ksk"
set_keylifetime "KEY1" "0"
set_keydir "KEY1" "ns3/ksk"
set_keyalgorithm "KEY1" "$DEFAULT_ALGORITHM_NUMBER" "$DEFAULT_ALGORITHM" "$DEFAULT_BITS"
set_keysigning "KEY1" "yes"
set_zonesigning "KEY1" "no"
key_clear "KEY2"
set_keyrole "KEY2" "zsk"
set_keylifetime "KEY2" "0"
set_keydir "KEY2" "ns3/zsk"
set_keyalgorithm "KEY2" "$DEFAULT_ALGORITHM_NUMBER" "$DEFAULT_ALGORITHM" "$DEFAULT_BITS"
set_keysigning "KEY2" "no"
set_zonesigning "KEY2" "yes"
# KSK: DNSKEY, RRSIG (ksk) published. DS needs to wait.
# ZSK: DNSKEY, RRSIG (zsk) published.
set_keystate "KEY1" "GOAL" "omnipresent"
set_keystate "KEY1" "STATE_DNSKEY" "rumoured"
set_keystate "KEY1" "STATE_KRRSIG" "rumoured"
set_keystate "KEY1" "STATE_DS" "hidden"
set_keystate "KEY2" "GOAL" "omnipresent"
set_keystate "KEY2" "STATE_DNSKEY" "rumoured"
set_keystate "KEY2" "STATE_ZRRSIG" "rumoured"
# Two keys only.
key_clear "KEY3"
key_clear "KEY4"
check_keys
check_dnssecstatus "$SERVER" "$POLICY" "$ZONE"
# Reuse set_keytimes_csk_policy to set the KEY1 keytimes.
set_keytimes_csk_policy
created=$(key_get KEY2 CREATED)
set_keytime "KEY2" "PUBLISHED" "${created}"
set_keytime "KEY2" "ACTIVE" "${created}"
check_keytimes
check_apex
check_subdomain
dnssec_verify
#
# Zone: inherit.kasp.
#
set_zone "inherit.kasp"
set_policy "rsasha256" "3" "1234"
set_server "ns3" "10.53.0.3"
# Key properties.
key_clear "KEY1"
set_keyrole "KEY1" "ksk"
set_keylifetime "KEY1" "315360000"
set_keyalgorithm "KEY1" "8" "RSASHA256" "2048"
set_keysigning "KEY1" "yes"
set_zonesigning "KEY1" "no"
key_clear "KEY2"
set_keyrole "KEY2" "zsk"
set_keylifetime "KEY2" "157680000"
set_keyalgorithm "KEY2" "8" "RSASHA256" "2048"
set_keysigning "KEY2" "no"
set_zonesigning "KEY2" "yes"
key_clear "KEY3"
set_keyrole "KEY3" "zsk"
set_keylifetime "KEY3" "31536000"
set_keyalgorithm "KEY3" "8" "RSASHA256" "3072"
set_keysigning "KEY3" "no"
set_zonesigning "KEY3" "yes"
# KSK: DNSKEY, RRSIG (ksk) published. DS needs to wait.
# ZSK: DNSKEY, RRSIG (zsk) published.
set_keystate "KEY1" "GOAL" "omnipresent"
set_keystate "KEY1" "STATE_DNSKEY" "rumoured"
set_keystate "KEY1" "STATE_KRRSIG" "rumoured"
set_keystate "KEY1" "STATE_DS" "hidden"
set_keystate "KEY2" "GOAL" "omnipresent"
set_keystate "KEY2" "STATE_DNSKEY" "rumoured"
set_keystate "KEY2" "STATE_ZRRSIG" "rumoured"
set_keystate "KEY3" "GOAL" "omnipresent"
set_keystate "KEY3" "STATE_DNSKEY" "rumoured"
set_keystate "KEY3" "STATE_ZRRSIG" "rumoured"
# Three keys only.
key_clear "KEY4"
check_keys
check_dnssecstatus "$SERVER" "$POLICY" "$ZONE"
set_keytimes_algorithm_policy
check_keytimes
check_apex
check_subdomain
dnssec_verify
#
# Zone: dnssec-keygen.kasp.
#
set_zone "dnssec-keygen.kasp"
set_policy "rsasha256" "3" "1234"
set_server "ns3" "10.53.0.3"
# Key properties, timings and states same as above.
check_keys
check_dnssecstatus "$SERVER" "$POLICY" "$ZONE"
set_keytimes_algorithm_policy
check_keytimes
check_apex
check_subdomain
dnssec_verify
#
# Zone: some-keys.kasp.
#
set_zone "some-keys.kasp"
set_policy "rsasha256" "3" "1234"
set_server "ns3" "10.53.0.3"
# Key properties, timings and states same as above.
check_keys
check_dnssecstatus "$SERVER" "$POLICY" "$ZONE"
set_keytimes_algorithm_policy "pregenerated"
check_keytimes
check_apex
check_subdomain
dnssec_verify
#
# Zone: pregenerated.kasp.
#
# There are more pregenerated keys than needed, hence the number of keys is
# six, not three.
set_zone "pregenerated.kasp"
set_policy "rsasha256" "6" "1234"
set_server "ns3" "10.53.0.3"
# Key properties, timings and states same as above.
check_keys
check_dnssecstatus "$SERVER" "$POLICY" "$ZONE"
set_keytimes_algorithm_policy "pregenerated"
check_keytimes
check_apex
check_subdomain
dnssec_verify
#
# Zone: rumoured.kasp.
#
# There are three keys in rumoured state.
set_zone "rumoured.kasp"
set_policy "rsasha256" "3" "1234"
set_server "ns3" "10.53.0.3"
# Key properties, timings and states same as above.
check_keys
check_dnssecstatus "$SERVER" "$POLICY" "$ZONE"
set_keytimes_algorithm_policy
# Activation date is a day later.
set_addkeytime "KEY1" "ACTIVE" $(key_get KEY1 ACTIVE) 86400
set_addkeytime "KEY1" "RETIRED" $(key_get KEY1 RETIRED) 86400
set_addkeytime "KEY1" "REMOVED" $(key_get KEY1 REMOVED) 86400
set_addkeytime "KEY2" "ACTIVE" $(key_get KEY2 ACTIVE) 86400
set_addkeytime "KEY2" "RETIRED" $(key_get KEY2 RETIRED) 86400
set_addkeytime "KEY2" "REMOVED" $(key_get KEY2 REMOVED) 86400
set_addkeytime "KEY3" "ACTIVE" $(key_get KEY3 ACTIVE) 86400
set_addkeytime "KEY3" "RETIRED" $(key_get KEY3 RETIRED) 86400
set_addkeytime "KEY3" "REMOVED" $(key_get KEY3 REMOVED) 86400
check_keytimes
check_apex
check_subdomain
dnssec_verify
#
# Zone: secondary.kasp.
#
set_zone "secondary.kasp"
set_policy "rsasha256" "3" "1234"
set_server "ns3" "10.53.0.3"
# Key properties, timings and states same as above.
check_keys
check_dnssecstatus "$SERVER" "$POLICY" "$ZONE"
set_keytimes_algorithm_policy
check_keytimes
check_apex
check_subdomain
dnssec_verify
# Update zone.
n=$((n + 1))
echo_i "check that we correctly sign the zone after IXFR for zone ${ZONE} ($n)"
ret=0
cp ns2/secondary.kasp.db.in2 ns2/secondary.kasp.db
rndccmd 10.53.0.2 reload "$ZONE" >/dev/null || log_error "rndc reload zone ${ZONE} failed"
_wait_for_done_subdomains() {
ret=0
dig_with_opts "a.${ZONE}" "@${SERVER}" A >"dig.out.$DIR.test$n.a" || return 1
grep "status: NOERROR" "dig.out.$DIR.test$n.a" >/dev/null || return 1
grep "a.${ZONE}\..*${DEFAULT_TTL}.*IN.*A.*10\.0\.0\.11" "dig.out.$DIR.test$n.a" >/dev/null || return 1
check_signatures $_qtype "dig.out.$DIR.test$n.a" "ZSK"
if [ $ret -gt 0 ]; then return $ret; fi
dig_with_opts "d.${ZONE}" "@${SERVER}" A >"dig.out.$DIR.test$n.d" || return 1
grep "status: NOERROR" "dig.out.$DIR.test$n.d" >/dev/null || return 1
grep "d.${ZONE}\..*${DEFAULT_TTL}.*IN.*A.*10\.0\.0\.4" "dig.out.$DIR.test$n.d" >/dev/null || return 1
check_signatures $_qtype "dig.out.$DIR.test$n.d" "ZSK"
return $ret
}
retry_quiet 5 _wait_for_done_subdomains || ret=1
test "$ret" -eq 0 || echo_i "failed"
status=$((status + ret))
# TODO: we might want to test: # TODO: we might want to test:
# - configuring a zone with too many active keys (should trigger retire). # - configuring a zone with too many active keys (should trigger retire).
# - configuring a zone with keys not matching the policy. # - configuring a zone with keys not matching the policy.
#
# Zone: rsasha1-nsec3.kasp.
#
if [ $RSASHA1_SUPPORTED = 1 ]; then
set_zone "rsasha1-nsec3.kasp"
set_policy "rsasha1-nsec3" "3" "1234"
set_server "ns3" "10.53.0.3"
# Key properties.
set_keyalgorithm "KEY1" "7" "NSEC3RSASHA1" "2048"
set_keyalgorithm "KEY2" "7" "NSEC3RSASHA1" "2048"
set_keyalgorithm "KEY3" "7" "NSEC3RSASHA1" "2000"
# Key timings and states same as above.
check_keys
check_dnssecstatus "$SERVER" "$POLICY" "$ZONE"
set_keytimes_algorithm_policy
check_keytimes
check_apex
check_subdomain
dnssec_verify
fi
#
# Zone: rsasha256.kasp.
#
set_zone "rsasha256.kasp"
set_policy "rsasha256" "3" "1234"
set_server "ns3" "10.53.0.3"
# Key properties.
set_keyalgorithm "KEY1" "8" "RSASHA256" "2048"
set_keyalgorithm "KEY2" "8" "RSASHA256" "2048"
set_keyalgorithm "KEY3" "8" "RSASHA256" "3072"
# Key timings and states same as above.
check_keys
check_dnssecstatus "$SERVER" "$POLICY" "$ZONE"
set_keytimes_algorithm_policy
check_keytimes
check_apex
check_subdomain
dnssec_verify
#
# Zone: rsasha512.kasp.
#
set_zone "rsasha512.kasp"
set_policy "rsasha512" "3" "1234"
set_server "ns3" "10.53.0.3"
# Key properties.
set_keyalgorithm "KEY1" "10" "RSASHA512" "2048"
set_keyalgorithm "KEY2" "10" "RSASHA512" "2048"
set_keyalgorithm "KEY3" "10" "RSASHA512" "3072"
# Key timings and states same as above.
check_keys
check_dnssecstatus "$SERVER" "$POLICY" "$ZONE"
set_keytimes_algorithm_policy
check_keytimes
check_apex
check_subdomain
dnssec_verify
#
# Zone: ecdsa256.kasp.
#
set_zone "ecdsa256.kasp"
set_policy "ecdsa256" "3" "1234"
set_server "ns3" "10.53.0.3"
# Key properties.
set_keyalgorithm "KEY1" "13" "ECDSAP256SHA256" "256"
set_keyalgorithm "KEY2" "13" "ECDSAP256SHA256" "256"
set_keyalgorithm "KEY3" "13" "ECDSAP256SHA256" "256"
# Key timings and states same as above.
check_keys
check_dnssecstatus "$SERVER" "$POLICY" "$ZONE"
set_keytimes_algorithm_policy
check_keytimes
check_apex
check_subdomain
dnssec_verify
#
# Zone: ecdsa512.kasp.
#
set_zone "ecdsa384.kasp"
set_policy "ecdsa384" "3" "1234"
set_server "ns3" "10.53.0.3"
# Key properties.
set_keyalgorithm "KEY1" "14" "ECDSAP384SHA384" "384"
set_keyalgorithm "KEY2" "14" "ECDSAP384SHA384" "384"
set_keyalgorithm "KEY3" "14" "ECDSAP384SHA384" "384"
# Key timings and states same as above.
check_keys
check_dnssecstatus "$SERVER" "$POLICY" "$ZONE"
set_keytimes_algorithm_policy
check_keytimes
check_apex
check_subdomain
dnssec_verify
#
# Zone: ed25519.kasp.
#
if [ $ED25519_SUPPORTED = 1 ]; then
set_zone "ed25519.kasp"
set_policy "ed25519" "3" "1234"
set_server "ns3" "10.53.0.3"
# Key properties.
set_keyalgorithm "KEY1" "15" "ED25519" "256"
set_keyalgorithm "KEY2" "15" "ED25519" "256"
set_keyalgorithm "KEY3" "15" "ED25519" "256"
# Key timings and states same as above.
check_keys
check_dnssecstatus "$SERVER" "$POLICY" "$ZONE"
set_keytimes_algorithm_policy
check_keytimes
check_apex
check_subdomain
dnssec_verify
fi
#
# Zone: ed448.kasp.
#
if [ $ED448_SUPPORTED = 1 ]; then
set_zone "ed448.kasp"
set_policy "ed448" "3" "1234"
set_server "ns3" "10.53.0.3"
# Key properties.
set_keyalgorithm "KEY1" "16" "ED448" "456"
set_keyalgorithm "KEY2" "16" "ED448" "456"
set_keyalgorithm "KEY3" "16" "ED448" "456"
# Key timings and states same as above.
check_keys
check_dnssecstatus "$SERVER" "$POLICY" "$ZONE"
set_keytimes_algorithm_policy
check_keytimes
check_apex
check_subdomain
dnssec_verify
fi
# Set key times for 'autosign' policy. # Set key times for 'autosign' policy.
set_keytimes_autosign_policy() { set_keytimes_autosign_policy() {
# The KSK was published six months ago (with settime). # The KSK was published six months ago (with settime).
@@ -889,256 +437,39 @@ set_keytimes_autosign_policy() {
set_addkeytime "KEY2" "REMOVED" "${retired}" 695100 set_addkeytime "KEY2" "REMOVED" "${retired}" 695100
} }
#
# Zone: expired-sigs.autosign.
#
set_zone "expired-sigs.autosign"
set_policy "autosign" "2" "300"
set_server "ns3" "10.53.0.3"
# Key properties.
key_clear "KEY1"
set_keyrole "KEY1" "ksk"
set_keylifetime "KEY1" "63072000"
set_keyalgorithm "KEY1" "$DEFAULT_ALGORITHM_NUMBER" "$DEFAULT_ALGORITHM" "$DEFAULT_BITS"
set_keysigning "KEY1" "yes"
set_zonesigning "KEY1" "no"
key_clear "KEY2"
set_keyrole "KEY2" "zsk"
set_keylifetime "KEY2" "31536000"
set_keyalgorithm "KEY2" "$DEFAULT_ALGORITHM_NUMBER" "$DEFAULT_ALGORITHM" "$DEFAULT_BITS"
set_keysigning "KEY2" "no"
set_zonesigning "KEY2" "yes"
# Both KSK and ZSK stay OMNIPRESENT.
set_keystate "KEY1" "GOAL" "omnipresent"
set_keystate "KEY1" "STATE_DNSKEY" "omnipresent"
set_keystate "KEY1" "STATE_KRRSIG" "omnipresent"
set_keystate "KEY1" "STATE_DS" "omnipresent"
set_keystate "KEY2" "GOAL" "omnipresent"
set_keystate "KEY2" "STATE_DNSKEY" "omnipresent"
set_keystate "KEY2" "STATE_ZRRSIG" "omnipresent"
# Expect only two keys.
key_clear "KEY3"
key_clear "KEY4"
check_keys
check_dnssecstatus "$SERVER" "$POLICY" "$ZONE"
set_keytimes_autosign_policy
check_keytimes
check_apex
check_subdomain
dnssec_verify
# Verify all signatures have been refreshed.
check_rrsig_refresh() {
# Apex.
_qtypes="DNSKEY SOA NS NSEC"
for _qtype in $_qtypes; do
n=$((n + 1))
echo_i "check ${_qtype} rrsig is refreshed correctly for zone ${ZONE} ($n)"
ret=0
dig_with_opts "$ZONE" "@${SERVER}" "$_qtype" >"dig.out.$DIR.test$n" || log_error "dig ${ZONE} ${_qtype} failed"
grep "status: NOERROR" "dig.out.$DIR.test$n" >/dev/null || log_error "mismatch status in DNS response"
grep "${ZONE}\..*IN.*RRSIG.*${_qtype}.*${ZONE}" "dig.out.$DIR.test$n" >"rrsig.out.$ZONE.$_qtype" || log_error "missing RRSIG (${_qtype}) record in response"
# If this exact RRSIG is also in the zone file it is not refreshed.
_rrsig=$(cat "rrsig.out.$ZONE.$_qtype")
grep "${_rrsig}" "${DIR}/${ZONE}.db" >/dev/null && log_error "RRSIG (${_qtype}) not refreshed in zone ${ZONE}"
test "$ret" -eq 0 || echo_i "failed"
status=$((status + ret))
done
# Below apex.
_labels="a b c ns3"
for _label in $_labels; do
_qtypes="A NSEC"
for _qtype in $_qtypes; do
n=$((n + 1))
echo_i "check ${_label} ${_qtype} rrsig is refreshed correctly for zone ${ZONE} ($n)"
ret=0
dig_with_opts "${_label}.${ZONE}" "@${SERVER}" "$_qtype" >"dig.out.$DIR.test$n" || log_error "dig ${_label}.${ZONE} ${_qtype} failed"
grep "status: NOERROR" "dig.out.$DIR.test$n" >/dev/null || log_error "mismatch status in DNS response"
grep "${ZONE}\..*IN.*RRSIG.*${_qtype}.*${ZONE}" "dig.out.$DIR.test$n" >"rrsig.out.$ZONE.$_qtype" || log_error "missing RRSIG (${_qtype}) record in response"
_rrsig=$(cat "rrsig.out.$ZONE.$_qtype")
grep "${_rrsig}" "${DIR}/${ZONE}.db" >/dev/null && log_error "RRSIG (${_qtype}) not refreshed in zone ${ZONE}"
test "$ret" -eq 0 || echo_i "failed"
status=$((status + ret))
done
done
}
check_rrsig_refresh
#
# Zone: dnskey-ttl-mismatch.autosign
#
set_zone "dnskey-ttl-mismatch.autosign"
set_policy "autosign" "2" "300"
set_server "ns3" "10.53.0.3"
# Key properties.
key_clear "KEY1"
set_keyrole "KEY1" "ksk"
set_keylifetime "KEY1" "63072000"
set_keyalgorithm "KEY1" "$DEFAULT_ALGORITHM_NUMBER" "$DEFAULT_ALGORITHM" "$DEFAULT_BITS"
set_keysigning "KEY1" "yes"
set_zonesigning "KEY1" "no"
key_clear "KEY2"
set_keyrole "KEY2" "zsk"
set_keylifetime "KEY2" "31536000"
set_keyalgorithm "KEY2" "$DEFAULT_ALGORITHM_NUMBER" "$DEFAULT_ALGORITHM" "$DEFAULT_BITS"
set_keysigning "KEY2" "no"
set_zonesigning "KEY2" "yes"
# Both KSK and ZSK stay OMNIPRESENT.
set_keystate "KEY1" "GOAL" "omnipresent"
set_keystate "KEY1" "STATE_DNSKEY" "omnipresent"
set_keystate "KEY1" "STATE_KRRSIG" "omnipresent"
set_keystate "KEY1" "STATE_DS" "omnipresent"
set_keystate "KEY2" "GOAL" "omnipresent"
set_keystate "KEY2" "STATE_DNSKEY" "omnipresent"
set_keystate "KEY2" "STATE_ZRRSIG" "omnipresent"
# Expect only two keys.
key_clear "KEY3"
key_clear "KEY4"
check_keys
check_dnssecstatus "$SERVER" "$POLICY" "$ZONE"
set_keytimes_autosign_policy
check_keytimes
check_apex
check_subdomain
dnssec_verify
#
# Zone: fresh-sigs.autosign.
#
set_zone "fresh-sigs.autosign"
set_policy "autosign" "2" "300"
set_server "ns3" "10.53.0.3"
# Key properties, timings and states same as above.
check_keys
check_dnssecstatus "$SERVER" "$POLICY" "$ZONE"
set_keytimes_autosign_policy
check_keytimes
check_apex
check_subdomain
dnssec_verify
# Verify signature reuse.
check_rrsig_reuse() {
# Apex.
_qtypes="NS NSEC"
for _qtype in $_qtypes; do
n=$((n + 1))
echo_i "check ${_qtype} rrsig is reused correctly for zone ${ZONE} ($n)"
ret=0
dig_with_opts "$ZONE" "@${SERVER}" "$_qtype" >"dig.out.$DIR.test$n" || log_error "dig ${ZONE} ${_qtype} failed"
grep "status: NOERROR" "dig.out.$DIR.test$n" >/dev/null || log_error "mismatch status in DNS response"
grep "${ZONE}\..*IN.*RRSIG.*${_qtype}.*${ZONE}" "dig.out.$DIR.test$n" >"rrsig.out.$ZONE.$_qtype" || log_error "missing RRSIG (${_qtype}) record in response"
# If this exact RRSIG is also in the signed zone file it is not refreshed.
_rrsig=$(awk '{print $5, $6, $7, $8, $9, $10, $11, $12, $13, $14;}' <"rrsig.out.$ZONE.$_qtype")
$CHECKZONE -f raw -F text -s full -o zone.out.${ZONE}.test$n "${ZONE}" "${DIR}/${ZONE}.db.signed" >/dev/null
grep "${_rrsig}" zone.out.${ZONE}.test$n >/dev/null || log_error "RRSIG (${_qtype}) not reused in zone ${ZONE}"
test "$ret" -eq 0 || echo_i "failed"
status=$((status + ret))
done
# Below apex.
_labels="a b c ns3"
for _label in $_labels; do
_qtypes="A NSEC"
for _qtype in $_qtypes; do
n=$((n + 1))
echo_i "check ${_label} ${_qtype} rrsig is reused correctly for zone ${ZONE} ($n)"
ret=0
dig_with_opts "${_label}.${ZONE}" "@${SERVER}" "$_qtype" >"dig.out.$DIR.test$n" || log_error "dig ${_label}.${ZONE} ${_qtype} failed"
grep "status: NOERROR" "dig.out.$DIR.test$n" >/dev/null || log_error "mismatch status in DNS response"
grep "${ZONE}\..*IN.*RRSIG.*${_qtype}.*${ZONE}" "dig.out.$DIR.test$n" >"rrsig.out.$ZONE.$_qtype" || log_error "missing RRSIG (${_qtype}) record in response"
# If this exact RRSIG is also in the signed zone file it is not refreshed.
_rrsig=$(awk '{print $5, $6, $7, $8, $9, $10, $11, $12, $13, $14;}' <"rrsig.out.$ZONE.$_qtype")
$CHECKZONE -f raw -F text -s full -o zone.out.${ZONE}.test$n "${ZONE}" "${DIR}/${ZONE}.db.signed" >/dev/null
grep "${_rrsig}" zone.out.${ZONE}.test$n >/dev/null || log_error "RRSIG (${_qtype}) not reused in zone ${ZONE}"
test "$ret" -eq 0 || echo_i "failed"
status=$((status + ret))
done
done
}
check_rrsig_reuse
#
# Zone: unfresh-sigs.autosign.
#
set_zone "unfresh-sigs.autosign"
set_policy "autosign" "2" "300"
set_server "ns3" "10.53.0.3"
# Key properties, timings and states same as above.
check_keys
check_dnssecstatus "$SERVER" "$POLICY" "$ZONE"
set_keytimes_autosign_policy
check_keytimes
check_apex
check_subdomain
dnssec_verify
check_rrsig_refresh
#
# Zone: ksk-missing.autosign.
#
set_zone "ksk-missing.autosign"
set_policy "autosign" "2" "300"
set_server "ns3" "10.53.0.3"
# Key properties, timings and states same as above.
# Skip checking the private file, because it is missing.
key_set "KEY1" "PRIVATE" "no"
check_keys
check_dnssecstatus "$SERVER" "$POLICY" "$ZONE"
check_apex
check_subdomain
dnssec_verify
# Restore the PRIVATE variable.
key_set "KEY1" "PRIVATE" "yes"
#
# Zone: zsk-missing.autosign.
#
set_zone "zsk-missing.autosign"
set_policy "autosign" "2" "300"
set_server "ns3" "10.53.0.3"
# Key properties, timings and states same as above.
# Skip checking the private file, because it is missing.
key_set "KEY2" "PRIVATE" "no"
check_keys
check_dnssecstatus "$SERVER" "$POLICY" "$ZONE"
# For the apex, we expect the SOA to be signed with the KSK because the ZSK is
# offline. Temporary treat KEY1 as a zone signing key too.
set_keyrole "KEY1" "csk"
set_zonesigning "KEY1" "yes"
set_zonesigning "KEY2" "no"
check_apex
set_keyrole "KEY1" "ksk"
set_zonesigning "KEY1" "no"
set_zonesigning "KEY2" "yes"
check_subdomain
dnssec_verify
# Restore the PRIVATE variable.
key_set "KEY2" "PRIVATE" "yes"
# #
# Zone: zsk-retired.autosign. # Zone: zsk-retired.autosign.
# #
set_zone "zsk-retired.autosign" set_zone "zsk-retired.autosign"
set_policy "autosign" "3" "300" set_policy "autosign" "3" "300"
set_server "ns3" "10.53.0.3" set_server "ns3" "10.53.0.3"
# Key properties.
key_clear "KEY1"
set_keyrole "KEY1" "ksk"
set_keylifetime "KEY1" "63072000"
set_keyalgorithm "KEY1" "$DEFAULT_ALGORITHM_NUMBER" "$DEFAULT_ALGORITHM" "$DEFAULT_BITS"
set_keysigning "KEY1" "yes"
set_zonesigning "KEY1" "no"
key_clear "KEY2"
set_keyrole "KEY2" "zsk"
set_keylifetime "KEY2" "31536000"
set_keyalgorithm "KEY2" "$DEFAULT_ALGORITHM_NUMBER" "$DEFAULT_ALGORITHM" "$DEFAULT_BITS"
set_keysigning "KEY2" "no"
set_zonesigning "KEY2" "yes"
# Both KSK and ZSK stay OMNIPRESENT.
set_keystate "KEY1" "GOAL" "omnipresent"
set_keystate "KEY1" "STATE_DNSKEY" "omnipresent"
set_keystate "KEY1" "STATE_KRRSIG" "omnipresent"
set_keystate "KEY1" "STATE_DS" "omnipresent"
set_keystate "KEY2" "GOAL" "omnipresent"
set_keystate "KEY2" "STATE_DNSKEY" "omnipresent"
set_keystate "KEY2" "STATE_ZRRSIG" "omnipresent"
# Expect only two keys.
key_clear "KEY3"
key_clear "KEY4"
# The third key is not yet expected to be signing. # The third key is not yet expected to be signing.
set_keyrole "KEY3" "zsk" set_keyrole "KEY3" "zsk"
set_keylifetime "KEY3" "31536000" set_keylifetime "KEY3" "31536000"
@@ -1185,7 +516,7 @@ check_keytimes
check_apex check_apex
check_subdomain check_subdomain
dnssec_verify dnssec_verify
check_rrsig_refresh #check_rrsig_refresh
# Load again, make sure the purged key is not an issue when verifying keys. # Load again, make sure the purged key is not an issue when verifying keys.
echo_i "load keys for $ZONE, making sure a recently purged key is not an issue when verifying keys ($n)" echo_i "load keys for $ZONE, making sure a recently purged key is not an issue when verifying keys ($n)"
@@ -1196,164 +527,6 @@ grep "zone $ZONE/IN (signed): zone_rekey:zone_verifykeys failed: some key files
test "$ret" -eq 0 || echo_i "failed" test "$ret" -eq 0 || echo_i "failed"
status=$((status + ret)) status=$((status + ret))
#
# Zone: legacy-keys.kasp.
#
set_zone "legacy-keys.kasp"
# This zone has two active keys and two old keys left in key directory, so
# expect 4 key files.
set_policy "migrate-to-dnssec-policy" "4" "1234"
set_server "ns3" "10.53.0.3"
# Key properties.
key_clear "KEY1"
set_keyrole "KEY1" "ksk"
set_keylifetime "KEY1" "16070400"
set_keyalgorithm "KEY1" "8" "RSASHA256" "2048"
set_keysigning "KEY1" "yes"
set_zonesigning "KEY1" "no"
key_clear "KEY2"
set_keyrole "KEY2" "zsk"
set_keylifetime "KEY2" "16070400"
set_keyalgorithm "KEY2" "8" "RSASHA256" "2048"
set_keysigning "KEY2" "no"
set_zonesigning "KEY2" "yes"
# KSK: DNSKEY, RRSIG (ksk) published. DS needs to wait.
# ZSK: DNSKEY, RRSIG (zsk) published.
set_keystate "KEY1" "GOAL" "omnipresent"
set_keystate "KEY1" "STATE_DNSKEY" "rumoured"
set_keystate "KEY1" "STATE_KRRSIG" "rumoured"
set_keystate "KEY1" "STATE_DS" "hidden"
set_keystate "KEY2" "GOAL" "omnipresent"
set_keystate "KEY2" "STATE_DNSKEY" "rumoured"
set_keystate "KEY2" "STATE_ZRRSIG" "rumoured"
# Two keys only.
key_clear "KEY3"
key_clear "KEY4"
check_keys
check_dnssecstatus "$SERVER" "$POLICY" "$ZONE"
# Make sure the correct legacy keys were used (and not the removed predecessor
# keys).
n=$((n + 1))
echo_i "check correct keys were used when migrating zone ${ZONE} to dnssec-policy ($n)"
ret=0
kskfile=$(cat ns3/legacy-keys.kasp.ksk)
basefile=$(key_get KEY1 BASEFILE)
echo_i "filename: $basefile (expect $kskfile)"
test "$DIR/$kskfile" = "$basefile" || ret=1
zskfile=$(cat ns3/legacy-keys.kasp.zsk)
basefile=$(key_get KEY2 BASEFILE)
echo_i "filename: $basefile (expect $zskfile)"
test "$DIR/$zskfile" = "$basefile" || ret=1
test "$ret" -eq 0 || echo_i "failed"
status=$((status + ret))
# KSK times.
created=$(key_get KEY1 CREATED)
keyfile=$(key_get KEY1 BASEFILE)
grep "; Publish:" "${keyfile}.key" >published.test${n}.key1
published=$(awk '{print $3}' <published.test${n}.key1)
set_keytime "KEY1" "PUBLISHED" "${published}"
set_keytime "KEY1" "ACTIVE" "${published}"
published=$(key_get KEY1 PUBLISHED)
# The DS can be published if the zone is fully signed.
# This happens after max-zone-ttl (1d) plus
# zone-propagation-delay (300s) = 86400 + 300 = 86700.
set_addkeytime "KEY1" "SYNCPUBLISH" "${published}" 86700
# Key lifetime is 6 months, 315360000 seconds.
set_addkeytime "KEY1" "RETIRED" "${published}" 16070400
# The key is removed after the retire time plus DS TTL (1d), parent
# propagation delay (1h), and retire safety (1h) = 86400 + 3600 + 3600 = 93600.
retired=$(key_get KEY1 RETIRED)
set_addkeytime "KEY1" "REMOVED" "${retired}" 93600
# ZSK times.
created=$(key_get KEY2 CREATED)
keyfile=$(key_get KEY2 BASEFILE)
grep "; Publish:" "${keyfile}.key" >published.test${n}.key2
published=$(awk '{print $3}' <published.test${n}.key2)
set_keytime "KEY2" "PUBLISHED" "${published}"
set_keytime "KEY2" "ACTIVE" "${published}"
published=$(key_get KEY2 PUBLISHED)
# Key lifetime is 6 months, 315360000 seconds.
set_addkeytime "KEY2" "RETIRED" "${published}" 16070400
# The key is removed after the retire time plus max zone ttl (1d), zone
# propagation delay (300s), retire safety (1h), and sign delay (signature
# validity minus refresh, 9d) = 86400 + 300 + 3600 + 777600 = 867900.
retired=$(key_get KEY2 RETIRED)
set_addkeytime "KEY2" "REMOVED" "${retired}" 867900
check_keytimes
check_apex
check_subdomain
dnssec_verify
#
# Zone: keyfiles-missing.autosign.
#
set_zone "keyfiles-missing.autosign"
set_policy "autosign" "2" "300"
set_server "ns3" "10.53.0.3"
# Key properties.
key_clear "KEY1"
set_keyrole "KEY1" "ksk"
set_keylifetime "KEY1" "63072000"
set_keyalgorithm "KEY1" "$DEFAULT_ALGORITHM_NUMBER" "$DEFAULT_ALGORITHM" "$DEFAULT_BITS"
set_keysigning "KEY1" "yes"
set_zonesigning "KEY1" "no"
key_clear "KEY2"
set_keyrole "KEY2" "zsk"
set_keylifetime "KEY2" "31536000"
set_keyalgorithm "KEY2" "$DEFAULT_ALGORITHM_NUMBER" "$DEFAULT_ALGORITHM" "$DEFAULT_BITS"
set_keysigning "KEY2" "no"
set_zonesigning "KEY2" "yes"
# Both KSK and ZSK stay OMNIPRESENT.
set_keystate "KEY1" "GOAL" "omnipresent"
set_keystate "KEY1" "STATE_DNSKEY" "omnipresent"
set_keystate "KEY1" "STATE_KRRSIG" "omnipresent"
set_keystate "KEY1" "STATE_DS" "omnipresent"
set_keystate "KEY2" "GOAL" "omnipresent"
set_keystate "KEY2" "STATE_DNSKEY" "omnipresent"
set_keystate "KEY2" "STATE_ZRRSIG" "omnipresent"
check_keys
check_dnssecstatus "$SERVER" "$POLICY" "$ZONE"
set_keytimes_autosign_policy
check_keytimes
check_apex
check_subdomain
dnssec_verify
# All good, now remove key files and reload keys.
rm_keyfiles() {
_basefile=$(key_get "$1" BASEFILE)
echo_i "remove key files $_basefile"
_keyfile="${_basefile}.key"
_privatefile="${_basefile}.private"
_statefile="${_basefile}.state"
rm -f $_keyfile
rm -f $_privatefile
rm -f $_statefile
}
rm_keyfiles "KEY1"
rm_keyfiles "KEY2"
rndccmd 10.53.0.3 loadkeys "$ZONE" >/dev/null || log_error "rndc loadkeys zone ${ZONE} failed"
wait_for_log 3 "zone $ZONE/IN (signed): zone_rekey:zone_verifykeys failed: some key files are missing" $DIR/named.run || ret=1
# Check keys again, make sure no new keys are created.
set_policy "autosign" "0" "300"
key_clear "KEY1"
key_clear "KEY2"
check_keys
# Zone is still signed correctly.
dnssec_verify
# #
# Test dnssec-policy inheritance. # Test dnssec-policy inheritance.
# #

View File

@@ -21,6 +21,7 @@ import pytest
pytest.importorskip("dns", minversion="2.0.0") pytest.importorskip("dns", minversion="2.0.0")
import isctest import isctest
import isctest.mark
from isctest.kasp import ( from isctest.kasp import (
KeyProperties, KeyProperties,
KeyTimingMetadata, KeyTimingMetadata,
@@ -80,11 +81,76 @@ pytestmark = pytest.mark.extra_artifacts(
) )
def check_all(server, zone, policy, ksks, zsks, tsig=None): kasp_config = {
"dnskey-ttl": timedelta(seconds=1234),
"ds-ttl": timedelta(days=1),
"key-directory": "{keydir}",
"max-zone-ttl": timedelta(days=1),
"parent-propagation-delay": timedelta(hours=1),
"publish-safety": timedelta(hours=1),
"retire-safety": timedelta(hours=1),
"signatures-refresh": timedelta(days=5),
"signatures-validity": timedelta(days=14),
"zone-propagation-delay": timedelta(minutes=5),
}
autosign_config = {
"dnskey-ttl": timedelta(seconds=300),
"ds-ttl": timedelta(days=1),
"key-directory": "{keydir}",
"max-zone-ttl": timedelta(days=1),
"parent-propagation-delay": timedelta(hours=1),
"publish-safety": timedelta(hours=1),
"retire-safety": timedelta(hours=1),
"signatures-refresh": timedelta(days=7),
"signatures-validity": timedelta(days=14),
"zone-propagation-delay": timedelta(minutes=5),
}
lifetime = {
"P10Y": int(timedelta(days=10 * 365).total_seconds()),
"P5Y": int(timedelta(days=5 * 365).total_seconds()),
"P2Y": int(timedelta(days=2 * 365).total_seconds()),
"P1Y": int(timedelta(days=365).total_seconds()),
"P30D": int(timedelta(days=30).total_seconds()),
"P6M": int(timedelta(days=31 * 6).total_seconds()),
}
def autosign_properties(alg, size):
return [
f"ksk {lifetime['P2Y']} {alg} {size} goal:omnipresent dnskey:omnipresent krrsig:omnipresent ds:omnipresent",
f"zsk {lifetime['P1Y']} {alg} {size} goal:omnipresent dnskey:omnipresent zrrsig:omnipresent",
]
def rsa1_properties(alg):
return [
f"ksk {lifetime['P10Y']} {alg} 2048 goal:omnipresent dnskey:rumoured krrsig:rumoured ds:hidden",
f"zsk {lifetime['P5Y']} {alg} 2048 goal:omnipresent dnskey:rumoured zrrsig:rumoured",
f"zsk {lifetime['P1Y']} {alg} 2000 goal:omnipresent dnskey:rumoured zrrsig:rumoured",
]
def fips_properties(alg, bits=None):
sizes = [2048, 2048, 3072]
if bits is not None:
sizes = [bits, bits, bits]
return [
f"ksk {lifetime['P10Y']} {alg} {sizes[0]} goal:omnipresent dnskey:rumoured krrsig:rumoured ds:hidden",
f"zsk {lifetime['P5Y']} {alg} {sizes[1]} goal:omnipresent dnskey:rumoured zrrsig:rumoured",
f"zsk {lifetime['P1Y']} {alg} {sizes[2]} goal:omnipresent dnskey:rumoured zrrsig:rumoured",
]
def check_all(server, zone, policy, ksks, zsks, zsk_missing=False, tsig=None):
isctest.kasp.check_dnssecstatus(server, zone, ksks + zsks, policy=policy) isctest.kasp.check_dnssecstatus(server, zone, ksks + zsks, policy=policy)
isctest.kasp.check_apex(server, zone, ksks, zsks, tsig=tsig) isctest.kasp.check_apex(
server, zone, ksks, zsks, zsk_missing=zsk_missing, tsig=tsig
)
isctest.kasp.check_subdomain(server, zone, ksks, zsks, tsig=tsig) isctest.kasp.check_subdomain(server, zone, ksks, zsks, tsig=tsig)
isctest.kasp.check_dnssec_verify(server, zone) isctest.kasp.check_dnssec_verify(server, zone, tsig=tsig)
def set_keytimes_default_policy(kp): def set_keytimes_default_policy(kp):
@@ -103,6 +169,522 @@ def set_keytimes_default_policy(kp):
kp.timing["ZRRSIGChange"] = kp.timing["Active"] kp.timing["ZRRSIGChange"] = kp.timing["Active"]
def cb_ixfr_is_signed(expected_updates, params, ksks=None, zsks=None):
zone = params["zone"]
policy = params["policy"]
servers = params["servers"]
isctest.log.info(f"check that the zone {zone} is correctly signed after ixfr")
isctest.log.debug(
f"expected updates {expected_updates} policy {policy} ksks {ksks} zsks {zsks}"
)
shutil.copyfile(f"ns2/{zone}.db.in2", f"ns2/{zone}.db")
servers["ns2"].rndc(f"reload {zone}", log=False)
def update_is_signed():
parts = update.split()
qname = parts[0]
qtype = dns.rdatatype.from_text(parts[1])
rdata = parts[2]
return isctest.kasp.verify_update_is_signed(
servers["ns3"], zone, qname, qtype, rdata, ksks, zsks
)
for update in expected_updates:
isctest.run.retry_with_timeout(update_is_signed, timeout=5)
def cb_rrsig_refresh(params, ksks=None, zsks=None):
zone = params["zone"]
servers = params["servers"]
isctest.log.info(f"check that the zone {zone} refreshes expired signatures")
def rrsig_is_refreshed():
parts = query.split()
qname = parts[0]
qtype = dns.rdatatype.from_text(parts[1])
return isctest.kasp.verify_rrsig_is_refreshed(
servers["ns3"], zone, f"ns3/{zone}.db.signed", qname, qtype, ksks, zsks
)
queries = [
f"{zone} DNSKEY",
f"{zone} SOA",
f"{zone} NS",
f"{zone} NSEC",
f"a.{zone} A",
f"a.{zone} NSEC",
f"b.{zone} A",
f"b.{zone} NSEC",
f"c.{zone} A",
f"c.{zone} NSEC",
f"ns3.{zone} A",
f"ns3.{zone} NSEC",
]
for query in queries:
isctest.run.retry_with_timeout(rrsig_is_refreshed, timeout=5)
def cb_rrsig_reuse(params, ksks=None, zsks=None):
zone = params["zone"]
servers = params["servers"]
isctest.log.info(f"check that the zone {zone} reuses fresh signatures")
def rrsig_is_reused():
parts = query.split()
qname = parts[0]
qtype = dns.rdatatype.from_text(parts[1])
return isctest.kasp.verify_rrsig_is_reused(
servers["ns3"], zone, f"ns3/{zone}.db.signed", qname, qtype, ksks, zsks
)
queries = [
f"{zone} NS",
f"{zone} NSEC",
f"a.{zone} A",
f"a.{zone} NSEC",
f"b.{zone} A",
f"b.{zone} NSEC",
f"c.{zone} A",
f"c.{zone} NSEC",
f"ns3.{zone} A",
f"ns3.{zone} NSEC",
]
for query in queries:
rrsig_is_reused()
def cb_legacy_keys(params, ksks=None, zsks=None):
zone = params["zone"]
keydir = params["config"]["key-directory"]
isctest.log.info(f"check that the zone {zone} uses correct legacy keys")
assert len(ksks) == 1
assert len(zsks) == 1
# This assumes the zone has a policy that dictates one KSK and one ZSK.
# The right keys to be used are stored in "{zone}.ksk" and "{zone}.zsk".
with open(f"{keydir}/{zone}.ksk", "r", encoding="utf-8") as file:
kskfile = file.read()
with open(f"{keydir}/{zone}.zsk", "r", encoding="utf-8") as file:
zskfile = file.read()
assert f"{keydir}/{kskfile}".strip() == ksks[0].path
assert f"{keydir}/{zskfile}".strip() == zsks[0].path
def cb_remove_keyfiles(params, ksks=None, zsks=None):
zone = params["zone"]
servers = params["servers"]
keydir = params["config"]["key-directory"]
isctest.log.info(
"check that removing key files does not create new keys to be generated"
)
for k in ksks + zsks:
os.remove(k.keyfile)
os.remove(k.privatefile)
os.remove(k.statefile)
with servers["ns3"].watch_log_from_here() as watcher:
servers["ns3"].rndc(f"loadkeys {zone}", log=False)
watcher.wait_for_line(
f"zone {zone}/IN (signed): zone_rekey:zone_verifykeys failed: some key files are missing"
)
# Check keys again, make sure no new keys are created.
keys = isctest.kasp.keydir_to_keylist(zone, keydir)
isctest.kasp.check_keys(zone, keys, [])
# Zone is still signed correctly.
isctest.kasp.check_dnssec_verify(servers["ns3"], zone)
@pytest.mark.parametrize(
"params",
[
pytest.param(
{
"zone": "rsasha1.kasp",
"policy": "rsasha1",
"config": kasp_config,
"key-properties": rsa1_properties(5),
},
id="rsasha1.kasp",
marks=isctest.mark.with_algorithm("RSASHA1"),
),
pytest.param(
{
"zone": "rsasha1-nsec3.kasp",
"policy": "rsasha1",
"config": kasp_config,
"key-properties": rsa1_properties(7),
},
id="rsasha1-nsec3.kasp",
marks=isctest.mark.with_algorithm("RSASHA1"),
),
pytest.param(
{
"zone": "dnskey-ttl-mismatch.autosign",
"policy": "autosign",
"config": autosign_config,
"offset": -timedelta(days=30 * 6),
"key-properties": autosign_properties(
os.environ["DEFAULT_ALGORITHM_NUMBER"], os.environ["DEFAULT_BITS"]
),
},
id="dnskey-ttl-mismatch.autosign",
),
pytest.param(
{
"zone": "expired-sigs.autosign",
"policy": "autosign",
"config": autosign_config,
"offset": -timedelta(days=30 * 6),
"key-properties": autosign_properties(
os.environ["DEFAULT_ALGORITHM_NUMBER"], os.environ["DEFAULT_BITS"]
),
"additional-tests": [
{
"callback": cb_rrsig_refresh,
"arguments": [],
},
],
},
id="expired-sigs.autosign",
),
pytest.param(
{
"zone": "fresh-sigs.autosign",
"policy": "autosign",
"config": autosign_config,
"offset": -timedelta(days=30 * 6),
"key-properties": autosign_properties(
os.environ["DEFAULT_ALGORITHM_NUMBER"], os.environ["DEFAULT_BITS"]
),
"additional-tests": [
{
"callback": cb_rrsig_reuse,
"arguments": [],
},
],
},
id="fresh-sigs.autosign",
),
pytest.param(
{
"zone": "unfresh-sigs.autosign",
"policy": "autosign",
"config": autosign_config,
"offset": -timedelta(days=30 * 6),
"key-properties": autosign_properties(
os.environ["DEFAULT_ALGORITHM_NUMBER"], os.environ["DEFAULT_BITS"]
),
"additional-tests": [
{
"callback": cb_rrsig_refresh,
"arguments": [],
},
],
},
id="unfresh-sigs.autosign",
),
pytest.param(
{
"zone": "keyfiles-missing.autosign",
"policy": "autosign",
"config": autosign_config,
"offset": -timedelta(days=30 * 6),
"key-properties": autosign_properties(
os.environ["DEFAULT_ALGORITHM_NUMBER"], os.environ["DEFAULT_BITS"]
),
"additional-tests": [
{
"callback": cb_remove_keyfiles,
"arguments": [],
},
],
},
id="keyfiles-missing.autosign",
),
pytest.param(
{
"zone": "ksk-missing.autosign",
"policy": "autosign",
"config": autosign_config,
"offset": -timedelta(days=30 * 6),
"key-properties": [
f"ksk 63072000 {os.environ['DEFAULT_ALGORITHM_NUMBER']} {os.environ['DEFAULT_BITS']} goal:omnipresent dnskey:omnipresent krrsig:omnipresent ds:omnipresent missing",
f"zsk 31536000 {os.environ['DEFAULT_ALGORITHM_NUMBER']} {os.environ['DEFAULT_BITS']} goal:omnipresent dnskey:omnipresent zrrsig:omnipresent",
],
},
id="ksk-missing.autosign",
),
pytest.param(
{
"zone": "zsk-missing.autosign",
"policy": "autosign",
"config": autosign_config,
"offset": -timedelta(days=30 * 6),
"key-properties": [
f"ksk 63072000 {os.environ['DEFAULT_ALGORITHM_NUMBER']} {os.environ['DEFAULT_BITS']} goal:omnipresent dnskey:omnipresent krrsig:omnipresent ds:omnipresent",
f"zsk 31536000 {os.environ['DEFAULT_ALGORITHM_NUMBER']} {os.environ['DEFAULT_BITS']} goal:omnipresent dnskey:omnipresent zrrsig:omnipresent missing",
],
},
id="zsk-missing.autosign",
),
pytest.param(
{
"zone": "dnssec-keygen.kasp",
"policy": "rsasha256",
"config": kasp_config,
"key-properties": fips_properties(8),
},
id="dnssec-keygen.kasp",
),
pytest.param(
{
"zone": "ecdsa256.kasp",
"policy": "ecdsa256",
"config": kasp_config,
"key-properties": fips_properties(13, bits=256),
},
id="ecdsa256.kasp",
),
pytest.param(
{
"zone": "ecdsa384.kasp",
"policy": "ecdsa384",
"config": kasp_config,
"key-properties": fips_properties(14, bits=384),
},
id="ecdsa384.kasp",
),
pytest.param(
{
"zone": "inherit.kasp",
"policy": "rsasha256",
"config": kasp_config,
"key-properties": fips_properties(8),
},
id="inherit.kasp",
),
pytest.param(
{
"zone": "keystore.kasp",
"policy": "keystore",
"config": {
"dnskey-ttl": timedelta(seconds=303),
"ds-ttl": timedelta(days=1),
"key-directory": "{keydir}",
"max-zone-ttl": timedelta(days=1),
"parent-propagation-delay": timedelta(hours=1),
"publish-safety": timedelta(hours=1),
"retire-safety": timedelta(hours=1),
"signatures-refresh": timedelta(days=5),
"signatures-validity": timedelta(days=14),
"zone-propagation-delay": timedelta(minutes=5),
},
"key-directories": ["{keydir}/ksk", "{keydir}/zsk"],
"key-properties": [
f"ksk unlimited {os.environ['DEFAULT_ALGORITHM_NUMBER']} {os.environ['DEFAULT_BITS']} goal:omnipresent dnskey:rumoured krrsig:rumoured ds:hidden",
f"zsk unlimited {os.environ['DEFAULT_ALGORITHM_NUMBER']} {os.environ['DEFAULT_BITS']} goal:omnipresent dnskey:rumoured zrrsig:rumoured",
],
},
id="keystore.kasp",
),
pytest.param(
{
"zone": "legacy-keys.kasp",
"policy": "migrate-to-dnssec-policy",
"config": kasp_config,
"pregenerated": True,
"key-properties": [
"ksk 16070400 8 2048 goal:omnipresent dnskey:rumoured krrsig:rumoured ds:hidden",
"zsk 16070400 8 2048 goal:omnipresent dnskey:rumoured zrrsig:rumoured",
],
"additional-tests": [
{
"callback": cb_legacy_keys,
"arguments": [],
},
],
},
id="legacy-keys.kasp",
),
pytest.param(
{
"zone": "pregenerated.kasp",
"policy": "rsasha256",
"config": kasp_config,
"pregenerated": True,
"key-properties": fips_properties(8),
},
id="pregenerated.kasp",
),
pytest.param(
{
"zone": "rsasha256.kasp",
"policy": "rsasha256",
"config": kasp_config,
"key-properties": fips_properties(8),
},
id="rsasha256.kasp",
),
pytest.param(
{
"zone": "rsasha512.kasp",
"policy": "rsasha512",
"config": kasp_config,
"key-properties": fips_properties(10),
},
id="rsasha512.kasp",
),
pytest.param(
{
"zone": "rumoured.kasp",
"policy": "rsasha256",
"config": kasp_config,
"rumoured": True,
"key-properties": fips_properties(8),
},
id="rumoured.kasp",
),
pytest.param(
{
"zone": "secondary.kasp",
"policy": "rsasha256",
"config": kasp_config,
"key-properties": fips_properties(8),
"additional-tests": [
{
"callback": cb_ixfr_is_signed,
"arguments": [
[
"a.secondary.kasp. A 10.0.0.11",
"d.secondary.kasp. A 10.0.0.4",
],
],
},
],
},
id="secondary.kasp",
),
pytest.param(
{
"zone": "some-keys.kasp",
"policy": "rsasha256",
"config": kasp_config,
"pregenerated": True,
"key-properties": fips_properties(8),
},
id="some-keys.kasp",
),
pytest.param(
{
"zone": "unlimited.kasp",
"policy": "unlimited",
"config": kasp_config,
"key-properties": [
f"csk 0 {os.environ['DEFAULT_ALGORITHM_NUMBER']} {os.environ['DEFAULT_BITS']} goal:omnipresent dnskey:rumoured krrsig:rumoured zrrsig:rumoured ds:hidden",
],
},
id="unlimited.kasp",
),
pytest.param(
{
"zone": "ed25519.kasp",
"policy": "ed25519",
"config": kasp_config,
"key-properties": fips_properties(15, bits=256),
},
id="ed25519.kasp",
marks=isctest.mark.with_algorithm("ED25519"),
),
pytest.param(
{
"zone": "ed448.kasp",
"policy": "ed448",
"config": kasp_config,
"key-properties": fips_properties(16, bits=456),
},
id="ed448.kasp",
marks=isctest.mark.with_algorithm("ED448"),
),
],
)
def test_kasp_case(servers, params):
# Test many different configurations and expected keys and states after
# initial startup.
server = servers["ns3"]
keydir = server.identifier
# Get test parameters.
zone = params["zone"]
policy = params["policy"]
params["config"]["key-directory"] = params["config"]["key-directory"].replace(
"{keydir}", keydir
)
if "key-directories" in params:
for i, val in enumerate(params["key-directories"]):
params["key-directories"][i] = val.replace("{keydir}", keydir)
ttl = int(params["config"]["dnskey-ttl"].total_seconds())
pregenerated = False
if params.get("pregenerated"):
pregenerated = params["pregenerated"]
zsk_missing = zone == "zsk-missing.autosign"
# Test case.
isctest.log.info(f"check test case zone {zone} policy {policy}")
# First make sure the zone is signed.
isctest.kasp.check_zone_is_signed(server, zone)
# Key properties.
expected = isctest.kasp.policy_to_properties(ttl=ttl, keys=params["key-properties"])
# Key files.
if "key-directories" in params:
kdir = params["key-directories"][0]
ksks = isctest.kasp.keydir_to_keylist(zone, kdir, in_use=pregenerated)
kdir = params["key-directories"][1]
zsks = isctest.kasp.keydir_to_keylist(zone, kdir, in_use=pregenerated)
keys = ksks + zsks
else:
keys = isctest.kasp.keydir_to_keylist(
zone, params["config"]["key-directory"], in_use=pregenerated
)
ksks = [k for k in keys if k.is_ksk()]
zsks = [k for k in keys if not k.is_ksk()]
isctest.kasp.check_keys(zone, keys, expected)
offset = params["offset"] if "offset" in params else None
for kp in expected:
kp.set_expected_keytimes(
params["config"], offset=offset, pregenerated=pregenerated
)
if "rumoured" not in params:
isctest.kasp.check_keytimes(keys, expected)
check_all(server, zone, policy, ksks, zsks, zsk_missing=zsk_missing)
if "additional-tests" in params:
params["servers"] = servers
for additional_test in params["additional-tests"]:
callback = additional_test["callback"]
arguments = additional_test["arguments"]
callback(*arguments, params=params, ksks=ksks, zsks=zsks)
def test_kasp_default(servers): def test_kasp_default(servers):
server = servers["ns3"] server = servers["ns3"]
@@ -404,11 +986,6 @@ def test_kasp_dnssec_keygen():
return isctest.run.cmd(keygen_command, log_stdout=True).stdout.decode("utf-8") return isctest.run.cmd(keygen_command, log_stdout=True).stdout.decode("utf-8")
# check that 'dnssec-keygen -k' (configured policy) creates valid files. # check that 'dnssec-keygen -k' (configured policy) creates valid files.
lifetime = {
"P1Y": int(timedelta(days=365).total_seconds()),
"P30D": int(timedelta(days=30).total_seconds()),
"P6M": int(timedelta(days=31 * 6).total_seconds()),
}
keyprops = [ keyprops = [
f"csk {lifetime['P1Y']} 13 256", f"csk {lifetime['P1Y']} 13 256",
f"ksk {lifetime['P1Y']} 8 2048", f"ksk {lifetime['P1Y']} 8 2048",

View File

@@ -673,9 +673,9 @@ def test_ksr_common(servers):
# - check keys # - check keys
check_keys(overlapping_zsks, lifetime, with_state=True) check_keys(overlapping_zsks, lifetime, with_state=True)
# - check apex # - check apex
isctest.kasp.check_apex(ns1, zone, ksks, overlapping_zsks) isctest.kasp.check_apex(ns1, zone, ksks, overlapping_zsks, offline_ksk=True)
# - check subdomain # - check subdomain
isctest.kasp.check_subdomain(ns1, zone, ksks, overlapping_zsks) isctest.kasp.check_subdomain(ns1, zone, ksks, overlapping_zsks, offline_ksk=True)
def test_ksr_lastbundle(servers): def test_ksr_lastbundle(servers):
@@ -748,9 +748,9 @@ def test_ksr_lastbundle(servers):
# - check keys # - check keys
check_keys(zsks, lifetime, offset=offset, with_state=True) check_keys(zsks, lifetime, offset=offset, with_state=True)
# - check apex # - check apex
isctest.kasp.check_apex(ns1, zone, ksks, zsks) isctest.kasp.check_apex(ns1, zone, ksks, zsks, offline_ksk=True)
# - check subdomain # - check subdomain
isctest.kasp.check_subdomain(ns1, zone, ksks, zsks) isctest.kasp.check_subdomain(ns1, zone, ksks, zsks, offline_ksk=True)
# check that last bundle warning is logged # check that last bundle warning is logged
warning = "last bundle in skr, please import new skr file" warning = "last bundle in skr, please import new skr file"
@@ -828,9 +828,9 @@ def test_ksr_inthemiddle(servers):
# - check keys # - check keys
check_keys(zsks, lifetime, offset=offset, with_state=True) check_keys(zsks, lifetime, offset=offset, with_state=True)
# - check apex # - check apex
isctest.kasp.check_apex(ns1, zone, ksks, zsks) isctest.kasp.check_apex(ns1, zone, ksks, zsks, offline_ksk=True)
# - check subdomain # - check subdomain
isctest.kasp.check_subdomain(ns1, zone, ksks, zsks) isctest.kasp.check_subdomain(ns1, zone, ksks, zsks, offline_ksk=True)
# check that no last bundle warning is logged # check that no last bundle warning is logged
warning = "last bundle in skr, please import new skr file" warning = "last bundle in skr, please import new skr file"
@@ -1023,9 +1023,9 @@ def test_ksr_unlimited(servers):
# - check keys # - check keys
check_keys(zsks, lifetime, with_state=True) check_keys(zsks, lifetime, with_state=True)
# - check apex # - check apex
isctest.kasp.check_apex(ns1, zone, ksks, zsks) isctest.kasp.check_apex(ns1, zone, ksks, zsks, offline_ksk=True)
# - check subdomain # - check subdomain
isctest.kasp.check_subdomain(ns1, zone, ksks, zsks) isctest.kasp.check_subdomain(ns1, zone, ksks, zsks, offline_ksk=True)
def test_ksr_twotone(servers): def test_ksr_twotone(servers):
@@ -1141,9 +1141,9 @@ def test_ksr_twotone(servers):
lifetime = timedelta(days=31 * 5) lifetime = timedelta(days=31 * 5)
check_keys(zsks_altalg, lifetime, alg, size, with_state=True) check_keys(zsks_altalg, lifetime, alg, size, with_state=True)
# - check apex # - check apex
isctest.kasp.check_apex(ns1, zone, ksks, zsks) isctest.kasp.check_apex(ns1, zone, ksks, zsks, offline_ksk=True)
# - check subdomain # - check subdomain
isctest.kasp.check_subdomain(ns1, zone, ksks, zsks) isctest.kasp.check_subdomain(ns1, zone, ksks, zsks, offline_ksk=True)
def test_ksr_kskroll(servers): def test_ksr_kskroll(servers):
@@ -1215,6 +1215,6 @@ def test_ksr_kskroll(servers):
# - check keys # - check keys
check_keys(zsks, None, with_state=True) check_keys(zsks, None, with_state=True)
# - check apex # - check apex
isctest.kasp.check_apex(ns1, zone, ksks, zsks) isctest.kasp.check_apex(ns1, zone, ksks, zsks, offline_ksk=True)
# - check subdomain # - check subdomain
isctest.kasp.check_subdomain(ns1, zone, ksks, zsks) isctest.kasp.check_subdomain(ns1, zone, ksks, zsks, offline_ksk=True)