[9.20] new: usr: adds support for EDE code 1 and 2

Add support for EDE codes 1 & 2 which might occurs during DNSSEC validation in case of unsupported RRSIG algorithm or DNSKEY digest.

See #2715

Backport of MR !9948

Merge branch 'backport-2715-ede-unsupported-digest-alg-9.20' into 'bind-9.20'

See merge request isc-projects/bind9!9996
This commit is contained in:
Colin Vidal 2025-01-24 14:58:46 +00:00
commit b3eab79bc1
18 changed files with 314 additions and 16 deletions

View file

@ -106,6 +106,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

View file

@ -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 \

View file

@ -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

View file

@ -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

View file

@ -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";

View file

@ -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

View file

@ -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.

View file

@ -28,9 +28,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.

View file

@ -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 {

View file

@ -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 {

View file

@ -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 {

View file

@ -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"
@ -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))
@ -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))
@ -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"
@ -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"

View file

@ -83,6 +83,7 @@ pytestmark = pytest.mark.extra_artifacts(
"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",
@ -131,6 +132,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",
"ns4/managed.conf",
"ns4/managed-keys.bind",
"ns4/named.secroots",

View file

@ -265,6 +265,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,
@ -646,4 +648,32 @@ dns_resolver_freefresp(dns_fetchresponse_t **frespp);
* \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
*/
ISC_LANG_ENDDECLS

View file

@ -148,13 +148,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;
};
/*%
@ -173,7 +180,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.

View file

@ -988,7 +988,7 @@ valcreate(fetchctx_t *fctx, dns_message_t *message, dns_adbaddrinfo_t *addrinfo,
result = dns_validator_create(
fctx->res->view, name, type, rdataset, sigrdataset, message,
valoptions, fctx->loop, validated, valarg, &fctx->nvalidations,
&fctx->nfails, fctx->qc, fctx->gqc, &validator);
&fctx->nfails, fctx->qc, fctx->gqc, fctx, &validator);
RUNTIME_CHECK(result == ISC_R_SUCCESS);
inc_stats(fctx->res, dns_resstatscounter_val);
if ((valoptions & DNS_VALIDATOR_DEFER) == 0) {
@ -1337,8 +1337,6 @@ fctx_cleanup(fetchctx_t *fctx) {
ISC_LIST_UNLINK(fctx->altaddrs, addr, publink);
dns_adb_freeaddrinfo(fctx->adb, &addr);
}
dns_ede_unlinkall(fctx->mctx, &fctx->edelist);
}
static void
@ -1603,7 +1601,7 @@ fctx_sendevents(fetchctx_t *fctx, isc_result_t result) {
/*
* Copy EDE that occured during the resolution to all
* clients
* clients.
*/
for (dns_ede_t *ede = ISC_LIST_HEAD(fctx->edelist); ede != NULL;
ede = ISC_LIST_NEXT(ede, link))
@ -4201,6 +4199,7 @@ resume_qmin(void *arg) {
}
UNLOCK(&fctx->lock);
dns_resolver_copyede(fctx->qminfetch, fctx);
dns_resolver_destroyfetch(&fctx->qminfetch);
/*
@ -4339,7 +4338,6 @@ fctx_destroy(fetchctx_t *fctx) {
REQUIRE(ISC_LIST_EMPTY(fctx->queries));
REQUIRE(ISC_LIST_EMPTY(fctx->finds));
REQUIRE(ISC_LIST_EMPTY(fctx->altfinds));
REQUIRE(ISC_LIST_EMPTY(fctx->edelist));
REQUIRE(atomic_load_acquire(&fctx->pending) == 0);
REQUIRE(ISC_LIST_EMPTY(fctx->validators));
REQUIRE(fctx->state != fetchstate_active);
@ -4375,6 +4373,8 @@ fctx_destroy(fetchctx_t *fctx) {
isc_mem_put(fctx->mctx, sa, sizeof(*sa));
}
dns_ede_unlinkall(fctx->mctx, &fctx->edelist);
isc_counter_detach(&fctx->qc);
if (fctx->gqc != NULL) {
isc_counter_detach(&fctx->gqc);
@ -7208,6 +7208,7 @@ resume_dslookup(void *arg) {
}
cleanup:
dns_resolver_copyede(fetch, fctx);
dns_resolver_destroyfetch(&fetch);
if (result != ISC_R_SUCCESS) {
@ -11114,3 +11115,44 @@ dns_resolver_freefresp(dns_fetchresponse_t **frespp) {
dns_ede_unlinkall(fresp->mctx, &fresp->edelist);
isc_mem_putanddetach(&fresp->mctx, fresp, sizeof(*fresp));
}
void
dns_resolver_edeappend(fetchctx_t *fctx, uint16_t info_code, const char *what,
const dns_name_t *name, dns_rdatatype_t type) {
REQUIRE(VALID_FCTX(fctx));
REQUIRE(what);
REQUIRE(name);
char extra[DNS_NAME_FORMATSIZE + DNS_RDATATYPE_FORMATSIZE +
DNS_EDE_EXTRATEXT_LEN];
size_t offset = 0;
/*
* -2 to leave room for separator "/" and NULL terminator
*/
snprintf(extra, DNS_EDE_EXTRATEXT_LEN - 2, "%s ", what);
offset += strlen(extra);
dns_name_format(name, extra + offset, DNS_NAME_FORMATSIZE);
offset = strlcat(extra, "/", sizeof(extra));
dns_rdatatype_format(type, extra + offset,
DNS_RDATATYPE_FORMATSIZE + 1);
LOCK(&fctx->lock);
dns_ede_append(fctx->mctx, &fctx->edelist, info_code, extra);
UNLOCK(&fctx->lock)
}
void
dns_resolver_copyede(dns_fetch_t *from, fetchctx_t *to) {
REQUIRE(DNS_FETCH_VALID(from));
REQUIRE(VALID_FCTX(to));
LOCK(&to->lock);
for (dns_ede_t *ede = ISC_LIST_HEAD(from->private->edelist);
ede != NULL; ede = ISC_LIST_NEXT(ede, link))
{
dns_ede_append(to->mctx, &to->edelist, ede->info_code,
ede->extra_text);
}
UNLOCK(&to->lock);
}

View file

@ -173,6 +173,9 @@ expire_rdatasets(dns_validator_t *val) {
}
}
static void
validate_extendederror(dns_validator_t *val);
/*%
* Ensure the validator's rdatasets are disassociated.
*/
@ -410,6 +413,7 @@ fetch_callback_dnskey(void *arg) {
}
validator_log(val, ISC_LOG_DEBUG(3), "in fetch_callback_dnskey");
dns_resolver_copyede(val->fetch, val->fctx);
dns_resolver_destroyfetch(&val->fetch);
if (CANCELED(val) || CANCELING(val)) {
@ -484,6 +488,7 @@ fetch_callback_ds(void *arg) {
}
validator_log(val, ISC_LOG_DEBUG(3), "in fetch_callback_ds");
dns_resolver_copyede(val->fetch, val->fctx);
dns_resolver_destroyfetch(&val->fetch);
if (CANCELED(val) || CANCELING(val)) {
@ -976,7 +981,7 @@ create_validator(dns_validator_t *val, dns_name_t *name, dns_rdatatype_t type,
result = dns_validator_create(val->view, name, type, rdataset, sig,
NULL, vopts, val->loop, cb, val,
val->nvalidations, val->nfails, val->qc,
val->gqc, &val->subvalidator);
val->gqc, val->fctx, &val->subvalidator);
if (result == ISC_R_SUCCESS) {
dns_validator_attach(val, &val->subvalidator->parent);
val->subvalidator->depth = val->depth + 1;
@ -1536,6 +1541,8 @@ cleanup:
return;
}
val->unsupported_algorithm = 0;
val->unsupported_digest = 0;
result = validate_async_run(val, validate_answer_process);
INSIST(result == DNS_R_WAIT);
}
@ -1656,6 +1663,9 @@ validate_answer_process(void *arg) {
if (!dns_resolver_algorithm_supported(val->view->resolver, val->name,
val->siginfo->algorithm))
{
if (val->unsupported_algorithm == 0) {
val->unsupported_algorithm = val->siginfo->algorithm;
}
goto next_key;
}
@ -1779,6 +1789,10 @@ validate_answer_iter_done(dns_validator_t *val, isc_result_t result) {
return;
}
if (result != ISC_R_SUCCESS && result != DNS_R_WAIT) {
validate_extendederror(val);
}
validator_log(val, ISC_LOG_INFO, "no valid signature found");
validate_async_done(val, val->result);
}
@ -1979,12 +1993,15 @@ validate_dnskey_dsset_done(dns_validator_t *val, isc_result_t result) {
validator_log(val, ISC_LOG_DEBUG(3), "marking as secure (DS)");
break;
case ISC_R_NOMORE:
if (!val->supported_algorithm) {
if (val->unsupported_algorithm != 0 ||
val->unsupported_digest != 0)
{
validator_log(val, ISC_LOG_DEBUG(3),
"no supported algorithm/digest (DS)");
result = markanswer(
val, "validate_dnskey (3)",
"no supported algorithm/digest (DS)");
validate_extendederror(val);
break;
}
FALLTHROUGH;
@ -2021,17 +2038,21 @@ validate_dnskey_dsset(dns_validator_t *val) {
if (!dns_resolver_ds_digest_supported(val->view->resolver, val->name,
ds.digest_type))
{
if (val->unsupported_digest == 0) {
val->unsupported_digest = ds.digest_type;
}
return DNS_R_BADALG;
}
if (!dns_resolver_algorithm_supported(val->view->resolver, val->name,
ds.algorithm))
{
if (val->unsupported_algorithm == 0) {
val->unsupported_algorithm = ds.algorithm;
}
return DNS_R_BADALG;
}
val->supported_algorithm = true;
/*
* Find the DNSKEY matching the DS...
*/
@ -2203,8 +2224,8 @@ validate_dnskey(void *arg) {
* key set and the matching signature. For each such key, attempt
* verification.
*/
val->supported_algorithm = false;
val->unsupported_algorithm = 0;
val->unsupported_digest = 0;
/*
* If DNS_DSDIGEST_SHA256 or DNS_DSDIGEST_SHA384 is present we
@ -2942,6 +2963,13 @@ check_ds_algs(dns_validator_t *val, dns_name_t *name,
}
dns_rdata_reset(&dsrdata);
}
/*
* No unsupported alg/digest EDE error is raised here because the prove
* unsecure flow always runs after a validate/validatenx flow. So if an
* unsupported alg/digest was found while building the chain of trust,
* it would be raised already.
*/
return false;
}
@ -3392,7 +3420,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) {
isc_result_t result = ISC_R_FAILURE;
dns_validator_t *val = NULL;
@ -3425,6 +3453,7 @@ dns_validator_create(dns_view_t *view, dns_name_t *name, dns_rdatatype_t type,
.rdata = DNS_RDATA_INIT,
.nvalidations = nvalidations,
.nfails = nfails,
.fctx = fctx,
};
isc_refcount_init(&val->references, 1);
@ -3532,8 +3561,10 @@ destroy_validator(dns_validator_t *val) {
if (val->gqc != NULL) {
isc_counter_detach(&val->gqc);
}
dns_view_detach(&val->view);
isc_loop_detach(&val->loop);
isc_mem_put(mctx, val, sizeof(*val));
}
@ -3632,6 +3663,25 @@ validator_logcreate(dns_validator_t *val, dns_name_t *name,
caller, operation, namestr, typestr);
}
static void
validate_extendederror(dns_validator_t *val) {
char txt[32];
REQUIRE(VALID_VALIDATOR(val));
if (val->unsupported_algorithm != 0) {
dns_secalg_format(val->unsupported_algorithm, txt, sizeof(txt));
dns_resolver_edeappend(val->fctx, DNS_EDE_DNSKEYALG, txt,
val->name, val->type);
}
if (val->unsupported_digest != 0) {
dns_dsdigest_format(val->unsupported_digest, txt, sizeof(txt));
dns_resolver_edeappend(val->fctx, DNS_EDE_DSDIGESTTYPE, txt,
val->name, val->type);
}
}
#if DNS_VALIDATOR_TRACE
ISC_REFCOUNT_TRACE_IMPL(dns_validator, destroy_validator);
#else

View file

@ -2499,6 +2499,18 @@ validate(ns_client_t *client, dns_db_t *db, dns_name_t *name,
if (!dns_resolver_algorithm_supported(client->view->resolver,
name, rrsig.algorithm))
{
char txt[DNS_NAME_FORMATSIZE + 32];
isc_buffer_t buffer;
isc_buffer_init(&buffer, txt, sizeof(txt));
dns_secalg_totext(rrsig.algorithm, &buffer);
isc_buffer_putstr(&buffer, " ");
dns_name_totext(name, DNS_NAME_OMITFINALDOT, &buffer);
isc_buffer_putstr(&buffer, " (cached)");
isc_buffer_putuint8(&buffer, 0);
ns_client_extendederror(client, DNS_EDE_DNSKEYALG,
isc_buffer_base(&buffer));
continue;
}
if (!dns_name_issubdomain(name, &rrsig.signer)) {