From 2554a724d4e3435491bf797fd25dbdfe83a82665 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. (cherry picked from commit a0945f6337fb4a27fb7104838ee51d3722e1e9a0) --- .../dnssec/ns3/badalg.secure.example.db.in | 22 +++++++++++++++++++ bin/tests/system/dnssec/ns3/named.conf.in | 6 +++++ .../system/dnssec/ns3/secure.example.db.in | 4 +++- bin/tests/system/dnssec/ns3/sign.sh | 15 ++++++++++++- bin/tests/system/dnssec/tests.sh | 10 +++++++++ bin/tests/system/dnssec/tests_sh_dnssec.py | 1 + lib/dns/validator.c | 3 ++- lib/ns/query.c | 3 ++- 8 files changed, 60 insertions(+), 4 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.in b/bin/tests/system/dnssec/ns3/named.conf.in index 293ff2dda8..3b66a9d696 100644 --- a/bin/tests/system/dnssec/ns3/named.conf.in +++ b/bin/tests/system/dnssec/ns3/named.conf.in @@ -91,6 +91,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 9aebd98007..43ad1e557e 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 f61ea28381..3669cd3f7b 100644 --- a/bin/tests/system/dnssec/ns3/sign.sh +++ b/bin/tests/system/dnssec/ns3/sign.sh @@ -77,6 +77,19 @@ done echo_i "ns3/sign.sh: example 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 @@ -85,7 +98,7 @@ cnameandkey=$("$KEYGEN" -T KEY -q -a "$DEFAULT_ALGORITHM" -b "$DEFAULT_BITS" -n dnameandkey=$("$KEYGEN" -T KEY -q -a "$DEFAULT_ALGORITHM" -b "$DEFAULT_BITS" -n host "dnameandkey.$zone") keyname=$("$KEYGEN" -q -a "$DEFAULT_ALGORITHM" -b "$DEFAULT_BITS" -n zone "$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.sh b/bin/tests/system/dnssec/tests.sh index cf7ce13d3a..3702cf7eb4 100644 --- a/bin/tests/system/dnssec/tests.sh +++ b/bin/tests/system/dnssec/tests.sh @@ -3757,6 +3757,16 @@ n=$((n + 1)) test "$ret" -eq 0 || echo_i "failed" status=$((status + ret)) +echo_i "check that DS records are still treated as secure at the disable-algorithm name ($n)" +ret=0 +dig_with_opts @10.53.0.4 badalg.secure.example DS >dig.out.ns4.test$n || ret=1 +grep "ANSWER: 2," dig.out.ns4.test$n >/dev/null || ret=1 +grep "status: NOERROR" dig.out.ns4.test$n >/dev/null || ret=1 +grep "flags:.*ad.*QUERY" dig.out.ns4.test$n >/dev/null || ret=1 +n=$((n + 1)) +test "$ret" -eq 0 || echo_i "failed" +status=$((status + ret)) + echo_i "checking EDE code 1 for bad alg mnemonic ($n)" ret=0 dig_with_opts @10.53.0.4 badalg.secure.example >dig.out.ns4.test$n || ret=1 diff --git a/bin/tests/system/dnssec/tests_sh_dnssec.py b/bin/tests/system/dnssec/tests_sh_dnssec.py index d3350561d9..52730aec0b 100644 --- a/bin/tests/system/dnssec/tests_sh_dnssec.py +++ b/bin/tests/system/dnssec/tests_sh_dnssec.py @@ -79,6 +79,7 @@ pytestmark = pytest.mark.extra_artifacts( "ns3/NSEC3", "ns3/auto-nsec.example.db", "ns3/auto-nsec3.example.db", + "ns3/badalg.secure.example.db", "ns3/badds.example.db", "ns3/bogus.example.db", "ns3/disabled.managed.db", diff --git a/lib/dns/validator.c b/lib/dns/validator.c index 1f7c7154e8..bcbe026f91 100644 --- a/lib/dns/validator.c +++ b/lib/dns/validator.c @@ -1679,7 +1679,8 @@ validate_answer_process(void *arg) { * At this point we could check that the signature algorithm * was known and "sufficiently good". */ - if (!dns_resolver_algorithm_supported(val->view->resolver, val->name, + if (!dns_resolver_algorithm_supported(val->view->resolver, + &val->siginfo->signer, val->siginfo->algorithm)) { if (val->unsupported_algorithm == 0) { diff --git a/lib/ns/query.c b/lib/ns/query.c index 54c541d55d..1710cabb6f 100644 --- a/lib/ns/query.c +++ b/lib/ns/query.c @@ -2504,7 +2504,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->view->resolver, - name, rrsig.algorithm)) + &rrsig.signer, + rrsig.algorithm)) { char txt[DNS_NAME_FORMATSIZE + 32]; isc_buffer_t buffer; From 3a6021beb370835c81c90dd356514499ba1b6bec 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. (cherry picked from commit 21934102d3be19729af78cba08f974984de3488e) --- bin/tests/system/dnssec/tests.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/bin/tests/system/dnssec/tests.sh b/bin/tests/system/dnssec/tests.sh index 3702cf7eb4..a192f5e004 100644 --- a/bin/tests/system/dnssec/tests.sh +++ b/bin/tests/system/dnssec/tests.sh @@ -3771,6 +3771,7 @@ echo_i "checking EDE code 1 for bad alg mnemonic ($n)" ret=0 dig_with_opts @10.53.0.4 badalg.secure.example >dig.out.ns4.test$n || ret=1 grep "; EDE: 1 (Unsupported DNSKEY Algorithm): (ECDSAP256SHA256 badalg.secure.example/A)" dig.out.ns4.test$n >/dev/null || ret=1 +grep "status: NOERROR" dig.out.ns4.test$n >/dev/null || ret=1 grep "flags:.*ad.*QUERY" dig.out.ns4.test$n >/dev/null && ret=1 n=$((n + 1)) test "$ret" -eq 0 || echo_i "failed" From 3ddf4e957b2482cea0ecafc5ea61364a10ead1de 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 (cherry picked from commit 28848ab57839689cf894fffb36d4638c89d9230c) --- 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 82036f2cfe..3fc92abc40 100644 --- a/doc/arm/reference.rst +++ b/doc/arm/reference.rst @@ -1617,7 +1617,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 dd891dd761bd24aef9a019d115760b09728e7ac7 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). (cherry picked from commit 81d3a29e4ef0730871bdc4954a5c4b6fd3e030b8) --- bin/tests/system/dnssec/ns3/named.conf.in | 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/named1.conf.in | 2 ++ bin/tests/system/dnssec/ns4/named2.conf.in | 2 ++ bin/tests/system/dnssec/ns4/named3.conf.in | 2 ++ bin/tests/system/dnssec/ns4/named4.conf.in | 2 ++ bin/tests/system/dnssec/tests.sh | 21 ++++++++++++++++++ bin/tests/system/dnssec/tests_sh_dnssec.py | 3 ++- 10 files changed, 74 insertions(+), 1 deletion(-) create mode 100644 bin/tests/system/dnssec/ns3/zonecut.ent.secure.example.db.in diff --git a/bin/tests/system/dnssec/ns3/named.conf.in b/bin/tests/system/dnssec/ns3/named.conf.in index 3b66a9d696..5eba816b79 100644 --- a/bin/tests/system/dnssec/ns3/named.conf.in +++ b/bin/tests/system/dnssec/ns3/named.conf.in @@ -97,6 +97,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 43ad1e557e..eeb5a4cf49 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 3669cd3f7b..350a504a13 100644 --- a/bin/tests/system/dnssec/ns3/sign.sh +++ b/bin/tests/system/dnssec/ns3/sign.sh @@ -89,6 +89,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/named1.conf.in b/bin/tests/system/dnssec/ns4/named1.conf.in index 8e29a45db7..c3e055f8e9 100644 --- a/bin/tests/system/dnssec/ns4/named1.conf.in +++ b/bin/tests/system/dnssec/ns4/named1.conf.in @@ -34,6 +34,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; }; # Note: We only reference the bind.keys file here to confirm that it # is *not* being used. It contains the real root key, and we're diff --git a/bin/tests/system/dnssec/ns4/named2.conf.in b/bin/tests/system/dnssec/ns4/named2.conf.in index bf82385f71..ab14d44f34 100644 --- a/bin/tests/system/dnssec/ns4/named2.conf.in +++ b/bin/tests/system/dnssec/ns4/named2.conf.in @@ -29,6 +29,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; }; }; key rndc_key { diff --git a/bin/tests/system/dnssec/ns4/named3.conf.in b/bin/tests/system/dnssec/ns4/named3.conf.in index d6a44c799d..be9bb5431a 100644 --- a/bin/tests/system/dnssec/ns4/named3.conf.in +++ b/bin/tests/system/dnssec/ns4/named3.conf.in @@ -32,6 +32,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; }; }; key rndc_key { diff --git a/bin/tests/system/dnssec/ns4/named4.conf.in b/bin/tests/system/dnssec/ns4/named4.conf.in index 34f59b498a..f0dc264ddc 100644 --- a/bin/tests/system/dnssec/ns4/named4.conf.in +++ b/bin/tests/system/dnssec/ns4/named4.conf.in @@ -25,6 +25,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; }; }; key rndc_key { diff --git a/bin/tests/system/dnssec/tests.sh b/bin/tests/system/dnssec/tests.sh index a192f5e004..5a01561eaa 100644 --- a/bin/tests/system/dnssec/tests.sh +++ b/bin/tests/system/dnssec/tests.sh @@ -3757,6 +3757,27 @@ n=$((n + 1)) test "$ret" -eq 0 || echo_i "failed" status=$((status + ret)) +echo_i "check that zone contents are still secure despite disable-algorithms on query name (name below zone name) ($n)" +ret=0 +dig_with_opts @10.53.0.4 z.secure.example >dig.out.ns4.test$n || ret=1 +grep "ANSWER: 2," dig.out.ns4.test$n >/dev/null || ret=1 +grep "status: NOERROR" dig.out.ns4.test$n >/dev/null || ret=1 +grep "flags:.*ad.*QUERY" dig.out.ns4.test$n >/dev/null || ret=1 +n=$((n + 1)) +test "$ret" -eq 0 || echo_i "failed" +status=$((status + ret)) + +echo_i "check that zone contents are treated as insecure when disable-algorithms name is above zone name ($n)" +ret=0 +dig_with_opts @10.53.0.4 zonecut.ent.secure.example >dig.out.ns4.test$n || ret=1 +grep "ANSWER: 2," dig.out.ns4.test$n >/dev/null || ret=1 +grep "status: NOERROR" dig.out.ns4.test$n >/dev/null || ret=1 +grep "flags:.*ad.*QUERY" dig.out.ns4.test$n >/dev/null && ret=1 +grep "; EDE: 1 (Unsupported DNSKEY Algorithm): " dig.out.ns4.test$n >/dev/null || ret=1 +n=$((n + 1)) +test "$ret" -eq 0 || echo_i "failed" +status=$((status + ret)) + echo_i "check that DS records are still treated as secure at the disable-algorithm name ($n)" ret=0 dig_with_opts @10.53.0.4 badalg.secure.example DS >dig.out.ns4.test$n || ret=1 diff --git a/bin/tests/system/dnssec/tests_sh_dnssec.py b/bin/tests/system/dnssec/tests_sh_dnssec.py index 52730aec0b..7cd2633fe3 100644 --- a/bin/tests/system/dnssec/tests_sh_dnssec.py +++ b/bin/tests/system/dnssec/tests_sh_dnssec.py @@ -92,6 +92,7 @@ pytestmark = pytest.mark.extra_artifacts( "ns3/dnskey-unsupported-2.example.db", "ns3/dnskey-unsupported.example.db", "ns3/dnskey-unsupported.example.db.tmp", + "ns3/ds-unsupported.example.db", "ns3/dynamic.example.db", "ns3/digest-alg-unsupported.example.db", "ns3/enabled.managed.db", @@ -142,7 +143,7 @@ pytestmark = pytest.mark.extra_artifacts( "ns3/update-nsec3.example.db.signed", "ns3/upper.example.db", "ns3/upper.example.db.lower", - "ns3/ds-unsupported.example.db", + "ns3/zonecut.ent.secure.example.db", "ns4/managed.conf", "ns4/managed-keys.bind", "ns4/named.secroots",