Merge branch '2931-cds-delete-removed-on-signing-v9_18' into 'v9_18'

[v9_18] Don't delete CDS DELETE after zone sign

See merge request isc-projects/bind9!6126
This commit is contained in:
Matthijs Mekking 2022-04-13 13:12:04 +00:00
commit da30a638a2
13 changed files with 294 additions and 50 deletions

View file

@ -1,3 +1,6 @@
5858. [bug] Don't remove CDS/CDNSKEY DELETE records on zone sign
when using 'auto-dnssec maintain;'. [GL #2931]
5856. [bug] The "starting maxtime timer" message related to outgoing
zone transfers was incorrectly logged at the ERROR level
instead of DEBUG(1). [GL #3208]

View file

@ -35,6 +35,8 @@ rm -f ns2/private.secure.example.db ns2/bar.db
rm -f ns3/*.nzd ns3/*.nzd-lock ns3/*.nzf
rm -f ns3/*.nzf
rm -f ns3/autonsec3.example.db
rm -f ns3/cdnskey-delete.example.db
rm -f ns3/cds-delete.example.db
rm -f ns3/delzsk.example.db
rm -f ns3/dname-at-apex-nsec3.example.db
rm -f ns3/inacksk2.example.db

View file

@ -16,8 +16,9 @@
# Have the child generate subdomain keys and pass DS sets to us.
( cd ../ns3 && $SHELL keygen.sh )
for subdomain in secure nsec3 autonsec3 optout rsasha256 rsasha512 nsec3-to-nsec oldsigs sync \
dname-at-apex-nsec3
for subdomain in secure nsec3 autonsec3 optout rsasha256 rsasha512 \
nsec3-to-nsec oldsigs sync dname-at-apex-nsec3 cds-delete \
cdnskey-delete
do
cp ../ns3/dsset-$subdomain.example. .
done

View file

@ -0,0 +1,28 @@
; Copyright (C) Internet Systems Consortium, Inc. ("ISC")
;
; SPDX-License-Identifier: MPL-2.0
;
; This Source Code Form is subject to the terms of the Mozilla Public
; License, v. 2.0. If a copy of the MPL was not distributed with this
; file, You can obtain one at http://mozilla.org/MPL/2.0/.
;
; See the COPYRIGHT file distributed with this work for additional
; information regarding copyright ownership.
$TTL 300 ; 5 minutes
@ IN SOA mname1. . (
2009102722 ; serial
20 ; refresh (20 seconds)
20 ; retry (20 seconds)
1814400 ; expire (3 weeks)
3600 ; minimum (1 hour)
)
NS ns
ns A 10.53.0.3
a A 10.0.0.1
b A 10.0.0.2
d A 10.0.0.4
z A 10.0.0.26
a.a.a.a.a.a.a.a.a.a.e A 10.0.0.27
x CNAME a

View file

@ -0,0 +1,28 @@
; Copyright (C) Internet Systems Consortium, Inc. ("ISC")
;
; SPDX-License-Identifier: MPL-2.0
;
; This Source Code Form is subject to the terms of the Mozilla Public
; License, v. 2.0. If a copy of the MPL was not distributed with this
; file, You can obtain one at http://mozilla.org/MPL/2.0/.
;
; See the COPYRIGHT file distributed with this work for additional
; information regarding copyright ownership.
$TTL 300 ; 5 minutes
@ IN SOA mname1. . (
2009102722 ; serial
20 ; refresh (20 seconds)
20 ; retry (20 seconds)
1814400 ; expire (3 weeks)
3600 ; minimum (1 hour)
)
NS ns
ns A 10.53.0.3
a A 10.0.0.1
b A 10.0.0.2
d A 10.0.0.4
z A 10.0.0.26
a.a.a.a.a.a.a.a.a.a.e A 10.0.0.27
x CNAME a

View file

@ -332,7 +332,7 @@ $KEYGEN -a $DEFAULT_ALGORITHM -3 -q -P now -A now+3600 $zone > kg.out 2>&1 || du
$DSFROMKEY $ksk.key > dsset-${zone}.
#
# A zone that starts with a active KSK + ZSK and a inactive ZSK.
# A zone that starts with a active KSK + ZSK and a inactive ZSK.
#
setup inacksk3.example
cp $infile $zonefile
@ -342,7 +342,7 @@ $KEYGEN -a $DEFAULT_ALGORITHM -3 -q $zone > kg.out 2>&1 || dumpit kg.out
$DSFROMKEY $ksk.key > dsset-${zone}.
#
# A zone that starts with a active KSK + ZSK and a inactive ZSK.
# A zone that starts with a active KSK + ZSK and a inactive ZSK.
#
setup inaczsk3.example
cp $infile $zonefile
@ -363,10 +363,29 @@ zsk=`$KEYGEN -a $DEFAULT_ALGORITHM -3 -q -I now-1w $zone 2>kg.out` || dumpit kg.
echo $zsk > ../delzsk.key
#
# Check that NSEC3 are correctly signed and returned from below a DNAME
# Check that NSEC3 are correctly signed and returned from below a DNAME
#
setup dname-at-apex-nsec3.example
cp $infile $zonefile
ksk=`$KEYGEN -q -a $DEFAULT_ALGORITHM -3 -fk $zone 2> kg.out` || dumpit kg.out
$KEYGEN -q -a $DEFAULT_ALGORITHM -3 $zone > kg.out 2>&1 || dumpit kg.out
$DSFROMKEY $ksk.key > dsset-${zone}.
#
# Check that dynamically added CDS (DELETE) is kept in the zone after signing.
#
setup cds-delete.example
cp $infile $zonefile
ksk=`$KEYGEN -q -a $DEFAULT_ALGORITHM -3 -fk $zone 2> kg.out` || dumpit kg.out
$KEYGEN -q -a $DEFAULT_ALGORITHM -3 $zone > kg.out 2>&1 || dumpit kg.out
$DSFROMKEY $ksk.key > dsset-${zone}.
#
# Check that dynamically added CDNSKEY (DELETE) is kept in the zone after
# signing.
#
setup cdnskey-delete.example
cp $infile $zonefile
ksk=`$KEYGEN -q -a $DEFAULT_ALGORITHM -3 -fk $zone 2> kg.out` || dumpit kg.out
$KEYGEN -q -a $DEFAULT_ALGORITHM -3 $zone > kg.out 2>&1 || dumpit kg.out
$DSFROMKEY $ksk.key > dsset-${zone}.

View file

@ -318,4 +318,18 @@ zone "dname-at-apex-nsec3.example" {
auto-dnssec maintain;
};
zone "cds-delete.example" {
type primary;
file "cds-delete.example.db";
allow-update { any; };
auto-dnssec maintain;
};
zone "cdnskey-delete.example" {
type primary;
file "cdnskey-delete.example.db";
allow-update { any; };
auto-dnssec maintain;
};
include "trusted.conf";

View file

@ -1645,6 +1645,89 @@ inac=`grep "DNSKEY .* is now inactive" ns1/named.run | wc -l`
[ "$inac" -eq 1 ] || ret=1
del=`grep "DNSKEY .* is now deleted" ns1/named.run | wc -l`
[ "$del" -eq 1 ] || ret=1
n=`expr $n + 1`
if [ $ret != 0 ]; then echo_i "failed"; fi
status=`expr $status + $ret`
echo_i "checking that CDS (DELETE) persists after zone sign ($n)"
echo_i "update add cds-delete.example. CDS 0 0 00"
ret=0
$NSUPDATE > nsupdate.out 2>&1 <<END
server 10.53.0.3 ${PORT}
zone cds-delete.example.
update add cds-delete.example. 3600 CDS 0 0 0 00
send
END
_cds_delete() (
$DIG $DIGOPTS +noall +answer $1 cds @10.53.0.3 > dig.out.ns3.test$n || return 1
grep "CDS.*0.*0.*0.*00" dig.out.ns3.test$n > /dev/null 2>&1 || return 1
return 0
)
_cdnskey_delete_nx() {
$DIG $DIGOPTS +noall +answer $1 cdnskey @10.53.0.3 > dig.out.ns3.test$n || return 1
grep "CDNSKEY.*0.*3.*0.*AA==" dig.out.ns3.test$n > /dev/null 2>&1 && return 1
return 0
}
echo_i "query cds-delete.example. CDS"
retry_quiet 10 _cds_delete cds-delete.example. || ret=1
echo_i "query cds-delete.example. CDNSKEY"
retry_quiet 1 _cdnskey_delete_nx cds-delete.example. || ret=1
echo_i "sign cds-delete.example."
nextpart ns3/named.run >/dev/null
$RNDCCMD 10.53.0.3 sign cds-delete.example > /dev/null 2>&1 || ret=1
wait_for_log 10 "zone cds-delete.example/IN: next key event" ns3/named.run
# The CDS (DELETE) record should still be here.
echo_i "query cds-delete.example. CDS"
retry_quiet 1 _cds_delete cds-delete.example. || ret=1
# The CDNSKEY (DELETE) record should still not be added.
echo_i "query cds-delete.example. CDNSKEY"
retry_quiet 1 _cdnskey_delete_nx cds-delete.example. || ret=1
n=`expr $n + 1`
if [ $ret != 0 ]; then echo_i "failed"; fi
status=`expr $status + $ret`
echo_i "checking that CDNSKEY (DELETE) persists after zone sign ($n)"
echo_i "update add cdnskey-delete.example. CDNSKEY 0 3 0 AA=="
ret=0
$NSUPDATE > nsupdate.out 2>&1 <<END
server 10.53.0.3 ${PORT}
zone cdnskey-delete.example.
update add cdnskey-delete.example. 3600 CDNSKEY 0 3 0 AA==
send
END
_cds_delete_nx() (
$DIG $DIGOPTS +noall +answer $1 cds @10.53.0.3 > dig.out.ns3.test$n || return 1
grep "CDS.*0.*0.*0.*00" dig.out.ns3.test$n > /dev/null 2>&1 && return 1
return 0
)
_cdnskey_delete() {
$DIG $DIGOPTS +noall +answer $1 cdnskey @10.53.0.3 > dig.out.ns3.test$n || return 1
grep "CDNSKEY.*0.*3.*0.*AA==" dig.out.ns3.test$n > /dev/null 2>&1 || return 1
return 0
}
echo_i "query cdnskey-delete.example. CDNSKEY"
retry_quiet 10 _cdnskey_delete cdnskey-delete.example. || ret=1
echo_i "query cdnskey-delete.example. CDS"
retry_quiet 1 _cds_delete_nx cdnskey-delete.example. || ret=1
echo_i "sign cdsnskey-delete.example."
nextpart ns3/named.run >/dev/null
$RNDCCMD 10.53.0.3 sign cdnskey-delete.example > /dev/null 2>&1 || ret=1
wait_for_log 10 "zone cdnskey-delete.example/IN: next key event" ns3/named.run
# The CDNSKEY (DELETE) record should still be here.
echo_i "query cdnskey-delete.example. CDNSKEY"
retry_quiet 1 _cdnskey_delete cdnskey-delete.example. || ret=1
# The CDS (DELETE) record should still not be added.
echo_i "query cdnskey-delete.example. CDS"
retry_quiet 1 _cds_delete_nx cdnskey-delete.example. || ret=1
n=`expr $n + 1`
if [ $ret != 0 ]; then echo_i "failed"; fi
status=`expr $status + $ret`

View file

@ -1067,6 +1067,12 @@ Below is an example showing how to remove DS records using the
Revert to Unsigned Step #4
If your parent allows managing DS record via CDS/CDNSKEY, as described in
:rfc:`5155`, you could add CDS/CDNSKEY DELETE records in your zone to signal
that the corresponding DS records from the parent zone needs to be removed.
If it is unclear which format the parent zone is expecting, you should publish
both CDS and CDNSKEY DELETE records.
To be on the safe side, wait a while before actually deleting
all signed data from your zone, just in case some validating resolvers
have cached information. After you are certain that all cached
@ -1099,7 +1105,8 @@ Then use :option:`rndc reload` to reload the zone.
The "insecure" policy is a built-in policy (like "default"). It will make sure
the zone is still DNSSEC maintained, to allow for a graceful transition to
unsigned.
unsigned. It also publishes the CDS and CDNSKEY DELETE records for you when
the time is right.
When the DS records have been removed from the parent zone, use
:option:`rndc dnssec -checkds -key id withdrawn example.com <rndc dnssec>` to tell :iscman:`named` that

View file

@ -40,4 +40,5 @@ Feature Changes
Bug Fixes
~~~~~~~~~
- None.
- CDS and CDNSKEY DELETE records are removed from the zone when configured with
'auto-dnssec maintain;'. This has been fixed. :gl:`#2931`.

View file

@ -2143,7 +2143,7 @@ isc_result_t
dns_dnssec_syncdelete(dns_rdataset_t *cds, dns_rdataset_t *cdnskey,
dns_name_t *origin, dns_rdataclass_t zclass,
dns_ttl_t ttl, dns_diff_t *diff, isc_mem_t *mctx,
bool dnssec_insecure) {
bool expect_cds_delete, bool expect_cdnskey_delete) {
unsigned char dsbuf[5] = { 0, 0, 0, 0, 0 }; /* CDS DELETE rdata */
unsigned char keybuf[5] = { 0, 0, 3, 0, 0 }; /* CDNSKEY DELETE rdata */
char namebuf[DNS_NAME_FORMATSIZE];
@ -2163,7 +2163,30 @@ dns_dnssec_syncdelete(dns_rdataset_t *cds, dns_rdataset_t *cdnskey,
dns_name_format(origin, namebuf, sizeof(namebuf));
if (dnssec_insecure) {
if (expect_cds_delete) {
if (!dns_rdataset_isassociated(cds) ||
!exists(cds, &cds_delete)) {
isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL,
DNS_LOGMODULE_DNSSEC, ISC_LOG_INFO,
"CDS (DELETE) for zone %s is now "
"published",
namebuf);
RETERR(addrdata(&cds_delete, diff, origin, ttl, mctx));
}
} else {
if (dns_rdataset_isassociated(cds) && exists(cds, &cds_delete))
{
isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL,
DNS_LOGMODULE_DNSSEC, ISC_LOG_INFO,
"CDS (DELETE) for zone %s is now "
"deleted",
namebuf);
RETERR(delrdata(&cds_delete, diff, origin, cds->ttl,
mctx));
}
}
if (expect_cdnskey_delete) {
if (!dns_rdataset_isassociated(cdnskey) ||
!exists(cdnskey, &cdnskey_delete)) {
isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL,
@ -2174,16 +2197,6 @@ dns_dnssec_syncdelete(dns_rdataset_t *cds, dns_rdataset_t *cdnskey,
RETERR(addrdata(&cdnskey_delete, diff, origin, ttl,
mctx));
}
if (!dns_rdataset_isassociated(cds) ||
!exists(cds, &cds_delete)) {
isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL,
DNS_LOGMODULE_DNSSEC, ISC_LOG_INFO,
"CDS (DELETE) for zone %s is now "
"published",
namebuf);
RETERR(addrdata(&cds_delete, diff, origin, ttl, mctx));
}
} else {
if (dns_rdataset_isassociated(cdnskey) &&
exists(cdnskey, &cdnskey_delete)) {
@ -2195,17 +2208,6 @@ dns_dnssec_syncdelete(dns_rdataset_t *cds, dns_rdataset_t *cdnskey,
RETERR(delrdata(&cdnskey_delete, diff, origin,
cdnskey->ttl, mctx));
}
if (dns_rdataset_isassociated(cds) && exists(cds, &cds_delete))
{
isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL,
DNS_LOGMODULE_DNSSEC, ISC_LOG_INFO,
"CDS (DELETE) for zone %s is now "
"deleted",
namebuf);
RETERR(delrdata(&cds_delete, diff, origin, cds->ttl,
mctx));
}
}
result = ISC_R_SUCCESS;

View file

@ -369,11 +369,14 @@ isc_result_t
dns_dnssec_syncdelete(dns_rdataset_t *cds, dns_rdataset_t *cdnskey,
dns_name_t *origin, dns_rdataclass_t zclass,
dns_ttl_t ttl, dns_diff_t *diff, isc_mem_t *mctx,
bool dnssec_insecure);
bool expect_cds_delete, bool expect_cdnskey_delete);
/*%<
* Add or remove the CDS DELETE record and the CDNSKEY DELETE record.
* If 'dnssec_insecure' is true, the DELETE records should be present.
* Otherwise, the DELETE records must be removed from the RRsets (if present).
* If 'expect_cds_delete' is true, the CDS DELETE record should be present.
* Otherwise, the CDS DELETE record must be removed from the RRsets (if
* present). If 'expect_cdnskey_delete' is true, the CDNSKEY DELETE record
* should be present. Otherwise, the CDNSKEY DELETE record must be removed
* from the RRsets (if present).
*
* Returns:
*\li ISC_R_SUCCESS

View file

@ -21688,16 +21688,69 @@ zone_rekey(dns_zone_t *zone) {
KASP_UNLOCK(kasp);
if (result == ISC_R_SUCCESS) {
bool cds_delete = false;
bool cdsdel = false;
bool cdnskeydel = false;
isc_stdtime_t when;
/*
* Publish CDS/CDNSKEY DELETE records if the zone is
* transitioning from secure to insecure.
*/
if (kasp != NULL &&
strcmp(dns_kasp_getname(kasp), "insecure") == 0) {
cds_delete = true;
if (kasp != NULL) {
if (strcmp(dns_kasp_getname(kasp), "insecure") == 0) {
cdsdel = true;
cdnskeydel = true;
}
} else {
/* Check if there is a CDS DELETE record. */
if (dns_rdataset_isassociated(&cdsset)) {
for (result = dns_rdataset_first(&cdsset);
result == ISC_R_SUCCESS;
result = dns_rdataset_next(&cdsset))
{
dns_rdata_t crdata = DNS_RDATA_INIT;
dns_rdataset_current(&cdsset, &crdata);
/*
* CDS deletion record has this form
* "0 0 0 00" which is 5 zero octets.
*/
if (crdata.length == 5U &&
memcmp(crdata.data,
(unsigned char[5]){ 0, 0, 0,
0, 0 },
5) == 0)
{
cdsdel = true;
break;
}
}
}
/* Check if there is a CDNSKEY DELETE record. */
if (dns_rdataset_isassociated(&cdnskeyset)) {
for (result = dns_rdataset_first(&cdnskeyset);
result == ISC_R_SUCCESS;
result = dns_rdataset_next(&cdnskeyset))
{
dns_rdata_t crdata = DNS_RDATA_INIT;
dns_rdataset_current(&cdnskeyset,
&crdata);
/*
* CDNSKEY deletion record has this form
* "0 3 0 AA==" which is 2 zero octets,
* a 3, and 2 zero octets.
*/
if (crdata.length == 5U &&
memcmp(crdata.data,
(unsigned char[5]){ 0, 0, 3,
0, 0 },
5) == 0)
{
cdnskeydel = true;
break;
}
}
}
}
/*
@ -21734,36 +21787,36 @@ zone_rekey(dns_zone_t *zone) {
goto failure;
}
if (cds_delete) {
if (cdsdel || cdnskeydel) {
/*
* Only publish CDS/CDNSKEY DELETE records if there is
* a KSK that can be used to verify the RRset. This
* means there must be a key with the KSK role that is
* published and is used for signing.
*/
cds_delete = false;
bool allow = false;
for (key = ISC_LIST_HEAD(dnskeys); key != NULL;
key = ISC_LIST_NEXT(key, link)) {
dst_key_t *dstk = key->key;
bool ksk = false;
(void)dst_key_getbool(dstk, DST_BOOL_KSK, &ksk);
if (!ksk) {
continue;
}
if (dst_key_haskasp(dstk) &&
dst_key_is_published(dstk, now, &when) &&
if (dst_key_is_published(dstk, now, &when) &&
dst_key_is_signing(dstk, DST_BOOL_KSK, now,
&when))
{
cds_delete = true;
allow = true;
break;
}
}
if (cdsdel) {
cdsdel = allow;
}
if (cdnskeydel) {
cdnskeydel = allow;
}
}
result = dns_dnssec_syncdelete(&cdsset, &cdnskeyset,
&zone->origin, zone->rdclass,
ttl, &diff, mctx, cds_delete);
result = dns_dnssec_syncdelete(
&cdsset, &cdnskeyset, &zone->origin, zone->rdclass, ttl,
&diff, mctx, cdsdel, cdnskeydel);
if (result != ISC_R_SUCCESS) {
dnssec_log(zone, ISC_LOG_ERROR,
"zone_rekey:couldn't update CDS/CDNSKEY "