Backport upstream commit af84538a2ce6 to fix CVE-2026-13321.
The patch adds validation in dns_dnssec_verify() to reject
out-of-zone NSEC next owner names by checking that the NSEC
next name is a subdomain of the signer field, as required by
RFC 4034 section 4.1.1.
CVE: CVE-2026-13321
Upstream patches:
- af84538a2c.patch
Resolves: RHEL-213313
This commit was backported by Ymir, a Red Hat Enterprise Linux software maintenance AI agent.
Assisted-by: Ymir
86 lines
3.0 KiB
Diff
86 lines
3.0 KiB
Diff
From db08a828d3a2fae9bdcc901645d63adcd9d090eb Mon Sep 17 00:00:00 2001
|
|
From: =?UTF-8?q?Ayd=C4=B1n=20Mercan?= <aydin@isc.org>
|
|
Date: Thu, 7 May 2026 18:59:20 +0300
|
|
Subject: [PATCH] Reject out-of-zone NSEC next owner names
|
|
|
|
When verifying DNSSEC records, make sure that a next owner name of
|
|
an NSEC record is a subdomain of the signer field.
|
|
|
|
This follows the specification RFC 4034, section 4.1.1:
|
|
|
|
Owner names of RRsets for which the given zone is not authoritative
|
|
(such as glue records) MUST NOT be listed in the Next Domain Name
|
|
unless at least one authoritative RRset exists at the same owner
|
|
name.
|
|
|
|
While the above paragraph is intended for glue records, it also
|
|
applies to out-of-zone data.
|
|
|
|
(cherry picked from commit 4065512d25b71605b9502bb69dfb903776d35aa9)
|
|
---
|
|
lib/dns/dnssec.c | 17 +++++++++++++++++
|
|
lib/dns/include/dns/dnssec.h | 6 ++++++
|
|
2 files changed, 23 insertions(+)
|
|
|
|
diff --git a/lib/dns/dnssec.c b/lib/dns/dnssec.c
|
|
index c168fed..2ab9c02 100644
|
|
--- a/lib/dns/dnssec.c
|
|
+++ b/lib/dns/dnssec.c
|
|
@@ -376,8 +376,10 @@ isc_result_t
|
|
dns_dnssec_verify(const dns_name_t *name, dns_rdataset_t *set, dst_key_t *key,
|
|
bool ignoretime, unsigned int maxbits, isc_mem_t *mctx,
|
|
dns_rdata_t *sigrdata, dns_name_t *wild) {
|
|
+ dns_rdata_nsec_t nsec;
|
|
dns_rdata_rrsig_t sig;
|
|
dns_fixedname_t fnewname;
|
|
+ dns_rdata_t rdata = DNS_RDATA_INIT;
|
|
isc_region_t r;
|
|
isc_buffer_t envbuf;
|
|
dns_rdata_t *rdatas;
|
|
@@ -451,6 +453,21 @@ dns_dnssec_verify(const dns_name_t *name, dns_rdataset_t *set, dst_key_t *key,
|
|
}
|
|
break;
|
|
}
|
|
+ /*
|
|
+ * Check for out of zone NSEC entries.
|
|
+ */
|
|
+ if (set->type == dns_rdatatype_nsec) {
|
|
+ if (dns_rdataset_first(set) != ISC_R_SUCCESS) {
|
|
+ return (DNS_R_NOVALIDNSEC);
|
|
+ }
|
|
+ dns_rdataset_current(set, &rdata);
|
|
+ if (dns_rdata_tostruct(&rdata, &nsec, NULL) != ISC_R_SUCCESS) {
|
|
+ return (DNS_R_NOVALIDNSEC);
|
|
+ }
|
|
+ if (!dns_name_issubdomain(&nsec.next, &sig.signer)) {
|
|
+ return (DNS_R_NOVALIDNSEC);
|
|
+ }
|
|
+ }
|
|
|
|
/*
|
|
* Is the key allowed to sign data?
|
|
diff --git a/lib/dns/include/dns/dnssec.h b/lib/dns/include/dns/dnssec.h
|
|
index e74ec47..c811e25 100644
|
|
--- a/lib/dns/include/dns/dnssec.h
|
|
+++ b/lib/dns/include/dns/dnssec.h
|
|
@@ -133,6 +133,9 @@ dns_dnssec_verify(const dns_name_t *name, dns_rdataset_t *set, dst_key_t *key,
|
|
* this record, as this requires a resolver or database.
|
|
* If 'ignoretime' is true, temporal validity will not be checked.
|
|
*
|
|
+ * If 'set' is of type NSEC, this function also verifies that the
|
|
+ * Next Name is a subdomain of the Signer's Name from 'sigrdata'.
|
|
+ *
|
|
* 'maxbits' specifies the maximum number of rsa exponent bits accepted.
|
|
*
|
|
* Requires:
|
|
@@ -155,6 +158,9 @@ dns_dnssec_verify(const dns_name_t *name, dns_rdataset_t *set, dst_key_t *key,
|
|
*\li #DNS_R_KEYUNAUTHORIZED - the key cannot sign this data (either
|
|
* it is not a zone key or its flags prevent
|
|
* authentication)
|
|
+ *
|
|
+ *\li #DNS_R_NOVALIDNSEC - the NSEC rdata is not valid
|
|
+ *\li #DNS_R_KEYUNAUTHORIZED - the key cannot sign this data
|
|
*\li DST_R_*
|
|
*/
|
|
|