bind/bind-9.18-CVE-2025-8677.patch

224 lines
6.5 KiB
Diff

From b76aec47a318a1f1c0664b329697e41e4d94427c Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Ond=C5=99ej=20Sur=C3=BD?= <ondrej@isc.org>
Date: Tue, 22 Jul 2025 08:07:02 +0200
Subject: [PATCH] Fail the DNSSEC validation if matching but invalid DNSKEY is
found
If a matching but cryptographically invalid key was encountered during
the DNSSEC validation, the key would be just skipped and not counted
towards validation failures. Treat such DNSSEC keys as hard failures
and fail the DNSSEC validation immediatelly instead of continuing the
DNSSEC validation with the next DNSKEYs in the RRset.
Co-authored-by: Matthijs Mekking <matthijs@isc.org>
(cherry picked from commit f00117a4226be90d1bc865aff19bddf114242914)
(cherry picked from commit 7c5b8ef055900224f0424c341927562c5a9ebe19)
Fix an issue with selfsigned_dnskey() return value
The selfsigned_dnskey() function currently returns boolean. There
was a recent change to make it return a isc_result_t error code,
which is implicitly converted to bool, which is obviously an error.
If instead of the result code we return true/false, it still doesn't
indicate the error to the caller that has happened before.
Change the function to return isc_result_t, and change the caller
routine to process the new return type.
(cherry picked from commit 40c396ba2d955c32d70db04e900e40bf96519c59)
---
lib/dns/validator.c | 79 +++++++++++++++++++++++++++++----------------
1 file changed, 51 insertions(+), 28 deletions(-)
diff --git a/lib/dns/validator.c b/lib/dns/validator.c
index 712fc0755a..15e177e4d7 100644
--- a/lib/dns/validator.c
+++ b/lib/dns/validator.c
@@ -431,6 +431,8 @@ fetch_callback_dnskey(isc_task_t *task, isc_event_t *event) {
result = select_signing_key(val, rdataset);
if (result == ISC_R_SUCCESS) {
val->keyset = &val->frdataset;
+ } else {
+ val->failed = true;
}
}
result = validate_answer(val, true);
@@ -1161,6 +1163,8 @@ select_signing_key(dns_validator_t *val, dns_rdataset_t *rdataset) {
goto done;
}
dst_key_free(&val->key);
+ } else {
+ break;
}
dns_rdata_reset(&rdata);
result = dns_rdataset_next(rdataset);
@@ -1285,13 +1289,15 @@ seek_dnskey(dns_validator_t *val) {
"keyset with trust %s",
dns_trust_totext(val->frdataset.trust));
result = select_signing_key(val, val->keyset);
- if (result != ISC_R_SUCCESS) {
+ if (result == ISC_R_NOTFOUND) {
/*
- * Either the key we're looking for is not
- * in the rrset, or something bad happened.
- * Give up.
+ * The key we're looking for is not
+ * in the rrset
*/
result = DNS_R_CONTINUE;
+ } else if (result != ISC_R_SUCCESS) {
+ /* Something bad happened. Give up. */
+ break;
}
}
break;
@@ -1352,17 +1358,17 @@ compute_keytag(dns_rdata_t *rdata) {
/*%
* Is the DNSKEY rrset in val->event->rdataset self-signed?
*/
-static bool
+static isc_result_t
selfsigned_dnskey(dns_validator_t *val) {
dns_rdataset_t *rdataset = val->event->rdataset;
dns_rdataset_t *sigrdataset = val->event->sigrdataset;
dns_name_t *name = val->event->name;
isc_result_t result;
isc_mem_t *mctx = val->view->mctx;
- bool answer = false;
+ bool match = false;
if (rdataset->type != dns_rdatatype_dnskey) {
- return false;
+ return DNS_R_NOKEYMATCH;
}
for (result = dns_rdataset_first(rdataset); result == ISC_R_SUCCESS;
@@ -1384,8 +1390,6 @@ selfsigned_dnskey(dns_validator_t *val) {
result == ISC_R_SUCCESS;
result = dns_rdataset_next(sigrdataset))
{
- dst_key_t *dstkey = NULL;
-
dns_rdata_reset(&sigrdata);
dns_rdataset_current(sigrdataset, &sigrdata);
result = dns_rdata_tostruct(&sigrdata, &sig, NULL);
@@ -1400,18 +1404,16 @@ selfsigned_dnskey(dns_validator_t *val) {
/*
* If the REVOKE bit is not set we have a
- * theoretically self signed DNSKEY RRset.
- * This will be verified later.
+ * theoretically self-signed DNSKEY RRset;
+ * this will be verified later.
+ *
+ * We don't return the answer yet, though,
+ * because we need to check the remaining keys
+ * and possbly remove them if they're revoked.
*/
if ((key.flags & DNS_KEYFLAG_REVOKE) == 0) {
- answer = true;
- continue;
- }
-
- result = dns_dnssec_keyfromrdata(name, &keyrdata, mctx,
- &dstkey);
- if (result != ISC_R_SUCCESS) {
- continue;
+ match = true;
+ break;
}
/*
@@ -1421,6 +1423,14 @@ selfsigned_dnskey(dns_validator_t *val) {
if (DNS_TRUST_PENDING(rdataset->trust) &&
dns_view_istrusted(val->view, name, &key))
{
+ dst_key_t *dstkey = NULL;
+
+ result = dns_dnssec_keyfromrdata(
+ name, &keyrdata, mctx, &dstkey);
+ if (result != ISC_R_SUCCESS) {
+ break;
+ }
+
result = dns_dnssec_verify(
name, rdataset, dstkey, true,
val->view->maxbits, mctx, &sigrdata,
@@ -1433,6 +1443,8 @@ selfsigned_dnskey(dns_validator_t *val) {
*/
dns_view_untrust(val->view, name, &key);
}
+
+ dst_key_free(&dstkey);
} else if (rdataset->trust >= dns_trust_secure) {
/*
* We trust this RRset so if the key is
@@ -1440,12 +1452,14 @@ selfsigned_dnskey(dns_validator_t *val) {
*/
dns_view_untrust(val->view, name, &key);
}
-
- dst_key_free(&dstkey);
}
}
- return answer;
+ if (!match) {
+ return DNS_R_NOKEYMATCH;
+ }
+
+ return ISC_R_SUCCESS;
}
/*%
@@ -1680,10 +1694,7 @@ check_signer(dns_validator_t *val, dns_rdata_t *keyrdata, uint16_t keyid,
val->event->name, keyrdata, val->view->mctx,
&dstkey);
if (result != ISC_R_SUCCESS) {
- /*
- * This really shouldn't happen, but...
- */
- continue;
+ return result;
}
}
result = verify(val, dstkey, &rdata, sig.keyid);
@@ -3064,11 +3075,22 @@ validator_start(isc_task_t *task, isc_event_t *event) {
INSIST(dns_rdataset_isassociated(val->event->rdataset));
INSIST(dns_rdataset_isassociated(val->event->sigrdataset));
- if (selfsigned_dnskey(val)) {
+
+ result = selfsigned_dnskey(val);
+ switch (result) {
+ case ISC_R_SUCCESS:
result = validate_dnskey(val);
- } else {
+ break;
+ case DNS_R_NOKEYMATCH:
result = validate_answer(val, false);
+ break;
+ default:
+ validator_log(val, ISC_LOG_INFO,
+ "invalid selfsigned DNSKEY: %s",
+ isc_result_totext(result));
+ goto cleanup;
}
+
if (result == DNS_R_NOVALIDSIG &&
(val->attributes & VALATTR_TRIEDVERIFY) == 0)
{
@@ -3137,6 +3159,7 @@ validator_start(isc_task_t *task, isc_event_t *event) {
UNREACHABLE();
}
+cleanup:
if (result != DNS_R_WAIT) {
want_destroy = exit_check(val);
validator_done(val, result);
--
2.51.0