mirror of
https://github.com/isc-projects/bind9.git
synced 2026-06-09 02:32:03 -04:00
Merge branch '1706-dnssec-policy-migration' into 'master'
Resolve "Changing from auto-dnssec maintain to dnssec-policy x immediately deletes existing keys" Closes #1706 See merge request isc-projects/bind9!3322
This commit is contained in:
commit
157eb5cd30
8 changed files with 699 additions and 117 deletions
3
CHANGES
3
CHANGES
|
|
@ -1,3 +1,6 @@
|
|||
5372. [bug] Fix migration from existing DNSSEC key files using
|
||||
auto-dnssec maintain to dnssec-policy. [GL #1706]
|
||||
|
||||
5371. [bug] Improve incremental updates of the RPZ summary
|
||||
database to reduce delays that could occur when
|
||||
a policy zone update included a large number of
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@ options {
|
|||
listen-on-v6 { none; };
|
||||
allow-transfer { any; };
|
||||
recursion no;
|
||||
key-directory ".";
|
||||
};
|
||||
|
||||
key rndc_key {
|
||||
|
|
@ -35,6 +36,35 @@ controls {
|
|||
inet 10.53.0.6 port @CONTROLPORT@ allow { any; } keys { rndc_key; };
|
||||
};
|
||||
|
||||
/* These are zones that migrate to dnssec-policy. */
|
||||
zone "migrate.kasp" {
|
||||
type master;
|
||||
file "migrate.kasp.db";
|
||||
auto-dnssec maintain;
|
||||
allow-update { any; };
|
||||
dnssec-dnskey-kskonly yes;
|
||||
update-check-ksk yes;
|
||||
};
|
||||
|
||||
zone "migrate-nomatch-algnum.kasp" {
|
||||
type master;
|
||||
file "migrate-nomatch-algnum.kasp.db";
|
||||
auto-dnssec maintain;
|
||||
allow-update { any; };
|
||||
dnssec-dnskey-kskonly yes;
|
||||
update-check-ksk yes;
|
||||
};
|
||||
|
||||
zone "migrate-nomatch-alglen.kasp" {
|
||||
type master;
|
||||
file "migrate-nomatch-alglen.kasp.db";
|
||||
auto-dnssec maintain;
|
||||
allow-update { any; };
|
||||
dnssec-dnskey-kskonly yes;
|
||||
update-check-ksk yes;
|
||||
};
|
||||
|
||||
/* These are alorithm rollover test zones. */
|
||||
zone "step1.algorithm-roll.kasp" {
|
||||
type master;
|
||||
file "step1.algorithm-roll.kasp.db";
|
||||
|
|
|
|||
|
|
@ -35,6 +35,31 @@ controls {
|
|||
inet 10.53.0.6 port @CONTROLPORT@ allow { any; } keys { rndc_key; };
|
||||
};
|
||||
|
||||
/* These are zones that migrate to dnssec-policy. */
|
||||
zone "migrate.kasp" {
|
||||
type master;
|
||||
file "migrate.kasp.db";
|
||||
allow-update { any; };
|
||||
dnssec-policy "migrate";
|
||||
};
|
||||
|
||||
zone "migrate-nomatch-algnum.kasp" {
|
||||
type master;
|
||||
file "migrate-nomatch-algnum.kasp.db";
|
||||
allow-update { any; };
|
||||
dnssec-policy "migrate-nomatch-algnum";
|
||||
};
|
||||
|
||||
zone "migrate-nomatch-alglen.kasp" {
|
||||
type master;
|
||||
file "migrate-nomatch-alglen.kasp.db";
|
||||
allow-update { any; };
|
||||
dnssec-policy "migrate-nomatch-alglen";
|
||||
};
|
||||
|
||||
/*
|
||||
* Zones for testing KSK/ZSK algorithm roll.
|
||||
*/
|
||||
zone "step1.algorithm-roll.kasp" {
|
||||
type master;
|
||||
file "step1.algorithm-roll.kasp.db";
|
||||
|
|
|
|||
|
|
@ -48,3 +48,56 @@ dnssec-policy "ecdsa256" {
|
|||
parent-propagation-delay pt1h;
|
||||
parent-ds-ttl 7200;
|
||||
};
|
||||
|
||||
dnssec-policy "migrate" {
|
||||
dnskey-ttl 300;
|
||||
|
||||
keys {
|
||||
ksk key-directory lifetime unlimited algorithm ECDSAP256SHA256;
|
||||
zsk key-directory lifetime P60D algorithm ECDSAP256SHA256;
|
||||
};
|
||||
};
|
||||
|
||||
/*
|
||||
* This policy tests migration from existing keys with 1024 bits RSASHA1 keys
|
||||
* to ECDSAP256SHA256 keys.
|
||||
*/
|
||||
dnssec-policy "migrate-nomatch-algnum" {
|
||||
dnskey-ttl 300;
|
||||
|
||||
keys {
|
||||
ksk key-directory lifetime unlimited algorithm ecdsa256;
|
||||
zsk key-directory lifetime P60D algorithm ecdsa256;
|
||||
};
|
||||
|
||||
// Together 12h
|
||||
zone-propagation-delay 3600;
|
||||
max-zone-ttl 11h;
|
||||
|
||||
// Together 24h
|
||||
parent-registration-delay 21h;
|
||||
parent-propagation-delay pt1h;
|
||||
parent-ds-ttl 7200;
|
||||
};
|
||||
|
||||
/*
|
||||
* This policy tests migration from existing keys with 1024 bits RSASHA1 keys
|
||||
* to 2048 bits RSASHA1 keys.
|
||||
*/
|
||||
dnssec-policy "migrate-nomatch-alglen" {
|
||||
dnskey-ttl 300;
|
||||
|
||||
keys {
|
||||
ksk key-directory lifetime unlimited algorithm rsasha1 2048;
|
||||
zsk key-directory lifetime P60D algorithm rsasha1 2048;
|
||||
};
|
||||
|
||||
// Together 12h
|
||||
zone-propagation-delay 3600;
|
||||
max-zone-ttl 11h;
|
||||
|
||||
// Together 24h
|
||||
parent-registration-delay 21h;
|
||||
parent-propagation-delay pt1h;
|
||||
parent-ds-ttl 7200;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -39,6 +39,54 @@ R="RUMOURED"
|
|||
O="OMNIPRESENT"
|
||||
U="UNRETENTIVE"
|
||||
|
||||
# Set up a zone with auto-dnssec maintain to migrate to dnssec-policy.
|
||||
setup migrate.kasp
|
||||
echo "$zone" >> zones
|
||||
KSK=$($KEYGEN -a ECDSAP256SHA256 -f KSK -L 300 $zone 2> keygen.out.$zone.1)
|
||||
ZSK=$($KEYGEN -a ECDSAP256SHA256 -L 300 $zone 2> keygen.out.$zone.2)
|
||||
$SETTIME -P now -P sync now -A now "$KSK" > settime.out.$zone.1 2>&1
|
||||
$SETTIME -P now -A now "$ZSK" > settime.out.$zone.2 2>&1
|
||||
cat template.db.in "${KSK}.key" "${ZSK}.key" > "$infile"
|
||||
private_type_record $zone 5 "$KSK" >> "$infile"
|
||||
private_type_record $zone 5 "$ZSK" >> "$infile"
|
||||
$SIGNER -S -x -s now-1h -e now+2w -o $zone -O full -f $zonefile $infile > signer.out.$zone.1 2>&1
|
||||
|
||||
# Set up a zone with auto-dnssec maintain to migrate to dnssec-policy, but this
|
||||
# time the existing keys do not match the policy. The existing keys are
|
||||
# RSASHA1 keys, and will be migrated to a dnssec-policy that dictates
|
||||
# ECDSAP256SHA256 keys.
|
||||
setup migrate-nomatch-algnum.kasp
|
||||
echo "$zone" >> zones
|
||||
KSK=$($KEYGEN -a RSASHA1 -b 2048 -f KSK -L 300 $zone 2> keygen.out.$zone.1)
|
||||
ZSK=$($KEYGEN -a RSASHA1 -b 1024 -L 300 $zone 2> keygen.out.$zone.2)
|
||||
Tds="now-24h" # Time according to dnssec-policy that DS will be OMNIPRESENT
|
||||
Tkey="now-3900s" # DNSKEY TTL + propagation delay
|
||||
Tsig="now-12h" # Zone's maximum TTL + propagation delay
|
||||
$SETTIME -P $Tkey -P sync $Tds -A $Tkey "$KSK" > settime.out.$zone.1 2>&1
|
||||
$SETTIME -P $Tsig -A $Tsig "$ZSK" > settime.out.$zone.2 2>&1
|
||||
cat template.db.in "${KSK}.key" "${ZSK}.key" > "$infile"
|
||||
private_type_record $zone 5 "$KSK" >> "$infile"
|
||||
private_type_record $zone 5 "$ZSK" >> "$infile"
|
||||
$SIGNER -S -x -s now-1h -e now+2w -o $zone -O full -f $zonefile $infile > signer.out.$zone.1 2>&1
|
||||
|
||||
# Set up a zone with auto-dnssec maintain to migrate to dnssec-policy, but this
|
||||
# time the existing keys do not match the policy. The existing keys are
|
||||
# 1024 bits RSASHA1 keys, and will be migrated to a dnssec-policy that
|
||||
# dictates 2048 bits RSASHA1 keys.
|
||||
setup migrate-nomatch-alglen.kasp
|
||||
echo "$zone" >> zones
|
||||
KSK=$($KEYGEN -a RSASHA1 -b 1024 -f KSK -L 300 $zone 2> keygen.out.$zone.1)
|
||||
ZSK=$($KEYGEN -a RSASHA1 -b 1024 -L 300 $zone 2> keygen.out.$zone.2)
|
||||
Tds="now-24h" # Time according to dnssec-policy that DS will be OMNIPRESENT
|
||||
Tkey="now-3900s" # DNSKEY TTL + propagation delay
|
||||
Tsig="now-12h" # Zone's maximum TTL + propagation delay
|
||||
$SETTIME -P $Tkey -P sync $Tds -A $Tkey "$KSK" > settime.out.$zone.1 2>&1
|
||||
$SETTIME -P $Tsig -A $Tsig "$ZSK" > settime.out.$zone.2 2>&1
|
||||
cat template.db.in "${KSK}.key" "${ZSK}.key" > "$infile"
|
||||
private_type_record $zone 5 "$KSK" >> "$infile"
|
||||
private_type_record $zone 5 "$ZSK" >> "$infile"
|
||||
$SIGNER -S -x -s now-1h -e now+2w -o $zone -O full -f $zonefile $infile > signer.out.$zone.1 2>&1
|
||||
|
||||
#
|
||||
# The zones at algorithm-roll.kasp represent the various steps of a ZSK/KSK
|
||||
# algorithm rollover.
|
||||
|
|
@ -47,6 +95,7 @@ U="UNRETENTIVE"
|
|||
# Step 1:
|
||||
# Introduce the first key. This will immediately be active.
|
||||
setup step1.algorithm-roll.kasp
|
||||
echo "$zone" >> zones
|
||||
KSK=$($KEYGEN -a RSASHA1 -f KSK -L 3600 $zone 2> keygen.out.$zone.1)
|
||||
ZSK=$($KEYGEN -a RSASHA1 -L 3600 $zone 2> keygen.out.$zone.2)
|
||||
TactN="now"
|
||||
|
|
|
|||
|
|
@ -55,6 +55,7 @@ VIEW2="4xILSZQnuO1UKubXHkYUsvBRPu8="
|
|||
# STATE_DS=18
|
||||
# EXPECT_ZRRSIG=19
|
||||
# EXPECT_KRRSIG=20
|
||||
# LEGACY=21
|
||||
|
||||
key_key() {
|
||||
echo "${1}__${2}"
|
||||
|
|
@ -77,7 +78,7 @@ key_clear() {
|
|||
key_set "$1" "ROLE" 'none'
|
||||
key_set "$1" "KSK" 'no'
|
||||
key_set "$1" "ZSK" 'no'
|
||||
key_set "$1" "LIFETIME" '0'
|
||||
key_set "$1" "LIFETIME" 'none'
|
||||
key_set "$1" "ALG_NUM" '0'
|
||||
key_set "$1" "ALG_STR" 'none'
|
||||
key_set "$1" "ALG_LEN" '0'
|
||||
|
|
@ -93,6 +94,7 @@ key_clear() {
|
|||
key_set "$1" "STATE_DS" 'none'
|
||||
key_set "$1" "EXPECT_ZRRSIG" 'no'
|
||||
key_set "$1" "EXPECT_KRRSIG" 'no'
|
||||
key_set "$1" "LEGACY" 'no'
|
||||
}
|
||||
|
||||
# Start clear.
|
||||
|
|
@ -238,6 +240,7 @@ check_key() {
|
|||
_length=$(key_get "$1" "ALG_LEN")
|
||||
_dnskey_ttl="$DNSKEY_TTL"
|
||||
_lifetime=$(key_get "$1" LIFETIME)
|
||||
_legacy=$(key_get "$1" LEGACY)
|
||||
|
||||
_published=$(key_get "$1" PUBLISHED)
|
||||
_active=$(key_get "$1" ACTIVE)
|
||||
|
|
@ -277,10 +280,13 @@ check_key() {
|
|||
# Check file existence.
|
||||
[ -s "$KEY_FILE" ] || ret=1
|
||||
[ -s "$PRIVATE_FILE" ] || ret=1
|
||||
[ -s "$STATE_FILE" ] || ret=1
|
||||
if [ "$_legacy" == "no" ]; then
|
||||
[ -s "$STATE_FILE" ] || ret=1
|
||||
fi
|
||||
[ "$ret" -eq 0 ] || log_error "${BASE_FILE} files missing"
|
||||
[ "$ret" -eq 0 ] || return
|
||||
|
||||
test $_log -eq 1 && echo_i "check key $BASE_FILE"
|
||||
test $_log -eq 1 && echo_i "check key file $BASE_FILE"
|
||||
|
||||
# Check the public key file.
|
||||
grep "This is a ${_role2} key, keyid ${_key_id}, for ${_zone}." "$KEY_FILE" > /dev/null || log_error "mismatch top comment in $KEY_FILE"
|
||||
|
|
@ -289,106 +295,134 @@ check_key() {
|
|||
grep "Private-key-format: v1.3" "$PRIVATE_FILE" > /dev/null || log_error "mismatch private key format in $PRIVATE_FILE"
|
||||
grep "Algorithm: ${_alg_num} (${_alg_string})" "$PRIVATE_FILE" > /dev/null || log_error "mismatch algorithm in $PRIVATE_FILE"
|
||||
# Now check the key state file.
|
||||
grep "This is the state of key ${_key_id}, for ${_zone}." "$STATE_FILE" > /dev/null || log_error "mismatch top comment in $STATE_FILE"
|
||||
grep "Lifetime: ${_lifetime}" "$STATE_FILE" > /dev/null || log_error "mismatch lifetime in $STATE_FILE"
|
||||
grep "Algorithm: ${_alg_num}" "$STATE_FILE" > /dev/null || log_error "mismatch algorithm in $STATE_FILE"
|
||||
grep "Length: ${_length}" "$STATE_FILE" > /dev/null || log_error "mismatch length in $STATE_FILE"
|
||||
grep "KSK: ${_ksk}" "$STATE_FILE" > /dev/null || log_error "mismatch ksk in $STATE_FILE"
|
||||
grep "ZSK: ${_zsk}" "$STATE_FILE" > /dev/null || log_error "mismatch zsk in $STATE_FILE"
|
||||
if [ "$_legacy" == "no" ]; then
|
||||
grep "This is the state of key ${_key_id}, for ${_zone}." "$STATE_FILE" > /dev/null || log_error "mismatch top comment in $STATE_FILE"
|
||||
if [ "$_lifetime" == "none" ]; then
|
||||
grep "Lifetime: " "$STATE_FILE" > /dev/null && log_error "unexpected lifetime in $STATE_FILE"
|
||||
else
|
||||
grep "Lifetime: ${_lifetime}" "$STATE_FILE" > /dev/null || log_error "mismatch lifetime in $STATE_FILE"
|
||||
fi
|
||||
grep "Algorithm: ${_alg_num}" "$STATE_FILE" > /dev/null || log_error "mismatch algorithm in $STATE_FILE"
|
||||
grep "Length: ${_length}" "$STATE_FILE" > /dev/null || log_error "mismatch length in $STATE_FILE"
|
||||
grep "KSK: ${_ksk}" "$STATE_FILE" > /dev/null || log_error "mismatch ksk in $STATE_FILE"
|
||||
grep "ZSK: ${_zsk}" "$STATE_FILE" > /dev/null || log_error "mismatch zsk in $STATE_FILE"
|
||||
|
||||
# Check key states.
|
||||
if [ "$_goal" = "none" ]; then
|
||||
grep "GoalState: " "$STATE_FILE" > /dev/null && log_error "unexpected goal state in $STATE_FILE"
|
||||
else
|
||||
grep "GoalState: ${_goal}" "$STATE_FILE" > /dev/null || log_error "mismatch goal state in $STATE_FILE"
|
||||
fi
|
||||
# Check key states.
|
||||
if [ "$_goal" = "none" ]; then
|
||||
grep "GoalState: " "$STATE_FILE" > /dev/null && log_error "unexpected goal state in $STATE_FILE"
|
||||
else
|
||||
grep "GoalState: ${_goal}" "$STATE_FILE" > /dev/null || log_error "mismatch goal state in $STATE_FILE"
|
||||
fi
|
||||
|
||||
if [ "$_state_dnskey" = "none" ]; then
|
||||
grep "DNSKEYState: " "$STATE_FILE" > /dev/null && log_error "unexpected dnskey state in $STATE_FILE"
|
||||
grep "DNSKEYChange: " "$STATE_FILE" > /dev/null && log_error "unexpected dnskey change in $STATE_FILE"
|
||||
else
|
||||
grep "DNSKEYState: ${_state_dnskey}" "$STATE_FILE" > /dev/null || log_error "mismatch dnskey state in $STATE_FILE"
|
||||
grep "DNSKEYChange: " "$STATE_FILE" > /dev/null || log_error "mismatch dnskey change in $STATE_FILE"
|
||||
fi
|
||||
if [ "$_state_dnskey" = "none" ]; then
|
||||
grep "DNSKEYState: " "$STATE_FILE" > /dev/null && log_error "unexpected dnskey state in $STATE_FILE"
|
||||
grep "DNSKEYChange: " "$STATE_FILE" > /dev/null && log_error "unexpected dnskey change in $STATE_FILE"
|
||||
else
|
||||
grep "DNSKEYState: ${_state_dnskey}" "$STATE_FILE" > /dev/null || log_error "mismatch dnskey state in $STATE_FILE"
|
||||
grep "DNSKEYChange: " "$STATE_FILE" > /dev/null || log_error "mismatch dnskey change in $STATE_FILE"
|
||||
fi
|
||||
|
||||
if [ "$_state_zrrsig" = "none" ]; then
|
||||
grep "ZRRSIGState: " "$STATE_FILE" > /dev/null && log_error "unexpected zrrsig state in $STATE_FILE"
|
||||
grep "ZRRSIGChange: " "$STATE_FILE" > /dev/null && log_error "unexpected zrrsig change in $STATE_FILE"
|
||||
else
|
||||
grep "ZRRSIGState: ${_state_zrrsig}" "$STATE_FILE" > /dev/null || log_error "mismatch zrrsig state in $STATE_FILE"
|
||||
grep "ZRRSIGChange: " "$STATE_FILE" > /dev/null || log_error "mismatch zrrsig change in $STATE_FILE"
|
||||
fi
|
||||
if [ "$_state_zrrsig" = "none" ]; then
|
||||
grep "ZRRSIGState: " "$STATE_FILE" > /dev/null && log_error "unexpected zrrsig state in $STATE_FILE"
|
||||
grep "ZRRSIGChange: " "$STATE_FILE" > /dev/null && log_error "unexpected zrrsig change in $STATE_FILE"
|
||||
else
|
||||
grep "ZRRSIGState: ${_state_zrrsig}" "$STATE_FILE" > /dev/null || log_error "mismatch zrrsig state in $STATE_FILE"
|
||||
grep "ZRRSIGChange: " "$STATE_FILE" > /dev/null || log_error "mismatch zrrsig change in $STATE_FILE"
|
||||
fi
|
||||
|
||||
if [ "$_state_krrsig" = "none" ]; then
|
||||
grep "KRRSIGState: " "$STATE_FILE" > /dev/null && log_error "unexpected krrsig state in $STATE_FILE"
|
||||
grep "KRRSIGChange: " "$STATE_FILE" > /dev/null && log_error "unexpected krrsig change in $STATE_FILE"
|
||||
else
|
||||
grep "KRRSIGState: ${_state_krrsig}" "$STATE_FILE" > /dev/null || log_error "mismatch krrsig state in $STATE_FILE"
|
||||
grep "KRRSIGChange: " "$STATE_FILE" > /dev/null || log_error "mismatch krrsig change in $STATE_FILE"
|
||||
fi
|
||||
if [ "$_state_krrsig" = "none" ]; then
|
||||
grep "KRRSIGState: " "$STATE_FILE" > /dev/null && log_error "unexpected krrsig state in $STATE_FILE"
|
||||
grep "KRRSIGChange: " "$STATE_FILE" > /dev/null && log_error "unexpected krrsig change in $STATE_FILE"
|
||||
else
|
||||
grep "KRRSIGState: ${_state_krrsig}" "$STATE_FILE" > /dev/null || log_error "mismatch krrsig state in $STATE_FILE"
|
||||
grep "KRRSIGChange: " "$STATE_FILE" > /dev/null || log_error "mismatch krrsig change in $STATE_FILE"
|
||||
fi
|
||||
|
||||
if [ "$_state_ds" = "none" ]; then
|
||||
grep "DSState: " "$STATE_FILE" > /dev/null && log_error "unexpected ds state in $STATE_FILE"
|
||||
grep "DSChange: " "$STATE_FILE" > /dev/null && log_error "unexpected ds change in $STATE_FILE"
|
||||
else
|
||||
grep "DSState: ${_state_ds}" "$STATE_FILE" > /dev/null || log_error "mismatch ds state in $STATE_FILE"
|
||||
grep "DSChange: " "$STATE_FILE" > /dev/null || log_error "mismatch ds change in $STATE_FILE"
|
||||
if [ "$_state_ds" = "none" ]; then
|
||||
grep "DSState: " "$STATE_FILE" > /dev/null && log_error "unexpected ds state in $STATE_FILE"
|
||||
grep "DSChange: " "$STATE_FILE" > /dev/null && log_error "unexpected ds change in $STATE_FILE"
|
||||
else
|
||||
grep "DSState: ${_state_ds}" "$STATE_FILE" > /dev/null || log_error "mismatch ds state in $STATE_FILE"
|
||||
grep "DSChange: " "$STATE_FILE" > /dev/null || log_error "mismatch ds change in $STATE_FILE"
|
||||
fi
|
||||
fi
|
||||
|
||||
# Check timing metadata.
|
||||
if [ "$_published" = "none" ]; then
|
||||
grep "; Publish:" "$KEY_FILE" > /dev/null && log_error "unexpected publish comment in $KEY_FILE"
|
||||
grep "Publish:" "$PRIVATE_FILE" > /dev/null && log_error "unexpected publish in $PRIVATE_FILE"
|
||||
grep "Published: " "$STATE_FILE" > /dev/null && log_error "unexpected publish in $STATE_FILE"
|
||||
if [ "$_legacy" == "no" ]; then
|
||||
grep "Published: " "$STATE_FILE" > /dev/null && log_error "unexpected publish in $STATE_FILE"
|
||||
fi
|
||||
else
|
||||
grep "; Publish:" "$KEY_FILE" > /dev/null || log_error "mismatch publish comment in $KEY_FILE ($KEY_PUBLISHED)"
|
||||
grep "Publish:" "$PRIVATE_FILE" > /dev/null || log_error "mismatch publish in $PRIVATE_FILE ($KEY_PUBLISHED)"
|
||||
grep "Published:" "$STATE_FILE" > /dev/null || log_error "mismatch publish in $STATE_FILE ($KEY_PUBLISHED)"
|
||||
grep "; Publish:" "$KEY_FILE" > /dev/null || log_error "mismatch publish comment in $KEY_FILE"
|
||||
grep "Publish:" "$PRIVATE_FILE" > /dev/null || log_error "mismatch publish in $PRIVATE_FILE"
|
||||
if [ "$_legacy" == "no" ]; then
|
||||
grep "Published:" "$STATE_FILE" > /dev/null || log_error "mismatch publish in $STATE_FILE"
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ "$_active" = "none" ]; then
|
||||
grep "; Activate:" "$KEY_FILE" > /dev/null && log_error "unexpected active comment in $KEY_FILE"
|
||||
grep "Activate:" "$PRIVATE_FILE" > /dev/null && log_error "unexpected active in $PRIVATE_FILE"
|
||||
grep "Active: " "$STATE_FILE" > /dev/null && log_error "unexpected active in $STATE_FILE"
|
||||
if [ "$_legacy" == "no" ]; then
|
||||
grep "Active: " "$STATE_FILE" > /dev/null && log_error "unexpected active in $STATE_FILE"
|
||||
fi
|
||||
else
|
||||
grep "; Activate:" "$KEY_FILE" > /dev/null || log_error "mismatch active comment in $KEY_FILE"
|
||||
grep "Activate:" "$PRIVATE_FILE" > /dev/null || log_error "mismatch active in $PRIVATE_FILE"
|
||||
grep "Active: " "$STATE_FILE" > /dev/null || log_error "mismatch active in $STATE_FILE"
|
||||
if [ "$_legacy" == "no" ]; then
|
||||
grep "Active: " "$STATE_FILE" > /dev/null || log_error "mismatch active in $STATE_FILE"
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ "$_retired" = "none" ]; then
|
||||
grep "; Inactive:" "$KEY_FILE" > /dev/null && log_error "unexpected retired comment in $KEY_FILE"
|
||||
grep "Inactive:" "$PRIVATE_FILE" > /dev/null && log_error "unexpected retired in $PRIVATE_FILE"
|
||||
grep "Retired: " "$STATE_FILE" > /dev/null && log_error "unexpected retired in $STATE_FILE"
|
||||
if [ "$_legacy" == "no" ]; then
|
||||
grep "Retired: " "$STATE_FILE" > /dev/null && log_error "unexpected retired in $STATE_FILE"
|
||||
fi
|
||||
else
|
||||
grep "; Inactive:" "$KEY_FILE" > /dev/null || log_error "mismatch retired comment in $KEY_FILE"
|
||||
grep "Inactive:" "$PRIVATE_FILE" > /dev/null || log_error "mismatch retired in $PRIVATE_FILE"
|
||||
grep "Retired: " "$STATE_FILE" > /dev/null || log_error "mismatch retired in $STATE_FILE"
|
||||
if [ "$_legacy" == "no" ]; then
|
||||
grep "Retired: " "$STATE_FILE" > /dev/null || log_error "mismatch retired in $STATE_FILE"
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ "$_revoked" = "none" ]; then
|
||||
grep "; Revoke:" "$KEY_FILE" > /dev/null && log_error "unexpected revoked comment in $KEY_FILE"
|
||||
grep "Revoke:" "$PRIVATE_FILE" > /dev/null && log_error "unexpected revoked in $PRIVATE_FILE"
|
||||
grep "Revoked: " "$STATE_FILE" > /dev/null && log_error "unexpected revoked in $STATE_FILE"
|
||||
if [ "$_legacy" == "no" ]; then
|
||||
grep "Revoked: " "$STATE_FILE" > /dev/null && log_error "unexpected revoked in $STATE_FILE"
|
||||
fi
|
||||
else
|
||||
grep "; Revoke:" "$KEY_FILE" > /dev/null || log_error "mismatch revoked comment in $KEY_FILE"
|
||||
grep "Revoke:" "$PRIVATE_FILE" > /dev/null || log_error "mismatch revoked in $PRIVATE_FILE"
|
||||
grep "Revoked: " "$STATE_FILE" > /dev/null || log_error "mismatch revoked in $STATE_FILE"
|
||||
if [ "$_legacy" == "no" ]; then
|
||||
grep "Revoked: " "$STATE_FILE" > /dev/null || log_error "mismatch revoked in $STATE_FILE"
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ "$_removed" = "none" ]; then
|
||||
grep "; Delete:" "$KEY_FILE" > /dev/null && log_error "unexpected removed comment in $KEY_FILE"
|
||||
grep "Delete:" "$PRIVATE_FILE" > /dev/null && log_error "unexpected removed in $PRIVATE_FILE"
|
||||
grep "Removed: " "$STATE_FILE" > /dev/null && log_error "unexpected removed in $STATE_FILE"
|
||||
if [ "$_legacy" == "no" ]; then
|
||||
grep "Removed: " "$STATE_FILE" > /dev/null && log_error "unexpected removed in $STATE_FILE"
|
||||
fi
|
||||
else
|
||||
grep "; Delete:" "$KEY_FILE" > /dev/null || log_error "mismatch removed comment in $KEY_FILE"
|
||||
grep "Delete:" "$PRIVATE_FILE" > /dev/null || log_error "mismatch removed in $PRIVATE_FILE"
|
||||
grep "Removed: " "$STATE_FILE" > /dev/null || log_error "mismatch removed in $STATE_FILE"
|
||||
if [ "$_legacy" == "no" ]; then
|
||||
grep "Removed: " "$STATE_FILE" > /dev/null || log_error "mismatch removed in $STATE_FILE"
|
||||
fi
|
||||
fi
|
||||
|
||||
grep "; Created:" "$KEY_FILE" > /dev/null || log_error "mismatch created comment in $KEY_FILE"
|
||||
grep "Created:" "$PRIVATE_FILE" > /dev/null || log_error "mismatch created in $PRIVATE_FILE"
|
||||
grep "Generated: " "$STATE_FILE" > /dev/null || log_error "mismatch generated in $STATE_FILE"
|
||||
if [ "$_legacy" == "no" ]; then
|
||||
grep "Generated: " "$STATE_FILE" > /dev/null || log_error "mismatch generated in $STATE_FILE"
|
||||
fi
|
||||
}
|
||||
|
||||
# Check the key with key id $1 and see if it is unused.
|
||||
|
|
@ -424,20 +458,24 @@ key_unused() {
|
|||
|
||||
# Check timing metadata.
|
||||
grep "; Publish:" "$KEY_FILE" > /dev/null && log_error "unexpected publish comment in $KEY_FILE"
|
||||
grep "Publish:" "$PRIVATE_FILE" > /dev/null && log_error "unexpected publish in $PRIVATE_FILE"
|
||||
grep "Published: " "$STATE_FILE" > /dev/null && log_error "unexpected publish in $STATE_FILE"
|
||||
grep "; Activate:" "$KEY_FILE" > /dev/null && log_error "unexpected active comment in $KEY_FILE"
|
||||
grep "Activate:" "$PRIVATE_FILE" > /dev/null && log_error "unexpected active in $PRIVATE_FILE"
|
||||
grep "Active: " "$STATE_FILE" > /dev/null && log_error "unexpected active in $STATE_FILE"
|
||||
grep "; Inactive:" "$KEY_FILE" > /dev/null && log_error "unexpected retired comment in $KEY_FILE"
|
||||
grep "Inactive:" "$PRIVATE_FILE" > /dev/null && log_error "unexpected retired in $PRIVATE_FILE"
|
||||
grep "Retired: " "$STATE_FILE" > /dev/null && log_error "unexpected retired in $STATE_FILE"
|
||||
grep "; Revoke:" "$KEY_FILE" > /dev/null && log_error "unexpected revoked comment in $KEY_FILE"
|
||||
grep "Revoke:" "$PRIVATE_FILE" > /dev/null && log_error "unexpected revoked in $PRIVATE_FILE"
|
||||
grep "Revoked: " "$STATE_FILE" > /dev/null && log_error "unexpected revoked in $STATE_FILE"
|
||||
grep "; Delete:" "$KEY_FILE" > /dev/null && log_error "unexpected removed comment in $KEY_FILE"
|
||||
|
||||
grep "Publish:" "$PRIVATE_FILE" > /dev/null && log_error "unexpected publish in $PRIVATE_FILE"
|
||||
grep "Activate:" "$PRIVATE_FILE" > /dev/null && log_error "unexpected active in $PRIVATE_FILE"
|
||||
grep "Inactive:" "$PRIVATE_FILE" > /dev/null && log_error "unexpected retired in $PRIVATE_FILE"
|
||||
grep "Revoke:" "$PRIVATE_FILE" > /dev/null && log_error "unexpected revoked in $PRIVATE_FILE"
|
||||
grep "Delete:" "$PRIVATE_FILE" > /dev/null && log_error "unexpected removed in $PRIVATE_FILE"
|
||||
grep "Removed: " "$STATE_FILE" > /dev/null && log_error "unexpected removed in $STATE_FILE"
|
||||
|
||||
if [ "$_legacy" == "no" ]; then
|
||||
grep "Published: " "$STATE_FILE" > /dev/null && log_error "unexpected publish in $STATE_FILE"
|
||||
grep "Active: " "$STATE_FILE" > /dev/null && log_error "unexpected active in $STATE_FILE"
|
||||
grep "Retired: " "$STATE_FILE" > /dev/null && log_error "unexpected retired in $STATE_FILE"
|
||||
grep "Revoked: " "$STATE_FILE" > /dev/null && log_error "unexpected revoked in $STATE_FILE"
|
||||
grep "Removed: " "$STATE_FILE" > /dev/null && log_error "unexpected removed in $STATE_FILE"
|
||||
fi
|
||||
}
|
||||
|
||||
# Test: dnssec-verify zone $1.
|
||||
|
|
@ -848,7 +886,7 @@ check_keys()
|
|||
for _id in $_ids; do
|
||||
# There are three key files with the same algorithm.
|
||||
# Check them until a match is found.
|
||||
echo_i "check key $_id"
|
||||
echo_i "check key id $_id"
|
||||
|
||||
if [ "no" = "$(key_get KEY1 ID)" ] && [ "$(key_get KEY1 EXPECT)" = "yes" ]; then
|
||||
ret=0
|
||||
|
|
@ -863,19 +901,19 @@ check_keys()
|
|||
if [ "no" = "$(key_get KEY3 ID)" ] && [ "$(key_get KEY3 EXPECT)" = "yes" ]; then
|
||||
ret=0
|
||||
check_key "KEY3" "$_id"
|
||||
test "$ret" -eq 0 && key_set KEY3 ID "$KEY_ID" && continue
|
||||
test "$ret" -eq 0 && key_set KEY3 "ID" "$KEY_ID" && continue
|
||||
fi
|
||||
if [ "no" = "$(key_get KEY4 ID)" ] && [ "$(key_get KEY4 EXPECT)" = "yes" ]; then
|
||||
ret=0
|
||||
check_key "KEY4" "$_id"
|
||||
test "$ret" -eq 0 && key_set KEY4 ID "$KEY_ID" && continue
|
||||
test "$ret" -eq 0 && key_set KEY4 "ID" "$KEY_ID" && continue
|
||||
fi
|
||||
|
||||
# This may be an unused key. Assume algorithm of KEY1.
|
||||
ret=0 && key_unused "$_id" "$(key_get KEY1 ALG_NUM)"
|
||||
test "$ret" -eq 0 && continue
|
||||
|
||||
# If ret is still non-zero, non of the files matched.
|
||||
# If ret is still non-zero, none of the files matched.
|
||||
test "$ret" -eq 0 || echo_i "failed"
|
||||
status=$((status+1))
|
||||
done
|
||||
|
|
@ -885,15 +923,19 @@ check_keys()
|
|||
|
||||
ret=0
|
||||
if [ "$(key_get KEY1 EXPECT)" = "yes" ]; then
|
||||
echo_i "KEY1 ID $(key_get KEY1 ID)"
|
||||
test "no" = "$(key_get KEY1 ID)" && log_error "No KEY1 found for zone ${ZONE}"
|
||||
fi
|
||||
if [ "$(key_get KEY2 EXPECT)" = "yes" ]; then
|
||||
echo_i "KEY2 ID $(key_get KEY2 ID)"
|
||||
test "no" = "$(key_get KEY2 ID)" && log_error "No KEY2 found for zone ${ZONE}"
|
||||
fi
|
||||
if [ "$(key_get KEY3 EXPECT)" = "yes" ]; then
|
||||
echo_i "KEY3 ID $(key_get KEY3 ID)"
|
||||
test "no" = "$(key_get KEY3 ID)" && log_error "No KEY3 found for zone ${ZONE}"
|
||||
fi
|
||||
if [ "$(key_get KEY4 EXPECT)" = "yes" ]; then
|
||||
echo_i "KEY4 ID $(key_get KEY4 ID)"
|
||||
test "no" = "$(key_get KEY4 ID)" && log_error "No KEY4 found for zone ${ZONE}"
|
||||
fi
|
||||
test "$ret" -eq 0 || echo_i "failed"
|
||||
|
|
@ -2821,7 +2863,166 @@ dnssec_verify
|
|||
# interval.
|
||||
check_next_key_event 3600
|
||||
|
||||
# Reconfig dnssec-policy (triggering algorithm roll).
|
||||
#
|
||||
# Testing good migration.
|
||||
#
|
||||
set_zone "migrate.kasp"
|
||||
set_policy "none" "2" "300"
|
||||
set_server "ns6" "10.53.0.6"
|
||||
|
||||
init_migration_match() {
|
||||
key_clear "KEY1"
|
||||
key_set "KEY1" "LEGACY" "yes"
|
||||
set_keyrole "KEY1" "ksk"
|
||||
set_keylifetime "KEY1" "0"
|
||||
set_keyalgorithm "KEY1" "13" "ECDSAP256SHA256" "256"
|
||||
set_keysigning "KEY1" "yes"
|
||||
set_zonesigning "KEY1" "no"
|
||||
|
||||
key_clear "KEY2"
|
||||
key_set "KEY2" "LEGACY" "yes"
|
||||
set_keyrole "KEY2" "zsk"
|
||||
set_keylifetime "KEY2" "5184000"
|
||||
set_keyalgorithm "KEY2" "13" "ECDSAP256SHA256" "256"
|
||||
set_keysigning "KEY2" "no"
|
||||
set_zonesigning "KEY2" "yes"
|
||||
|
||||
key_clear "KEY3"
|
||||
key_clear "KEY4"
|
||||
|
||||
set_keytime "KEY1" "PUBLISHED" "yes"
|
||||
set_keytime "KEY1" "ACTIVE" "yes"
|
||||
set_keytime "KEY1" "RETIRED" "none"
|
||||
set_keystate "KEY1" "GOAL" "omnipresent"
|
||||
set_keystate "KEY1" "STATE_DNSKEY" "rumoured"
|
||||
set_keystate "KEY1" "STATE_KRRSIG" "rumoured"
|
||||
set_keystate "KEY1" "STATE_DS" "rumoured"
|
||||
|
||||
set_keytime "KEY2" "PUBLISHED" "yes"
|
||||
set_keytime "KEY2" "ACTIVE" "yes"
|
||||
set_keytime "KEY2" "RETIRED" "none"
|
||||
set_keystate "KEY2" "GOAL" "omnipresent"
|
||||
set_keystate "KEY2" "STATE_DNSKEY" "rumoured"
|
||||
set_keystate "KEY2" "STATE_ZRRSIG" "rumoured"
|
||||
}
|
||||
init_migration_match
|
||||
|
||||
# Make sure the zone is signed with legacy keys.
|
||||
check_keys
|
||||
check_apex
|
||||
check_subdomain
|
||||
dnssec_verify
|
||||
|
||||
# Remember legacy key tags.
|
||||
_migrate_ksk=$(key_get KEY1 ID)
|
||||
_migrate_zsk=$(key_get KEY2 ID)
|
||||
|
||||
#
|
||||
# Testing migration with unmatched existing keys (different algorithm).
|
||||
#
|
||||
set_zone "migrate-nomatch-algnum.kasp"
|
||||
set_policy "none" "2" "300"
|
||||
set_server "ns6" "10.53.0.6"
|
||||
|
||||
init_migration_nomatch_algnum() {
|
||||
key_clear "KEY1"
|
||||
key_set "KEY1" "LEGACY" "yes"
|
||||
set_keyrole "KEY1" "ksk"
|
||||
set_keyalgorithm "KEY1" "5" "RSASHA1" "2048"
|
||||
set_keysigning "KEY1" "yes"
|
||||
set_zonesigning "KEY1" "no"
|
||||
|
||||
key_clear "KEY2"
|
||||
key_set "KEY2" "LEGACY" "yes"
|
||||
set_keyrole "KEY2" "zsk"
|
||||
set_keyalgorithm "KEY2" "5" "RSASHA1" "1024"
|
||||
set_keysigning "KEY2" "no"
|
||||
set_zonesigning "KEY2" "yes"
|
||||
|
||||
key_clear "KEY3"
|
||||
key_clear "KEY4"
|
||||
|
||||
set_keytime "KEY1" "PUBLISHED" "yes"
|
||||
set_keytime "KEY1" "ACTIVE" "yes"
|
||||
set_keytime "KEY1" "RETIRED" "none"
|
||||
set_keystate "KEY1" "GOAL" "omnipresent"
|
||||
set_keystate "KEY1" "STATE_DNSKEY" "omnipresent"
|
||||
set_keystate "KEY1" "STATE_KRRSIG" "omnipresent"
|
||||
set_keystate "KEY1" "STATE_DS" "omnipresent"
|
||||
|
||||
set_keytime "KEY2" "PUBLISHED" "yes"
|
||||
set_keytime "KEY2" "ACTIVE" "yes"
|
||||
set_keytime "KEY2" "RETIRED" "none"
|
||||
set_keystate "KEY2" "GOAL" "omnipresent"
|
||||
set_keystate "KEY2" "STATE_DNSKEY" "omnipresent"
|
||||
set_keystate "KEY2" "STATE_ZRRSIG" "omnipresent"
|
||||
}
|
||||
init_migration_nomatch_algnum
|
||||
|
||||
# Make sure the zone is signed with legacy keys.
|
||||
check_keys
|
||||
check_apex
|
||||
check_subdomain
|
||||
dnssec_verify
|
||||
|
||||
# Remember legacy key tags.
|
||||
_migratenomatch_algnum_ksk=$(key_get KEY1 ID)
|
||||
_migratenomatch_algnum_zsk=$(key_get KEY2 ID)
|
||||
|
||||
#
|
||||
# Testing migration with unmatched existing keys (different length).
|
||||
#
|
||||
set_zone "migrate-nomatch-alglen.kasp"
|
||||
set_policy "none" "2" "300"
|
||||
set_server "ns6" "10.53.0.6"
|
||||
|
||||
init_migration_nomatch_alglen() {
|
||||
key_clear "KEY1"
|
||||
key_set "KEY1" "LEGACY" "yes"
|
||||
set_keyrole "KEY1" "ksk"
|
||||
set_keyalgorithm "KEY1" "5" "RSASHA1" "1024"
|
||||
set_keysigning "KEY1" "yes"
|
||||
set_zonesigning "KEY1" "no"
|
||||
|
||||
key_clear "KEY2"
|
||||
key_set "KEY2" "LEGACY" "yes"
|
||||
set_keyrole "KEY2" "zsk"
|
||||
set_keyalgorithm "KEY2" "5" "RSASHA1" "1024"
|
||||
set_keysigning "KEY2" "no"
|
||||
set_zonesigning "KEY2" "yes"
|
||||
|
||||
key_clear "KEY3"
|
||||
key_clear "KEY4"
|
||||
|
||||
set_keytime "KEY1" "PUBLISHED" "yes"
|
||||
set_keytime "KEY1" "ACTIVE" "yes"
|
||||
set_keytime "KEY1" "RETIRED" "none"
|
||||
set_keystate "KEY1" "GOAL" "omnipresent"
|
||||
set_keystate "KEY1" "STATE_DNSKEY" "omnipresent"
|
||||
set_keystate "KEY1" "STATE_KRRSIG" "omnipresent"
|
||||
set_keystate "KEY1" "STATE_DS" "omnipresent"
|
||||
|
||||
set_keytime "KEY2" "PUBLISHED" "yes"
|
||||
set_keytime "KEY2" "ACTIVE" "yes"
|
||||
set_keytime "KEY2" "RETIRED" "none"
|
||||
set_keystate "KEY2" "GOAL" "omnipresent"
|
||||
set_keystate "KEY2" "STATE_DNSKEY" "omnipresent"
|
||||
set_keystate "KEY2" "STATE_ZRRSIG" "omnipresent"
|
||||
}
|
||||
init_migration_nomatch_alglen
|
||||
|
||||
# Make sure the zone is signed with legacy keys.
|
||||
check_keys
|
||||
check_apex
|
||||
check_subdomain
|
||||
dnssec_verify
|
||||
|
||||
# Remember legacy key tags.
|
||||
_migratenomatch_alglen_ksk=$(key_get KEY1 ID)
|
||||
_migratenomatch_alglen_zsk=$(key_get KEY2 ID)
|
||||
|
||||
# Reconfig dnssec-policy (triggering algorithm roll and other dnssec-policy
|
||||
# changes).
|
||||
echo_i "reconfig dnssec-policy to trigger algorithm rollover"
|
||||
copy_setports ns6/named2.conf.in ns6/named.conf
|
||||
rndc_reconfig ns6 10.53.0.6
|
||||
|
|
@ -2854,6 +3055,150 @@ status=$((status+ret))
|
|||
|
||||
next_key_event_threshold=$((next_key_event_threshold+i))
|
||||
|
||||
#
|
||||
# Testing migration.
|
||||
#
|
||||
set_zone "migrate.kasp"
|
||||
set_policy "migrate" "2" "300"
|
||||
set_server "ns6" "10.53.0.6"
|
||||
|
||||
# Key properties, timings and metadata should be the same as legacy keys above.
|
||||
# However, because the zsk has a lifetime, kasp will set the retired time.
|
||||
init_migration_match
|
||||
|
||||
key_set "KEY1" "LEGACY" "no"
|
||||
|
||||
key_set "KEY2" "LEGACY" "no"
|
||||
set_keytime "KEY2" "RETIRED" "yes"
|
||||
|
||||
check_keys
|
||||
check_apex
|
||||
check_subdomain
|
||||
dnssec_verify
|
||||
|
||||
# Check key tags, should be the same.
|
||||
n=$((n+1))
|
||||
echo_i "check that of zone ${ZONE} migration to dnssec-policy uses the same keys ($n)"
|
||||
ret=0
|
||||
[ $_migrate_ksk == $(key_get KEY1 ID) ] || log_error "mismatch ksk tag"
|
||||
[ $_migrate_zsk == $(key_get KEY2 ID) ] || log_error "mismatch zsk tag"
|
||||
status=$((status+ret))
|
||||
|
||||
# Test migration to dnssec-policy, existing keys do not match key algorithm.
|
||||
set_zone "migrate-nomatch-algnum.kasp"
|
||||
set_policy "migrate-nomatch-algnum" "4" "300"
|
||||
set_server "ns6" "10.53.0.6"
|
||||
|
||||
# The legacy keys need to be retired, but otherwise stay present until the
|
||||
# new keys are omnipresent, and can be used to construct a chain of trust.
|
||||
init_migration_nomatch_algnum
|
||||
|
||||
key_set "KEY1" "LEGACY" "no"
|
||||
set_keytime "KEY1" "RETIRED" "yes"
|
||||
set_keystate "KEY1" "GOAL" "hidden"
|
||||
|
||||
key_set "KEY2" "LEGACY" "no"
|
||||
set_keytime "KEY2" "RETIRED" "yes"
|
||||
set_keystate "KEY2" "GOAL" "hidden"
|
||||
|
||||
set_keyrole "KEY3" "ksk"
|
||||
set_keylifetime "KEY3" "0"
|
||||
set_keyalgorithm "KEY3" "13" "ECDSAP256SHA256" "256"
|
||||
set_keysigning "KEY3" "yes"
|
||||
set_zonesigning "KEY3" "no"
|
||||
|
||||
set_keyrole "KEY4" "zsk"
|
||||
set_keylifetime "KEY4" "5184000"
|
||||
set_keyalgorithm "KEY4" "13" "ECDSAP256SHA256" "256"
|
||||
set_keysigning "KEY4" "no"
|
||||
set_zonesigning "KEY4" "yes"
|
||||
|
||||
set_keytime "KEY3" "PUBLISHED" "yes"
|
||||
set_keytime "KEY3" "ACTIVE" "yes"
|
||||
set_keytime "KEY3" "RETIRED" "none"
|
||||
set_keystate "KEY3" "GOAL" "omnipresent"
|
||||
set_keystate "KEY3" "STATE_DNSKEY" "rumoured"
|
||||
set_keystate "KEY3" "STATE_KRRSIG" "rumoured"
|
||||
set_keystate "KEY3" "STATE_DS" "hidden"
|
||||
|
||||
set_keytime "KEY4" "PUBLISHED" "yes"
|
||||
set_keytime "KEY4" "ACTIVE" "yes"
|
||||
set_keytime "KEY4" "RETIRED" "yes"
|
||||
set_keystate "KEY4" "GOAL" "omnipresent"
|
||||
set_keystate "KEY4" "STATE_DNSKEY" "rumoured"
|
||||
set_keystate "KEY4" "STATE_ZRRSIG" "rumoured"
|
||||
|
||||
check_keys
|
||||
check_apex
|
||||
check_subdomain
|
||||
dnssec_verify
|
||||
|
||||
# Check key tags, should be the same.
|
||||
n=$((n+1))
|
||||
echo_i "check that of zone ${ZONE} migration to dnssec-policy keeps existing keys ($n)"
|
||||
ret=0
|
||||
[ $_migratenomatch_algnum_ksk == $(key_get KEY1 ID) ] || log_error "mismatch ksk tag"
|
||||
[ $_migratenomatch_algnum_zsk == $(key_get KEY2 ID) ] || log_error "mismatch zsk tag"
|
||||
status=$((status+ret))
|
||||
|
||||
# Test migration to dnssec-policy, existing keys do not match key length.
|
||||
set_zone "migrate-nomatch-alglen.kasp"
|
||||
set_policy "migrate-nomatch-alglen" "4" "300"
|
||||
set_server "ns6" "10.53.0.6"
|
||||
|
||||
# The legacy keys need to be retired, but otherwise stay present until the
|
||||
# new keys are omnipresent, and can be used to construct a chain of trust.
|
||||
init_migration_nomatch_alglen
|
||||
|
||||
key_set "KEY1" "LEGACY" "no"
|
||||
set_keytime "KEY1" "RETIRED" "yes"
|
||||
set_keystate "KEY1" "GOAL" "hidden"
|
||||
|
||||
key_set "KEY2" "LEGACY" "no"
|
||||
set_keytime "KEY2" "RETIRED" "yes"
|
||||
set_keystate "KEY2" "GOAL" "hidden"
|
||||
|
||||
set_keyrole "KEY3" "ksk"
|
||||
set_keylifetime "KEY3" "0"
|
||||
set_keyalgorithm "KEY3" "5" "RSASHA1" "2048"
|
||||
set_keysigning "KEY3" "yes"
|
||||
set_zonesigning "KEY3" "no"
|
||||
|
||||
set_keyrole "KEY4" "zsk"
|
||||
set_keylifetime "KEY4" "5184000"
|
||||
set_keyalgorithm "KEY4" "5" "RSASHA1" "2048"
|
||||
set_keysigning "KEY4" "no"
|
||||
# This key is considered to be prepublished, so it is not yet signing.
|
||||
set_zonesigning "KEY4" "no"
|
||||
|
||||
set_keytime "KEY3" "PUBLISHED" "yes"
|
||||
set_keytime "KEY3" "ACTIVE" "yes"
|
||||
set_keytime "KEY3" "RETIRED" "none"
|
||||
set_keystate "KEY3" "GOAL" "omnipresent"
|
||||
set_keystate "KEY3" "STATE_DNSKEY" "rumoured"
|
||||
set_keystate "KEY3" "STATE_KRRSIG" "rumoured"
|
||||
set_keystate "KEY3" "STATE_DS" "hidden"
|
||||
|
||||
set_keytime "KEY4" "PUBLISHED" "yes"
|
||||
set_keytime "KEY4" "ACTIVE" "yes"
|
||||
set_keytime "KEY4" "RETIRED" "yes"
|
||||
set_keystate "KEY4" "GOAL" "omnipresent"
|
||||
set_keystate "KEY4" "STATE_DNSKEY" "rumoured"
|
||||
set_keystate "KEY4" "STATE_ZRRSIG" "hidden"
|
||||
|
||||
check_keys
|
||||
check_apex
|
||||
check_subdomain
|
||||
dnssec_verify
|
||||
|
||||
# Check key tags, should be the same.
|
||||
n=$((n+1))
|
||||
echo_i "check that of zone ${ZONE} migration to dnssec-policy keeps existing keys ($n)"
|
||||
ret=0
|
||||
[ $_migratenomatch_alglen_ksk == $(key_get KEY1 ID) ] || log_error "mismatch ksk tag"
|
||||
[ $_migratenomatch_alglen_zsk == $(key_get KEY2 ID) ] || log_error "mismatch zsk tag"
|
||||
status=$((status+ret))
|
||||
|
||||
#
|
||||
# Testing KSK/ZSK algorithm rollover.
|
||||
#
|
||||
|
|
|
|||
|
|
@ -63,6 +63,14 @@
|
|||
reducing such delays. [GL #1447]
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
Migration to dnssec-policy from existing DNSSEC strategy with
|
||||
auto-dnssec maintain did not work due to bad initializing of the
|
||||
key states. Fixed by looking closely at the time metadata to
|
||||
set the key states to the correct values. [GL #1706]
|
||||
</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
</section>
|
||||
|
||||
|
|
|
|||
165
lib/dns/keymgr.c
165
lib/dns/keymgr.c
|
|
@ -43,13 +43,13 @@
|
|||
* Set key state to HIDDEN and change last changed to now,
|
||||
* only if key state has not been set before.
|
||||
*/
|
||||
#define INITIALIZE_STATE(key, state, time) \
|
||||
#define INITIALIZE_STATE(key, state, time, target) \
|
||||
do { \
|
||||
dst_key_state_t s; \
|
||||
if (dst_key_getstate((key), (state), &s) == ISC_R_NOTFOUND) { \
|
||||
isc_stdtime_t t; \
|
||||
dst_key_gettime((key), DST_TIME_CREATED, &t); \
|
||||
dst_key_setstate((key), (state), HIDDEN); \
|
||||
dst_key_setstate((key), (state), target); \
|
||||
dst_key_settime((key), (time), t); \
|
||||
} \
|
||||
} while (0)
|
||||
|
|
@ -105,7 +105,7 @@ static isc_stdtime_t
|
|||
keymgr_prepublication_time(dns_dnsseckey_t *key, dns_kasp_t *kasp,
|
||||
uint32_t lifetime, isc_stdtime_t now) {
|
||||
isc_result_t ret;
|
||||
isc_stdtime_t active, retire, prepub;
|
||||
isc_stdtime_t active, retire, pub, prepub;
|
||||
bool ksk = false;
|
||||
|
||||
REQUIRE(key != NULL);
|
||||
|
|
@ -125,7 +125,8 @@ keymgr_prepublication_time(dns_dnsseckey_t *key, dns_kasp_t *kasp,
|
|||
if (ret != ISC_R_SUCCESS) {
|
||||
uint32_t klifetime = 0;
|
||||
/*
|
||||
* An active key must have an activate timing metadata.
|
||||
* An active key must have publish and activate timing
|
||||
* metadata.
|
||||
*/
|
||||
ret = dst_key_gettime(key->key, DST_TIME_ACTIVATE, &active);
|
||||
if (ret != ISC_R_SUCCESS) {
|
||||
|
|
@ -133,6 +134,12 @@ keymgr_prepublication_time(dns_dnsseckey_t *key, dns_kasp_t *kasp,
|
|||
dst_key_settime(key->key, DST_TIME_ACTIVATE, now);
|
||||
active = now;
|
||||
}
|
||||
ret = dst_key_gettime(key->key, DST_TIME_PUBLISH, &pub);
|
||||
if (ret != ISC_R_SUCCESS) {
|
||||
/* Super weird, but if it happens, set it to now. */
|
||||
dst_key_settime(key->key, DST_TIME_PUBLISH, now);
|
||||
pub = now;
|
||||
}
|
||||
|
||||
ret = dst_key_getnum(key->key, DST_NUM_LIFETIME, &klifetime);
|
||||
if (ret != ISC_R_SUCCESS) {
|
||||
|
|
@ -1214,19 +1221,25 @@ transition:
|
|||
}
|
||||
|
||||
/*
|
||||
* See if this key needs to be initialized with a role. A key created and
|
||||
* derived from a dnssec-policy will have the required metadata available,
|
||||
* otherwise these may be missing and need to be initialized.
|
||||
* See if this key needs to be initialized with properties. A key created
|
||||
* and derived from a dnssec-policy will have the required metadata available,
|
||||
* otherwise these may be missing and need to be initialized. The key states
|
||||
* will be initialized according to existing timing metadata.
|
||||
*
|
||||
*/
|
||||
static void
|
||||
keymgr_key_init_role(dns_dnsseckey_t *key) {
|
||||
keymgr_key_init(dns_dnsseckey_t *key, dns_kasp_t *kasp, isc_stdtime_t now) {
|
||||
bool ksk, zsk;
|
||||
isc_result_t ret;
|
||||
isc_stdtime_t active = 0, pub = 0, syncpub = 0;
|
||||
dst_key_state_t dnskey_state = HIDDEN;
|
||||
dst_key_state_t ds_state = HIDDEN;
|
||||
dst_key_state_t zrrsig_state = HIDDEN;
|
||||
|
||||
REQUIRE(key != NULL);
|
||||
REQUIRE(key->key != NULL);
|
||||
|
||||
/* Initialize role. */
|
||||
ret = dst_key_getbool(key->key, DST_BOOL_KSK, &ksk);
|
||||
if (ret != ISC_R_SUCCESS) {
|
||||
ksk = ((dst_key_flags(key->key) & DNS_KEYFLAG_KSK) != 0);
|
||||
|
|
@ -1237,6 +1250,52 @@ keymgr_key_init_role(dns_dnsseckey_t *key) {
|
|||
zsk = ((dst_key_flags(key->key) & DNS_KEYFLAG_KSK) == 0);
|
||||
dst_key_setbool(key->key, DST_BOOL_ZSK, zsk);
|
||||
}
|
||||
|
||||
/* Get time metadata. */
|
||||
ret = dst_key_gettime(key->key, DST_TIME_ACTIVATE, &active);
|
||||
if (active <= now && ret == ISC_R_SUCCESS) {
|
||||
dns_ttl_t key_ttl = dst_key_getttl(key->key);
|
||||
key_ttl += dns_kasp_zonepropagationdelay(kasp);
|
||||
if ((active + key_ttl) <= now) {
|
||||
dnskey_state = OMNIPRESENT;
|
||||
} else {
|
||||
dnskey_state = RUMOURED;
|
||||
}
|
||||
}
|
||||
ret = dst_key_gettime(key->key, DST_TIME_PUBLISH, &pub);
|
||||
if (pub <= now && ret == ISC_R_SUCCESS) {
|
||||
dns_ttl_t zone_ttl = dns_kasp_zonemaxttl(kasp);
|
||||
zone_ttl += dns_kasp_zonepropagationdelay(kasp);
|
||||
if ((pub + zone_ttl) <= now) {
|
||||
zrrsig_state = OMNIPRESENT;
|
||||
} else {
|
||||
zrrsig_state = RUMOURED;
|
||||
}
|
||||
}
|
||||
ret = dst_key_gettime(key->key, DST_TIME_SYNCPUBLISH, &syncpub);
|
||||
if (syncpub <= now && ret == ISC_R_SUCCESS) {
|
||||
dns_ttl_t ds_ttl = dns_kasp_dsttl(kasp);
|
||||
ds_ttl += dns_kasp_parentregistrationdelay(kasp);
|
||||
ds_ttl += dns_kasp_parentpropagationdelay(kasp);
|
||||
if ((syncpub + ds_ttl) <= now) {
|
||||
ds_state = OMNIPRESENT;
|
||||
} else {
|
||||
ds_state = RUMOURED;
|
||||
}
|
||||
}
|
||||
|
||||
/* Set key states for all keys that do not have them. */
|
||||
INITIALIZE_STATE(key->key, DST_KEY_DNSKEY, DST_TIME_DNSKEY,
|
||||
dnskey_state);
|
||||
if (ksk) {
|
||||
INITIALIZE_STATE(key->key, DST_KEY_KRRSIG, DST_TIME_KRRSIG,
|
||||
dnskey_state);
|
||||
INITIALIZE_STATE(key->key, DST_KEY_DS, DST_TIME_DS, ds_state);
|
||||
}
|
||||
if (zsk) {
|
||||
INITIALIZE_STATE(key->key, DST_KEY_ZRRSIG, DST_TIME_ZRRSIG,
|
||||
zrrsig_state);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -1302,23 +1361,13 @@ dns_keymgr_run(const dns_name_t *origin, dns_rdataclass_t rdclass,
|
|||
{
|
||||
bool found_match = false;
|
||||
|
||||
/* Make sure this key knows about roles. */
|
||||
keymgr_key_init_role(dkey);
|
||||
keymgr_key_init(dkey, kasp, now);
|
||||
|
||||
for (kkey = ISC_LIST_HEAD(dns_kasp_keys(kasp)); kkey != NULL;
|
||||
kkey = ISC_LIST_NEXT(kkey, link))
|
||||
{
|
||||
if (keymgr_dnsseckey_kaspkey_match(dkey, kkey)) {
|
||||
found_match = true;
|
||||
dst_key_format(dkey->key, keystr,
|
||||
sizeof(keystr));
|
||||
isc_log_write(dns_lctx, DNS_LOGCATEGORY_DNSSEC,
|
||||
DNS_LOGMODULE_DNSSEC,
|
||||
ISC_LOG_DEBUG(1),
|
||||
"keymgr: DNSKEY %s (%s) matches "
|
||||
"policy %s",
|
||||
keystr, keymgr_keyrole(dkey->key),
|
||||
dns_kasp_getname(kasp));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
@ -1343,8 +1392,17 @@ dns_keymgr_run(const dns_name_t *origin, dns_rdataclass_t rdclass,
|
|||
{
|
||||
if (keymgr_dnsseckey_kaspkey_match(dkey, kkey)) {
|
||||
/* Found a match. */
|
||||
dst_key_format(dkey->key, keystr,
|
||||
sizeof(keystr));
|
||||
isc_log_write(dns_lctx, DNS_LOGCATEGORY_DNSSEC,
|
||||
DNS_LOGMODULE_DNSSEC,
|
||||
ISC_LOG_DEBUG(1),
|
||||
"keymgr: DNSKEY %s (%s) matches "
|
||||
"policy %s",
|
||||
keystr, keymgr_keyrole(dkey->key),
|
||||
dns_kasp_getname(kasp));
|
||||
|
||||
/* Initialize lifetime. */
|
||||
/* Initialize lifetime if not set. */
|
||||
uint32_t l;
|
||||
if (dst_key_getnum(dkey->key, DST_NUM_LIFETIME,
|
||||
&l) != ISC_R_SUCCESS) {
|
||||
|
|
@ -1353,18 +1411,49 @@ dns_keymgr_run(const dns_name_t *origin, dns_rdataclass_t rdclass,
|
|||
lifetime);
|
||||
}
|
||||
|
||||
if (dst_key_goal(dkey->key) == OMNIPRESENT) {
|
||||
if (active_key != NULL) {
|
||||
if (active_key) {
|
||||
/* We already have an active key that
|
||||
* matches the kasp policy.
|
||||
*/
|
||||
if (!dst_key_is_unused(dkey->key) &&
|
||||
(dst_key_goal(dkey->key) ==
|
||||
OMNIPRESENT) &&
|
||||
!keymgr_key_is_successor(
|
||||
dkey->key,
|
||||
active_key->key) &&
|
||||
!keymgr_key_is_successor(
|
||||
active_key->key, dkey->key))
|
||||
{
|
||||
/*
|
||||
* Multiple signing keys match
|
||||
* the kasp key configuration.
|
||||
* Retire excess keys.
|
||||
* Retire excess keys in use.
|
||||
*/
|
||||
keymgr_key_retire(dkey, now);
|
||||
} else {
|
||||
/* Save the matched key. */
|
||||
active_key = dkey;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
/*
|
||||
* This is possibly an active key created
|
||||
* outside dnssec-policy. Initialize goal,
|
||||
* if not set.
|
||||
*/
|
||||
dst_key_state_t goal;
|
||||
if (dst_key_getstate(dkey->key, DST_KEY_GOAL,
|
||||
&goal) != ISC_R_SUCCESS) {
|
||||
dst_key_setstate(dkey->key,
|
||||
DST_KEY_GOAL,
|
||||
OMNIPRESENT);
|
||||
}
|
||||
|
||||
/*
|
||||
* Save the matched key only if it is active
|
||||
* or desires to be active.
|
||||
*/
|
||||
if (dst_key_goal(dkey->key) == OMNIPRESENT ||
|
||||
dst_key_is_active(dkey->key, now)) {
|
||||
active_key = dkey;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1377,7 +1466,7 @@ dns_keymgr_run(const dns_name_t *origin, dns_rdataclass_t rdclass,
|
|||
isc_log_write(
|
||||
dns_lctx, DNS_LOGCATEGORY_DNSSEC,
|
||||
DNS_LOGMODULE_DNSSEC, ISC_LOG_DEBUG(1),
|
||||
"keymgr: DNSKEY %s (%s) matches "
|
||||
"keymgr: DNSKEY %s (%s) is active in "
|
||||
"policy %s",
|
||||
keystr, keymgr_keyrole(active_key->key),
|
||||
dns_kasp_getname(kasp));
|
||||
|
|
@ -1446,6 +1535,7 @@ dns_keymgr_run(const dns_name_t *origin, dns_rdataclass_t rdclass,
|
|||
dst_key_setttl(dst_key, dns_kasp_dnskeyttl(kasp));
|
||||
dst_key_settime(dst_key, DST_TIME_CREATED, now);
|
||||
RETERR(dns_dnsseckey_create(mctx, &dst_key, &newkey));
|
||||
keymgr_key_init(newkey, kasp, now);
|
||||
} else {
|
||||
newkey = candidate;
|
||||
dst_key_setnum(newkey->key, DST_NUM_LIFETIME, lifetime);
|
||||
|
|
@ -1512,27 +1602,6 @@ dns_keymgr_run(const dns_name_t *origin, dns_rdataclass_t rdclass,
|
|||
ISC_LIST_APPENDLIST(*keyring, newkeys, link);
|
||||
}
|
||||
|
||||
/* Initialize key states (for keys that don't have them yet). */
|
||||
for (dns_dnsseckey_t *dkey = ISC_LIST_HEAD(*keyring); dkey != NULL;
|
||||
dkey = ISC_LIST_NEXT(dkey, link))
|
||||
{
|
||||
bool ksk = false, zsk = false;
|
||||
|
||||
/* Set key states for all keys that do not have them. */
|
||||
INITIALIZE_STATE(dkey->key, DST_KEY_DNSKEY, DST_TIME_DNSKEY);
|
||||
(void)dst_key_getbool(dkey->key, DST_BOOL_KSK, &ksk);
|
||||
if (ksk) {
|
||||
INITIALIZE_STATE(dkey->key, DST_KEY_KRRSIG,
|
||||
DST_TIME_KRRSIG);
|
||||
INITIALIZE_STATE(dkey->key, DST_KEY_DS, DST_TIME_DS);
|
||||
}
|
||||
(void)dst_key_getbool(dkey->key, DST_BOOL_ZSK, &zsk);
|
||||
if (zsk) {
|
||||
INITIALIZE_STATE(dkey->key, DST_KEY_ZRRSIG,
|
||||
DST_TIME_ZRRSIG);
|
||||
}
|
||||
}
|
||||
|
||||
/* Read to update key states. */
|
||||
keymgr_update(keyring, kasp, now, nexttime);
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue