Merge branch '1554-cds-cdnskey-consistency-checks-don-t-work-with-deletion-records-v9_14' into 'v9_14'

Resolve "CDS / CDNSKEY consistency checks don't work with deletion records"

See merge request isc-projects/bind9!2977
This commit is contained in:
Mark Andrews 2020-01-30 23:08:02 +00:00
commit f3cf7ccaa1
5 changed files with 185 additions and 33 deletions

View file

@ -1,3 +1,6 @@
5351. [bug] CDS / CDNSKEY consistency checks failed to handle
removal records. [GL #1554]
5350. [bug] When a view was configured with class CHAOS, the
server could crash while processing a query for a
non-existent record. [GL #1540]

View file

@ -24,9 +24,9 @@ rm -f ./canonical?.*
rm -f ./delv.out*
rm -f ./delve.out*
rm -f ./dig.out.*
rm -f ./dnssectools.out*
rm -f ./dsfromkey.out.*
rm -f ./keygen.err
rm -f ./dnssectools.out*
rm -f ./named.secroots.test*
rm -f ./nosign.before
rm -f ./ns*/*.nta
@ -37,11 +37,13 @@ rm -f ./ns1/root.db ./ns2/example.db ./ns2/managed.db ./ns2/trusted.db
rm -f ./ns2/algroll.db
rm -f ./ns2/badparam.db ./ns2/badparam.db.bad
rm -f ./ns2/cdnskey-kskonly.secure.db
rm -f ./ns2/cdnskey-kskonly.secure.id
rm -f ./ns2/cdnskey-update.secure.db
rm -f ./ns2/cdnskey-x.secure.db
rm -f ./ns2/cdnskey.secure.db
rm -f ./ns2/cds-auto.secure.db ./ns2/cds-auto.secure.db.jnl
rm -f ./ns2/cds-kskonly.secure.db
rm -f ./ns2/cds-kskonly.secure.id
rm -f ./ns2/cds-update.secure.db ./ns2/cds-update.secure.db.jnl
rm -f ./ns2/cds.secure.db ./ns2/cds-x.secure.db
rm -f ./ns2/dlv.db
@ -50,8 +52,6 @@ rm -f ./ns2/nsec3chain-test.db
rm -f ./ns2/private.secure.example.db
rm -f ./ns2/single-nsec3.db
rm -f ./ns2/updatecheck-kskonly.secure.*
rm -f ./ns3/secure.example.db ./ns3/*.managed.db ./ns3/*.trusted.db
rm -f ./ns3/unsupported.managed.db.tmp ./ns3/unsupported.trusted.db.tmp
rm -f ./ns3/auto-nsec.example.db ./ns3/auto-nsec3.example.db
rm -f ./ns3/badds.example.db
rm -f ./ns3/dname-at-apex-nsec3.example.db
@ -59,10 +59,10 @@ rm -f ./ns3/dnskey-nsec3-unknown.example.db
rm -f ./ns3/dnskey-nsec3-unknown.example.db.tmp
rm -f ./ns3/dnskey-unknown.example.db
rm -f ./ns3/dnskey-unknown.example.db.tmp
rm -f ./ns3/dnskey-unsupported.example.db
rm -f ./ns3/dnskey-unsupported.example.db.tmp
rm -f ./ns3/dnskey-unsupported-2.example.db
rm -f ./ns3/dnskey-unsupported-2.example.db.tmp
rm -f ./ns3/dnskey-unsupported.example.db
rm -f ./ns3/dnskey-unsupported.example.db.tmp
rm -f ./ns3/dynamic.example.db ./ns3/dynamic.example.db.signed.jnl
rm -f ./ns3/expired.example.db ./ns3/update-nsec3.example.db
rm -f ./ns3/expiring.example.db ./ns3/nosign.example.db
@ -82,6 +82,7 @@ rm -f ./ns3/publish-inactive.example.db
rm -f ./ns3/revkey.example.db
rm -f ./ns3/rsasha256.example.db ./ns3/rsasha512.example.db
rm -f ./ns3/secure.below-cname.example.db
rm -f ./ns3/secure.example.db ./ns3/*.managed.db ./ns3/*.trusted.db
rm -f ./ns3/secure.nsec3.example.db
rm -f ./ns3/secure.optout.example.db
rm -f ./ns3/siginterval.conf
@ -91,6 +92,7 @@ rm -f ./ns3/split-smart.example.db
rm -f ./ns3/ttlpatch.example.db ./ns3/ttlpatch.example.db.signed
rm -f ./ns3/ttlpatch.example.db.patched
rm -f ./ns3/unsecure.example.db ./ns3/bogus.example.db ./ns3/keyless.example.db
rm -f ./ns3/unsupported.managed.db.tmp ./ns3/unsupported.trusted.db.tmp
rm -f ./ns4/managed-keys.bind*
rm -f ./ns4/named_dump.db*
rm -f ./ns6/optout-tld.db

View file

@ -263,6 +263,7 @@ key1=$("$KEYGEN" -q -a "$DEFAULT_ALGORITHM" -b "$DEFAULT_BITS" -n zone -f KSK "$
key2=$("$KEYGEN" -q -a "$DEFAULT_ALGORITHM" -b "$DEFAULT_BITS" -n zone "$zone")
cat "$infile" "$key1.key" "$key2.key" > "$zonefile"
"$SIGNER" -P -g -o "$zone" "$zonefile" > /dev/null 2>&1
keyfile_to_key_id "$key1" > cds-kskonly.secure.id
zone=cds-auto.secure
infile=cds-auto.secure.db.in
@ -306,6 +307,7 @@ key1=$("$KEYGEN" -q -a "$DEFAULT_ALGORITHM" -b "$DEFAULT_BITS" -n zone -f KSK "$
key2=$("$KEYGEN" -q -a "$DEFAULT_ALGORITHM" -b "$DEFAULT_BITS" -n zone "$zone")
cat "$infile" "$key1.key" "$key2.key" > "$zonefile"
"$SIGNER" -P -g -o "$zone" "$zonefile" > /dev/null 2>&1
keyfile_to_key_id "$key1" > cdnskey-kskonly.secure.id
zone=cdnskey-auto.secure
infile=cdnskey-auto.secure.db.in

View file

@ -3377,6 +3377,24 @@ n=$((n+1))
test "$ret" -eq 0 || echo_i "failed"
status=$((status+ret))
echo_i "check that a CDS deletion record is accepted ($n)"
ret=0
(
echo zone cds-update.secure
echo server 10.53.0.2 "$PORT"
echo update delete cds-update.secure CDS
echo update add cds-update.secure 0 CDS 0 0 0 00
echo send
) | $NSUPDATE > nsupdate.out.test$n 2>&1
dig_with_opts +noall +answer @10.53.0.2 cds cds-update.secure > dig.out.test$n
lines=$(awk '$4 == "CDS" {print}' dig.out.test$n | wc -l)
test "${lines:-10}" -eq 1 || ret=1
lines=$(awk '$4 == "CDS" && $5 == "0" && $6 == "0" && $7 == "0" && $8 == "00" {print}' dig.out.test$n | wc -l)
test "$lines" -eq 1 || ret=1
n=$((n+1))
test "$ret" -eq 0 || echo_i "failed"
status=$((status+ret))
echo_i "check that CDS records are signed using KSK when added by nsupdate ($n)"
ret=0
(
@ -3402,6 +3420,7 @@ status=$((status+ret))
echo_i "check that CDS records are signed only using KSK when added by"
echo_i " nsupdate when dnssec-dnskey-kskonly is yes ($n)"
ret=0
keyid=$(cat ns2/cds-kskonly.secure.id)
(
echo zone cds-kskonly.secure
echo server 10.53.0.2 "$PORT"
@ -3416,12 +3435,38 @@ echo send
dig_with_opts +noall +answer @10.53.0.2 cds cds-kskonly.secure > dig.out.test$n
lines=$(awk '$4 == "RRSIG" && $5 == "CDS" {print}' dig.out.test$n | wc -l)
test "$lines" -eq 1 || ret=1
lines=$(awk -v id="${keyid}" '$4 == "RRSIG" && $5 == "CDS" && $11 == id {print}' dig.out.test$n | wc -l)
test "$lines" -eq 1 || ret=1
lines=$(awk '$4 == "CDS" {print}' dig.out.test$n | wc -l)
test "$lines" -eq 2 || ret=1
n=$((n+1))
test "$ret" -eq 0 || echo_i "failed"
status=$((status+ret))
echo_i "check that CDS deletion records are signed only using KSK when added by"
echo_i " nsupdate when dnssec-dnskey-kskonly is yes ($n)"
ret=0
keyid=$(cat ns2/cds-kskonly.secure.id)
(
echo zone cds-kskonly.secure
echo server 10.53.0.2 "$PORT"
echo update delete cds-kskonly.secure CDS
echo update add cds-kskonly.secure 0 CDS 0 0 0 00
echo send
) | $NSUPDATE
dig_with_opts +noall +answer @10.53.0.2 cds cds-kskonly.secure > dig.out.test$n
lines=$(awk '$4 == "RRSIG" && $5 == "CDS" {print}' dig.out.test$n | wc -l)
test "$lines" -eq 1 || ret=1
lines=$(awk -v id="${keyid}" '$4 == "RRSIG" && $5 == "CDS" && $11 == id {print}' dig.out.test$n | wc -l)
test "$lines" -eq 1 || ret=1
lines=$(awk '$4 == "CDS" {print}' dig.out.test$n | wc -l)
test "$lines" -eq 1 || ret=1
lines=$(awk '$4 == "CDS" && $5 == "0" && $6 == "0" && $7 == "0" && $8 == "00" {print}' dig.out.test$n | wc -l)
test "$lines" -eq 1 || ret=1
n=$((n+1))
test "$ret" -eq 0 || echo_i "failed"
status=$((status+ret))
echo_i "checking that positive unknown NSEC3 hash algorithm with OPTOUT does validate ($n)"
ret=0
dig_with_opts +noauth +noadd +nodnssec +adflag @10.53.0.3 optout-unknown.example SOA > dig.out.ns3.test$n
@ -3557,6 +3602,24 @@ n=$((n+1))
test "$ret" -eq 0 || echo_i "failed"
status=$((status+ret))
echo_i "check that a CDNSKEY deletion record is accepted ($n)"
ret=0
(
echo zone cdnskey-update.secure
echo server 10.53.0.2 "$PORT"
echo update delete cdnskey-update.secure CDNSKEY
echo update add cdnskey-update.secure 0 CDNSKEY 0 3 0 AA==
echo send
) | $NSUPDATE > nsupdate.out.test$n 2>&1
dig_with_opts +noall +answer @10.53.0.2 cdnskey cdnskey-update.secure > dig.out.test$n
lines=$(awk '$4 == "CDNSKEY" {print}' dig.out.test$n | wc -l)
test "${lines:-10}" -eq 1 || ret=1
lines=$(awk '$4 == "CDNSKEY" && $5 == "0" && $6 == "3" && $7 == "0" && $8 == "AA==" {print}' dig.out.test$n | wc -l)
test "${lines:-10}" -eq 1 || ret=1
n=$((n+1))
test "$ret" -eq 0 || echo_i "failed"
status=$((status+ret))
echo_i "checking that unknown DNSKEY algorithm + unknown NSEC3 has algorithm validates as insecure ($n)"
ret=0
dig_with_opts +noauth +noadd +nodnssec +adflag @10.53.0.3 dnskey-nsec3-unknown.example A > dig.out.ns3.test$n
@ -3590,6 +3653,7 @@ status=$((status+ret))
echo_i "check that CDNSKEY records are signed only using KSK when added by"
echo_i " nsupdate when dnssec-dnskey-kskonly is yes ($n)"
ret=0
keyid=$(cat ns2/cdnskey-kskonly.secure.id)
(
echo zone cdnskey-kskonly.secure
echo server 10.53.0.2 "$PORT"
@ -3601,12 +3665,38 @@ echo send
dig_with_opts +noall +answer @10.53.0.2 cdnskey cdnskey-kskonly.secure > dig.out.test$n
lines=$(awk '$4 == "RRSIG" && $5 == "CDNSKEY" {print}' dig.out.test$n | wc -l)
test "$lines" -eq 1 || ret=1
lines=$(awk -v id="${keyid}" '$4 == "RRSIG" && $5 == "CDNSKEY" && $11 == id {print}' dig.out.test$n | wc -l)
test "$lines" -eq 1 || ret=1
lines=$(awk '$4 == "CDNSKEY" {print}' dig.out.test$n | wc -l)
test "$lines" -eq 1 || ret=1
n=$((n+1))
test "$ret" -eq 0 || echo_i "failed"
status=$((status+ret))
echo_i "check that CDNSKEY deletion records are signed only using KSK when added by"
echo_i " nsupdate when dnssec-dnskey-kskonly is yes ($n)"
ret=0
keyid=$(cat ns2/cdnskey-kskonly.secure.id)
(
echo zone cdnskey-kskonly.secure
echo server 10.53.0.2 "$PORT"
echo update delete cdnskey-kskonly.secure CDNSKEY
echo update add cdnskey-kskonly.secure 0 CDNSKEY 0 3 0 AA==
echo send
) | $NSUPDATE
dig_with_opts +noall +answer @10.53.0.2 cdnskey cdnskey-kskonly.secure > dig.out.test$n
lines=$(awk '$4 == "RRSIG" && $5 == "CDNSKEY" {print}' dig.out.test$n | wc -l)
test "$lines" -eq 1 || ret=1
lines=$(awk -v id="${keyid}" '$4 == "RRSIG" && $5 == "CDNSKEY" && $11 == id {print}' dig.out.test$n | wc -l)
test "$lines" -eq 1 || ret=1
lines=$(awk '$4 == "CDNSKEY" {print}' dig.out.test$n | wc -l)
test "$lines" -eq 1 || ret=1
lines=$(awk '$4 == "CDNSKEY" && $5 == "0" && $6 == "3" && $7 == "0" && $8 == "AA==" {print}' dig.out.test$n | wc -l)
test "${lines:-10}" -eq 1 || ret=1
n=$((n+1))
test "$ret" -eq 0 || echo_i "failed"
status=$((status+ret))
echo_i "checking initialization with a revoked managed key ($n)"
ret=0
copy_setports ns5/named2.conf.in ns5/named.conf

View file

@ -18985,11 +18985,14 @@ dns_zone_cdscheck(dns_zone_t *zone, dns_db_t *db, dns_dbversion_t *version) {
unsigned char algorithms[256];
unsigned int i;
enum { notexpected = 0, expected = 1, found = 2 };
REQUIRE(DNS_ZONE_VALID(zone));
result = dns_db_getoriginnode(db, &node);
if (result != ISC_R_SUCCESS)
if (result != ISC_R_SUCCESS) {
return (result);
}
dns_rdataset_init(&cds);
dns_rdataset_init(&dnskey);
@ -18997,16 +19000,19 @@ dns_zone_cdscheck(dns_zone_t *zone, dns_db_t *db, dns_dbversion_t *version) {
result = dns_db_findrdataset(db, node, version, dns_rdatatype_cds,
dns_rdatatype_none, 0, &cds, NULL);
if (result != ISC_R_SUCCESS && result != ISC_R_NOTFOUND)
if (result != ISC_R_SUCCESS && result != ISC_R_NOTFOUND) {
goto failure;
}
result = dns_db_findrdataset(db, node, version, dns_rdatatype_cdnskey,
dns_rdatatype_none, 0, &cdnskey, NULL);
if (result != ISC_R_SUCCESS && result != ISC_R_NOTFOUND)
if (result != ISC_R_SUCCESS && result != ISC_R_NOTFOUND) {
goto failure;
}
if (!dns_rdataset_isassociated(&cds) &&
!dns_rdataset_isassociated(&cdnskey)) {
!dns_rdataset_isassociated(&cdnskey))
{
result = ISC_R_SUCCESS;
goto failure;
}
@ -19014,21 +19020,25 @@ dns_zone_cdscheck(dns_zone_t *zone, dns_db_t *db, dns_dbversion_t *version) {
result = dns_db_findrdataset(db, node, version, dns_rdatatype_dnskey,
dns_rdatatype_none, 0, &dnskey, NULL);
if (result == ISC_R_NOTFOUND) {
if (dns_rdataset_isassociated(&cds))
if (dns_rdataset_isassociated(&cds)) {
result = DNS_R_BADCDS;
else
} else {
result = DNS_R_BADCDNSKEY;
}
goto failure;
}
if (result != ISC_R_SUCCESS)
if (result != ISC_R_SUCCESS) {
goto failure;
}
/*
* For each DNSSEC algorithm in the CDS RRset there must be
* a matching DNSKEY record.
* a matching DNSKEY record with the exception of a CDS deletion
* record which must be by itself.
*/
if (dns_rdataset_isassociated(&cds)) {
memset(algorithms, 0, sizeof(algorithms));
bool delete = false;
memset(algorithms, notexpected, sizeof(algorithms));
for (result = dns_rdataset_first(&cds);
result == ISC_R_SUCCESS;
result = dns_rdataset_next(&cds)) {
@ -19036,9 +19046,21 @@ dns_zone_cdscheck(dns_zone_t *zone, dns_db_t *db, dns_dbversion_t *version) {
dns_rdata_cds_t structcds;
dns_rdataset_current(&cds, &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)
{
delete = true;
continue;
}
CHECK(dns_rdata_tostruct(&crdata, &structcds, NULL));
if (algorithms[structcds.algorithm] == 0)
algorithms[structcds.algorithm] = 1;
if (algorithms[structcds.algorithm] == 0) {
algorithms[structcds.algorithm] = expected;
}
for (result = dns_rdataset_first(&dnskey);
result == ISC_R_SUCCESS;
result = dns_rdataset_next(&dnskey)) {
@ -19051,16 +19073,23 @@ dns_zone_cdscheck(dns_zone_t *zone, dns_db_t *db, dns_dbversion_t *version) {
buffer, &dsrdata));
if (crdata.length == dsrdata.length &&
memcmp(crdata.data, dsrdata.data,
dsrdata.length) == 0) {
algorithms[structcds.algorithm] = 2;
dsrdata.length) == 0)
{
algorithms[structcds.algorithm] = found;
}
}
if (result != ISC_R_NOMORE)
if (result != ISC_R_NOMORE) {
goto failure;
}
}
for (i = 0; i < sizeof(algorithms); i++) {
if (algorithms[i] == 1) {
result = DNS_R_BADCDNSKEY;
if (delete) {
if (algorithms[i] != notexpected) {
result = DNS_R_BADCDS;
goto failure;
}
} else if (algorithms[i] == expected) {
result = DNS_R_BADCDS;
goto failure;
}
}
@ -19068,10 +19097,12 @@ dns_zone_cdscheck(dns_zone_t *zone, dns_db_t *db, dns_dbversion_t *version) {
/*
* For each DNSSEC algorithm in the CDNSKEY RRset there must be
* a matching DNSKEY record.
* a matching DNSKEY record with the exception of a CDNSKEY deletion
* record which must be by itself.
*/
if (dns_rdataset_isassociated(&cdnskey)) {
memset(algorithms, 0, sizeof(algorithms));
bool delete = false;
memset(algorithms, notexpected, sizeof(algorithms));
for (result = dns_rdataset_first(&cdnskey);
result == ISC_R_SUCCESS;
result = dns_rdataset_next(&cdnskey)) {
@ -19079,10 +19110,23 @@ dns_zone_cdscheck(dns_zone_t *zone, dns_db_t *db, dns_dbversion_t *version) {
dns_rdata_cdnskey_t structcdnskey;
dns_rdataset_current(&cdnskey, &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)
{
delete = true;
continue;
}
CHECK(dns_rdata_tostruct(&crdata, &structcdnskey,
NULL));
if (algorithms[structcdnskey.algorithm] == 0)
algorithms[structcdnskey.algorithm] = 1;
if (algorithms[structcdnskey.algorithm] == 0) {
algorithms[structcdnskey.algorithm] = expected;
}
for (result = dns_rdataset_first(&dnskey);
result == ISC_R_SUCCESS;
result = dns_rdataset_next(&dnskey)) {
@ -19091,16 +19135,24 @@ dns_zone_cdscheck(dns_zone_t *zone, dns_db_t *db, dns_dbversion_t *version) {
dns_rdataset_current(&dnskey, &rdata);
if (crdata.length == rdata.length &&
memcmp(crdata.data, rdata.data,
rdata.length) == 0) {
algorithms[structcdnskey.algorithm] = 2;
rdata.length) == 0)
{
algorithms[structcdnskey.algorithm] =
found;
}
}
if (result != ISC_R_NOMORE)
if (result != ISC_R_NOMORE) {
goto failure;
}
}
for (i = 0; i < sizeof(algorithms); i++) {
if (algorithms[i] == 1) {
result = DNS_R_BADCDS;
if (delete) {
if (algorithms[i] != notexpected) {
result = DNS_R_BADCDNSKEY;
goto failure;
}
} else if (algorithms[i] == expected) {
result = DNS_R_BADCDNSKEY;
goto failure;
}
}
@ -19108,12 +19160,15 @@ dns_zone_cdscheck(dns_zone_t *zone, dns_db_t *db, dns_dbversion_t *version) {
result = ISC_R_SUCCESS;
failure:
if (dns_rdataset_isassociated(&cds))
if (dns_rdataset_isassociated(&cds)) {
dns_rdataset_disassociate(&cds);
if (dns_rdataset_isassociated(&dnskey))
}
if (dns_rdataset_isassociated(&dnskey)) {
dns_rdataset_disassociate(&dnskey);
if (dns_rdataset_isassociated(&cdnskey))
}
if (dns_rdataset_isassociated(&cdnskey)) {
dns_rdataset_disassociate(&cdnskey);
}
dns_db_detachnode(db, &node);
return (result);
}