From 35e6c3ff81d289627c5b3d63a68187e450740e50 Mon Sep 17 00:00:00 2001 From: Evan Hunt Date: Thu, 21 May 2026 14:41:55 -0700 Subject: [PATCH] Check NSEC3 signer matches the owning zone 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 (cherry picked from commit 6e5066bb1f0f12d090e8707adb7d6ccf74f8012b) --- lib/dns/dnssec.c | 19 +++++++++++++++++-- lib/dns/result.c | 2 +- 2 files changed, 18 insertions(+), 3 deletions(-) diff --git a/lib/dns/dnssec.c b/lib/dns/dnssec.c index c168fed..a91cbe3 100644 --- a/lib/dns/dnssec.c +++ b/lib/dns/dnssec.c @@ -426,10 +426,25 @@ dns_dnssec_verify(const dns_name_t *name, dns_rdataset_t *set, dst_key_t *key, } /* - * NS, SOA and DNSSKEY 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: diff --git a/lib/dns/result.c b/lib/dns/result.c index 01ce2b4..9ff2a3a 100644 --- a/lib/dns/result.c +++ b/lib/dns/result.c @@ -146,7 +146,7 @@ static const char *text[DNS_R_NRESULTS] = { "covering NSEC record returned", /*%< 101 DNS_R_COVERINGNSEC */ "MX is an address", /*%< 102 DNS_R_MXISADDRESS */ "duplicate query", /*%< 103 DNS_R_DUPLICATE */ - "invalid NSEC3 owner name (wildcard)", /*%< 104 DNS_R_INVALIDNSEC3 */ + "invalid NSEC3 owner name", /*%< 104 DNS_R_INVALIDNSEC3 */ "not master", /*%< 105 DNS_R_NOTMASTER */ "broken trust chain", /*%< 106 DNS_R_BROKENCHAIN */