fix: usr: Fail DNSKEY validation when supported but invalid DS is found

A regression was introduced when adding the EDE code for unsupported
DNSKEY and DS algorithms.  When the parent has both supported and
unsupported algorithm in the DS record, the validator would treat the
supported DS algorithm as insecure when validating DNSKEY records
instead of BOGUS.  This has not security impact as the rest of the child
zone correctly ends with BOGUS status, but it is incorrect and thus the
regression has been fixed.

Closes #5757

Merge branch '5757-fix-mixed-algorithm-DS-handling' into 'main'

See merge request isc-projects/bind9!11580
This commit is contained in:
Ondřej Surý 2026-02-23 20:57:50 +01:00
commit d4ec8ebee8
15 changed files with 411 additions and 3 deletions

View file

@ -0,0 +1,38 @@
/*
* 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.
*/
// NS1
options {
query-source address 10.53.0.1;
notify-source 10.53.0.1;
transfer-source 10.53.0.1;
port @PORT@;
pid-file "named.pid";
listen-on { 10.53.0.1; };
listen-on-v6 { none; };
minimal-any no;
minimal-responses no;
recursion no;
notify yes;
dnssec-validation yes;
/* test that we can turn off trust-anchor-telemetry */
trust-anchor-telemetry no;
};
zone "." {
type primary;
file "zones/root.db.signed";
};
include "trusted.conf";

View file

@ -0,0 +1,37 @@
#!/bin/sh -e
# 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.
# shellcheck source=conf.sh
. ../../conf.sh
set -e
echo_i "ns1/sign.sh"
zone=.
mkdir -p keys
ksk=$("$KEYGEN" -K keys -q -a "$DEFAULT_ALGORITHM" -b "$DEFAULT_BITS" -f KSK "${zone}")
zsk=$("$KEYGEN" -K keys -q -a "$DEFAULT_ALGORITHM" -b "$DEFAULT_BITS" "${zone}")
cat "zones/root.db.in" "keys/$ksk.key" "keys/$zsk.key" ../ns2/dsset-example. >"zones/root.db"
"$SIGNER" -S -K "keys" \
-o . \
-f "zones/root.db.signed" \
"zones/root.db" >/dev/null 2>&1
keyfile_to_static_ds "keys/$ksk" >trusted.conf
cp trusted.conf ../ns2/trusted.conf
cp trusted.conf ../ns3/trusted.conf
cp trusted.conf ../ns4/trusted.conf

View file

@ -0,0 +1,16 @@
; 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.
. 300 IN SOA gson.nominum.com. a.root.servers.nil. 2000042100 600 600 1200 600
ns2.example. 300 IN A 10.53.0.2
example. 300 IN NS ns2.example.
a.root-servers.nil. 300 IN A 10.53.0.1
. 300 IN NS a.root-servers.nil.

View file

@ -0,0 +1,47 @@
/*
* 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.
*/
// NS2
options {
query-source address 10.53.0.2;
notify-source 10.53.0.2;
transfer-source 10.53.0.2;
port @PORT@;
pid-file "named.pid";
listen-on { 10.53.0.2; };
listen-on-v6 { none; };
recursion no;
dnssec-validation yes;
};
key rndc_key {
secret "1234abcd8765";
algorithm @DEFAULT_HMAC@;
};
controls {
inet 10.53.0.2 port @CONTROLPORT@ allow { any; } keys { rndc_key; };
};
zone "." {
type hint;
file "../../_common/root.hint";
};
zone "example." {
type primary;
file "zones/example.db.signed";
};
include "trusted.conf";

View file

@ -0,0 +1,35 @@
#!/bin/sh -e
# 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.
# shellcheck source=conf.sh
. ../../conf.sh
set -e
echo_i "ns2/sign.sh"
zone=example.
mkdir -p keys
ksk=$("$KEYGEN" -K keys -q -a "$DEFAULT_ALGORITHM" -b "$DEFAULT_BITS" -f KSK "${zone}")
zsk=$("$KEYGEN" -K keys -q -a "$DEFAULT_ALGORITHM" -b "$DEFAULT_BITS" "${zone}")
cat "zones/${zone}db.in" "keys/$ksk.key" "keys/$zsk.key" >"zones/${zone}db"
<"../ns3/dsset-child.${zone}" sed -E "s/[[:space:]]+$DEFAULT_ALGORITHM_NUMBER[[:space:]]+/ 12 /" >>"zones/${zone}db"
<"../ns3/dsset-child.${zone}" sed -E "s/[[:space:]]+$DEFAULT_ALGORITHM_NUMBER[[:space:]]+2[[:space:]]+.*/ $DEFAULT_ALGORITHM_NUMBER 2 AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/" >>"zones/${zone}db"
"$SIGNER" -S -K "keys" \
-o "${zone}" \
-f "zones/${zone}db.signed" \
"zones/${zone}db" >/dev/null 2>&1

View file

@ -0,0 +1,16 @@
; 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.
example. 300 IN SOA ns1.example. admin.example. 2026021901 3600 900 86400 300
ns1.example. 300 IN A 10.53.0.2
ns1.child.example. 300 IN A 10.53.0.3
child.example. 300 IN NS ns1.child.example.
example. 300 IN NS ns1.example.

View file

@ -0,0 +1,47 @@
/*
* 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.
*/
// NS3
options {
query-source address 10.53.0.3;
notify-source 10.53.0.3;
transfer-source 10.53.0.3;
port @PORT@;
pid-file "named.pid";
listen-on { 10.53.0.3; };
listen-on-v6 { none; };
recursion no;
dnssec-validation yes;
};
key rndc_key {
secret "1234abcd8765";
algorithm @DEFAULT_HMAC@;
};
controls {
inet 10.53.0.3 port @CONTROLPORT@ allow { any; } keys { rndc_key; };
};
zone "." {
type hint;
file "../../_common/root.hint";
};
zone "child.example." {
type primary;
file "zones/child.example.db.signed";
};
include "trusted.conf";

View file

@ -0,0 +1,32 @@
#!/bin/sh -e
# 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.
# shellcheck source=conf.sh
. ../../conf.sh
set -e
echo_i "ns3/sign.sh"
zone=child.example.
mkdir -p keys
ksk=$("$KEYGEN" -K keys -q -a "$DEFAULT_ALGORITHM" -b "$DEFAULT_BITS" -f KSK "${zone}")
zsk=$("$KEYGEN" -K keys -q -a "$DEFAULT_ALGORITHM" -b "$DEFAULT_BITS" "${zone}")
cat "zones/${zone}db.in" "keys/$ksk.key" "keys/$zsk.key" >"zones/${zone}db"
"$SIGNER" -S -K "keys" \
-o "${zone}" \
-f "zones/${zone}db.signed" \
"zones/${zone}db" >/dev/null 2>&1

View file

@ -0,0 +1,18 @@
; 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.
child.example. 300 IN SOA ns1.child.example. admin.child.example. 2026021901 3600 900 86400 300
api.child.example. 300 IN A 192.0.2.102
child.example. 300 IN MX 10 mail.child.example.
mail.child.example. 300 IN A 192.0.2.101
www.child.example. 300 IN A 192.0.2.100
ns1.child.example. 300 IN A 10.53.0.3
child.example. 300 IN NS ns1.child.example.

View file

@ -0,0 +1,42 @@
/*
* 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.
*/
// NS4
options {
query-source address 10.53.0.4;
notify-source 10.53.0.4;
transfer-source 10.53.0.4;
port @PORT@;
pid-file "named.pid";
listen-on { 10.53.0.4; };
listen-on-v6 { none; };
recursion yes;
dnssec-validation yes;
};
key rndc_key {
secret "1234abcd8765";
algorithm @DEFAULT_HMAC@;
};
controls {
inet 10.53.0.4 port @CONTROLPORT@ allow { any; } keys { rndc_key; };
};
zone "." {
type hint;
file "../../_common/root.hint";
};
include "trusted.conf";

View file

@ -0,0 +1,32 @@
#!/bin/sh -e
# 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.
# shellcheck source=conf.sh
. ../conf.sh
set -e
(
cd ns3
$SHELL sign.sh
)
(
cd ns2
$SHELL sign.sh
)
(
cd ns1
$SHELL sign.sh
)

View file

@ -0,0 +1,36 @@
# 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.
import pytest
import isctest
pytestmark = pytest.mark.extra_artifacts(
[
"ns*/dsset-*",
"ns*/keys",
"ns*/keys/*.key",
"ns*/keys/*.private",
"ns*/trusted.conf",
"ns*/zones/*.db",
"ns*/zones/*.db.signed",
]
)
def test_mixed_ds():
msg = isctest.query.create("child.example.", "DNSKEY")
res = isctest.query.tcp(msg, "10.53.0.4")
isctest.check.servfail(res)
msg = isctest.query.create("child.example.", "A")
res = isctest.query.tcp(msg, "10.53.0.4")
isctest.check.servfail(res)

View file

@ -407,9 +407,7 @@ def test_private_algorithms(ns4):
res2 = isctest.query.tcp(msg, "10.53.0.4")
isctest.check.noerror(res1)
isctest.check.servfail(res2)
watcher.wait_for_line(
"No DNSKEY for extradsunknownoid.example/DS with PRIVATEOID"
)
watcher.wait_for_line("no DNSKEY matching DS")
@isctest.mark.extended_ds_digest

View file

@ -150,6 +150,7 @@ struct dns_validator {
bool digest_sha1;
uint8_t unsupported_algorithm;
uint8_t unsupported_digest;
uint8_t validation_attempts;
dns_rdata_t rdata;
bool resume;
isc_counter_t *nvalidations;

View file

@ -2089,6 +2089,8 @@ validate_dnskey_dsset(dns_validator_t *val) {
}
}
val->validation_attempts++;
/*
* Find the DNSKEY matching the DS...
*/
@ -2113,6 +2115,12 @@ validate_dnskey_dsset(dns_validator_t *val) {
val->name, key.algorithm,
key.data, key.datalen))
{
/*
* Don't count the unsupported algorithm into the
* validation attempts.
*/
val->validation_attempts--;
if (val->unsupported_algorithm == 0) {
val->unsupported_algorithm = key.algorithm;
/*
@ -2184,6 +2192,11 @@ validate_dnskey_dsset_next_done(void *arg) {
return;
}
if (val->validation_attempts != 0) {
val->unsupported_algorithm = 0;
val->unsupported_digest = 0;
}
validate_dnskey_dsset_done(val, result);
return;
}