[9.18] fix: usr: Update key lifetime and metadata after dnssec-policy reconfig

Adjust key state and timing metadata if dnssec-policy key lifetime configuration is updated, so that it also
affects existing keys.

Closes #4677

Backport of MR !9118

Merge branch 'backport-4677-dnssec-policy-key-lifetime-reconfigure-9.18' into 'bind-9.18'

See merge request isc-projects/bind9!9192
This commit is contained in:
Matthijs Mekking 2024-07-30 15:31:37 +00:00
commit 2107a64ee6
6 changed files with 190 additions and 37 deletions

View file

@ -89,15 +89,37 @@ zone "step1.csk-algorithm-roll.kasp" {
dnssec-policy "csk-algoroll";
};
dnssec-policy "modified" {
keys {
csk lifetime unlimited algorithm rsasha256 2048;
};
};
zone example {
type primary;
file "example.db";
inline-signing yes;
dnssec-policy modified;
};
zone longer-lifetime {
type primary;
file "longer-lifetime.db";
inline-signing yes;
dnssec-policy short-lifetime;
};
zone shorter-lifetime {
type primary;
file "shorter-lifetime.db";
inline-signing yes;
dnssec-policy long-lifetime;
};
zone limit-lifetime {
type primary;
file "limit-lifetime.db";
inline-signing yes;
dnssec-policy unlimited-lifetime;
};
zone unlimit-lifetime {
type primary;
file "unlimit-lifetime.db";
inline-signing yes;
dnssec-policy short-lifetime;
};

View file

@ -177,15 +177,37 @@ zone "step6.csk-algorithm-roll.kasp" {
dnssec-policy "csk-algoroll";
};
dnssec-policy "modified" {
keys {
csk lifetime unlimited algorithm rsasha256 2048;
};
};
zone example {
type primary;
file "example.db";
inline-signing yes;
dnssec-policy modified;
};
zone longer-lifetime {
type primary;
file "longer-lifetime.db";
inline-signing yes;
dnssec-policy long-lifetime;
};
zone shorter-lifetime {
type primary;
file "shorter-lifetime.db";
inline-signing yes;
dnssec-policy short-lifetime;
};
zone limit-lifetime {
type primary;
file "limit-lifetime.db";
inline-signing yes;
dnssec-policy short-lifetime;
};
zone unlimit-lifetime {
type primary;
file "unlimit-lifetime.db";
inline-signing yes;
dnssec-policy unlimited-lifetime;
};

View file

@ -24,6 +24,29 @@ dnssec-policy "nsec3" {
nsec3param iterations 0 optout no salt-length 0;
};
dnssec-policy "modified" {
keys {
csk lifetime unlimited algorithm rsasha256 2048;
};
};
dnssec-policy "unlimited-lifetime" {
keys {
csk lifetime unlimited algorithm @DEFAULT_ALGORITHM@;
};
};
dnssec-policy "short-lifetime" {
keys {
csk lifetime P6M algorithm @DEFAULT_ALGORITHM@;
};
};
dnssec-policy "long-lifetime" {
keys {
csk lifetime P1Y algorithm @DEFAULT_ALGORITHM@;
};
};
dnssec-policy "rsasha256" {
signatures-refresh P5D;
signatures-validity 30d;

View file

@ -29,6 +29,11 @@ R="RUMOURED"
O="OMNIPRESENT"
U="UNRETENTIVE"
for zn in shorter-lifetime longer-lifetime limit-lifetime unlimit-lifetime; do
setup $zn
cp template.db.in $zonefile
done
# The child zones (step1, step2) beneath these zones represent the various
# steps of unsigning a zone.
for zn in going-insecure.kasp going-insecure-dynamic.kasp; do

View file

@ -2153,9 +2153,6 @@ active=$(key_get KEY1 ACTIVE)
set_addkeytime "KEY1" "RETIRED" "${active}" 15552000
retired=$(key_get KEY1 RETIRED)
rndc_rollover "$SERVER" "$DIR" $(key_get KEY1 ID) "${retired}" "$ZONE"
# Rollover starts in six months, but lifetime is set to six months plus
# prepublication duration = 15552000 + 7500 = 15559500 seconds.
set_keylifetime "KEY1" "15559500"
set_addkeytime "KEY1" "RETIRED" "${active}" 15559500
retired=$(key_get KEY1 RETIRED)
# Retire interval of this policy is 26h (93600 seconds).
@ -2171,9 +2168,6 @@ dnssec_verify
# Schedule KSK rollover now.
set_policy "manual-rollover" "3" "3600"
set_keystate "KEY1" "GOAL" "hidden"
# This key was activated one day ago, so lifetime is set to 1d plus
# prepublication duration (7500 seconds) = 93900 seconds.
set_keylifetime "KEY1" "93900"
created=$(key_get KEY1 CREATED)
set_keytime "KEY1" "RETIRED" "${created}"
rndc_rollover "$SERVER" "$DIR" $(key_get KEY1 ID) "${created}" "$ZONE"
@ -2198,9 +2192,6 @@ dnssec_verify
# Schedule ZSK rollover now.
set_policy "manual-rollover" "4" "3600"
set_keystate "KEY2" "GOAL" "hidden"
# This key was activated one day ago, so lifetime is set to 1d plus
# prepublication duration (7500 seconds) = 93900 seconds.
set_keylifetime "KEY2" "93900"
created=$(key_get KEY2 CREATED)
set_keytime "KEY2" "RETIRED" "${created}"
rndc_rollover "$SERVER" "$DIR" $(key_get KEY2 ID) "${created}" "$ZONE"
@ -3655,9 +3646,6 @@ check_apex
check_subdomain
dnssec_verify
# Roll over KEY2.
# Set expected key lifetime, which is DNSKEY TTL plus the zone propagation delay,
# plus the publish-safety: 7200s + 1h + 1d = 97200 seconds.
set_keylifetime "KEY2" "97200"
created=$(key_get KEY2 CREATED)
rndc_rollover "$SERVER" "$DIR" $(key_get KEY2 ID) "${created}" "$ZONE"
# Update expected number of keys and key states.
@ -3709,6 +3697,65 @@ check_apex
check_subdomain
dnssec_verify
# Test key lifetime changes
set_keytimes_lifetime_update() {
if [ $1 -eq 0 ]; then
set_keytime "KEY1" "RETIRED" "none"
set_keytime "KEY1" "REMOVED" "none"
else
active=$(key_get KEY1 ACTIVE)
set_addkeytime "KEY1" "RETIRED" "${active}" $1
# The key is removed after the retire time plus max-zone-ttl (1d),
# sign delay (9d), zone propagation delay (5m), retire safety (1h) =
# 777600 + 86400 + 300 + 3600 = 867900
retired=$(key_get KEY1 RETIRED)
set_addkeytime "KEY1" "REMOVED" "${retired}" 867900
fi
}
check_key_lifetime() {
zone=$1
policy=$2
lifetime=$3
set_zone "$zone"
set_policy "$policy" "1" "3600"
set_server "ns6" "10.53.0.6"
# Key properties.
key_clear "KEY1"
set_keyrole "KEY1" "csk"
set_keylifetime "KEY1" "$lifetime"
set_keyalgorithm "KEY1" "13" "ECDSAP256SHA256" "256"
set_keysigning "KEY1" "yes"
set_zonesigning "KEY1" "yes"
key_clear "KEY2"
key_clear "KEY3"
key_clear "KEY4"
# The CSK is rumoured.
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
# Key timings.
set_keytimes_csk_policy
set_keytimes_lifetime_update $lifetime
# Variuous checks.
check_keytimes
check_dnssecstatus "$SERVER" "$POLICY" "$ZONE"
check_apex
check_subdomain
dnssec_verify
}
check_key_lifetime "shorter-lifetime" "long-lifetime" "31536000"
check_key_lifetime "longer-lifetime" "short-lifetime" "16070400"
check_key_lifetime "limit-lifetime" "unlimited-lifetime" "0"
check_key_lifetime "unlimit-lifetime" "short-lifetime" "16070400"
#
# Testing algorithm rollover.
#
@ -4004,6 +4051,12 @@ check_apex
check_subdomain
dnssec_verify
# Test key lifetime updates.
check_key_lifetime "shorter-lifetime" "short-lifetime" "16070400"
check_key_lifetime "longer-lifetime" "long-lifetime" "31536000"
check_key_lifetime "limit-lifetime" "short-lifetime" "16070400"
check_key_lifetime "unlimit-lifetime" "unlimited-lifetime" "0"
#
# Testing going insecure.
#

View file

@ -413,6 +413,41 @@ keymgr_dnsseckey_kaspkey_match(dns_dnsseckey_t *dkey, dns_kasp_key_t *kkey) {
return (true);
}
/* Update lifetime and retire and remove time accordingly. */
static void
keymgr_key_update_lifetime(dns_dnsseckey_t *key, dns_kasp_t *kasp,
isc_stdtime_t now, uint32_t lifetime) {
uint32_t l;
dst_key_state_t g = HIDDEN;
isc_result_t r;
(void)dst_key_getstate(key->key, DST_KEY_GOAL, &g);
r = dst_key_getnum(key->key, DST_NUM_LIFETIME, &l);
/* Initialize lifetime. */
if (r != ISC_R_SUCCESS) {
dst_key_setnum(key->key, DST_NUM_LIFETIME, lifetime);
return;
}
/* Skip keys that are still hidden or already retiring. */
if (g != OMNIPRESENT) {
return;
}
/* Update lifetime and timing metadata. */
if (l != lifetime) {
dst_key_setnum(key->key, DST_NUM_LIFETIME, lifetime);
if (lifetime > 0) {
uint32_t a = now;
(void)dst_key_gettime(key->key, DST_TIME_ACTIVATE, &a);
dst_key_settime(key->key, DST_TIME_INACTIVE,
(a + lifetime));
keymgr_settime_remove(key, kasp);
} else {
dst_key_unsettime(key->key, DST_TIME_INACTIVE);
dst_key_unsettime(key->key, DST_TIME_DELETE);
}
}
}
static bool
keymgr_keyid_conflict(dst_key_t *newkey, dns_dnsseckeylist_t *keys) {
uint16_t id = dst_key_id(newkey);
@ -2122,15 +2157,9 @@ dns_keymgr_run(const dns_name_t *origin, dns_rdataclass_t rdclass,
keystr, keymgr_keyrole(dkey->key),
dns_kasp_getname(kasp));
/* Initialize lifetime if not set. */
uint32_t l;
if (dst_key_getnum(dkey->key, DST_NUM_LIFETIME,
&l) != ISC_R_SUCCESS)
{
dst_key_setnum(dkey->key,
DST_NUM_LIFETIME,
lifetime);
}
/* Update lifetime if changed. */
keymgr_key_update_lifetime(dkey, kasp, now,
lifetime);
if (active_key) {
/* We already have an active key that
@ -2448,8 +2477,6 @@ rollover_status(dns_dnsseckey_t *dkey, dns_kasp_t *kasp, isc_stdtime_t now,
}
} else {
isc_stdtime_t retire_time = 0;
uint32_t lifetime = 0;
(void)dst_key_getnum(key, DST_NUM_LIFETIME, &lifetime);
ret = dst_key_gettime(key, retire, &retire_time);
if (ret == ISC_R_SUCCESS) {
if (now < retire_time) {
@ -2458,7 +2485,9 @@ rollover_status(dns_dnsseckey_t *dkey, dns_kasp_t *kasp, isc_stdtime_t now,
" Next rollover "
"scheduled on ");
retire_time = keymgr_prepublication_time(
dkey, kasp, lifetime, now);
dkey, kasp,
(retire_time - active_time),
now);
} else {
isc_buffer_printf(
buf, " Key will retire on ");
@ -2636,7 +2665,6 @@ dns_keymgr_rollover(dns_kasp_t *kasp, dns_dnsseckeylist_t *keyring,
retire = when + prepub;
dst_key_settime(key->key, DST_TIME_INACTIVE, retire);
dst_key_setnum(key->key, DST_NUM_LIFETIME, (retire - active));
/* Store key state and update hints. */
isc_dir_init(&dir);