mirror of
https://github.com/isc-projects/bind9.git
synced 2026-06-08 23:02:05 -04:00
Merge branch '3486-checkconf-dnssec-policy-nsec3-incompatible-algorithm' into 'main'
Graceful dnssec-policy transition from NSEC only to NSEC3 Closes #3486 See merge request isc-projects/bind9!6647
This commit is contained in:
commit
ae14334083
14 changed files with 586 additions and 174 deletions
3
CHANGES
3
CHANGES
|
|
@ -1,3 +1,6 @@
|
|||
5947. [func] Change dnssec-policy to allow graceful transition from
|
||||
an NSEC only zone to NSEC3. [GL #3486]
|
||||
|
||||
5946. [bug] Fix statistics channel's handling of multiple HTTP
|
||||
requests in a single connection which have non-empty
|
||||
request bodies. [GL #3463]
|
||||
|
|
|
|||
|
|
@ -3901,7 +3901,7 @@ main(int argc, char *argv[]) {
|
|||
hashlist_init(&hashlist,
|
||||
dns_db_nodecount(gdb, dns_dbtree_main) * 2,
|
||||
hash_length);
|
||||
result = dns_nsec_nseconly(gdb, gversion, &answer);
|
||||
result = dns_nsec_nseconly(gdb, gversion, NULL, &answer);
|
||||
if (result == ISC_R_NOTFOUND) {
|
||||
fprintf(stderr,
|
||||
"%s: warning: NSEC3 generation "
|
||||
|
|
|
|||
25
bin/tests/system/checkconf/bad-kasp-nsec3-alg.conf
Normal file
25
bin/tests/system/checkconf/bad-kasp-nsec3-alg.conf
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
dnssec-policy "badnsec3alg" {
|
||||
keys {
|
||||
csk lifetime unlimited algorithm rsasha1;
|
||||
};
|
||||
nsec3param iterations 0 optout 0 salt-length 0;
|
||||
};
|
||||
|
||||
zone "example.net" {
|
||||
type primary;
|
||||
file "example.db";
|
||||
dnssec-policy "badnsec3alg";
|
||||
};
|
||||
|
|
@ -13,9 +13,10 @@
|
|||
|
||||
set -e
|
||||
|
||||
rm -f dig.out.* rndc.signing.*
|
||||
rm -f dig.out.* rndc.signing.* verify.out.*
|
||||
rm -f ns*/named.conf ns*/named.memstats ns*/named.run*
|
||||
rm -f ns*/*.jnl ns*/*.jbk ns*/managed-keys.bind
|
||||
rm -f ns*/K*.private ns*/K*.key ns*/K*.state
|
||||
rm -f ns*/dsset-* ns*/*.db ns*/*.db.signed
|
||||
|
||||
rm -f ns*/keygen.out.* ns*/settime.out.*
|
||||
rm -f created.key-* *.created unused.key-*
|
||||
|
|
|
|||
|
|
@ -18,6 +18,12 @@ dnssec-policy "nsec" {
|
|||
// NSEC will be used;
|
||||
};
|
||||
|
||||
dnssec-policy "rsasha1" {
|
||||
keys {
|
||||
csk lifetime unlimited algorithm rsasha1;
|
||||
};
|
||||
};
|
||||
|
||||
dnssec-policy "nsec3" {
|
||||
nsec3param;
|
||||
};
|
||||
|
|
@ -59,6 +65,56 @@ zone "nsec-to-nsec3.kasp" {
|
|||
dnssec-policy "nsec";
|
||||
};
|
||||
|
||||
/*
|
||||
* This zone starts with NSEC, but will be reconfigured to use NSEC3.
|
||||
* This should work despite the incompatible RSAHSHA1 algorithm,
|
||||
* because the DS is still in hidden state.
|
||||
*/
|
||||
zone "rsasha1-to-nsec3.kasp" {
|
||||
type primary;
|
||||
file "rsasha1-to-nsec3.kasp.db";
|
||||
inline-signing yes;
|
||||
dnssec-policy "rsasha1";
|
||||
};
|
||||
|
||||
/*
|
||||
* This zone starts with NSEC, but will be reconfigured to use NSEC3.
|
||||
* This should block because RSASHA1 is not compatible with NSEC3,
|
||||
* and the DS is published.
|
||||
*/
|
||||
zone "rsasha1-to-nsec3-wait.kasp" {
|
||||
type primary;
|
||||
file "rsasha1-to-nsec3-wait.kasp.db";
|
||||
inline-signing yes;
|
||||
dnssec-policy "rsasha1";
|
||||
};
|
||||
|
||||
/*
|
||||
* This zone starts with NSEC3, but will be reconfigured to use NSEC with an
|
||||
* NSEC only algorithm. This should work despite the incompatible RSAHSHA1
|
||||
* algorithm, because the DS is still in hidden state.
|
||||
*/
|
||||
zone "nsec3-to-rsasha1.kasp" {
|
||||
type primary;
|
||||
file "nsec3-to-rsasha1.kasp.db";
|
||||
inline-signing yes;
|
||||
dnssec-policy "nsec3";
|
||||
};
|
||||
|
||||
/*
|
||||
* This zone starts with NSEC3, but will be reconfigured to use NSEC with an
|
||||
* NSEC only algorithm. This should also be fine because we are allowed
|
||||
* to change to NSEC with any algorithm, then we can also publish the new
|
||||
* DNSKEY and signatures of the RSASHA1 algorithm.
|
||||
*/
|
||||
zone "nsec3-to-rsasha1-ds.kasp" {
|
||||
type primary;
|
||||
file "nsec3-to-rsasha1-ds.kasp.db";
|
||||
inline-signing yes;
|
||||
dnssec-policy "nsec3";
|
||||
};
|
||||
|
||||
|
||||
/* These zones use the default NSEC3 settings. */
|
||||
zone "nsec3.kasp" {
|
||||
type primary;
|
||||
|
|
|
|||
|
|
@ -18,6 +18,12 @@ dnssec-policy "nsec" {
|
|||
// NSEC will be used;
|
||||
};
|
||||
|
||||
dnssec-policy "rsasha1" {
|
||||
keys {
|
||||
csk lifetime unlimited algorithm rsasha1;
|
||||
};
|
||||
};
|
||||
|
||||
dnssec-policy "nsec3" {
|
||||
nsec3param;
|
||||
};
|
||||
|
|
@ -60,6 +66,59 @@ zone "nsec-to-nsec3.kasp" {
|
|||
dnssec-policy "nsec3";
|
||||
};
|
||||
|
||||
/*
|
||||
* This zone starts with NSEC, but will be reconfigured to use NSEC3.
|
||||
* This should work despite the incompatible RSAHSHA1 algorithm,
|
||||
* because the DS is still in hidden state.
|
||||
*/
|
||||
zone "rsasha1-to-nsec3.kasp" {
|
||||
type primary;
|
||||
file "rsasha1-to-nsec3.kasp.db";
|
||||
inline-signing yes;
|
||||
//dnssec-policy "rsasha1";
|
||||
dnssec-policy "nsec3";
|
||||
};
|
||||
|
||||
/*
|
||||
* This zone starts with NSEC, but will be reconfigured to use NSEC3.
|
||||
* This should block because RSASHA1 is not compatible with NSEC3,
|
||||
* and the DS is published.
|
||||
*/
|
||||
zone "rsasha1-to-nsec3-wait.kasp" {
|
||||
type primary;
|
||||
file "rsasha1-to-nsec3-wait.kasp.db";
|
||||
inline-signing yes;
|
||||
//dnssec-policy "rsasha1";
|
||||
dnssec-policy "nsec3";
|
||||
};
|
||||
|
||||
/*
|
||||
* This zone starts with NSEC3, but will be reconfigured to use NSEC with an
|
||||
* NSEC only algorithm. This should work despite the incompatible RSAHSHA1
|
||||
* algorithm, because the DS is still in hidden state.
|
||||
*/
|
||||
zone "nsec3-to-rsasha1.kasp" {
|
||||
type primary;
|
||||
file "nsec3-to-rsasha1.kasp.db";
|
||||
inline-signing yes;
|
||||
//dnssec-policy "nsec3";
|
||||
dnssec-policy "rsasha1";
|
||||
};
|
||||
|
||||
/*
|
||||
* This zone starts with NSEC3, but will be reconfigured to use NSEC with an
|
||||
* NSEC only algorithm. This should also be fine because we are allowed
|
||||
* to change to NSEC with any algorithm, then we can also publish the new
|
||||
* DNSKEY and signatures of the RSASHA1 algorithm.
|
||||
*/
|
||||
zone "nsec3-to-rsasha1-ds.kasp" {
|
||||
type primary;
|
||||
file "nsec3-to-rsasha1-ds.kasp.db";
|
||||
inline-signing yes;
|
||||
//dnssec-policy "nsec3";
|
||||
dnssec-policy "rsasha1";
|
||||
};
|
||||
|
||||
/* These zones use the default NSEC3 settings. */
|
||||
zone "nsec3.kasp" {
|
||||
type primary;
|
||||
|
|
|
|||
|
|
@ -30,4 +30,29 @@ do
|
|||
setup "${zn}.kasp"
|
||||
done
|
||||
|
||||
if (cd ..; $SHELL ../testcrypto.sh -q RSASHA1)
|
||||
then
|
||||
for zn in rsasha1-to-nsec3 rsasha1-to-nsec3-wait nsec3-to-rsasha1 \
|
||||
nsec3-to-rsasha1-ds
|
||||
do
|
||||
setup "${zn}.kasp"
|
||||
done
|
||||
|
||||
longago="now-1y"
|
||||
keytimes="-P ${longago} -A ${longago}"
|
||||
O="omnipresent"
|
||||
|
||||
zone="rsasha1-to-nsec3-wait.kasp"
|
||||
CSK=$($KEYGEN -k "rsasha1" -l named.conf $keytimes $zone 2> keygen.out.$zone)
|
||||
echo_i "Created key file $CSK"
|
||||
$SETTIME -s -g $O -k $O $longago -r $O $longago -z $O $longago -d $O $longago "$CSK" > settime.out.$zone 2>&1
|
||||
|
||||
zone="nsec3-to-rsasha1-ds.kasp"
|
||||
CSK=$($KEYGEN -k "default" -l named.conf $keytimes $zone 2> keygen.out.$zone)
|
||||
echo_i "Created key file $CSK"
|
||||
$SETTIME -s -g $O -k $O $longago -r $O $longago -z $O $longago -d $O $longago "$CSK" > settime.out.$zone 2>&1
|
||||
else
|
||||
echo_i "skip: skip rsasha1 zones - signing with RSASHA1 not supported"
|
||||
fi
|
||||
|
||||
cp nsec3-fails-to-load.kasp.db.in nsec3-fails-to-load.kasp.db
|
||||
|
|
|
|||
|
|
@ -36,6 +36,8 @@ rndccmd() {
|
|||
set_zone_policy() {
|
||||
ZONE=$1
|
||||
POLICY=$2
|
||||
NUM_KEYS=$3
|
||||
DNSKEY_TTL=$4
|
||||
}
|
||||
# Set expected NSEC3 parameters: flags ($1), iterations ($2), and
|
||||
# salt length ($3).
|
||||
|
|
@ -47,6 +49,49 @@ set_nsec3param() {
|
|||
SALT=""
|
||||
}
|
||||
|
||||
# Set expected default dnssec-policy keys values.
|
||||
set_key_default_values() {
|
||||
key_clear $1
|
||||
|
||||
set_keyrole $1 "csk"
|
||||
set_keylifetime $1 "0"
|
||||
set_keyalgorithm $1 "13" "ECDSAP256SHA256" "256"
|
||||
set_keysigning $1 "yes"
|
||||
set_zonesigning $1 "yes"
|
||||
|
||||
set_keystate $1 "GOAL" "omnipresent"
|
||||
set_keystate $1 "STATE_DNSKEY" "rumoured"
|
||||
set_keystate $1 "STATE_KRRSIG" "rumoured"
|
||||
set_keystate $1 "STATE_ZRRSIG" "rumoured"
|
||||
set_keystate $1 "STATE_DS" "hidden"
|
||||
}
|
||||
|
||||
# Set expected rsasha1 dnssec-policy keys values.
|
||||
set_key_rsasha1_values() {
|
||||
key_clear $1
|
||||
|
||||
set_keyrole $1 "csk"
|
||||
set_keylifetime $1 "0"
|
||||
set_keyalgorithm $1 "5" "RSASHA1" "2048"
|
||||
set_keysigning $1 "yes"
|
||||
set_zonesigning $1 "yes"
|
||||
|
||||
set_keystate $1 "GOAL" "omnipresent"
|
||||
set_keystate $1 "STATE_DNSKEY" "rumoured"
|
||||
set_keystate $1 "STATE_KRRSIG" "rumoured"
|
||||
set_keystate $1 "STATE_ZRRSIG" "rumoured"
|
||||
set_keystate $1 "STATE_DS" "hidden"
|
||||
}
|
||||
|
||||
# Update the key states.
|
||||
set_key_states() {
|
||||
set_keystate $1 "GOAL" "$2"
|
||||
set_keystate $1 "STATE_DNSKEY" "$3"
|
||||
set_keystate $1 "STATE_KRRSIG" "$4"
|
||||
set_keystate $1 "STATE_ZRRSIG" "$5"
|
||||
set_keystate $1 "STATE_DS" "$6"
|
||||
}
|
||||
|
||||
# The apex NSEC3PARAM record indicates that it is signed.
|
||||
_wait_for_nsec3param() {
|
||||
dig_with_opts +noquestion "@${SERVER}" "$ZONE" NSEC3PARAM > "dig.out.test$n.wait" || return 1
|
||||
|
|
@ -67,7 +112,7 @@ _wait_for_nsec() {
|
|||
wait_for_zone_is_signed() {
|
||||
n=$((n+1))
|
||||
ret=0
|
||||
echo_i "wait for ${ZONE} to be signed ($n)"
|
||||
echo_i "wait for ${ZONE} to be signed with $1 ($n)"
|
||||
|
||||
if [ "$1" = "nsec3" ]; then
|
||||
retry_quiet 10 _wait_for_nsec3param || log_error "wait for ${ZONE} to be signed failed"
|
||||
|
|
@ -79,24 +124,45 @@ wait_for_zone_is_signed() {
|
|||
status=$((status+ret))
|
||||
}
|
||||
|
||||
# Test: check DNSSEC verify
|
||||
_check_dnssec_verify() {
|
||||
dig_with_opts @$SERVER "${ZONE}" AXFR > "dig.out.test$n.axfr.$ZONE" || return 1
|
||||
$VERIFY -z -o "$ZONE" "dig.out.test$n.axfr.$ZONE" > "verify.out.test$n.$ZONE" 2>&1 || return 1
|
||||
return 0
|
||||
}
|
||||
|
||||
# Test: check NSEC in answers
|
||||
_check_nsec_nsec3param()
|
||||
{
|
||||
_check_nsec_nsec3param() {
|
||||
dig_with_opts +noquestion @$SERVER "${ZONE}" NSEC3PARAM > "dig.out.test$n.nsec3param.$ZONE" || return 1
|
||||
grep "NSEC3PARAM" "dig.out.test$n.nsec3param.$ZONE" > /dev/null && return 1
|
||||
return 0
|
||||
}
|
||||
|
||||
_check_nsec_nxdomain()
|
||||
{
|
||||
_check_nsec_nxdomain() {
|
||||
dig_with_opts @$SERVER "nosuchname.${ZONE}" > "dig.out.test$n.nxdomain.$ZONE" || return 1
|
||||
grep "${ZONE}.*IN.*NSEC.*NS.*SOA.*RRSIG.*NSEC.*DNSKEY" "dig.out.test$n.nxdomain.$ZONE" > /dev/null || return 1
|
||||
grep "NSEC3" "dig.out.test$n.nxdomain.$ZONE" > /dev/null && return 1
|
||||
return 0
|
||||
}
|
||||
|
||||
check_nsec()
|
||||
{
|
||||
check_nsec() {
|
||||
wait_for_zone_is_signed "nsec"
|
||||
|
||||
n=$((n+1))
|
||||
echo_i "check DNSKEY rrset is signed correctly for zone ${ZONE} ($n)"
|
||||
ret=0
|
||||
check_keys
|
||||
retry_quiet 10 _check_apex_dnskey || log_error "bad DNSKEY RRset for zone ${ZONE}"
|
||||
test "$ret" -eq 0 || echo_i "failed"
|
||||
status=$((status+ret))
|
||||
|
||||
n=$((n+1))
|
||||
echo_i "verify DNSSEC for zone ${ZONE} ($n)"
|
||||
ret=0
|
||||
retry_quiet 10 _check_dnssec_verify || log_error "DNSSEC verify failed for zone ${ZONE}"
|
||||
test "$ret" -eq 0 || echo_i "failed"
|
||||
status=$((status+ret))
|
||||
|
||||
n=$((n+1))
|
||||
echo_i "check NSEC3PARAM response for zone ${ZONE} ($n)"
|
||||
ret=0
|
||||
|
|
@ -113,8 +179,7 @@ check_nsec()
|
|||
}
|
||||
|
||||
# Test: check NSEC3 parameters in answers
|
||||
_check_nsec3_nsec3param()
|
||||
{
|
||||
_check_nsec3_nsec3param() {
|
||||
dig_with_opts +noquestion @$SERVER "${ZONE}" NSEC3PARAM > "dig.out.test$n.nsec3param.$ZONE" || return 1
|
||||
grep "${ZONE}.*0.*IN.*NSEC3PARAM.*1.*0.*${ITERATIONS}.*${SALT}" "dig.out.test$n.nsec3param.$ZONE" > /dev/null || return 1
|
||||
|
||||
|
|
@ -124,15 +189,15 @@ _check_nsec3_nsec3param()
|
|||
return 0
|
||||
}
|
||||
|
||||
_check_nsec3_nxdomain()
|
||||
{
|
||||
_check_nsec3_nxdomain() {
|
||||
dig_with_opts @$SERVER "nosuchname.${ZONE}" > "dig.out.test$n.nxdomain.$ZONE" || return 1
|
||||
grep ".*\.${ZONE}.*IN.*NSEC3.*1.${FLAGS}.*${ITERATIONS}.*${SALT}" "dig.out.test$n.nxdomain.$ZONE" > /dev/null || return 1
|
||||
return 0
|
||||
}
|
||||
|
||||
check_nsec3()
|
||||
{
|
||||
check_nsec3() {
|
||||
wait_for_zone_is_signed "nsec3"
|
||||
|
||||
n=$((n+1))
|
||||
echo_i "check that NSEC3PARAM 1 0 ${ITERATIONS} is published zone ${ZONE} ($n)"
|
||||
ret=0
|
||||
|
|
@ -146,74 +211,119 @@ check_nsec3()
|
|||
retry_quiet 10 _check_nsec3_nxdomain || log_error "bad NXDOMAIN response for zone ${ZONE}"
|
||||
test "$ret" -eq 0 || echo_i "failed"
|
||||
status=$((status+ret))
|
||||
|
||||
n=$((n+1))
|
||||
echo_i "verify DNSSEC for zone ${ZONE} ($n)"
|
||||
ret=0
|
||||
retry_quiet 10 _check_dnssec_verify || log_error "DNSSEC verify failed for zone ${ZONE}"
|
||||
test "$ret" -eq 0 || echo_i "failed"
|
||||
status=$((status+ret))
|
||||
}
|
||||
|
||||
start_time="$(TZ=UTC date +%s)"
|
||||
status=0
|
||||
n=0
|
||||
|
||||
key_clear "KEY1"
|
||||
key_clear "KEY2"
|
||||
key_clear "KEY3"
|
||||
key_clear "KEY4"
|
||||
|
||||
# Zone: nsec-to-nsec3.kasp.
|
||||
set_zone_policy "nsec-to-nsec3.kasp" "nsec"
|
||||
set_zone_policy "nsec-to-nsec3.kasp" "nsec" 1 3600
|
||||
set_server "ns3" "10.53.0.3"
|
||||
set_key_default_values "KEY1"
|
||||
echo_i "initial check zone ${ZONE}"
|
||||
check_nsec
|
||||
dnssec_verify
|
||||
|
||||
if ($SHELL ../testcrypto.sh -q RSASHA1)
|
||||
then
|
||||
# Zone: rsasha1-to-nsec3.kasp.
|
||||
set_zone_policy "rsasha1-to-nsec3.kasp" "rsasha1" 1 3600
|
||||
set_server "ns3" "10.53.0.3"
|
||||
set_key_rsasha1_values "KEY1"
|
||||
echo_i "initial check zone ${ZONE}"
|
||||
check_nsec
|
||||
|
||||
# Zone: rsasha1-to-nsec3-wait.kasp.
|
||||
set_zone_policy "rsasha1-to-nsec3-wait.kasp" "rsasha1" 1 3600
|
||||
set_server "ns3" "10.53.0.3"
|
||||
set_key_rsasha1_values "KEY1"
|
||||
set_key_states "KEY1" "omnipresent" "omnipresent" "omnipresent" "omnipresent" "omnipresent"
|
||||
echo_i "initial check zone ${ZONE}"
|
||||
check_nsec
|
||||
|
||||
# Zone: nsec3-to-rsasha1.kasp.
|
||||
set_zone_policy "nsec3-to-rsasha1.kasp" "nsec3" 1 3600
|
||||
set_server "ns3" "10.53.0.3"
|
||||
set_key_rsasha1_values "KEY1"
|
||||
echo_i "initial check zone ${ZONE}"
|
||||
check_nsec3
|
||||
|
||||
# Zone: nsec3-to-rsasha1-ds.kasp.
|
||||
set_zone_policy "nsec3-to-rsasha1-ds.kasp" "nsec3" 1 3600
|
||||
set_server "ns3" "10.53.0.3"
|
||||
set_key_rsasha1_values "KEY1"
|
||||
set_key_states "KEY1" "omnipresent" "omnipresent" "omnipresent" "omnipresent" "omnipresent"
|
||||
echo_i "initial check zone ${ZONE}"
|
||||
check_nsec3
|
||||
fi
|
||||
|
||||
# Zone: nsec3.kasp.
|
||||
set_zone_policy "nsec3.kasp" "nsec3"
|
||||
set_zone_policy "nsec3.kasp" "nsec3" 1 3600
|
||||
set_nsec3param "0" "0" "0"
|
||||
set_key_default_values "KEY1"
|
||||
echo_i "initial check zone ${ZONE}"
|
||||
check_nsec3
|
||||
dnssec_verify
|
||||
|
||||
# Zone: nsec3-dynamic.kasp.
|
||||
set_zone_policy "nsec3-dynamic.kasp" "nsec3"
|
||||
set_zone_policy "nsec3-dynamic.kasp" "nsec3" 1 3600
|
||||
set_nsec3param "0" "0" "0"
|
||||
set_key_default_values "KEY1"
|
||||
echo_i "initial check zone ${ZONE}"
|
||||
check_nsec3
|
||||
dnssec_verify
|
||||
|
||||
# Zone: nsec3-change.kasp.
|
||||
set_zone_policy "nsec3-change.kasp" "nsec3"
|
||||
set_zone_policy "nsec3-change.kasp" "nsec3" 1 3600
|
||||
set_nsec3param "0" "0" "0"
|
||||
set_key_default_values "KEY1"
|
||||
echo_i "initial check zone ${ZONE}"
|
||||
check_nsec3
|
||||
dnssec_verify
|
||||
|
||||
# Zone: nsec3-dynamic-change.kasp.
|
||||
set_zone_policy "nsec3-dynamic-change.kasp" "nsec3"
|
||||
set_zone_policy "nsec3-dynamic-change.kasp" "nsec3" 1 3600
|
||||
set_nsec3param "0" "0" "0"
|
||||
set_key_default_values "KEY1"
|
||||
echo_i "initial check zone ${ZONE}"
|
||||
check_nsec3
|
||||
dnssec_verify
|
||||
|
||||
# Zone: nsec3-to-nsec.kasp.
|
||||
set_zone_policy "nsec3-to-nsec.kasp" "nsec3"
|
||||
set_zone_policy "nsec3-to-nsec.kasp" "nsec3" 1 3600
|
||||
set_nsec3param "0" "0" "0"
|
||||
set_key_default_values "KEY1"
|
||||
echo_i "initial check zone ${ZONE}"
|
||||
check_nsec3
|
||||
dnssec_verify
|
||||
|
||||
# Zone: nsec3-to-optout.kasp.
|
||||
set_zone_policy "nsec3-to-optout.kasp" "nsec3"
|
||||
set_zone_policy "nsec3-to-optout.kasp" "nsec3" 1 3600
|
||||
set_nsec3param "0" "0" "0"
|
||||
set_key_default_values "KEY1"
|
||||
echo_i "initial check zone ${ZONE}"
|
||||
check_nsec3
|
||||
dnssec_verify
|
||||
|
||||
# Zone: nsec3-from-optout.kasp.
|
||||
set_zone_policy "nsec3-from-optout.kasp" "optout"
|
||||
set_zone_policy "nsec3-from-optout.kasp" "optout" 1 3600
|
||||
set_nsec3param "1" "0" "0"
|
||||
set_key_default_values "KEY1"
|
||||
echo_i "initial check zone ${ZONE}"
|
||||
check_nsec3
|
||||
dnssec_verify
|
||||
|
||||
# Zone: nsec3-other.kasp.
|
||||
set_zone_policy "nsec3-other.kasp" "nsec3-other"
|
||||
set_zone_policy "nsec3-other.kasp" "nsec3-other" 1 3600
|
||||
set_nsec3param "1" "11" "8"
|
||||
set_key_default_values "KEY1"
|
||||
echo_i "initial check zone ${ZONE}"
|
||||
check_nsec3
|
||||
dnssec_verify
|
||||
|
||||
# Reconfig named.
|
||||
echo_i "reconfig dnssec-policy to trigger nsec3 rollovers"
|
||||
|
|
@ -221,88 +331,141 @@ copy_setports ns3/named2.conf.in ns3/named.conf
|
|||
rndc_reconfig ns3 10.53.0.3
|
||||
|
||||
# Zone: nsec-to-nsec3.kasp. (reconfigured)
|
||||
set_zone_policy "nsec-to-nsec3.kasp" "nsec3"
|
||||
set_zone_policy "nsec-to-nsec3.kasp" "nsec3" 1 3600
|
||||
set_nsec3param "0" "0" "0"
|
||||
set_key_default_values "KEY1"
|
||||
echo_i "check zone ${ZONE} after reconfig"
|
||||
check_nsec3
|
||||
dnssec_verify
|
||||
|
||||
if ($SHELL ../testcrypto.sh -q RSASHA1)
|
||||
then
|
||||
# Zone: rsasha1-to-nsec3.kasp.
|
||||
set_zone_policy "rsasha1-to-nsec3.kasp" "nsec3" 2 3600
|
||||
set_server "ns3" "10.53.0.3"
|
||||
set_key_rsasha1_values "KEY1"
|
||||
set_key_states "KEY1" "hidden" "unretentive" "unretentive" "unretentive" "hidden"
|
||||
set_keysigning "KEY1" "no"
|
||||
set_zonesigning "KEY1" "no"
|
||||
set_key_default_values "KEY2"
|
||||
echo_i "check zone ${ZONE} after reconfig"
|
||||
check_nsec3
|
||||
|
||||
# Zone: rsasha1-to-nsec3-wait.kasp.
|
||||
set_zone_policy "rsasha1-to-nsec3-wait.kasp" "nsec3" 2 3600
|
||||
set_server "ns3" "10.53.0.3"
|
||||
set_key_rsasha1_values "KEY1"
|
||||
set_key_states "KEY1" "hidden" "omnipresent" "omnipresent" "omnipresent" "omnipresent"
|
||||
set_key_default_values "KEY2"
|
||||
echo_i "check zone ${ZONE} after reconfig"
|
||||
|
||||
ret=0
|
||||
wait_for_log 10 "zone $ZONE/IN (signed): wait building NSEC3 chain until NSEC only DNSKEYs are removed" ns3/named.run || ret=1
|
||||
test "$ret" -eq 0 || echo_i "failed"
|
||||
status=$((status+ret))
|
||||
|
||||
check_nsec
|
||||
|
||||
# Zone: nsec3-to-rsasha1.kasp.
|
||||
set_zone_policy "nsec3-to-rsasha1.kasp" "rsasha1" 2 3600
|
||||
set_nsec3param "1" "0" "0"
|
||||
set_server "ns3" "10.53.0.3"
|
||||
set_key_default_values "KEY1"
|
||||
set_key_states "KEY1" "hidden" "unretentive" "unretentive" "unretentive" "hidden"
|
||||
set_keysigning "KEY1" "no"
|
||||
set_zonesigning "KEY1" "no"
|
||||
set_key_rsasha1_values "KEY2"
|
||||
echo_i "check zone ${ZONE} after reconfig"
|
||||
check_nsec
|
||||
|
||||
# Zone: nsec3-to-rsasha1-ds.kasp.
|
||||
set_zone_policy "nsec3-to-rsasha1-ds.kasp" "rsasha1" 2 3600
|
||||
set_nsec3param "1" "0" "0"
|
||||
set_server "ns3" "10.53.0.3"
|
||||
set_key_default_values "KEY1"
|
||||
set_key_states "KEY1" "hidden" "omnipresent" "omnipresent" "omnipresent" "omnipresent"
|
||||
set_key_rsasha1_values "KEY2"
|
||||
echo_i "check zone ${ZONE} after reconfig"
|
||||
check_nsec
|
||||
|
||||
key_clear "KEY1"
|
||||
key_clear "KEY2"
|
||||
fi
|
||||
|
||||
# Zone: nsec3.kasp. (same)
|
||||
set_zone_policy "nsec3.kasp" "nsec3"
|
||||
set_zone_policy "nsec3.kasp" "nsec3" 1 3600
|
||||
set_nsec3param "0" "0" "0"
|
||||
set_key_default_values "KEY1"
|
||||
echo_i "check zone ${ZONE} after reconfig"
|
||||
check_nsec3
|
||||
dnssec_verify
|
||||
|
||||
# Zone: nsec3-dyamic.kasp. (same)
|
||||
set_zone_policy "nsec3-dynamic.kasp" "nsec3"
|
||||
set_zone_policy "nsec3-dynamic.kasp" "nsec3" 1 3600
|
||||
set_nsec3param "0" "0" "0"
|
||||
set_key_default_values "KEY1"
|
||||
echo_i "check zone ${ZONE} after reconfig"
|
||||
check_nsec3
|
||||
dnssec_verify
|
||||
|
||||
# Zone: nsec3-change.kasp. (reconfigured)
|
||||
set_zone_policy "nsec3-change.kasp" "nsec3-other"
|
||||
set_zone_policy "nsec3-change.kasp" "nsec3-other" 1 3600
|
||||
set_nsec3param "1" "11" "8"
|
||||
set_key_default_values "KEY1"
|
||||
echo_i "check zone ${ZONE} after reconfig"
|
||||
check_nsec3
|
||||
dnssec_verify
|
||||
|
||||
# Zone: nsec3-dynamic-change.kasp. (reconfigured)
|
||||
set_zone_policy "nsec3-dynamic-change.kasp" "nsec3-other"
|
||||
set_zone_policy "nsec3-dynamic-change.kasp" "nsec3-other" 1 3600
|
||||
set_nsec3param "1" "11" "8"
|
||||
set_key_default_values "KEY1"
|
||||
echo_i "check zone ${ZONE} after reconfig"
|
||||
check_nsec3
|
||||
dnssec_verify
|
||||
|
||||
# Zone: nsec3-to-nsec.kasp. (reconfigured)
|
||||
set_zone_policy "nsec3-to-nsec.kasp" "nsec"
|
||||
set_zone_policy "nsec3-to-nsec.kasp" "nsec" 1 3600
|
||||
set_nsec3param "1" "11" "8"
|
||||
set_key_default_values "KEY1"
|
||||
echo_i "check zone ${ZONE} after reconfig"
|
||||
check_nsec
|
||||
dnssec_verify
|
||||
|
||||
# Zone: nsec3-to-optout.kasp. (reconfigured)
|
||||
# DISABLED:
|
||||
# There is a bug in the nsec3param building code that thinks when the
|
||||
# optout bit is changed, the chain already exists. [GL #2216]
|
||||
#set_zone_policy "nsec3-to-optout.kasp" "optout"
|
||||
#set_zone_policy "nsec3-to-optout.kasp" "optout" 1 3600
|
||||
#set_nsec3param "1" "0" "0"
|
||||
#set_key_default_values "KEY1"
|
||||
#echo_i "check zone ${ZONE} after reconfig"
|
||||
#check_nsec3
|
||||
#dnssec_verify
|
||||
|
||||
# Zone: nsec3-from-optout.kasp. (reconfigured)
|
||||
# DISABLED:
|
||||
# There is a bug in the nsec3param building code that thinks when the
|
||||
# optout bit is changed, the chain already exists. [GL #2216]
|
||||
#set_zone_policy "nsec3-from-optout.kasp" "nsec3"
|
||||
#set_zone_policy "nsec3-from-optout.kasp" "nsec3" 1 3600
|
||||
#set_nsec3param "0" "0" "0"
|
||||
#set_key_default_values "KEY1"
|
||||
#echo_i "check zone ${ZONE} after reconfig"
|
||||
#check_nsec3
|
||||
#dnssec_verify
|
||||
|
||||
# Zone: nsec3-other.kasp. (same)
|
||||
set_zone_policy "nsec3-other.kasp" "nsec3-other"
|
||||
set_zone_policy "nsec3-other.kasp" "nsec3-other" 1 3600
|
||||
set_nsec3param "1" "11" "8"
|
||||
set_key_default_values "KEY1"
|
||||
echo_i "check zone ${ZONE} after reconfig"
|
||||
check_nsec3
|
||||
dnssec_verify
|
||||
|
||||
# Using rndc signing -nsec3param (should fail)
|
||||
set_zone_policy "nsec3-change.kasp" "nsec3-other"
|
||||
set_zone_policy "nsec3-change.kasp" "nsec3-other" 1 3600
|
||||
echo_i "use rndc signing -nsec3param ${ZONE} to change NSEC3 settings"
|
||||
rndccmd $SERVER signing -nsec3param 1 1 12 ffff $ZONE > rndc.signing.test$n.$ZONE || log_error "failed to call rndc signing -nsec3param $ZONE"
|
||||
grep "zone uses dnssec-policy, use rndc dnssec command instead" rndc.signing.test$n.$ZONE > /dev/null || log_error "rndc signing -nsec3param should fail"
|
||||
check_nsec3
|
||||
dnssec_verify
|
||||
|
||||
# Test NSEC3 and NSEC3PARAM is the same after restart
|
||||
set_zone_policy "nsec3.kasp" "nsec3"
|
||||
set_zone_policy "nsec3.kasp" "nsec3" 1 3600
|
||||
set_nsec3param "0" "0" "0"
|
||||
set_key_default_values "KEY1"
|
||||
echo_i "check zone ${ZONE} before restart"
|
||||
check_nsec3
|
||||
dnssec_verify
|
||||
|
||||
# Restart named, NSEC3 should stay the same.
|
||||
ret=0
|
||||
|
|
@ -318,22 +481,22 @@ test "$ret" -eq 0 || echo_i "failed"
|
|||
status=$((status+ret))
|
||||
|
||||
prevsalt="${SALT}"
|
||||
set_zone_policy "nsec3.kasp" "nsec3"
|
||||
set_zone_policy "nsec3.kasp" "nsec3" 1 3600
|
||||
set_nsec3param "0" "0" "0"
|
||||
set_key_default_values "KEY1"
|
||||
SALT="${prevsalt}"
|
||||
echo_i "check zone ${ZONE} after restart has salt ${SALT}"
|
||||
check_nsec3
|
||||
dnssec_verify
|
||||
|
||||
# Zone: nsec3-fails-to-load.kasp. (should be fixed after reload)
|
||||
cp ns3/template.db.in ns3/nsec3-fails-to-load.kasp.db
|
||||
rndc_reload ns3 10.53.0.3
|
||||
|
||||
set_zone_policy "nsec3-fails-to-load.kasp" "nsec3"
|
||||
set_zone_policy "nsec3-fails-to-load.kasp" "nsec3" 1 3600
|
||||
set_nsec3param "0" "0" "0"
|
||||
set_key_default_values "KEY1"
|
||||
echo_i "check zone ${ZONE} after reload"
|
||||
check_nsec3
|
||||
dnssec_verify
|
||||
|
||||
echo_i "exit status: $status"
|
||||
[ $status -eq 0 ] || exit 1
|
||||
|
|
|
|||
|
|
@ -38,6 +38,12 @@ Feature Changes
|
|||
- Zones using ``dnssec-policy`` now require dynamic DNS or
|
||||
``inline-signing`` to be configured explicitly :gl:`#3381`.
|
||||
|
||||
- When reconfiguring ``dnssec-policy`` from using NSEC with an NSEC-only DNSKEY
|
||||
algorithm (e.g. RSASHA1) to a policy that uses NSEC3, BIND will no longer fail
|
||||
to sign the zone, but keep using NSEC for a little longer until the offending
|
||||
DNSKEY records have been removed from the zone, then switch to using NSEC3.
|
||||
:gl:`#3486`
|
||||
|
||||
Bug Fixes
|
||||
~~~~~~~~~
|
||||
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@
|
|||
|
||||
#include <isc/lang.h>
|
||||
|
||||
#include <dns/diff.h>
|
||||
#include <dns/name.h>
|
||||
#include <dns/types.h>
|
||||
|
||||
|
|
@ -60,11 +61,15 @@ dns_nsec_typepresent(dns_rdata_t *nsec, dns_rdatatype_t type);
|
|||
*/
|
||||
|
||||
isc_result_t
|
||||
dns_nsec_nseconly(dns_db_t *db, dns_dbversion_t *version, bool *answer);
|
||||
dns_nsec_nseconly(dns_db_t *db, dns_dbversion_t *version, dns_diff_t *diff,
|
||||
bool *answer);
|
||||
/*
|
||||
* Report whether the DNSKEY RRset has a NSEC only algorithm. Unknown
|
||||
* algorithms are assumed to support NSEC3. If DNSKEY is not found,
|
||||
* *answer is set to false, and ISC_R_NOTFOUND is returned.
|
||||
* If 'diff' is provided, check if the NSEC only DNSKEY will be deleted.
|
||||
* If so, and there are no other NSEC only DNSKEYs that will stay in 'db',
|
||||
* consider the DNSKEY RRset to have no NSEC only DNSKEYs.
|
||||
*
|
||||
* Requires:
|
||||
* 'answer' to be non NULL.
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@
|
|||
#include <isc/tls.h>
|
||||
|
||||
#include <dns/catz.h>
|
||||
#include <dns/diff.h>
|
||||
#include <dns/master.h>
|
||||
#include <dns/masterdump.h>
|
||||
#include <dns/rdatastruct.h>
|
||||
|
|
@ -2761,3 +2762,20 @@ dns_zone_gettid(dns_zone_t *zone);
|
|||
*
|
||||
* \return thread id associated with the zone
|
||||
*/
|
||||
|
||||
bool
|
||||
dns_zone_check_dnskey_nsec3(dns_zone_t *zone, dns_db_t *db,
|
||||
dns_dbversion_t *ver, dns_diff_t *diff,
|
||||
dst_key_t **keys, unsigned int numkeys);
|
||||
/**<
|
||||
* Return whether the zone would enter an inconsistent state where NSEC only
|
||||
* DNSKEYs are present along NSEC3 chains.
|
||||
*
|
||||
* Requires:
|
||||
* \li 'zone' to be a valid zone.
|
||||
* \li 'db'is not NULL.
|
||||
*
|
||||
* Returns:
|
||||
* \li 'true' if the check passes, that is the zone remains consistent,
|
||||
* 'false' if the zone would have NSEC only DNSKEYs and an NSEC3 chain.
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -247,7 +247,8 @@ dns_nsec_typepresent(dns_rdata_t *nsec, dns_rdatatype_t type) {
|
|||
}
|
||||
|
||||
isc_result_t
|
||||
dns_nsec_nseconly(dns_db_t *db, dns_dbversion_t *version, bool *answer) {
|
||||
dns_nsec_nseconly(dns_db_t *db, dns_dbversion_t *version, dns_diff_t *diff,
|
||||
bool *answer) {
|
||||
dns_dbnode_t *node = NULL;
|
||||
dns_rdataset_t rdataset;
|
||||
dns_rdata_dnskey_t dnskey;
|
||||
|
|
@ -282,8 +283,35 @@ dns_nsec_nseconly(dns_db_t *db, dns_dbversion_t *version, bool *answer) {
|
|||
RUNTIME_CHECK(result == ISC_R_SUCCESS);
|
||||
|
||||
if (dnskey.algorithm == DST_ALG_RSAMD5 ||
|
||||
dnskey.algorithm == DST_ALG_RSASHA1) {
|
||||
break;
|
||||
dnskey.algorithm == DST_ALG_DH ||
|
||||
dnskey.algorithm == DST_ALG_DSA ||
|
||||
dnskey.algorithm == DST_ALG_RSASHA1)
|
||||
{
|
||||
bool deleted = false;
|
||||
if (diff != NULL) {
|
||||
for (dns_difftuple_t *tuple =
|
||||
ISC_LIST_HEAD(diff->tuples);
|
||||
tuple != NULL;
|
||||
tuple = ISC_LIST_NEXT(tuple, link))
|
||||
{
|
||||
if (tuple->rdata.type !=
|
||||
dns_rdatatype_dnskey ||
|
||||
tuple->op != DNS_DIFFOP_DEL) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (dns_rdata_compare(
|
||||
&rdata, &tuple->rdata) == 0)
|
||||
{
|
||||
deleted = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!deleted) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
dns_rdataset_disassociate(&rdataset);
|
||||
|
|
|
|||
192
lib/dns/zone.c
192
lib/dns/zone.c
|
|
@ -3726,7 +3726,7 @@ zone_addnsec3chain(dns_zone_t *zone, dns_rdata_nsec3param_t *nsec3param) {
|
|||
* latter to exist in the first place.
|
||||
*/
|
||||
dns_db_currentversion(db, &version);
|
||||
result = dns_nsec_nseconly(db, version, &nseconly);
|
||||
result = dns_nsec_nseconly(db, version, NULL, &nseconly);
|
||||
nsec3ok = (result == ISC_R_SUCCESS && !nseconly);
|
||||
dns_db_closeversion(db, &version, false);
|
||||
if (!nsec3ok && (nsec3param->flags & DNS_NSEC3FLAG_REMOVE) == 0) {
|
||||
|
|
@ -3918,7 +3918,7 @@ resume_addnsec3chain(dns_zone_t *zone) {
|
|||
* In order to create NSEC3 chains we need the DNSKEY RRset at zone
|
||||
* apex to exist and contain no keys using NSEC-only algorithms.
|
||||
*/
|
||||
result = dns_nsec_nseconly(db, version, &nseconly);
|
||||
result = dns_nsec_nseconly(db, version, NULL, &nseconly);
|
||||
nsec3ok = (result == ISC_R_SUCCESS && !nseconly);
|
||||
|
||||
/*
|
||||
|
|
@ -8186,7 +8186,7 @@ try_private:
|
|||
goto add;
|
||||
}
|
||||
|
||||
result = dns_nsec_nseconly(db, ver, &nseconly);
|
||||
result = dns_nsec_nseconly(db, ver, diff, &nseconly);
|
||||
nsec3ok = (result == ISC_R_SUCCESS && !nseconly);
|
||||
|
||||
/*
|
||||
|
|
@ -9508,6 +9508,105 @@ failure:
|
|||
return (result);
|
||||
}
|
||||
|
||||
/*
|
||||
* Prevent the zone entering a inconsistent state where
|
||||
* NSEC only DNSKEYs are present with NSEC3 chains.
|
||||
*/
|
||||
bool
|
||||
dns_zone_check_dnskey_nsec3(dns_zone_t *zone, dns_db_t *db,
|
||||
dns_dbversion_t *ver, dns_diff_t *diff,
|
||||
dst_key_t **keys, unsigned int numkeys) {
|
||||
uint8_t alg;
|
||||
dns_rdatatype_t privatetype;
|
||||
;
|
||||
bool nseconly = false, nsec3 = false;
|
||||
isc_result_t result;
|
||||
|
||||
REQUIRE(DNS_ZONE_VALID(zone));
|
||||
REQUIRE(db != NULL);
|
||||
|
||||
privatetype = dns_zone_getprivatetype(zone);
|
||||
|
||||
/* Scan the tuples for an NSEC-only DNSKEY */
|
||||
if (diff != NULL) {
|
||||
for (dns_difftuple_t *tuple = ISC_LIST_HEAD(diff->tuples);
|
||||
tuple != NULL; tuple = ISC_LIST_NEXT(tuple, link))
|
||||
{
|
||||
if (nseconly && nsec3) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (tuple->op != DNS_DIFFOP_ADD) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (tuple->rdata.type == dns_rdatatype_nsec3param) {
|
||||
nsec3 = true;
|
||||
}
|
||||
|
||||
if (tuple->rdata.type != dns_rdatatype_dnskey) {
|
||||
continue;
|
||||
}
|
||||
|
||||
alg = tuple->rdata.data[3];
|
||||
if (alg == DNS_KEYALG_RSAMD5 || alg == DNS_KEYALG_DH ||
|
||||
alg == DNS_KEYALG_DSA || alg == DNS_KEYALG_RSASHA1)
|
||||
{
|
||||
nseconly = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
/* Scan the zone keys for an NSEC-only DNSKEY */
|
||||
if (keys != NULL && !nseconly) {
|
||||
for (unsigned int i = 0; i < numkeys; i++) {
|
||||
alg = dst_key_alg(keys[i]);
|
||||
if (alg == DNS_KEYALG_RSAMD5 || alg == DNS_KEYALG_DH ||
|
||||
alg == DNS_KEYALG_DSA || alg == DNS_KEYALG_RSASHA1)
|
||||
{
|
||||
nseconly = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Check DB for NSEC-only DNSKEY */
|
||||
if (!nseconly) {
|
||||
result = dns_nsec_nseconly(db, ver, diff, &nseconly);
|
||||
/*
|
||||
* Adding an NSEC3PARAM record can proceed without a
|
||||
* DNSKEY (it will trigger a delayed change), so we can
|
||||
* ignore ISC_R_NOTFOUND here.
|
||||
*/
|
||||
if (result == ISC_R_NOTFOUND) {
|
||||
result = ISC_R_SUCCESS;
|
||||
}
|
||||
CHECK(result);
|
||||
}
|
||||
|
||||
/* Check existing DB for NSEC3 */
|
||||
if (!nsec3) {
|
||||
CHECK(dns_nsec3_activex(db, ver, false, privatetype, &nsec3));
|
||||
}
|
||||
|
||||
/* Check kasp for NSEC3PARAM settings */
|
||||
if (!nsec3) {
|
||||
dns_kasp_t *kasp = dns_zone_getkasp(zone);
|
||||
if (kasp != NULL) {
|
||||
nsec3 = dns_kasp_nsec3(kasp);
|
||||
}
|
||||
}
|
||||
|
||||
/* Refuse to allow NSEC3 with NSEC-only keys */
|
||||
if (nseconly && nsec3) {
|
||||
goto failure;
|
||||
}
|
||||
|
||||
return (true);
|
||||
|
||||
failure:
|
||||
return (false);
|
||||
}
|
||||
|
||||
/*
|
||||
* Incrementally sign the zone using the keys requested.
|
||||
* Builds the NSEC chain if required.
|
||||
|
|
@ -9643,6 +9742,15 @@ zone_sign(dns_zone_t *zone) {
|
|||
/* Determine which type of chain to build */
|
||||
if (use_kasp) {
|
||||
build_nsec3 = dns_kasp_nsec3(kasp);
|
||||
if (!dns_zone_check_dnskey_nsec3(zone, db, version, NULL,
|
||||
(dst_key_t **)&zone_keys,
|
||||
nkeys))
|
||||
{
|
||||
dnssec_log(zone, ISC_LOG_INFO,
|
||||
"wait building NSEC3 chain until NSEC only "
|
||||
"DNSKEYs are removed");
|
||||
build_nsec3 = false;
|
||||
}
|
||||
build_nsec = !build_nsec3;
|
||||
} else {
|
||||
CHECK(dns_private_chains(db, version, zone->privatetype,
|
||||
|
|
@ -20506,63 +20614,6 @@ failure:
|
|||
return (result);
|
||||
}
|
||||
|
||||
/*
|
||||
* Prevent the zone entering a inconsistent state where
|
||||
* NSEC only DNSKEYs are present with NSEC3 chains.
|
||||
* See update.c:check_dnssec()
|
||||
*/
|
||||
static bool
|
||||
dnskey_sane(dns_zone_t *zone, dns_db_t *db, dns_dbversion_t *ver,
|
||||
dns_diff_t *diff) {
|
||||
isc_result_t result;
|
||||
dns_difftuple_t *tuple;
|
||||
bool nseconly = false, nsec3 = false;
|
||||
dns_rdatatype_t privatetype = dns_zone_getprivatetype(zone);
|
||||
|
||||
/* Scan the tuples for an NSEC-only DNSKEY */
|
||||
for (tuple = ISC_LIST_HEAD(diff->tuples); tuple != NULL;
|
||||
tuple = ISC_LIST_NEXT(tuple, link))
|
||||
{
|
||||
uint8_t alg;
|
||||
if (tuple->rdata.type != dns_rdatatype_dnskey ||
|
||||
tuple->op != DNS_DIFFOP_ADD) {
|
||||
continue;
|
||||
}
|
||||
|
||||
alg = tuple->rdata.data[3];
|
||||
if (alg == DST_ALG_RSASHA1) {
|
||||
nseconly = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Check existing DB for NSEC-only DNSKEY */
|
||||
if (!nseconly) {
|
||||
result = dns_nsec_nseconly(db, ver, &nseconly);
|
||||
if (result == ISC_R_NOTFOUND) {
|
||||
result = ISC_R_SUCCESS;
|
||||
}
|
||||
CHECK(result);
|
||||
}
|
||||
|
||||
/* Check existing DB for NSEC3 */
|
||||
if (!nsec3) {
|
||||
CHECK(dns_nsec3_activex(db, ver, false, privatetype, &nsec3));
|
||||
}
|
||||
|
||||
/* Refuse to allow NSEC3 with NSEC-only keys */
|
||||
if (nseconly && nsec3) {
|
||||
dnssec_log(zone, ISC_LOG_ERROR,
|
||||
"NSEC only DNSKEYs and NSEC3 chains not allowed");
|
||||
goto failure;
|
||||
}
|
||||
|
||||
return (true);
|
||||
|
||||
failure:
|
||||
return (false);
|
||||
}
|
||||
|
||||
static isc_result_t
|
||||
clean_nsec3param(dns_zone_t *zone, dns_db_t *db, dns_dbversion_t *ver,
|
||||
dns_diff_t *diff) {
|
||||
|
|
@ -21558,6 +21609,7 @@ zone_rekey(dns_zone_t *zone) {
|
|||
if (result == ISC_R_SUCCESS) {
|
||||
bool cdsdel = false;
|
||||
bool cdnskeydel = false;
|
||||
bool sane_diff, sane_dnskey;
|
||||
isc_stdtime_t when;
|
||||
|
||||
/*
|
||||
|
|
@ -21726,9 +21778,21 @@ zone_rekey(dns_zone_t *zone) {
|
|||
}
|
||||
}
|
||||
|
||||
if ((newactive || fullsign || !ISC_LIST_EMPTY(diff.tuples)) &&
|
||||
dnskey_sane(zone, db, ver, &diff))
|
||||
{
|
||||
/*
|
||||
* A sane diff is one that is not empty, and that does not
|
||||
* introduce a zone with NSEC only DNSKEYs along with NSEC3
|
||||
* chains.
|
||||
*/
|
||||
sane_dnskey = dns_zone_check_dnskey_nsec3(zone, db, ver, &diff,
|
||||
NULL, 0);
|
||||
sane_diff = !ISC_LIST_EMPTY(diff.tuples) && sane_dnskey;
|
||||
if (!sane_dnskey) {
|
||||
dnssec_log(zone, ISC_LOG_ERROR,
|
||||
"NSEC only DNSKEYs and NSEC3 chains not "
|
||||
"allowed");
|
||||
}
|
||||
|
||||
if (newactive || fullsign || sane_diff) {
|
||||
CHECK(dns_diff_apply(&diff, db, ver));
|
||||
CHECK(clean_nsec3param(zone, db, ver, &diff));
|
||||
CHECK(add_signing_records(db, zone->privatetype, ver,
|
||||
|
|
@ -22913,7 +22977,7 @@ rss_post(dns_zone_t *zone, isc_event_t *event) {
|
|||
dns_rdata_init(&rdata);
|
||||
|
||||
np->data[2] |= DNS_NSEC3FLAG_CREATE;
|
||||
result = dns_nsec_nseconly(db, newver, &nseconly);
|
||||
result = dns_nsec_nseconly(db, newver, NULL, &nseconly);
|
||||
if (result == ISC_R_NOTFOUND || nseconly) {
|
||||
np->data[2] |= DNS_NSEC3FLAG_INITIAL;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2096,56 +2096,12 @@ failure:
|
|||
static isc_result_t
|
||||
check_dnssec(ns_client_t *client, dns_zone_t *zone, dns_db_t *db,
|
||||
dns_dbversion_t *ver, dns_diff_t *diff) {
|
||||
dns_difftuple_t *tuple;
|
||||
bool nseconly = false, nsec3 = false;
|
||||
isc_result_t result;
|
||||
unsigned int iterations = 0;
|
||||
dns_rdatatype_t privatetype = dns_zone_getprivatetype(zone);
|
||||
|
||||
/* Scan the tuples for an NSEC-only DNSKEY or an NSEC3PARAM */
|
||||
for (tuple = ISC_LIST_HEAD(diff->tuples); tuple != NULL;
|
||||
tuple = ISC_LIST_NEXT(tuple, link))
|
||||
{
|
||||
if (tuple->op != DNS_DIFFOP_ADD) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (tuple->rdata.type == dns_rdatatype_dnskey) {
|
||||
uint8_t alg;
|
||||
alg = tuple->rdata.data[3];
|
||||
if (alg == DST_ALG_RSASHA1) {
|
||||
nseconly = true;
|
||||
break;
|
||||
}
|
||||
} else if (tuple->rdata.type == dns_rdatatype_nsec3param) {
|
||||
nsec3 = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Check existing DB for NSEC-only DNSKEY */
|
||||
if (!nseconly) {
|
||||
result = dns_nsec_nseconly(db, ver, &nseconly);
|
||||
|
||||
/*
|
||||
* An NSEC3PARAM update can proceed without a DNSKEY (it
|
||||
* will trigger a delayed change), so we can ignore
|
||||
* ISC_R_NOTFOUND here.
|
||||
*/
|
||||
if (result == ISC_R_NOTFOUND) {
|
||||
result = ISC_R_SUCCESS;
|
||||
}
|
||||
|
||||
CHECK(result);
|
||||
}
|
||||
|
||||
/* Check existing DB for NSEC3 */
|
||||
if (!nsec3) {
|
||||
CHECK(dns_nsec3_activex(db, ver, false, privatetype, &nsec3));
|
||||
}
|
||||
|
||||
/* Refuse to allow NSEC3 with NSEC-only keys */
|
||||
if (nseconly && nsec3) {
|
||||
if (!dns_zone_check_dnskey_nsec3(zone, db, ver, diff, NULL, 0)) {
|
||||
update_log(client, zone, ISC_LOG_ERROR,
|
||||
"NSEC only DNSKEYs and NSEC3 chains not allowed");
|
||||
result = DNS_R_REFUSED;
|
||||
|
|
@ -2346,8 +2302,11 @@ add_nsec3param_records(ns_client_t *client, dns_zone_t *zone, dns_db_t *db,
|
|||
* supporting an NSEC3 chain, then we set the
|
||||
* INITIAL flag to indicate that these parameters
|
||||
* are to be used later.
|
||||
*
|
||||
* Don't provide a 'diff' here because we want to
|
||||
* know the capability of the current database.
|
||||
*/
|
||||
result = dns_nsec_nseconly(db, ver, &nseconly);
|
||||
result = dns_nsec_nseconly(db, ver, NULL, &nseconly);
|
||||
if (result == ISC_R_NOTFOUND || nseconly) {
|
||||
buf[2] |= DNS_NSEC3FLAG_INITIAL;
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue