2
0
mirror of https://gitlab.isc.org/isc-projects/bind9 synced 2025-09-02 23:55:27 +00:00

Set keytimes appropriately when using kasp

While kasp relies on key states to determine when a key needs to
be published or be used for signing, the keytimes are used by
operators to get some expectation of key publication and usage.

Update the code such that these keytimes are set appropriately.
That means:
- Print "PublishCDS" and "DeleteCDS" times in the state files.
- The keymgr sets the "Removed" and "PublishCDS" times and derives
  those from the dnssec-policy.
- Tweak setting of the "Retired" time, when retiring keys, only
  update the time to now when the retire time is not yet set, or is
  in the future.

This also fixes a bug in "keymgr_transition_time" where we may wait
too long before zone signatrues become omnipresent or hidden. Not
only can we skip waiting the sign delay Dsgn if there is no
predecessor, we can also skip it if there is no successor.

Finally, this commit moves setting the lifetime, reducing two calls
to one.
This commit is contained in:
Matthijs Mekking
2020-04-28 15:05:43 +02:00
parent 1c21631730
commit 18dc27afd3
2 changed files with 130 additions and 13 deletions

View File

@@ -2021,6 +2021,8 @@ write_key_state(const dst_key_t *key, int type, const char *directory) {
printtime(key, DST_TIME_INACTIVE, "Retired", fp); printtime(key, DST_TIME_INACTIVE, "Retired", fp);
printtime(key, DST_TIME_REVOKE, "Revoked", fp); printtime(key, DST_TIME_REVOKE, "Revoked", fp);
printtime(key, DST_TIME_DELETE, "Removed", fp); printtime(key, DST_TIME_DELETE, "Removed", fp);
printtime(key, DST_TIME_SYNCPUBLISH, "PublishCDS", fp);
printtime(key, DST_TIME_SYNCDELETE, "DeleteCDS", fp);
printtime(key, DST_TIME_DNSKEY, "DNSKEYChange", fp); printtime(key, DST_TIME_DNSKEY, "DNSKEYChange", fp);
printtime(key, DST_TIME_ZRRSIG, "ZRRSIGChange", fp); printtime(key, DST_TIME_ZRRSIG, "ZRRSIGChange", fp);

View File

@@ -88,12 +88,91 @@ keymgr_keyrole(dst_key_t *key) {
return ("NOSIGN"); return ("NOSIGN");
} }
/*
* Set the remove time on key given its retire time.
*
*/
static void
keymgr_settime_remove(dns_dnsseckey_t *key, dns_kasp_t *kasp) {
isc_stdtime_t retire = 0, remove = 0, ksk_remove = 0, zsk_remove = 0;
bool zsk = false, ksk = false;
isc_result_t ret;
REQUIRE(key != NULL);
REQUIRE(key->key != NULL);
ret = dst_key_gettime(key->key, DST_TIME_INACTIVE, &retire);
if (ret != ISC_R_SUCCESS) {
return;
}
ret = dst_key_getbool(key->key, DST_BOOL_ZSK, &zsk);
if (ret == ISC_R_SUCCESS && zsk) {
/* ZSK: Iret = Dsgn + Dprp + TTLsig */
zsk_remove = retire + dns_kasp_zonemaxttl(kasp) +
dns_kasp_zonepropagationdelay(kasp) +
dns_kasp_retiresafety(kasp) +
dns_kasp_signdelay(kasp);
}
ret = dst_key_getbool(key->key, DST_BOOL_KSK, &ksk);
if (ret == ISC_R_SUCCESS && ksk) {
/* KSK: Iret = DprpP + TTLds */
ksk_remove = retire + dns_kasp_dsttl(kasp) +
dns_kasp_parentregistrationdelay(kasp) +
dns_kasp_parentpropagationdelay(kasp) +
dns_kasp_retiresafety(kasp);
}
remove = ksk_remove > zsk_remove ? ksk_remove : zsk_remove;
dst_key_settime(key->key, DST_TIME_DELETE, remove);
}
/*
* Set the SyncPublish time (when the DS may be submitted to the parent)
*
*/
static void
keymgr_settime_syncpublish(dns_dnsseckey_t *key, dns_kasp_t *kasp, bool first) {
isc_stdtime_t published, syncpublish;
bool ksk = false;
isc_result_t ret;
REQUIRE(key != NULL);
REQUIRE(key->key != NULL);
ret = dst_key_gettime(key->key, DST_TIME_PUBLISH, &published);
if (ret != ISC_R_SUCCESS) {
return;
}
ret = dst_key_getbool(key->key, DST_BOOL_KSK, &ksk);
if (ret != ISC_R_SUCCESS || !ksk) {
return;
}
syncpublish = published + dst_key_getttl(key->key) +
dns_kasp_zonepropagationdelay(kasp) +
dns_kasp_publishsafety(kasp);
if (first) {
/* Also need to wait until the signatures are omnipresent. */
isc_stdtime_t zrrsig_present;
zrrsig_present = published + dns_kasp_zonemaxttl(kasp) +
dns_kasp_zonepropagationdelay(kasp) +
dns_kasp_publishsafety(kasp);
if (zrrsig_present > syncpublish) {
syncpublish = zrrsig_present;
}
}
dst_key_settime(key->key, DST_TIME_SYNCPUBLISH, syncpublish);
}
/* /*
* Calculate prepublication time of a successor key of 'key'. * Calculate prepublication time of a successor key of 'key'.
* This function can have side effects: * This function can have side effects:
* If the lifetime is not set, it will be set now. * 1. If there is no active time set, which would be super weird, set it now.
* If there should be a retire time and it is not set, it will be set now. * 2. If there is no published time set, also super weird, set it now.
* If there is no active time set, which would be super weird, set it now. * 3. If the lifetime is not set, it will be set now.
* 4. If there should be a retire time and it is not set, it will be set now.
* 5. The removed time is adjusted accordingly.
* *
* This returns when the successor key needs to be published in the zone. * This returns when the successor key needs to be published in the zone.
* A special value of 0 means there is no need for a successor. * A special value of 0 means there is no need for a successor.
@@ -156,6 +235,11 @@ keymgr_prepublication_time(dns_dnsseckey_t *key, dns_kasp_t *kasp,
dst_key_settime(key->key, DST_TIME_INACTIVE, retire); dst_key_settime(key->key, DST_TIME_INACTIVE, retire);
} }
/*
* Update remove time.
*/
keymgr_settime_remove(key, kasp);
/* /*
* Publish successor 'prepub' time before the 'retire' time of 'key'. * Publish successor 'prepub' time before the 'retire' time of 'key'.
*/ */
@@ -163,8 +247,10 @@ keymgr_prepublication_time(dns_dnsseckey_t *key, dns_kasp_t *kasp,
} }
static void static void
keymgr_key_retire(dns_dnsseckey_t *key, isc_stdtime_t now) { keymgr_key_retire(dns_dnsseckey_t *key, dns_kasp_t *kasp, isc_stdtime_t now) {
char keystr[DST_KEY_FORMATSIZE]; char keystr[DST_KEY_FORMATSIZE];
isc_result_t ret;
isc_stdtime_t retire;
dst_key_state_t s; dst_key_state_t s;
bool ksk, zsk; bool ksk, zsk;
@@ -172,8 +258,12 @@ keymgr_key_retire(dns_dnsseckey_t *key, isc_stdtime_t now) {
REQUIRE(key->key != NULL); REQUIRE(key->key != NULL);
/* This key wants to retire and hide in a corner. */ /* This key wants to retire and hide in a corner. */
dst_key_settime(key->key, DST_TIME_INACTIVE, now); ret = dst_key_gettime(key->key, DST_TIME_INACTIVE, &retire);
if (ret != ISC_R_SUCCESS || (retire > now)) {
dst_key_settime(key->key, DST_TIME_INACTIVE, now);
}
dst_key_setstate(key->key, DST_KEY_GOAL, HIDDEN); dst_key_setstate(key->key, DST_KEY_GOAL, HIDDEN);
keymgr_settime_remove(key, kasp);
/* This key may not have key states set yet. Pretend as if they are /* This key may not have key states set yet. Pretend as if they are
* in the OMNIPRESENT state. * in the OMNIPRESENT state.
@@ -1013,11 +1103,16 @@ keymgr_transition_time(dns_dnsseckey_t *key, int type,
dns_kasp_retiresafety(kasp); dns_kasp_retiresafety(kasp);
/* /*
* Only add the sign delay Dsgn if there is an actual * Only add the sign delay Dsgn if there is an actual
* predecessor key. * predecessor or successor key.
*/ */
uint32_t pre; uint32_t tag;
if (dst_key_getnum(key->key, DST_NUM_PREDECESSOR, ret = dst_key_getnum(key->key, DST_NUM_PREDECESSOR,
&pre) == ISC_R_SUCCESS) { &tag);
if (ret != ISC_R_SUCCESS) {
ret = dst_key_getnum(key->key,
DST_NUM_SUCCESSOR, &tag);
}
if (ret == ISC_R_SUCCESS) {
nexttime += dns_kasp_signdelay(kasp); nexttime += dns_kasp_signdelay(kasp);
} }
break; break;
@@ -1373,7 +1468,7 @@ dns_keymgr_run(const dns_name_t *origin, dns_rdataclass_t rdclass,
/* No match, so retire unwanted retire key. */ /* No match, so retire unwanted retire key. */
if (!found_match) { if (!found_match) {
keymgr_key_retire(dkey, now); keymgr_key_retire(dkey, kasp, now);
} }
} }
@@ -1428,7 +1523,8 @@ dns_keymgr_run(const dns_name_t *origin, dns_rdataclass_t rdclass,
* the kasp key configuration. * the kasp key configuration.
* Retire excess keys in use. * Retire excess keys in use.
*/ */
keymgr_key_retire(dkey, now); keymgr_key_retire(dkey, kasp,
now);
} }
continue; continue;
} }
@@ -1537,8 +1633,8 @@ dns_keymgr_run(const dns_name_t *origin, dns_rdataclass_t rdclass,
keymgr_key_init(newkey, kasp, now); keymgr_key_init(newkey, kasp, now);
} else { } else {
newkey = candidate; newkey = candidate;
dst_key_setnum(newkey->key, DST_NUM_LIFETIME, lifetime);
} }
dst_key_setnum(newkey->key, DST_NUM_LIFETIME, lifetime);
/* Got a key. */ /* Got a key. */
if (active_key == NULL) { if (active_key == NULL) {
@@ -1548,19 +1644,38 @@ dns_keymgr_run(const dns_name_t *origin, dns_rdataclass_t rdclass,
*/ */
dst_key_settime(newkey->key, DST_TIME_PUBLISH, now); dst_key_settime(newkey->key, DST_TIME_PUBLISH, now);
dst_key_settime(newkey->key, DST_TIME_ACTIVATE, now); dst_key_settime(newkey->key, DST_TIME_ACTIVATE, now);
keymgr_settime_syncpublish(newkey, kasp, true);
active = now; active = now;
} else { } else {
/* /*
* This is a successor. Mark the relationship. * This is a successor. Mark the relationship.
*/ */
isc_stdtime_t created;
(void)dst_key_gettime(newkey->key, DST_TIME_CREATED,
&created);
dst_key_setnum(newkey->key, DST_NUM_PREDECESSOR, dst_key_setnum(newkey->key, DST_NUM_PREDECESSOR,
dst_key_id(active_key->key)); dst_key_id(active_key->key));
dst_key_setnum(active_key->key, DST_NUM_SUCCESSOR, dst_key_setnum(active_key->key, DST_NUM_SUCCESSOR,
dst_key_id(newkey->key)); dst_key_id(newkey->key));
(void)dst_key_gettime(active_key->key, (void)dst_key_gettime(active_key->key,
DST_TIME_INACTIVE, &retire); DST_TIME_INACTIVE, &retire);
/*
* If prepublication time and/or retire time are
* in the past (before the new key was created), use
* creation time as published and active time,
* effectively immediately making the key active.
*/
if (prepub < created) {
retire += (created - prepub);
prepub = created;
}
if (retire < created) {
retire = created;
}
dst_key_settime(newkey->key, DST_TIME_PUBLISH, prepub); dst_key_settime(newkey->key, DST_TIME_PUBLISH, prepub);
dst_key_settime(newkey->key, DST_TIME_ACTIVATE, retire); dst_key_settime(newkey->key, DST_TIME_ACTIVATE, retire);
keymgr_settime_syncpublish(newkey, kasp, false);
active = retire; active = retire;
} }
@@ -1568,10 +1683,10 @@ dns_keymgr_run(const dns_name_t *origin, dns_rdataclass_t rdclass,
dst_key_setstate(newkey->key, DST_KEY_GOAL, OMNIPRESENT); dst_key_setstate(newkey->key, DST_KEY_GOAL, OMNIPRESENT);
/* Do we need to set retire time? */ /* Do we need to set retire time? */
(void)dst_key_getnum(newkey->key, DST_NUM_LIFETIME, &lifetime);
if (lifetime > 0) { if (lifetime > 0) {
dst_key_settime(newkey->key, DST_TIME_INACTIVE, dst_key_settime(newkey->key, DST_TIME_INACTIVE,
(active + lifetime)); (active + lifetime));
keymgr_settime_remove(newkey, kasp);
} }
/* Append dnsseckey to list of new keys. */ /* Append dnsseckey to list of new keys. */