]> git.ipfire.org Git - thirdparty/bind9.git/commitdiff
Check NSEC3 signer matches the owning zone
authorEvan Hunt <each@isc.org>
Thu, 21 May 2026 21:41:55 +0000 (14:41 -0700)
committerMichał Kępień <michal@isc.org>
Fri, 10 Jul 2026 07:26:46 +0000 (09:26 +0200)
When validating NSEC3 records, reject any signature whose signer field
does not match the zone owning the NSEC3.

This ensures that a child zone cannot impersonate its parent and forge
NXDOMAIN responses for sibling domains.

Fixes: isc-projects/bind9#5874
lib/dns/dnssec.c
lib/isc/result.c

index d71d1e68b9720276fa472b012889b5ccf7b9b6ee..f7aae5126c3e0edc63d7d18239f88b01508783ee 100644 (file)
@@ -409,10 +409,25 @@ dns_dnssec_verify(const dns_name_t *name, dns_rdataset_t *set, dst_key_t *key,
        }
 
        /*
-        * NS, SOA and DNSKEY records are signed by their owner.
-        * DS records are signed by the parent.
+        * NS, SOA and DNSKEY records are signed by their owners.
+        * NSEC3 records are signed by the apex, exactly one level up
+        * from their owner names.
+        * DS records are signed by the parent zone.
         */
        switch (set->type) {
+       case dns_rdatatype_nsec3: {
+               dns_name_t apex = DNS_NAME_INITEMPTY;
+               labels = dns_name_countlabels(name);
+               if (labels <= 1) {
+                       inc_stat(dns_dnssecstats_fail);
+                       return DNS_R_INVALIDNSEC3;
+               }
+               dns_name_split(name, labels - 1, NULL, &apex);
+               if (!dns_name_equal(&apex, &sig.signer)) {
+                       inc_stat(dns_dnssecstats_fail);
+                       return DNS_R_SIGINVALID;
+               }
+       } break;
        case dns_rdatatype_ns:
        case dns_rdatatype_soa:
        case dns_rdatatype_dnskey:
index 5b2fbb4ac849cca5a584303e47877ad1f7805938..14308233dadbc030e59540691345b95d70d7169a 100644 (file)
@@ -184,7 +184,7 @@ static const char *description[ISC_R_NRESULTS] = {
        [DNS_R_COVERINGNSEC] = "covering NSEC record returned",
        [DNS_R_MXISADDRESS] = "MX is an address",
        [DNS_R_DUPLICATE] = "duplicate query",
-       [DNS_R_INVALIDNSEC3] = "invalid NSEC3 owner name (wildcard)",
+       [DNS_R_INVALIDNSEC3] = "invalid NSEC3 owner name",
        [DNS_R_NOTPRIMARY] = "not primary",
        [DNS_R_BROKENCHAIN] = "broken trust chain",
        [DNS_R_EXPIRED] = "expired",