mirror of
https://gitlab.isc.org/isc-projects/bind9
synced 2025-08-29 13:38:26 +00:00
Implement 'rndc dnssec -checkds'
Add a new 'rndc' command 'dnssec -checkds' that allows the user to signal named that a new DS record has been seen published in the parent, or that an existing DS record has been withdrawn from the parent. Upon the 'checkds' request, 'named' will write out the new state for the key, updating the 'DSPublish' or 'DSRemoved' timing metadata. This replaces the "parent-registration-delay" configuration option, this was unreliable because it was purely time based (if the user did not actually submit the new DS to the parent for example, this could result in an invalid DNSSEC state). Because we cannot rely on the parent registration delay for state transition, we need to replace it with a different guard. Instead, if a key wants its DS state to be moved to RUMOURED, the "DSPublish" time must be set and must not be in the future. If a key wants its DS state to be moved to UNRETENTIVE, the "DSRemoved" time must be set and must not be in the future. By default, with '-checkds' you set the time that the DS has been published or withdrawn to now, but you can set a different time with '-when'. If there is only one KSK for the zone, that key has its DS state moved to RUMOURED. If there are multiple keys for the zone, specify the right key with '-key'.
This commit is contained in:
parent
f0fa6f0245
commit
04d8fc0143
4
CHANGES
4
CHANGES
@ -1,3 +1,7 @@
|
||||
5486. [func] Add 'rndc dnssec -checkds' command to tell named
|
||||
that the DS record has been published in the parent.
|
||||
[GL #1613]
|
||||
|
||||
5485. [placeholder]
|
||||
|
||||
5484. [func] Expire the 0 TTL RRSet quickly rather using them for
|
||||
|
@ -89,6 +89,7 @@
|
||||
#include <dns/secalg.h>
|
||||
#include <dns/soa.h>
|
||||
#include <dns/stats.h>
|
||||
#include <dns/time.h>
|
||||
#include <dns/tkey.h>
|
||||
#include <dns/tsig.h>
|
||||
#include <dns/ttl.h>
|
||||
@ -14497,6 +14498,23 @@ cleanup:
|
||||
return (result);
|
||||
}
|
||||
|
||||
static inline bool
|
||||
argcheck(char *cmd, const char *full) {
|
||||
size_t l;
|
||||
|
||||
if (cmd == NULL || cmd[0] != '-') {
|
||||
return (false);
|
||||
}
|
||||
|
||||
cmd++;
|
||||
l = strlen(cmd);
|
||||
if (l > strlen(full) || strncasecmp(cmd, full, l) != 0) {
|
||||
return (false);
|
||||
}
|
||||
|
||||
return (true);
|
||||
}
|
||||
|
||||
isc_result_t
|
||||
named_server_dnssec(named_server_t *server, isc_lex_t *lex,
|
||||
isc_buffer_t **text) {
|
||||
@ -14505,11 +14523,16 @@ named_server_dnssec(named_server_t *server, isc_lex_t *lex,
|
||||
dns_kasp_t *kasp = NULL;
|
||||
dns_dnsseckeylist_t keys;
|
||||
dns_dnsseckey_t *key;
|
||||
const char *ptr;
|
||||
char *ptr;
|
||||
const char *msg = NULL;
|
||||
/* variables for -checkds */
|
||||
bool checkds = false, dspublish = false, use_keyid = false;
|
||||
dns_keytag_t keyid = 0;
|
||||
/* variables for -status */
|
||||
bool status = false;
|
||||
char output[4096];
|
||||
isc_stdtime_t now;
|
||||
isc_time_t timenow;
|
||||
isc_stdtime_t now, when;
|
||||
isc_time_t timenow, timewhen;
|
||||
const char *dir;
|
||||
|
||||
/* Skip the command name. */
|
||||
@ -14524,43 +14547,163 @@ named_server_dnssec(named_server_t *server, isc_lex_t *lex,
|
||||
return (ISC_R_UNEXPECTEDEND);
|
||||
}
|
||||
|
||||
if (strcasecmp(ptr, "-status") != 0) {
|
||||
return (DNS_R_SYNTAX);
|
||||
}
|
||||
/* Initialize current time and key list. */
|
||||
TIME_NOW(&timenow);
|
||||
now = isc_time_seconds(&timenow);
|
||||
when = now;
|
||||
|
||||
ISC_LIST_INIT(keys);
|
||||
|
||||
if (strcasecmp(ptr, "-status") == 0) {
|
||||
status = true;
|
||||
} else if (strcasecmp(ptr, "-checkds") == 0) {
|
||||
checkds = true;
|
||||
|
||||
/* Check for options */
|
||||
for (;;) {
|
||||
ptr = next_token(lex, text);
|
||||
if (ptr == NULL) {
|
||||
msg = "Bad format";
|
||||
CHECK(ISC_R_UNEXPECTEDEND);
|
||||
}
|
||||
if (argcheck(ptr, "key")) {
|
||||
uint16_t id;
|
||||
ptr = next_token(lex, text);
|
||||
if (ptr == NULL) {
|
||||
msg = "No key identifier specified";
|
||||
CHECK(ISC_R_UNEXPECTEDEND);
|
||||
}
|
||||
CHECK(isc_parse_uint16(&id, ptr, 10));
|
||||
keyid = (dns_keytag_t)id;
|
||||
use_keyid = true;
|
||||
continue;
|
||||
} else if (argcheck(ptr, "when")) {
|
||||
uint32_t tw;
|
||||
ptr = next_token(lex, text);
|
||||
if (ptr == NULL) {
|
||||
msg = "No time specified";
|
||||
CHECK(ISC_R_UNEXPECTEDEND);
|
||||
}
|
||||
CHECK(dns_time32_fromtext(ptr, &tw));
|
||||
when = (isc_stdtime_t)tw;
|
||||
continue;
|
||||
} else if (ptr[0] == '-') {
|
||||
msg = "Unknown option";
|
||||
CHECK(DNS_R_SYNTAX);
|
||||
} else {
|
||||
/*
|
||||
* No arguments provided, so we must be
|
||||
* parsing "published|withdrawn".
|
||||
*/
|
||||
if (strcasecmp(ptr, "publish") == 0) {
|
||||
dspublish = true;
|
||||
} else if (strcasecmp(ptr, "withdraw") != 0) {
|
||||
CHECK(DNS_R_SYNTAX);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
CHECK(DNS_R_SYNTAX);
|
||||
}
|
||||
|
||||
/* Get zone. */
|
||||
CHECK(zone_from_args(server, lex, NULL, &zone, NULL, text, false));
|
||||
if (zone == NULL) {
|
||||
msg = "Zone not found";
|
||||
CHECK(ISC_R_UNEXPECTEDEND);
|
||||
}
|
||||
|
||||
/* Trailing garbage? */
|
||||
ptr = next_token(lex, text);
|
||||
if (ptr != NULL) {
|
||||
msg = "Too many arguments";
|
||||
CHECK(DNS_R_SYNTAX);
|
||||
}
|
||||
|
||||
/* Get dnssec-policy. */
|
||||
kasp = dns_zone_getkasp(zone);
|
||||
if (kasp == NULL) {
|
||||
CHECK(putstr(text, "zone does not have dnssec-policy"));
|
||||
CHECK(putnull(text));
|
||||
msg = "Zone does not have dnssec-policy";
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/* -status */
|
||||
TIME_NOW(&timenow);
|
||||
now = isc_time_seconds(&timenow);
|
||||
/* Get DNSSEC keys. */
|
||||
dir = dns_zone_getkeydirectory(zone);
|
||||
LOCK(&kasp->lock);
|
||||
result = dns_dnssec_findmatchingkeys(dns_zone_getorigin(zone), dir, now,
|
||||
dns_zone_getmctx(zone), &keys);
|
||||
UNLOCK(&kasp->lock);
|
||||
|
||||
if (result != ISC_R_SUCCESS && result != ISC_R_NOTFOUND) {
|
||||
goto cleanup;
|
||||
}
|
||||
LOCK(&kasp->lock);
|
||||
dns_keymgr_status(kasp, &keys, now, &output[0], sizeof(output));
|
||||
UNLOCK(&kasp->lock);
|
||||
CHECK(putstr(text, output));
|
||||
|
||||
if (status) {
|
||||
/*
|
||||
* Output the DNSSEC status of the key and signing policy.
|
||||
*/
|
||||
LOCK(&kasp->lock);
|
||||
dns_keymgr_status(kasp, &keys, now, &output[0], sizeof(output));
|
||||
UNLOCK(&kasp->lock);
|
||||
CHECK(putstr(text, output));
|
||||
} else if (checkds) {
|
||||
/*
|
||||
* Mark DS record has been seen, so it may move to the
|
||||
* rumoured state.
|
||||
*/
|
||||
char whenbuf[80];
|
||||
isc_time_set(&timewhen, when, 0);
|
||||
isc_time_formattimestamp(&timewhen, whenbuf, sizeof(whenbuf));
|
||||
|
||||
LOCK(&kasp->lock);
|
||||
if (use_keyid) {
|
||||
result = dns_keymgr_checkds_id(kasp, &keys, dir, when,
|
||||
dspublish, keyid);
|
||||
} else {
|
||||
result = dns_keymgr_checkds(kasp, &keys, dir, when,
|
||||
dspublish);
|
||||
}
|
||||
UNLOCK(&kasp->lock);
|
||||
|
||||
switch (result) {
|
||||
case ISC_R_SUCCESS:
|
||||
if (use_keyid) {
|
||||
char tagbuf[6];
|
||||
snprintf(tagbuf, sizeof(tagbuf), "%u", keyid);
|
||||
CHECK(putstr(text, "KSK "));
|
||||
CHECK(putstr(text, tagbuf));
|
||||
CHECK(putstr(text, ": "));
|
||||
}
|
||||
CHECK(putstr(text, "Marked DS as "));
|
||||
if (dspublish) {
|
||||
CHECK(putstr(text, "published "));
|
||||
} else {
|
||||
CHECK(putstr(text, "withdrawn "));
|
||||
}
|
||||
CHECK(putstr(text, "since "));
|
||||
CHECK(putstr(text, whenbuf));
|
||||
break;
|
||||
case ISC_R_NOTFOUND:
|
||||
CHECK(putstr(text, "No matching KSK found"));
|
||||
break;
|
||||
case ISC_R_FAILURE:
|
||||
CHECK(putstr(text,
|
||||
"Error: multiple possible KSKs found, "
|
||||
"retry command with -key id"));
|
||||
break;
|
||||
default:
|
||||
CHECK(putstr(text, "Error executing checkds command"));
|
||||
break;
|
||||
}
|
||||
}
|
||||
CHECK(putnull(text));
|
||||
|
||||
cleanup:
|
||||
if (msg != NULL) {
|
||||
(void)putstr(text, msg);
|
||||
(void)putnull(text);
|
||||
}
|
||||
|
||||
while (!ISC_LIST_EMPTY(keys)) {
|
||||
key = ISC_LIST_HEAD(keys);
|
||||
ISC_LIST_UNLINK(keys, key, link);
|
||||
@ -14905,23 +15048,6 @@ cleanup:
|
||||
return (result);
|
||||
}
|
||||
|
||||
static inline bool
|
||||
argcheck(char *cmd, const char *full) {
|
||||
size_t l;
|
||||
|
||||
if (cmd == NULL || cmd[0] != '-') {
|
||||
return (false);
|
||||
}
|
||||
|
||||
cmd++;
|
||||
l = strlen(cmd);
|
||||
if (l > strlen(full) || strncasecmp(cmd, full, l) != 0) {
|
||||
return (false);
|
||||
}
|
||||
|
||||
return (true);
|
||||
}
|
||||
|
||||
isc_result_t
|
||||
named_server_nta(named_server_t *server, isc_lex_t *lex, bool readonly,
|
||||
isc_buffer_t **text) {
|
||||
|
@ -108,6 +108,11 @@ command is one of the following:\n\
|
||||
Add zone to given view. Requires allow-new-zones option.\n\
|
||||
delzone [-clean] zone [class [view]]\n\
|
||||
Removes zone from given view.\n\
|
||||
dnssec -checkds [-key id] [-when time] (published|withdrawn) zone [class [view]]\n\
|
||||
Mark the DS record for the KSK of the given zone as seen\n\
|
||||
in the parent. If the zone has multiple KSKs, select a\n\
|
||||
specific key by providing the keytag with -key id.\n\
|
||||
Requires the zone to have a dnssec-policy.\n\
|
||||
dnssec -status zone [class [view]]\n\
|
||||
Show the DNSSEC signing state for the specified zone.\n\
|
||||
Requires the zone to have a dnssec-policy.\n\
|
||||
|
@ -161,9 +161,20 @@ Currently supported commands are:
|
||||
|
||||
See also ``rndc addzone`` and ``rndc modzone``.
|
||||
|
||||
``dnssec`` [**-status** *zone* [*class* [*view*]]
|
||||
Show the DNSSEC signing state for the specified zone. Requires the
|
||||
zone to have a "dnssec-policy".
|
||||
``dnssec`` ( **-status** | **-checkds** [**-key** *id*] [**-when** *time*] ( *published* | *withdrawn* )) *zone* [*class* [*view*]]
|
||||
This command allows you to interact with the "dnssec-policy" of a given
|
||||
zone.
|
||||
|
||||
``rndc dnssec -status`` show the DNSSEC signing state for the specified
|
||||
zone.
|
||||
|
||||
``rndc dnssec -checkds`` will let ``named`` know that the DS for the given
|
||||
key has been seen published into or withdrawn from the parent. This is
|
||||
required in order to complete a KSK rollover. If the ``-key id`` argument
|
||||
is specified, look for the key with the given identifier, otherwise if there
|
||||
is only one key acting as a KSK in the zone, assume the DS of that key.
|
||||
The time that the DS has been published or withdrawn is set to now, unless
|
||||
otherwise specified with the argument ``-when time``.
|
||||
|
||||
``dnstap`` ( **-reopen** | **-roll** [*number*] )
|
||||
This command closes and re-opens DNSTAP output files. ``rndc dnstap -reopen`` allows
|
||||
|
@ -161,9 +161,20 @@ recreated. To remove it permanently, it must also be removed from
|
||||
.sp
|
||||
See also \fBrndc addzone\fP and \fBrndc modzone\fP\&.
|
||||
.TP
|
||||
\fBdnssec\fP [\fB\-status\fP \fIzone\fP [\fIclass\fP [\fIview\fP]]
|
||||
Show the DNSSEC signing state for the specified zone. Requires the
|
||||
zone to have a "dnssec\-policy".
|
||||
\fBdnssec\fP ( \fB\-status\fP | \fB\-checkds\fP [\fB\-key\fP \fIid\fP] [\fB\-when\fP \fItime\fP] ( \fIpublished\fP | \fIwithdrawn\fP )) \fIzone\fP [\fIclass\fP [\fIview\fP]]
|
||||
This command allows you to interact with the "dnssec\-policy" of a given
|
||||
zone.
|
||||
.sp
|
||||
\fBrndc dnssec \-status\fP show the DNSSEC signing state for the specified
|
||||
zone.
|
||||
.sp
|
||||
\fBrndc dnssec \-checkds\fP will let \fBnamed\fP know that the DS for the given
|
||||
key has been seen published into or withdrawn from the parent. This is
|
||||
required in order to complete a KSK rollover. If the \fB\-key id\fP argument
|
||||
is specified, look for the key with the given identifier, otherwise if there
|
||||
is only one key acting as a KSK in the zone, assume the DS of that key.
|
||||
The time that the DS has been published or withdrawn is set to now, unless
|
||||
otherwise specified with the argument \fB\-when time\fP\&.
|
||||
.TP
|
||||
\fBdnstap\fP ( \fB\-reopen\fP | \fB\-roll\fP [\fInumber\fP] )
|
||||
This command closes and re\-opens DNSTAP output files. \fBrndc dnstap \-reopen\fP allows
|
||||
|
@ -110,7 +110,9 @@ static const char *timingtags[TIMING_NTAGS] = {
|
||||
|
||||
"DSPublish:", "SyncPublish:", "SyncDelete:",
|
||||
|
||||
"DNSKEYChange:", "ZRRSIGChange:", "KRRSIGChange:", "DSChange:"
|
||||
"DNSKEYChange:", "ZRRSIGChange:", "KRRSIGChange:", "DSChange:",
|
||||
|
||||
"DSRemoved:"
|
||||
};
|
||||
|
||||
#define KEYSTATES_NTAGS (DST_MAX_KEYSTATES + 1)
|
||||
@ -2009,6 +2011,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_REVOKE, "Revoked", fp);
|
||||
printtime(key, DST_TIME_DELETE, "Removed", fp);
|
||||
printtime(key, DST_TIME_DSPUBLISH, "DSPublish", fp);
|
||||
printtime(key, DST_TIME_DSDELETE, "DSRemoved", fp);
|
||||
printtime(key, DST_TIME_SYNCPUBLISH, "PublishCDS", fp);
|
||||
printtime(key, DST_TIME_SYNCDELETE, "DeleteCDS", fp);
|
||||
|
||||
|
@ -51,6 +51,31 @@ dns_keymgr_run(const dns_name_t *origin, dns_rdataclass_t rdclass,
|
||||
*\li On error, keypool is unchanged
|
||||
*/
|
||||
|
||||
isc_result_t
|
||||
dns_keymgr_checkds(dns_kasp_t *kasp, dns_dnsseckeylist_t *keyring,
|
||||
const char *directory, isc_stdtime_t now, bool dspublish);
|
||||
isc_result_t
|
||||
dns_keymgr_checkds_id(dns_kasp_t *kasp, dns_dnsseckeylist_t *keyring,
|
||||
const char *directory, isc_stdtime_t now, bool dspublish,
|
||||
dns_keytag_t id);
|
||||
/*%<
|
||||
* Check DS for one key in 'keyring'. The key must have the KSK role.
|
||||
* If 'dspublish' is set to true, set the DS Publish time to 'now'.
|
||||
* If 'dspublish' is set to false, set the DS Removed time to 'now'.
|
||||
* If a specific key 'id' is given it must match the keytag.
|
||||
* The result is stored in the key state file.
|
||||
*
|
||||
* Requires:
|
||||
*\li 'kasp' is not NULL.
|
||||
*\li 'keyring' is not NULL.
|
||||
*
|
||||
* Returns:
|
||||
*\li #ISC_R_SUCCESS (No error).
|
||||
*\li #ISC_R_FAILURE (More than one matching KSK found).
|
||||
*\li #ISC_R_NOTFOUND (No matching KSK found).
|
||||
*
|
||||
*/
|
||||
|
||||
void
|
||||
dns_keymgr_status(dns_kasp_t *kasp, dns_dnsseckeylist_t *keyring,
|
||||
isc_stdtime_t now, char *out, size_t out_len);
|
||||
|
@ -133,7 +133,8 @@ typedef enum dst_key_state {
|
||||
#define DST_TIME_ZRRSIG 10
|
||||
#define DST_TIME_KRRSIG 11
|
||||
#define DST_TIME_DS 12
|
||||
#define DST_MAX_TIMES 12
|
||||
#define DST_TIME_DSDELETE 13
|
||||
#define DST_MAX_TIMES 13
|
||||
|
||||
/* Numeric metadata definitions */
|
||||
#define DST_NUM_PREDECESSOR 0
|
||||
|
135
lib/dns/keymgr.c
135
lib/dns/keymgr.c
@ -128,9 +128,6 @@ keymgr_settime_remove(dns_dnsseckey_t *key, dns_kasp_t *kasp) {
|
||||
dns_kasp_parentpropagationdelay(kasp) +
|
||||
dns_kasp_retiresafety(kasp);
|
||||
}
|
||||
if (zsk && ksk) {
|
||||
ksk_remove += dns_kasp_parentregistrationdelay(kasp);
|
||||
}
|
||||
|
||||
remove = ksk_remove > zsk_remove ? ksk_remove : zsk_remove;
|
||||
dst_key_settime(key->key, DST_TIME_DELETE, remove);
|
||||
@ -263,12 +260,6 @@ keymgr_prepublication_time(dns_dnsseckey_t *key, dns_kasp_t *kasp,
|
||||
* so ignore the result code.
|
||||
*/
|
||||
(void)dst_key_getbool(key->key, DST_BOOL_ZSK, &zsk);
|
||||
if (!zsk && ksk) {
|
||||
/*
|
||||
* Include registration delay in prepublication time.
|
||||
*/
|
||||
prepub += dns_kasp_parentregistrationdelay(kasp);
|
||||
}
|
||||
|
||||
ret = dst_key_gettime(key->key, DST_TIME_INACTIVE, &retire);
|
||||
if (ret != ISC_R_SUCCESS) {
|
||||
@ -965,10 +956,14 @@ keymgr_have_rrsig(dns_dnsseckeylist_t *keyring, dns_dnsseckey_t *key, int type,
|
||||
* - First introduce the DNSKEY record, as well as the KRRSIG records.
|
||||
* - Only if the DNSKEY record is OMNIPRESENT, suggest to introduce the DS.
|
||||
*
|
||||
* Also check the DS Publish or Delete times, to see if the DS record
|
||||
* already reached the parent.
|
||||
*/
|
||||
static bool
|
||||
keymgr_policy_approval(dns_dnsseckeylist_t *keyring, dns_dnsseckey_t *key,
|
||||
int type, dst_key_state_t next) {
|
||||
int type, dst_key_state_t next, isc_stdtime_t now) {
|
||||
isc_result_t ret;
|
||||
isc_stdtime_t dstime;
|
||||
dst_key_state_t dnskeystate = HIDDEN;
|
||||
dst_key_state_t ksk_present[4] = { OMNIPRESENT, NA, OMNIPRESENT,
|
||||
OMNIPRESENT };
|
||||
@ -980,10 +975,10 @@ keymgr_policy_approval(dns_dnsseckeylist_t *keyring, dns_dnsseckey_t *key,
|
||||
dst_key_state_t ksk_retired[4] = { UNRETENTIVE, NA, NA, OMNIPRESENT };
|
||||
dst_key_state_t na[4] = { NA, NA, NA, NA }; /* successor n/a */
|
||||
|
||||
if (next != RUMOURED) {
|
||||
if (next != RUMOURED && next != UNRETENTIVE) {
|
||||
/*
|
||||
* Local policy only adds an extra barrier on transitions to
|
||||
* the RUMOURED state.
|
||||
* the RUMOURED and UNRETENTIVE states.
|
||||
*/
|
||||
return (true);
|
||||
}
|
||||
@ -993,6 +988,9 @@ keymgr_policy_approval(dns_dnsseckeylist_t *keyring, dns_dnsseckey_t *key,
|
||||
/* No restrictions. */
|
||||
return (true);
|
||||
case DST_KEY_ZRRSIG:
|
||||
if (next != RUMOURED) {
|
||||
return (true);
|
||||
}
|
||||
/* Make sure the DNSKEY record is OMNIPRESENT. */
|
||||
(void)dst_key_getstate(key->key, DST_KEY_DNSKEY, &dnskeystate);
|
||||
if (dnskeystate == OMNIPRESENT) {
|
||||
@ -1013,13 +1011,35 @@ keymgr_policy_approval(dns_dnsseckeylist_t *keyring, dns_dnsseckey_t *key,
|
||||
keyring, key, type, next, ksk_retired,
|
||||
ksk_rumoured, true, true)));
|
||||
case DST_KEY_KRRSIG:
|
||||
if (next != RUMOURED) {
|
||||
return (true);
|
||||
}
|
||||
/* Only introduce if the DNSKEY is also introduced. */
|
||||
(void)dst_key_getstate(key->key, DST_KEY_DNSKEY, &dnskeystate);
|
||||
return (dnskeystate != HIDDEN);
|
||||
case DST_KEY_DS:
|
||||
/* Make sure the DNSKEY record is OMNIPRESENT. */
|
||||
(void)dst_key_getstate(key->key, DST_KEY_DNSKEY, &dnskeystate);
|
||||
return (dnskeystate == OMNIPRESENT);
|
||||
if (next == RUMOURED) {
|
||||
/* Make sure the DNSKEY record is OMNIPRESENT. */
|
||||
(void)dst_key_getstate(key->key, DST_KEY_DNSKEY,
|
||||
&dnskeystate);
|
||||
if (dnskeystate != OMNIPRESENT) {
|
||||
return (false);
|
||||
}
|
||||
/* Make sure DS has been seen in the parent. */
|
||||
ret = dst_key_gettime(key->key, DST_TIME_DSPUBLISH,
|
||||
&dstime);
|
||||
if (ret != ISC_R_SUCCESS || dstime > now) {
|
||||
return (false);
|
||||
}
|
||||
} else if (next == UNRETENTIVE) {
|
||||
/* Make sure DS has been withdrawn from the parent. */
|
||||
ret = dst_key_gettime(key->key, DST_TIME_DSDELETE,
|
||||
&dstime);
|
||||
if (ret != ISC_R_SUCCESS || dstime > now) {
|
||||
return (false);
|
||||
}
|
||||
}
|
||||
return (true);
|
||||
default:
|
||||
return (false);
|
||||
}
|
||||
@ -1203,16 +1223,13 @@ keymgr_transition_time(dns_dnsseckey_t *key, int type,
|
||||
*
|
||||
* Iret = DprpP + TTLds
|
||||
*
|
||||
* So we need to wait Dreg + Iret before the DS becomes
|
||||
* OMNIPRESENT. This translates to:
|
||||
* This translates to:
|
||||
*
|
||||
* parent-registration-delay +
|
||||
* parent-propagation-delay + parent-ds-ttl.
|
||||
*
|
||||
* We will also add the retire-safety interval.
|
||||
*/
|
||||
nexttime = lastchange + dns_kasp_dsttl(kasp) +
|
||||
dns_kasp_parentregistrationdelay(kasp) +
|
||||
dns_kasp_parentpropagationdelay(kasp) +
|
||||
dns_kasp_retiresafety(kasp);
|
||||
break;
|
||||
@ -1302,7 +1319,7 @@ transition:
|
||||
|
||||
/* Is the transition allowed according to policy? */
|
||||
if (!keymgr_policy_approval(keyring, dkey, i,
|
||||
next_state)) {
|
||||
next_state, now)) {
|
||||
/* No, please respect rollover methods. */
|
||||
isc_log_write(
|
||||
dns_lctx, DNS_LOGCATEGORY_DNSSEC,
|
||||
@ -1433,7 +1450,6 @@ keymgr_key_init(dns_dnsseckey_t *key, dns_kasp_t *kasp, isc_stdtime_t now) {
|
||||
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;
|
||||
@ -1854,6 +1870,83 @@ failure:
|
||||
return (result);
|
||||
}
|
||||
|
||||
static isc_result_t
|
||||
keymgr_checkds(dns_kasp_t *kasp, dns_dnsseckeylist_t *keyring,
|
||||
const char *directory, isc_stdtime_t now, bool dspublish,
|
||||
dns_keytag_t id, bool check_id) {
|
||||
int options = (DST_TYPE_PRIVATE | DST_TYPE_PUBLIC | DST_TYPE_STATE);
|
||||
isc_dir_t dir;
|
||||
isc_result_t result;
|
||||
dns_dnsseckey_t *ksk_key = NULL;
|
||||
|
||||
REQUIRE(DNS_KASP_VALID(kasp));
|
||||
REQUIRE(keyring != NULL);
|
||||
|
||||
for (dns_dnsseckey_t *dkey = ISC_LIST_HEAD(*keyring); dkey != NULL;
|
||||
dkey = ISC_LIST_NEXT(dkey, link))
|
||||
{
|
||||
isc_result_t ret;
|
||||
bool ksk = false;
|
||||
|
||||
ret = dst_key_getbool(dkey->key, DST_BOOL_KSK, &ksk);
|
||||
if (ret == ISC_R_SUCCESS && ksk) {
|
||||
if (check_id && dst_key_id(dkey->key) != id) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ksk_key != NULL) {
|
||||
/*
|
||||
* Only checkds for one key at a time.
|
||||
*/
|
||||
return (ISC_R_FAILURE);
|
||||
}
|
||||
|
||||
ksk_key = dkey;
|
||||
}
|
||||
}
|
||||
|
||||
if (ksk_key == NULL) {
|
||||
return (ISC_R_NOTFOUND);
|
||||
}
|
||||
|
||||
if (dspublish) {
|
||||
dst_key_settime(ksk_key->key, DST_TIME_DSPUBLISH, now);
|
||||
} else {
|
||||
dst_key_settime(ksk_key->key, DST_TIME_DSDELETE, now);
|
||||
}
|
||||
|
||||
/* Store key state and update hints. */
|
||||
isc_dir_init(&dir);
|
||||
if (directory == NULL) {
|
||||
directory = ".";
|
||||
}
|
||||
result = isc_dir_open(&dir, directory);
|
||||
if (result != ISC_R_SUCCESS) {
|
||||
return result;
|
||||
}
|
||||
|
||||
dns_dnssec_get_hints(ksk_key, now);
|
||||
result = dst_key_tofile(ksk_key->key, options, directory);
|
||||
isc_dir_close(&dir);
|
||||
|
||||
return (result);
|
||||
}
|
||||
|
||||
isc_result_t
|
||||
dns_keymgr_checkds(dns_kasp_t *kasp, dns_dnsseckeylist_t *keyring,
|
||||
const char *directory, isc_stdtime_t now, bool dspublish) {
|
||||
return (keymgr_checkds(kasp, keyring, directory, now, dspublish, 0,
|
||||
false));
|
||||
}
|
||||
|
||||
isc_result_t
|
||||
dns_keymgr_checkds_id(dns_kasp_t *kasp, dns_dnsseckeylist_t *keyring,
|
||||
const char *directory, isc_stdtime_t now, bool dspublish,
|
||||
dns_keytag_t id) {
|
||||
return (keymgr_checkds(kasp, keyring, directory, now, dspublish, id,
|
||||
true));
|
||||
}
|
||||
|
||||
static void
|
||||
keytime_status(dst_key_t *key, isc_stdtime_t now, isc_buffer_t *buf,
|
||||
const char *pre, int ks, int kt) {
|
||||
|
@ -470,6 +470,8 @@ dns_kasplist_find
|
||||
dns_keydata_fromdnskey
|
||||
dns_keydata_todnskey
|
||||
dns_keyflags_fromtext
|
||||
dns_keymgr_checkds
|
||||
dns_keymgr_checkds_id
|
||||
dns_keymgr_run
|
||||
dns_keymgr_status
|
||||
dns_keynode_dsset
|
||||
|
Loading…
x
Reference in New Issue
Block a user