Skip to content

Commit

Permalink
new: usr: adds support for EDE code 1 and 2
Browse files Browse the repository at this point in the history
Add support for EDE codes 1 & 2 which might occurs during DNSSEC validation in case of unsupported RRSIG algorithm or DNSKEY digest.

See #2715

Merge branch '2715-ede-unsupported-digest-alg' into 'main'

See merge request isc-projects/bind9!9948
  • Loading branch information
Colin Vidal committed Jan 24, 2025
2 parents 98522ab + 244923b commit 5a8fce4
Show file tree
Hide file tree
Showing 18 changed files with 316 additions and 19 deletions.
6 changes: 6 additions & 0 deletions bin/tests/system/dnssec/ns2/example.db.in
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,12 @@ ns.dnskey-unknown A 10.53.0.3
dnskey-unsupported NS ns.dnskey-unsupported
ns.dnskey-unsupported A 10.53.0.3

ds-unsupported NS ns.ds-unsupported
ns.ds-unsupported A 10.53.0.3

digest-alg-unsupported NS ns.digest-alg-unsupported
ns.digest-alg-unsupported A 10.53.0.3

dnskey-nsec3-unknown NS ns.dnskey-nsec3-unknown
ns.dnskey-nsec3-unknown A 10.53.0.3

Expand Down
3 changes: 2 additions & 1 deletion bin/tests/system/dnssec/ns2/sign.sh
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,8 @@ infile=example.db.in
zonefile=example.db

# Get the DS records for the "example." zone.
for subdomain in secure badds bogus dynamic keyless nsec3 optout \
for subdomain in digest-alg-unsupported ds-unsupported secure badds \
bogus dynamic keyless nsec3 optout \
nsec3-unknown optout-unknown multiple rsasha256 rsasha512 \
kskonly update-nsec3 auto-nsec auto-nsec3 secure.below-cname \
ttlpatch split-dnssec split-smart expired expiring upper lower \
Expand Down
22 changes: 22 additions & 0 deletions bin/tests/system/dnssec/ns3/digest-alg-unsupported.example.db.in
Original file line number Diff line number Diff line change
@@ -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 ns
ns A 10.53.0.3
a A 10.0.0.1
22 changes: 22 additions & 0 deletions bin/tests/system/dnssec/ns3/ds-unsupported.example.db.in
Original file line number Diff line number Diff line change
@@ -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 ns
ns A 10.53.0.3
a A 10.0.0.1
12 changes: 12 additions & 0 deletions bin/tests/system/dnssec/ns3/named.conf.in
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,18 @@ zone "dnskey-unknown.example" {
file "dnskey-unknown.example.db.signed";
};

zone "digest-alg-unsupported.example" {
type primary;
file "digest-alg-unsupported.example.db.signed";
allow-update { any; };
};

zone "ds-unsupported.example" {
type primary;
file "ds-unsupported.example.db.signed";
allow-update { any; };
};

zone "dnskey-unsupported.example" {
type primary;
file "dnskey-unsupported.example.db.signed";
Expand Down
1 change: 1 addition & 0 deletions bin/tests/system/dnssec/ns3/secure.example.db.in
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ 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

private NS ns.private
ns.private A 10.53.0.2
Expand Down
42 changes: 42 additions & 0 deletions bin/tests/system/dnssec/ns3/sign.sh
Original file line number Diff line number Diff line change
Expand Up @@ -298,6 +298,48 @@ awk '$4 == "DNSKEY" { $7 = 255 } $4 == "RRSIG" { $6 = 255 } { print }' ${zonefil
DSFILE="dsset-${zone}."
$DSFROMKEY -A -f ${zonefile}.signed "$zone" >"$DSFILE"

#
# A zone which uses an unsupported algorithm for a DNSKEY and an unsupported
# digest for another DNSKEY
#
zone=digest-alg-unsupported.example.
infile=digest-alg-unsupported.example.db.in
zonefile=digest-alg-unsupported.example.db

cnameandkey=$("$KEYGEN" -T KEY -q -a "$DEFAULT_ALGORITHM" -b "$DEFAULT_BITS" -n host "cnameandkey.$zone")
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")
keyname2=$("$KEYGEN" -q -a ED448 -b "$DEFAULT_BITS" -n zone "$zone")

cat "$infile" "$cnameandkey.key" "$dnameandkey.key" "$keyname.key" "$keyname2.key" >"$zonefile"

"$SIGNER" -z -D -o "$zone" "$zonefile" >/dev/null
cat "$zonefile" "$zonefile".signed >"$zonefile".tmp
mv "$zonefile".tmp "$zonefile".signed

# override generated DS record file so we can set different digest to each keys
DSFILE="dsset-${zone}"
$DSFROMKEY -1 -A -f ${zonefile}.signed "$zone" | head -n 1 >"$DSFILE"
$DSFROMKEY -2 -A -f ${zonefile}.signed "$zone" | tail -1 >>"$DSFILE"

#
# A zone which is fine by itself (supported algorithm) but that is used
# to mimic unsupported DS digest (see ns8).
#
zone=ds-unsupported.example.
infile=ds-unsupported.example.db.in
zonefile=ds-unsupported.example.db

cnameandkey=$("$KEYGEN" -T KEY -q -a "$DEFAULT_ALGORITHM" -b "$DEFAULT_BITS" -n host "cnameandkey.$zone")
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"

"$SIGNER" -z -D -o "$zone" "$zonefile" >/dev/null
cat "$zonefile" "$zonefile".signed >"$zonefile".tmp
mv "$zonefile".tmp "$zonefile".signed

#
# A zone with a published unsupported DNSKEY algorithm (Reserved).
# Different from above because this key is not intended for signing.
Expand Down
6 changes: 5 additions & 1 deletion bin/tests/system/dnssec/ns4/named1.conf.in
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,13 @@ options {

nta-lifetime 12s;
nta-recheck 9s;

validate-except { corp; };

disable-algorithms "digest-alg-unsupported.example." { ED448; };
disable-ds-digests "digest-alg-unsupported.example." { "SHA1"; "SHA-1"; };
disable-ds-digests "ds-unsupported.example." {"SHA1"; "SHA-1"; "SHA256"; "SHA-256"; "SHA384"; "SHA-384"; };
disable-algorithms "badalg.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
# using a local toy root zone for the tests, so it wouldn't work.
Expand Down
4 changes: 4 additions & 0 deletions bin/tests/system/dnssec/ns4/named2.conf.in
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,10 @@ options {
dnssec-validation auto;
bindkeys-file "managed.conf";
minimal-responses no;
disable-algorithms "digest-alg-unsupported.example." { ED448; };
disable-ds-digests "digest-alg-unsupported.example." { "SHA1"; "SHA-1"; };
disable-ds-digests "ds-unsupported.example." {"SHA1"; "SHA-1"; "SHA256"; "SHA-256"; "SHA384"; "SHA-384"; };
disable-algorithms "badalg.secure.example." { ECDSAP256SHA256; };
};

key rndc_key {
Expand Down
4 changes: 4 additions & 0 deletions bin/tests/system/dnssec/ns4/named3.conf.in
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,10 @@ options {
bindkeys-file "managed.conf";
dnssec-accept-expired yes;
minimal-responses no;
disable-algorithms "digest-alg-unsupported.example." { ED448; };
disable-ds-digests "digest-alg-unsupported.example." { "SHA1"; "SHA-1"; };
disable-ds-digests "ds-unsupported.example." {"SHA1"; "SHA-1"; "SHA256"; "SHA-256"; "SHA384"; "SHA-384"; };
disable-algorithms "badalg.secure.example." { ECDSAP256SHA256; };
};

key rndc_key {
Expand Down
4 changes: 4 additions & 0 deletions bin/tests/system/dnssec/ns4/named4.conf.in
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,10 @@ options {
pid-file "named.pid";
listen-on { 10.53.0.4; };
listen-on-v6 { none; };
disable-algorithms "digest-alg-unsupported.example." { ED448; };
disable-ds-digests "digest-alg-unsupported.example." { "SHA1"; "SHA-1"; };
disable-ds-digests "ds-unsupported.example." {"SHA1"; "SHA-1"; "SHA256"; "SHA-256"; "SHA384"; "SHA-384"; };
disable-algorithms "badalg.secure.example." { ECDSAP256SHA256; };
};

key rndc_key {
Expand Down
33 changes: 33 additions & 0 deletions bin/tests/system/dnssec/tests.sh
Original file line number Diff line number Diff line change
Expand Up @@ -3677,6 +3677,35 @@ dig_with_opts +noauth +noadd +nodnssec +adflag @10.53.0.3 dnskey-unsupported.exa
dig_with_opts +noauth +noadd +nodnssec +adflag @10.53.0.4 dnskey-unsupported.example A >dig.out.ns4.test$n
grep "status: NOERROR," dig.out.ns3.test$n >/dev/null || ret=1
grep "status: NOERROR," dig.out.ns4.test$n >/dev/null || ret=1
grep "; EDE: 1 (Unsupported DNSKEY Algorithm): (255 dnskey-unsupported.example/SOA)" 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 2 for unsupported DS digest ($n)"
ret=0
dig_with_opts @10.53.0.4 a.ds-unsupported.example >dig.out.ns4.test$n || ret=1
grep "; EDE: 2 (Unsupported DS Digest Type): (SHA-256 ds-unsupported.example/DNSKEY)" 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
grep "; EDE: 1 (Unsupported DNSKEY Algorithm): (ECDSAP256SHA256 badalg.secure.example/A)" 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 both EDE code 1 and 2 for unsupported digest on one DNSKEY and alg on the other ($n)"
ret=0
dig_with_opts @10.53.0.4 a.digest-alg-unsupported.example >dig.out.ns4.test$n || ret=1
grep "; EDE: 1 (Unsupported DNSKEY Algorithm): (ED448 digest-alg-unsupported.example/DNSKEY)" dig.out.ns4.test$n >/dev/null || ret=1
grep "; EDE: 2 (Unsupported DS Digest Type): (SHA-1 digest-alg-unsupported.example/DNSKEY)" 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"
Expand Down Expand Up @@ -3974,6 +4003,7 @@ dig_with_opts @10.53.0.8 a.secure.trusted A >dig.out.ns8.test$n
grep "status: NOERROR," dig.out.ns3.test$n >/dev/null || ret=1
grep "status: NOERROR," dig.out.ns8.test$n >/dev/null || ret=1
grep "flags:.*ad.*QUERY" dig.out.ns8.test$n >/dev/null || ret=1
grep "; EDE: " dig.out.ns8.test$n >/dev/null && ret=1
n=$((n + 1))
test "$ret" -eq 0 || echo_i "failed"
status=$((status + ret))
Expand All @@ -3985,6 +4015,7 @@ dig_with_opts @10.53.0.8 a.secure.managed A >dig.out.ns8.test$n
grep "status: NOERROR," dig.out.ns3.test$n >/dev/null || ret=1
grep "status: NOERROR," dig.out.ns8.test$n >/dev/null || ret=1
grep "flags:.*ad.*QUERY" dig.out.ns8.test$n >/dev/null || ret=1
grep "; EDE: " dig.out.ns8.test$n >/dev/null && ret=1
n=$((n + 1))
test "$ret" -eq 0 || echo_i "failed"
status=$((status + ret))
Expand All @@ -3999,6 +4030,7 @@ dig_with_opts @10.53.0.3 a.unsupported.trusted A >dig.out.ns3.test$n
dig_with_opts @10.53.0.8 a.unsupported.trusted A >dig.out.ns8.test$n
grep "status: NOERROR," dig.out.ns3.test$n >/dev/null || ret=1
grep "status: NOERROR," dig.out.ns8.test$n >/dev/null || ret=1
grep "; EDE: 1 (Unsupported DNSKEY Algorithm): (255 ns3.unsupported.trusted (cached))" dig.out.ns8.test$n >/dev/null || ret=1
grep "flags:.*ad.*QUERY" dig.out.ns8.test$n >/dev/null && ret=1
n=$((n + 1))
test "$ret" -eq 0 || echo_i "failed"
Expand All @@ -4010,6 +4042,7 @@ dig_with_opts @10.53.0.3 a.unsupported.managed A >dig.out.ns3.test$n
dig_with_opts @10.53.0.8 a.unsupported.managed A >dig.out.ns8.test$n
grep "status: NOERROR," dig.out.ns3.test$n >/dev/null || ret=1
grep "status: NOERROR," dig.out.ns8.test$n >/dev/null || ret=1
grep "; EDE: 1 (Unsupported DNSKEY Algorithm): (255 ns3.unsupported.managed (cached))" dig.out.ns8.test$n >/dev/null || ret=1
grep "flags:.*ad.*QUERY" dig.out.ns8.test$n >/dev/null && ret=1
n=$((n + 1))
test "$ret" -eq 0 || echo_i "failed"
Expand Down
2 changes: 2 additions & 0 deletions bin/tests/system/dnssec/tests_sh_dnssec.py
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@
"ns3/dnskey-unsupported.example.db",
"ns3/dnskey-unsupported.example.db.tmp",
"ns3/dynamic.example.db",
"ns3/digest-alg-unsupported.example.db",
"ns3/enabled.managed.db",
"ns3/enabled.trusted.db",
"ns3/example.bk",
Expand Down Expand Up @@ -131,6 +132,7 @@
"ns3/update-nsec3.example.db.signed",
"ns3/upper.example.db",
"ns3/upper.example.db.lower",
"ns3/ds-unsupported.example.db",
"ns4/managed.conf",
"ns4/managed-keys.bind",
"ns4/named.secroots",
Expand Down
32 changes: 31 additions & 1 deletion lib/dns/include/dns/resolver.h
Original file line number Diff line number Diff line change
Expand Up @@ -262,6 +262,8 @@ ISC_REFCOUNT_TRACE_DECL(dns_resolver);
ISC_REFCOUNT_DECL(dns_resolver);
#endif

typedef struct fetchctx fetchctx_t;

isc_result_t
dns_resolver_createfetch(dns_resolver_t *res, const dns_name_t *name,
dns_rdatatype_t type, const dns_name_t *domain,
Expand Down Expand Up @@ -631,4 +633,32 @@ dns_resolver_freefresp(dns_fetchresponse_t **frespp);
*
* Requires:
* \li 'frespp' is valid. No-op if *frespp == NULL
*/
*/

void
dns_resolver_edeappend(fetchctx_t *fctx, uint16_t info_code, const char *what,
const dns_name_t *name, dns_rdatatype_t type);
/*%<
* Helper for EDE message creation in resolver context. Creates message
* containing the "what" context message as well as the "name"/"type" being
* resolved
*
* Requires:
* \li "fctx" is valid
* \li "what" is valid
* \li "info_code" is within the range of defined EDE codes
* \li "name" is valid
*/

void
dns_resolver_copyede(dns_fetch_t *from, fetchctx_t *to);
/*%<
* Copy all EDE messages from the fetchctx_t "from->private" to the fetchctx_t
* "to". The fetchctx_t from "from" is not locked. This is reponsability of the
* caller to lock it if this function is called in a context needing "from"
* synchronization.
*
* Requires:
* \li "from" is valid
* \li "to" is valid
*/
11 changes: 9 additions & 2 deletions lib/dns/include/dns/validator.h
Original file line number Diff line number Diff line change
Expand Up @@ -146,13 +146,20 @@ struct dns_validator {
isc_stdtime_t start;

bool digest_sha1;
bool supported_algorithm;
uint8_t unsupported_algorithm;
uint8_t unsupported_digest;
dns_rdata_t rdata;
bool resume;
uint32_t *nvalidations;
uint32_t *nfails;
isc_counter_t *qc;
isc_counter_t *gqc;

/*
* opaque type here, used to send EDE errors during DNSSEC valiration
* to the fetch context.
*/
fetchctx_t *fctx;
};

/*%
Expand All @@ -169,7 +176,7 @@ dns_validator_create(dns_view_t *view, dns_name_t *name, dns_rdatatype_t type,
dns_message_t *message, unsigned int options,
isc_loop_t *loop, isc_job_cb cb, void *arg,
uint32_t *nvalidations, uint32_t *nfails,
isc_counter_t *qc, isc_counter_t *gqc,
isc_counter_t *qc, isc_counter_t *gqc, fetchctx_t *fctx,
dns_validator_t **validatorp);
/*%<
* Start a DNSSEC validation.
Expand Down
Loading

0 comments on commit 5a8fce4

Please sign in to comment.