diff --git a/bin/named/server.c b/bin/named/server.c index 89f8eaa29b..547df1147a 100644 --- a/bin/named/server.c +++ b/bin/named/server.c @@ -14528,6 +14528,7 @@ named_server_dnssec(named_server_t *server, isc_lex_t *lex, /* variables for -checkds */ bool checkds = false, dspublish = false, use_keyid = false; dns_keytag_t keyid = 0; + uint8_t algorithm = 0; /* variables for -status */ bool status = false; char output[4096]; @@ -14565,8 +14566,23 @@ named_server_dnssec(named_server_t *server, isc_lex_t *lex, if (ptr == NULL) { msg = "Bad format"; CHECK(ISC_R_UNEXPECTEDEND); - } - if (argcheck(ptr, "key")) { + } else if (argcheck(ptr, "alg")) { + isc_consttextregion_t alg; + ptr = next_token(lex, text); + if (ptr == NULL) { + msg = "No key algorithm specified"; + CHECK(ISC_R_UNEXPECTEDEND); + } + alg.base = ptr; + alg.length = strlen(alg.base); + result = dns_secalg_fromtext( + &algorithm, (isc_textregion_t *)&alg); + if (result != ISC_R_SUCCESS) { + msg = "Bad algorithm"; + CHECK(DNS_R_SYNTAX); + } + continue; + } else if (argcheck(ptr, "key")) { uint16_t id; ptr = next_token(lex, text); if (ptr == NULL) { @@ -14595,14 +14611,19 @@ named_server_dnssec(named_server_t *server, isc_lex_t *lex, * No arguments provided, so we must be * parsing "published|withdrawn". */ - if (strcasecmp(ptr, "publish") == 0) { + if (strcasecmp(ptr, "published") == 0) { dspublish = true; - } else if (strcasecmp(ptr, "withdraw") != 0) { + } else if (strcasecmp(ptr, "withdrawn") != 0) { CHECK(DNS_R_SYNTAX); } } break; } + + if (algorithm > 0 && !use_keyid) { + msg = "Key id is required when setting algorithm"; + CHECK(DNS_R_SYNTAX); + } } else { CHECK(DNS_R_SYNTAX); } @@ -14658,7 +14679,8 @@ named_server_dnssec(named_server_t *server, isc_lex_t *lex, LOCK(&kasp->lock); if (use_keyid) { result = dns_keymgr_checkds_id(kasp, &keys, dir, when, - dspublish, keyid); + dspublish, keyid, + (unsigned int)algorithm); } else { result = dns_keymgr_checkds(kasp, &keys, dir, when, dspublish); diff --git a/bin/rndc/rndc.c b/bin/rndc/rndc.c index e68c2e2244..53a1cdccd6 100644 --- a/bin/rndc/rndc.c +++ b/bin/rndc/rndc.c @@ -108,10 +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\ + dnssec -checkds [-key id [-alg algorithm] [-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\ + specific key by providing the keytag with -key id and\n\ + optionally the key's algorithm with -alg algorithm.\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\ diff --git a/bin/rndc/rndc.rst b/bin/rndc/rndc.rst index 72e42384cb..f6501d4022 100644 --- a/bin/rndc/rndc.rst +++ b/bin/rndc/rndc.rst @@ -161,7 +161,7 @@ Currently supported commands are: See also ``rndc addzone`` and ``rndc modzone``. -``dnssec`` ( **-status** | **-checkds** [**-key** *id*] [**-when** *time*] ( *published* | *withdrawn* )) *zone* [*class* [*view*]] +``dnssec`` ( **-status** | **-checkds** [**-key** *id* [**-alg** *algorithm*]] [**-when** *time*] ( *published* | *withdrawn* )) *zone* [*class* [*view*]] This command allows you to interact with the "dnssec-policy" of a given zone. @@ -172,9 +172,10 @@ Currently supported commands are: 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``. + is only one key acting as a KSK in the zone, assume the DS of that key (if + there are multiple keys with the same tag, use ``-alg algorithm`` to + select the correct algorithm). 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 diff --git a/bin/tests/system/kasp/tests.sh b/bin/tests/system/kasp/tests.sh index d83017b6ba..335b411f1f 100644 --- a/bin/tests/system/kasp/tests.sh +++ b/bin/tests/system/kasp/tests.sh @@ -1476,6 +1476,22 @@ grep "DSRemoved:" "${basefile2}.state" > /dev/null && log_error "DSPublish incor test "$ret" -eq 0 || echo_i "failed" status=$((status+ret)) +n=$((n+1)) +echo_i "checkds published does not set DSPublish for zone $ZONE (wrong algorithm) ($n)" +rndccmd "$SERVER" dnssec -checkds -key $(key_get KEY1 ID) -alg 8 "published" "$ZONE" > rndc.dnssec.checkds.out.$ZONE.$n +grep "DSPublish:" "${basefile1}.state" > /dev/null && log_error "DSPublish incorrectly set in ${basefile1}" +grep "DSPublish:" "${basefile2}.state" > /dev/null && log_error "DSPublish incorrectly set in ${basefile2}" +test "$ret" -eq 0 || echo_i "failed" +status=$((status+ret)) + +n=$((n+1)) +echo_i "checkds withdrawn does not set DSRemoved for zone $ZONE (wrong algorithm) ($n)" +rndccmd "$SERVER" dnssec -checkds -key $(key_get KEY1 ID) -alg RSASHA256 "withdrawn" "$ZONE" > rndc.dnssec.checkds.out.$ZONE.$n +grep "DSRemoved:" "${basefile1}.state" > /dev/null && log_error "DSRemoved incorrectly set in ${basefile1}" +grep "DSRemoved:" "${basefile2}.state" > /dev/null && log_error "DSRemoved incorrectly set in ${basefile2}" +test "$ret" -eq 0 || echo_i "failed" +status=$((status+ret)) + n=$((n+1)) echo_i "checkds published -key correctly sets DSPublish for key $(key_get KEY1 ID) zone $ZONE (multiple KSK) ($n)" rndc_checkds "$SERVER" "$DIR" $(key_get KEY1 ID) "20190102121314" "published" "$ZONE" diff --git a/doc/man/rndc.8in b/doc/man/rndc.8in index 81fd8f642b..59f03abe68 100644 --- a/doc/man/rndc.8in +++ b/doc/man/rndc.8in @@ -161,7 +161,7 @@ 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 | \fB\-checkds\fP [\fB\-key\fP \fIid\fP] [\fB\-when\fP \fItime\fP] ( \fIpublished\fP | \fIwithdrawn\fP )) \fIzone\fP [\fIclass\fP [\fIview\fP]] +\fBdnssec\fP ( \fB\-status\fP | \fB\-checkds\fP [\fB\-key\fP \fIid\fP [\fB\-alg\fP \fIalgorithm\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 @@ -172,9 +172,10 @@ zone. 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\&. +is only one key acting as a KSK in the zone, assume the DS of that key (if +there are multiple keys with the same tag, use \fB\-alg algorithm\fP to +select the correct algorithm). 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 diff --git a/lib/dns/include/dns/keymgr.h b/lib/dns/include/dns/keymgr.h index 3e8ad6af30..cdbc791efe 100644 --- a/lib/dns/include/dns/keymgr.h +++ b/lib/dns/include/dns/keymgr.h @@ -57,12 +57,13 @@ dns_keymgr_checkds(dns_kasp_t *kasp, dns_dnsseckeylist_t *keyring, 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); + dns_keytag_t id, unsigned int algorithm); /*%< * 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. + * If the 'algorithm' is non-zero, it must match the key's algorithm. * The result is stored in the key state file. * * Requires: diff --git a/lib/dns/keymgr.c b/lib/dns/keymgr.c index c8a5badb78..1a24786c39 100644 --- a/lib/dns/keymgr.c +++ b/lib/dns/keymgr.c @@ -1873,7 +1873,7 @@ failure: 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) { + dns_keytag_t id, unsigned int alg, bool check_id) { int options = (DST_TYPE_PRIVATE | DST_TYPE_PUBLIC | DST_TYPE_STATE); isc_dir_t dir; isc_result_t result; @@ -1893,6 +1893,9 @@ keymgr_checkds(dns_kasp_t *kasp, dns_dnsseckeylist_t *keyring, if (check_id && dst_key_id(dkey->key) != id) { continue; } + if (alg > 0 && dst_key_alg(dkey->key) != alg) { + continue; + } if (ksk_key != NULL) { /* @@ -1935,16 +1938,16 @@ keymgr_checkds(dns_kasp_t *kasp, dns_dnsseckeylist_t *keyring, 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, + return (keymgr_checkds(kasp, keyring, directory, now, dspublish, 0, 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) { + dns_keytag_t id, unsigned int alg) { return (keymgr_checkds(kasp, keyring, directory, now, dspublish, id, - true)); + alg, true)); } static void