Merge branch '2445-nsec3-iterations-resolver' into 'main'

Resolve "NSEC3 iterations"

Closes #2445

See merge request isc-projects/bind9!4957
This commit is contained in:
Matthijs Mekking
2021-04-29 13:09:30 +00:00
6 changed files with 101 additions and 4 deletions

View File

@@ -1,3 +1,6 @@
5630. [func] Treat DNSSEC responses with NSEC3 iterations greater
than 150 as insecure. [GL #2445]
5629. [func] Reduce the supported maximum number of iterations
that can be configured in an NSEC3 zone to 150.
[GL #2642]

View File

@@ -4331,5 +4331,56 @@ n=$((n+1))
test "$ret" -eq 0 || echo_i "failed"
status=$((status+ret))
# Check that the validating resolver will fallback to insecure if the answer
# contains NSEC3 records with high iteration count.
echo_i "checking fallback to insecure when NSEC3 iterations is too high (nxdomain) ($n)"
ret=0
dig_with_opts @10.53.0.2 does-not-exist.too-many-iterations > dig.out.ns2.test$n || ret=1
dig_with_opts @10.53.0.4 does-not-exist.too-many-iterations > dig.out.ns4.test$n || ret=1
digcomp dig.out.ns2.test$n dig.out.ns4.test$n || ret=1
grep "flags: qr rd ra;" dig.out.ns4.test$n >/dev/null || ret=1
grep "status: NXDOMAIN" dig.out.ns4.test$n >/dev/null || ret=1
grep "ANSWER: 0, AUTHORITY: 6" 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 fallback to insecure when NSEC3 iterations is too high (nodata) ($n)"
ret=0
dig_with_opts @10.53.0.2 a.too-many-iterations txt > dig.out.ns2.test$n || ret=1
dig_with_opts @10.53.0.4 a.too-many-iterations txt > dig.out.ns4.test$n || ret=1
digcomp dig.out.ns2.test$n dig.out.ns4.test$n || ret=1
grep "flags: qr rd ra;" dig.out.ns4.test$n >/dev/null || ret=1
grep "status: NOERROR" dig.out.ns4.test$n >/dev/null || ret=1
grep "ANSWER: 0, AUTHORITY: 4" 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 fallback to insecure when NSEC3 iterations is too high (wildcard) ($n)"
ret=0
dig_with_opts @10.53.0.2 wild.a.too-many-iterations > dig.out.ns2.test$n || ret=1
dig_with_opts @10.53.0.4 wild.a.too-many-iterations > dig.out.ns4.test$n || ret=1
digcomp dig.out.ns2.test$n dig.out.ns4.test$n || ret=1
grep "flags: qr rd ra;" dig.out.ns4.test$n >/dev/null || ret=1
grep "status: NOERROR" dig.out.ns4.test$n >/dev/null || ret=1
grep 'wild\.a\.too-many-iterations\..*A.10\.0\.0\.3' dig.out.ns4.test$n >/dev/null || ret=1
grep "ANSWER: 2, AUTHORITY: 4" 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 fallback to insecure when NSEC3 iterations is too high (wildcard nodata) ($n)"
ret=0
dig_with_opts @10.53.0.2 type100 wild.a.too-many-iterations > dig.out.ns2.test$n || ret=1
dig_with_opts @10.53.0.4 type100 wild.a.too-many-iterations > dig.out.ns4.test$n || ret=1
digcomp dig.out.ns2.test$n dig.out.ns4.test$n || ret=1
grep "flags: qr rd ra;" dig.out.ns4.test$n >/dev/null || ret=1
grep "status: NOERROR" dig.out.ns4.test$n >/dev/null || ret=1
grep "ANSWER: 0, AUTHORITY: 8" dig.out.ns4.test$n > /dev/null || ret=1
n=$((n+1))
test "$ret" -eq 0 || echo_i "failed"
status=$((status+ret))
echo_i "exit status: $status"
[ $status -eq 0 ] || exit 1

View File

@@ -40,6 +40,9 @@ Feature Changes
- Reduce the supported maximum number of iterations that can be
configured in an NSEC3 zones to 150. :gl:`#2642`
- Treat DNSSEC responses with NSEC3 iterations greater than 150 as insecure.
[GL #2445]
Bug Fixes
~~~~~~~~~

View File

@@ -24,7 +24,8 @@
#include <dns/rdatastruct.h>
#include <dns/types.h>
#define DNS_NSEC3_SALTSIZE 255
#define DNS_NSEC3_SALTSIZE 255
#define DNS_NSEC3_MAXITERATIONS 150U
/*
* hash = 1, flags =1, iterations = 2, salt length = 1, salt = 255 (max)

View File

@@ -1880,7 +1880,7 @@ try_private:
unsigned int
dns_nsec3_maxiterations(void) {
return (150);
return (DNS_NSEC3_MAXITERATIONS);
}
isc_result_t
@@ -2022,6 +2022,13 @@ dns_nsec3_noexistnodata(dns_rdatatype_t type, const dns_name_t *name,
first = true;
while (qlabels >= zlabels) {
/*
* If there are too many iterations reject the NSEC3 record.
*/
if (nsec3.iterations > DNS_NSEC3_MAXITERATIONS) {
return (DNS_R_NSEC3ITERRANGE);
}
length = isc_iterated_hash(hash, nsec3.hash, nsec3.iterations,
nsec3.salt, nsec3.salt_length,
qname->ndata, qname->length);

View File

@@ -2245,6 +2245,26 @@ findnsec3proofs(dns_validator_t *val) {
if (unknown) {
val->attributes |= VALATTR_FOUNDUNKNOWN;
}
if (result == DNS_R_NSEC3ITERRANGE) {
/*
* We don't really know which NSEC3 record provides
* which proof. Just populate them.
*/
if (NEEDNOQNAME(val) &&
proofs[DNS_VALIDATOR_NOQNAMEPROOF] == NULL) {
proofs[DNS_VALIDATOR_NOQNAMEPROOF] = name;
} else if (setclosest) {
proofs[DNS_VALIDATOR_CLOSESTENCLOSER] = name;
} else if (NEEDNODATA(val) &&
proofs[DNS_VALIDATOR_NODATAPROOF] == NULL) {
proofs[DNS_VALIDATOR_NODATAPROOF] = name;
} else if (NEEDNOWILDCARD(val) &&
proofs[DNS_VALIDATOR_NOWILDCARDPROOF] ==
NULL) {
proofs[DNS_VALIDATOR_NOWILDCARDPROOF] = name;
}
return (result);
}
if (result != ISC_R_SUCCESS) {
continue;
}
@@ -2501,7 +2521,13 @@ validate_nx(dns_validator_t *val, bool resume) {
*/
if (!NEEDNODATA(val) && !NEEDNOWILDCARD(val) && NEEDNOQNAME(val)) {
if (!FOUNDNOQNAME(val)) {
findnsec3proofs(val);
result = findnsec3proofs(val);
if (result == DNS_R_NSEC3ITERRANGE) {
validator_log(val, ISC_LOG_DEBUG(3),
"too many iterations");
markanswer(val, "validate_nx (3)", NULL);
return (ISC_R_SUCCESS);
}
}
if (FOUNDNOQNAME(val) && FOUNDCLOSEST(val) && !FOUNDOPTOUT(val))
@@ -2531,7 +2557,13 @@ validate_nx(dns_validator_t *val, bool resume) {
}
if (!FOUNDNOQNAME(val) && !FOUNDNODATA(val)) {
findnsec3proofs(val);
result = findnsec3proofs(val);
if (result == DNS_R_NSEC3ITERRANGE) {
validator_log(val, ISC_LOG_DEBUG(3),
"too many iterations");
markanswer(val, "validate_nx (4)", NULL);
return (ISC_R_SUCCESS);
}
}
/*