From a0945f6337fb4a27fb7104838ee51d3722e1e9a0 Mon Sep 17 00:00:00 2001 From: Mark Andrews Date: Thu, 7 Aug 2025 14:37:33 +1000 Subject: [PATCH 1/4] Use signer name when disabling DNSSEC algorithms When disabling algorithms, use the signer name to determine if the algorithm is disabled or not. This allows for algorithms to be cleanly disabled on a zone level basis. Previously, just using the records owner name, "disable-algorithms" could impact resolution of names that where not disabled. This does now mean that "disable-algorithms" can not be used to disable part of a zone anymore. --- .../dnssec/ns3/badalg.secure.example.db.in | 22 +++++++++++++++++++ bin/tests/system/dnssec/ns3/named.conf.j2 | 6 +++++ .../system/dnssec/ns3/secure.example.db.in | 4 +++- bin/tests/system/dnssec/ns3/sign.sh | 16 +++++++++++++- bin/tests/system/dnssec/tests_validation.py | 8 +++++++ lib/dns/validator.c | 5 +++-- lib/ns/query.c | 4 ++-- 7 files changed, 59 insertions(+), 6 deletions(-) create mode 100644 bin/tests/system/dnssec/ns3/badalg.secure.example.db.in diff --git a/bin/tests/system/dnssec/ns3/badalg.secure.example.db.in b/bin/tests/system/dnssec/ns3/badalg.secure.example.db.in new file mode 100644 index 0000000000..93cb34385c --- /dev/null +++ b/bin/tests/system/dnssec/ns3/badalg.secure.example.db.in @@ -0,0 +1,22 @@ +; Copyright (C) Internet Systems Consortium, Inc. ("ISC") +; +; SPDX-License-Identifier: MPL-2.0 +; +; This Source Code Form is subject to the terms of the Mozilla Public +; License, v. 2.0. If a copy of the MPL was not distributed with this +; file, you can obtain one at https://mozilla.org/MPL/2.0/. +; +; See the COPYRIGHT file distributed with this work for additional +; information regarding copyright ownership. + +$TTL 300 ; 5 minutes +@ IN SOA mname1. . ( + 2000042407 ; serial + 20 ; refresh (20 seconds) + 20 ; retry (20 seconds) + 1814400 ; expire (3 weeks) + 3600 ; minimum (1 hour) + ) + NS ns3 + A 10.53.0.4 +ns3 A 10.53.0.3 diff --git a/bin/tests/system/dnssec/ns3/named.conf.j2 b/bin/tests/system/dnssec/ns3/named.conf.j2 index 6c9e18976c..bfaa553369 100644 --- a/bin/tests/system/dnssec/ns3/named.conf.j2 +++ b/bin/tests/system/dnssec/ns3/named.conf.j2 @@ -93,6 +93,12 @@ zone "secure.example" { allow-update { any; }; }; +zone "badalg.secure.example" { + type primary; + file "badalg.secure.example.db.signed"; + allow-update { any; }; +}; + zone "bogus.example" { type primary; file "bogus.example.db.signed"; diff --git a/bin/tests/system/dnssec/ns3/secure.example.db.in b/bin/tests/system/dnssec/ns3/secure.example.db.in index decb1eb3f0..fa8e398ff0 100644 --- a/bin/tests/system/dnssec/ns3/secure.example.db.in +++ b/bin/tests/system/dnssec/ns3/secure.example.db.in @@ -30,7 +30,9 @@ g A 10.0.0.7 z A 10.0.0.26 a.a.a.a.a.a.a.a.a.a.e A 10.0.0.27 x CNAME a -badalg A 10.53.0.4 + +badalg NS ns3.badalg +ns3.badalg A 10.53.0.3 private NS ns.private ns.private A 10.53.0.2 diff --git a/bin/tests/system/dnssec/ns3/sign.sh b/bin/tests/system/dnssec/ns3/sign.sh index b7ec530e3c..c611b61e4f 100644 --- a/bin/tests/system/dnssec/ns3/sign.sh +++ b/bin/tests/system/dnssec/ns3/sign.sh @@ -85,6 +85,20 @@ cp template.db.in insecure.optout.example.db cp extrakey.example.db.in extrakey.example.db # now the signed zones: + +# A zone that will be treated as insecure as the DEFAULT_ALGORITHM is +# disabled for it. +zone=badalg.secure.example. +infile=badalg.secure.example.db.in +zonefile=badalg.secure.example.db + +keyname=$("$KEYGEN" -q -a "$DEFAULT_ALGORITHM" -b "$DEFAULT_BITS" "$zone") + +cat "$infile" "$keyname.key" >"$zonefile" + +"$SIGNER" -z -o "$zone" "$zonefile" >/dev/null + +# zone=secure.example. infile=secure.example.db.in zonefile=secure.example.db @@ -93,7 +107,7 @@ cnameandkey=$("$KEYGEN" -T KEY -q -a "$DEFAULT_ALGORITHM" -b "$DEFAULT_BITS" "cn dnameandkey=$("$KEYGEN" -T KEY -q -a "$DEFAULT_ALGORITHM" -b "$DEFAULT_BITS" "dnameandkey.$zone") keyname=$("$KEYGEN" -q -a "$DEFAULT_ALGORITHM" -b "$DEFAULT_BITS" "$zone") -cat "$infile" "$cnameandkey.key" "$dnameandkey.key" "$keyname.key" >"$zonefile" +cat "$infile" dsset-badalg.secure.example. "$cnameandkey.key" "$dnameandkey.key" "$keyname.key" >"$zonefile" "$SIGNER" -z -D -o "$zone" "$zonefile" >/dev/null cat "$zonefile" "$zonefile".signed >"$zonefile".tmp diff --git a/bin/tests/system/dnssec/tests_validation.py b/bin/tests/system/dnssec/tests_validation.py index 95d1dbb5c4..fdd529c310 100644 --- a/bin/tests/system/dnssec/tests_validation.py +++ b/bin/tests/system/dnssec/tests_validation.py @@ -1326,6 +1326,14 @@ def test_unknown_algorithms(): res.extended_errors()[0].code == edns.EDECode.UNSUPPORTED_DNSKEY_ALGORITHM ) + # check that DS records are still treated as secure at the + # disable-algorithm name + msg = isctest.query.create("badalg.secure.example", "DS") + res = isctest.query.tcp(msg, "10.53.0.4") + isctest.check.rr_count_eq(res.answer, 2) + isctest.check.noerror(res) + isctest.check.adflag(res) + # check both EDE code 1 and 2 for unsupported digest on one DNSKEY # and unsupported algorithm on the other msg = isctest.query.create("a.digest-alg-unsupported.example", "A") diff --git a/lib/dns/validator.c b/lib/dns/validator.c index 6ce9607f22..e81146763b 100644 --- a/lib/dns/validator.c +++ b/lib/dns/validator.c @@ -1675,8 +1675,9 @@ validate_answer_process(void *arg) { * was known and "sufficiently good". */ if (!dns_resolver_algorithm_supported( - val->view->resolver, val->name, val->siginfo->algorithm, - val->siginfo->signature, val->siginfo->siglen)) + val->view->resolver, &val->siginfo->signer, + val->siginfo->algorithm, val->siginfo->signature, + val->siginfo->siglen)) { if (val->unsupported_algorithm == 0) { val->unsupported_algorithm = val->siginfo->algorithm; diff --git a/lib/ns/query.c b/lib/ns/query.c index 26a5c2c8b4..47d02947c3 100644 --- a/lib/ns/query.c +++ b/lib/ns/query.c @@ -2541,8 +2541,8 @@ validate(ns_client_t *client, dns_db_t *db, dns_name_t *name, result = dns_rdata_tostruct(&rdata, &rrsig, NULL); RUNTIME_CHECK(result == ISC_R_SUCCESS); if (!dns_resolver_algorithm_supported( - client->inner.view->resolver, name, rrsig.algorithm, - rrsig.signature, rrsig.siglen)) + client->inner.view->resolver, &rrsig.signer, + rrsig.algorithm, rrsig.signature, rrsig.siglen)) { char txt[DNS_NAME_FORMATSIZE + 32]; isc_buffer_t buffer; From 21934102d3be19729af78cba08f974984de3488e Mon Sep 17 00:00:00 2001 From: Mark Andrews Date: Thu, 7 Aug 2025 16:27:32 +1000 Subject: [PATCH 2/4] Check that badalg.secure.example resolves Previously, badalg.secure.example would return SERVFAIL because the DS records (from the parent) could not be validated. --- bin/tests/system/dnssec/tests_validation.py | 1 + 1 file changed, 1 insertion(+) diff --git a/bin/tests/system/dnssec/tests_validation.py b/bin/tests/system/dnssec/tests_validation.py index fdd529c310..025ec80f3b 100644 --- a/bin/tests/system/dnssec/tests_validation.py +++ b/bin/tests/system/dnssec/tests_validation.py @@ -1320,6 +1320,7 @@ def test_unknown_algorithms(): # check EDE code 1 for bad algorithm mnemonic msg = isctest.query.create("badalg.secure.example", "A") res = isctest.query.tcp(msg, "10.53.0.4") + isctest.check.noerror(res) isctest.check.noadflag(res) if hasattr(res, "extended_errors"): assert ( From 28848ab57839689cf894fffb36d4638c89d9230c Mon Sep 17 00:00:00 2001 From: Mark Andrews Date: Tue, 9 Sep 2025 16:57:35 +1000 Subject: [PATCH 3/4] Make it clearer that disable-algorithms applies to zone names --- doc/arm/reference.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/arm/reference.rst b/doc/arm/reference.rst index 7cb67f01fe..3a761cfd1b 100644 --- a/doc/arm/reference.rst +++ b/doc/arm/reference.rst @@ -1618,7 +1618,7 @@ default is used. :short: Disables DNSSEC algorithms from a specified zone. This disables the specified DNSSEC algorithms at and below the specified - name. Multiple :any:`disable-algorithms` statements are allowed. Only + zone. Multiple :any:`disable-algorithms` statements are allowed. Only the best-match :any:`disable-algorithms` clause is used to determine the algorithms. From 81d3a29e4ef0730871bdc4954a5c4b6fd3e030b8 Mon Sep 17 00:00:00 2001 From: Matthijs Mekking Date: Tue, 23 Sep 2025 15:36:56 +0200 Subject: [PATCH 4/4] Check disable-algorithms with non-zone names Test that if disable-algorithms is configured on a name that is below the zonecut, it still validates (z.secure.example). Test that if disable-algorithms is configured on a name that is above the zonecut, it is treated as insecure (zonecut.ent.secure.example). --- bin/tests/system/dnssec/ns3/named.conf.j2 | 6 +++++ .../system/dnssec/ns3/secure.example.db.in | 3 +++ bin/tests/system/dnssec/ns3/sign.sh | 12 ++++++++++ .../ns3/zonecut.ent.secure.example.db.in | 22 +++++++++++++++++++ bin/tests/system/dnssec/ns4/named.conf.j2 | 2 ++ bin/tests/system/dnssec/tests_validation.py | 19 ++++++++++++++++ 6 files changed, 64 insertions(+) create mode 100644 bin/tests/system/dnssec/ns3/zonecut.ent.secure.example.db.in diff --git a/bin/tests/system/dnssec/ns3/named.conf.j2 b/bin/tests/system/dnssec/ns3/named.conf.j2 index bfaa553369..1a0edc14bb 100644 --- a/bin/tests/system/dnssec/ns3/named.conf.j2 +++ b/bin/tests/system/dnssec/ns3/named.conf.j2 @@ -99,6 +99,12 @@ zone "badalg.secure.example" { allow-update { any; }; }; +zone "zonecut.ent.secure.example" { + type primary; + file "zonecut.ent.secure.example.db.signed"; + allow-update { any; }; +}; + zone "bogus.example" { type primary; file "bogus.example.db.signed"; diff --git a/bin/tests/system/dnssec/ns3/secure.example.db.in b/bin/tests/system/dnssec/ns3/secure.example.db.in index fa8e398ff0..104d39ff6c 100644 --- a/bin/tests/system/dnssec/ns3/secure.example.db.in +++ b/bin/tests/system/dnssec/ns3/secure.example.db.in @@ -34,6 +34,9 @@ x CNAME a badalg NS ns3.badalg ns3.badalg A 10.53.0.3 +zonecut.ent NS ns3.zonecut.ent +ns3.zonecut.ent A 10.53.0.3 + private NS ns.private ns.private A 10.53.0.2 diff --git a/bin/tests/system/dnssec/ns3/sign.sh b/bin/tests/system/dnssec/ns3/sign.sh index c611b61e4f..5512888b2f 100644 --- a/bin/tests/system/dnssec/ns3/sign.sh +++ b/bin/tests/system/dnssec/ns3/sign.sh @@ -98,6 +98,18 @@ cat "$infile" "$keyname.key" >"$zonefile" "$SIGNER" -z -o "$zone" "$zonefile" >/dev/null +# A zone that will be treated as insecure as the DEFAULT_ALGORITHM is +# disabled for ent.secure.example. +zone=zonecut.ent.secure.example. +infile=zonecut.ent.secure.example.db.in +zonefile=zonecut.ent.secure.example.db + +keyname=$("$KEYGEN" -q -a "$DEFAULT_ALGORITHM" -b "$DEFAULT_BITS" "$zone") + +cat "$infile" "$keyname.key" >"$zonefile" + +"$SIGNER" -z -o "$zone" "$zonefile" >/dev/null + # zone=secure.example. infile=secure.example.db.in diff --git a/bin/tests/system/dnssec/ns3/zonecut.ent.secure.example.db.in b/bin/tests/system/dnssec/ns3/zonecut.ent.secure.example.db.in new file mode 100644 index 0000000000..93cb34385c --- /dev/null +++ b/bin/tests/system/dnssec/ns3/zonecut.ent.secure.example.db.in @@ -0,0 +1,22 @@ +; Copyright (C) Internet Systems Consortium, Inc. ("ISC") +; +; SPDX-License-Identifier: MPL-2.0 +; +; This Source Code Form is subject to the terms of the Mozilla Public +; License, v. 2.0. If a copy of the MPL was not distributed with this +; file, you can obtain one at https://mozilla.org/MPL/2.0/. +; +; See the COPYRIGHT file distributed with this work for additional +; information regarding copyright ownership. + +$TTL 300 ; 5 minutes +@ IN SOA mname1. . ( + 2000042407 ; serial + 20 ; refresh (20 seconds) + 20 ; retry (20 seconds) + 1814400 ; expire (3 weeks) + 3600 ; minimum (1 hour) + ) + NS ns3 + A 10.53.0.4 +ns3 A 10.53.0.3 diff --git a/bin/tests/system/dnssec/ns4/named.conf.j2 b/bin/tests/system/dnssec/ns4/named.conf.j2 index 9a67908bde..bc3e2fd87b 100644 --- a/bin/tests/system/dnssec/ns4/named.conf.j2 +++ b/bin/tests/system/dnssec/ns4/named.conf.j2 @@ -50,6 +50,8 @@ options { disable-ds-digests "digest-alg-unsupported.example." { "SHA384"; "SHA-384"; }; disable-ds-digests "ds-unsupported.example." { "SHA256"; "SHA-256"; "SHA384"; "SHA-384"; }; disable-algorithms "badalg.secure.example." { ECDSAP256SHA256; }; + disable-algorithms "z.secure.example." { ECDSAP256SHA256; }; + disable-algorithms "ent.secure.example." { ECDSAP256SHA256; }; }; {% if not managed_key %} diff --git a/bin/tests/system/dnssec/tests_validation.py b/bin/tests/system/dnssec/tests_validation.py index 025ec80f3b..338f7f4e71 100644 --- a/bin/tests/system/dnssec/tests_validation.py +++ b/bin/tests/system/dnssec/tests_validation.py @@ -1327,6 +1327,25 @@ def test_unknown_algorithms(): res.extended_errors()[0].code == edns.EDECode.UNSUPPORTED_DNSKEY_ALGORITHM ) + # check that zone contents are still secure despite disable-algorithms + # on query name (name below zone name). + msg = isctest.query.create("z.secure.example", "A") + res = isctest.query.tcp(msg, "10.53.0.4") + isctest.check.rr_count_eq(res.answer, 2) + isctest.check.noerror(res) + isctest.check.adflag(res) + + # check that zone contents are trated insecure (name above zone name). + msg = isctest.query.create("zonecut.ent.secure.example", "A") + res = isctest.query.tcp(msg, "10.53.0.4") + isctest.check.rr_count_eq(res.answer, 2) + isctest.check.noerror(res) + isctest.check.noadflag(res) + if hasattr(res, "extended_errors"): + assert ( + res.extended_errors()[0].code == edns.EDECode.UNSUPPORTED_DNSKEY_ALGORITHM + ) + # check that DS records are still treated as secure at the # disable-algorithm name msg = isctest.query.create("badalg.secure.example", "DS")