64 lines
2.2 KiB
Diff
64 lines
2.2 KiB
Diff
From 01bb483cbf162b79dde64f7005f2cbc76aaee96e Mon Sep 17 00:00:00 2001
|
|
From: Evan Hunt <each@isc.org>
|
|
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/isc/result.c | 2 +-
|
|
2 files changed, 18 insertions(+), 3 deletions(-)
|
|
|
|
diff --git a/lib/dns/dnssec.c b/lib/dns/dnssec.c
|
|
index 662136db87..d6259f939e 100644
|
|
--- a/lib/dns/dnssec.c
|
|
+++ b/lib/dns/dnssec.c
|
|
@@ -424,10 +424,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 DNSSKEY 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/isc/result.c b/lib/isc/result.c
|
|
index 493c1a5309..5e242ac285 100644
|
|
--- a/lib/isc/result.c
|
|
+++ b/lib/isc/result.c
|
|
@@ -198,7 +198,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",
|