diff --git a/bin/tests/system/dnssec/tests.sh b/bin/tests/system/dnssec/tests.sh index 89e98de86f..e3f47640db 100644 --- a/bin/tests/system/dnssec/tests.sh +++ b/bin/tests/system/dnssec/tests.sh @@ -3362,6 +3362,25 @@ 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 +( +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 '$4 == "CDS" {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 diff --git a/lib/dns/zone.c b/lib/dns/zone.c index a625d689f9..ade48d8a59 100644 --- a/lib/dns/zone.c +++ b/lib/dns/zone.c @@ -19177,9 +19177,11 @@ dns_zone_cdscheck(dns_zone_t *zone, dns_db_t *db, dns_dbversion_t *version) { /* * 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)) { + bool delete = false; memset(algorithms, 0, sizeof(algorithms)); for (result = dns_rdataset_first(&cds); result == ISC_R_SUCCESS; @@ -19188,6 +19190,16 @@ 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, "\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; @@ -19211,7 +19223,12 @@ dns_zone_cdscheck(dns_zone_t *zone, dns_db_t *db, dns_dbversion_t *version) { goto failure; } for (i = 0; i < sizeof(algorithms); i++) { - if (algorithms[i] == 1) { + if (delete) { + if (algorithms[i] != 0) { + result = DNS_R_BADCDNSKEY; + goto failure; + } + } else if (algorithms[i] == 1) { result = DNS_R_BADCDNSKEY; goto failure; }