From 75e0d394dd2147a0b07524521c084a71801e4eee Mon Sep 17 00:00:00 2001 From: Matthijs Mekking Date: Wed, 22 Nov 2023 12:29:56 +0100 Subject: [PATCH 1/6] dnssec-policy: refuse to load non-zero iterations According to RFC 9276, if NSEC3 must be used, then an iterations count of 0 MUST be used to alleviate computational burdens. --- lib/isccfg/kaspconf.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/lib/isccfg/kaspconf.c b/lib/isccfg/kaspconf.c index 19365fdc06..861cf514b3 100644 --- a/lib/isccfg/kaspconf.c +++ b/lib/isccfg/kaspconf.c @@ -291,15 +291,12 @@ cfg_nsec3param_fromconfig(const cfg_obj_t *config, dns_kasp_t *kasp, return (DNS_R_NSEC3BADALG); } - if (iter > dns_nsec3_maxiterations()) { - ret = DNS_R_NSEC3ITERRANGE; - } - - if (ret == DNS_R_NSEC3ITERRANGE) { + if (iter != DEFAULT_NSEC3PARAM_ITER) { cfg_obj_log(obj, logctx, ISC_LOG_ERROR, "dnssec-policy: nsec3 iterations value %u " - "out of range", + "not allowed, must be zero", iter); + return (DNS_R_NSEC3ITERRANGE); return (ret); } From 3c08fbc79fd3047ac8cba8e82d3be7d1efce2c2f Mon Sep 17 00:00:00 2001 From: Matthijs Mekking Date: Wed, 22 Nov 2023 12:32:55 +0100 Subject: [PATCH 2/6] Change NSEC3 iterations to 0 in system tests The system tests need to be updated because non-zero iterations are no longer accepted. The autosign system test changes its iterations from 1 to 0 in one test case. This requires the hash to be updated. The checkconf system test needs to change the iterations in the good configuration files to 0, and in the bad ones to 1 (any non-zero value would suffice, but we test the corner case here). Also, the expected failure message is change, so needs to be adjusted. The nsec3 system test also needs iteration configuration adjustments. In addition, the test script no longer needs the ITERATIONS environment variable. In the process of updating the system tests, I noticed an error in the dnssec-policy "nsec3-other", where the salt length in one configuration file is different than in the other (they need to be the same). Furthermore, the 'rndc signing -nsec3param' test case is operated on the zone 'nsec-change.kasp', so is moved so that the tests on the same zone are grouped together. --- bin/tests/system/autosign/ns2/named.conf.in | 2 +- bin/tests/system/autosign/tests.sh | 4 +- bin/tests/system/checkconf/good-kasp.conf | 2 +- .../system/checkconf/good-key-directory.conf | 6 +- .../checkconf/kasp-bad-nsec3-iter-fips.conf | 8 +- .../system/checkconf/kasp-bad-nsec3-iter.conf | 12 +-- bin/tests/system/checkconf/tests.sh | 2 +- bin/tests/system/nsec3/ns3/named-fips.conf.in | 2 +- .../system/nsec3/ns3/named2-fips.conf.in | 2 +- bin/tests/system/nsec3/tests.sh | 81 +++++++++---------- 10 files changed, 59 insertions(+), 62 deletions(-) diff --git a/bin/tests/system/autosign/ns2/named.conf.in b/bin/tests/system/autosign/ns2/named.conf.in index 83da464595..fc5740c84f 100644 --- a/bin/tests/system/autosign/ns2/named.conf.in +++ b/bin/tests/system/autosign/ns2/named.conf.in @@ -67,7 +67,7 @@ dnssec-policy "optout" { zsk key-directory lifetime unlimited algorithm @DEFAULT_ALGORITHM@; }; - nsec3param iterations 1 optout yes salt-length 0; + nsec3param iterations 0 optout yes salt-length 0; }; zone "." { diff --git a/bin/tests/system/autosign/tests.sh b/bin/tests/system/autosign/tests.sh index 41cbb0b613..61afacf1e4 100755 --- a/bin/tests/system/autosign/tests.sh +++ b/bin/tests/system/autosign/tests.sh @@ -1269,9 +1269,9 @@ n=$((n + 1)) if [ $ret != 0 ]; then echo_i "failed"; fi status=$((status + ret)) -echo_i "check removal of ENT NSEC3 records when opt out delegations are removed" +echo_i "check removal of ENT NSEC3 records when opt out delegations are removed ($n)" zone=optout-with-ent -hash=JTR8R6AVFULU0DQH9I6HNN2KUK5956EL +hash=JE76PJ65FUO86UIR594L8P0SNJJ6RMNI # check that NSEC3 for ENT is present echo_i "check ENT NSEC3 is initially present" diff --git a/bin/tests/system/checkconf/good-kasp.conf b/bin/tests/system/checkconf/good-kasp.conf index fb3fceab0a..d5da98fc6d 100644 --- a/bin/tests/system/checkconf/good-kasp.conf +++ b/bin/tests/system/checkconf/good-kasp.conf @@ -29,7 +29,7 @@ dnssec-policy "test" { csk key-directory lifetime unlimited algorithm rsasha256 2048; }; max-zone-ttl 86400; - nsec3param iterations 5 optout no salt-length 8; + nsec3param iterations 0 optout no salt-length 8; parent-ds-ttl 7200; parent-propagation-delay PT1H; publish-safety PT3600S; diff --git a/bin/tests/system/checkconf/good-key-directory.conf b/bin/tests/system/checkconf/good-key-directory.conf index 07deb28993..063c4a9928 100644 --- a/bin/tests/system/checkconf/good-key-directory.conf +++ b/bin/tests/system/checkconf/good-key-directory.conf @@ -17,7 +17,7 @@ dnssec-policy "internet" { zsk key-directory lifetime P90D algorithm ecdsa256; }; - nsec3param iterations 15 optout no salt-length 8; + nsec3param iterations 0 optout no salt-length 8; }; dnssec-policy "intranet" { @@ -25,7 +25,7 @@ dnssec-policy "intranet" { ksk key-directory lifetime unlimited algorithm ecdsa256; zsk key-directory lifetime P30D algorithm ecdsa256; }; - nsec3param iterations 15 optout no salt-length 8; + nsec3param iterations 0 optout no salt-length 8; }; dnssec-policy "localhost" { @@ -33,7 +33,7 @@ dnssec-policy "localhost" { ksk key-directory lifetime unlimited algorithm ecdsa256; zsk key-directory lifetime P30D algorithm ecdsa256; }; - nsec3param iterations 15 optout no salt-length 8; + nsec3param iterations 0 optout no salt-length 8; }; options { diff --git a/bin/tests/system/checkconf/kasp-bad-nsec3-iter-fips.conf b/bin/tests/system/checkconf/kasp-bad-nsec3-iter-fips.conf index e54df3b360..da896a2447 100644 --- a/bin/tests/system/checkconf/kasp-bad-nsec3-iter-fips.conf +++ b/bin/tests/system/checkconf/kasp-bad-nsec3-iter-fips.conf @@ -15,28 +15,28 @@ dnssec-policy "rsasha256" { keys { csk lifetime P10Y algorithm rsasha256 2048; }; - nsec3param iterations 150; + nsec3param iterations 0; }; dnssec-policy "rsasha256-bad" { keys { csk lifetime P10Y algorithm rsasha256 2048; }; - nsec3param iterations 151; + nsec3param iterations 1; }; dnssec-policy "rsasha512" { keys { csk lifetime P10Y algorithm rsasha512 4096; }; - nsec3param iterations 150; + nsec3param iterations 0; }; dnssec-policy "rsasha512-bad" { keys { csk lifetime P10Y algorithm rsasha512 4096; }; - nsec3param iterations 151; + nsec3param iterations 1; }; zone "example.net" { diff --git a/bin/tests/system/checkconf/kasp-bad-nsec3-iter.conf b/bin/tests/system/checkconf/kasp-bad-nsec3-iter.conf index 8dc710f29c..967c29fc0f 100644 --- a/bin/tests/system/checkconf/kasp-bad-nsec3-iter.conf +++ b/bin/tests/system/checkconf/kasp-bad-nsec3-iter.conf @@ -15,42 +15,42 @@ dnssec-policy "rsasha1" { keys { csk lifetime P10Y algorithm nsec3rsasha1 1024; }; - nsec3param iterations 150; + nsec3param iterations 0; }; dnssec-policy "rsasha1-bad" { keys { csk lifetime P10Y algorithm nsec3rsasha1 1024; }; - nsec3param iterations 151; + nsec3param iterations 1; }; dnssec-policy "rsasha256" { keys { csk lifetime P10Y algorithm rsasha256 2048; }; - nsec3param iterations 150; + nsec3param iterations 0; }; dnssec-policy "rsasha256-bad" { keys { csk lifetime P10Y algorithm rsasha256 2048; }; - nsec3param iterations 151; + nsec3param iterations 1; }; dnssec-policy "rsasha512" { keys { csk lifetime P10Y algorithm rsasha512 4096; }; - nsec3param iterations 150; + nsec3param iterations 0; }; dnssec-policy "rsasha512-bad" { keys { csk lifetime P10Y algorithm rsasha512 4096; }; - nsec3param iterations 151; + nsec3param iterations 1; }; zone "example.net" { diff --git a/bin/tests/system/checkconf/tests.sh b/bin/tests/system/checkconf/tests.sh index 458b1a41ec..606c8487a3 100644 --- a/bin/tests/system/checkconf/tests.sh +++ b/bin/tests/system/checkconf/tests.sh @@ -620,7 +620,7 @@ else expect=3 fi $CHECKCONF $conf >checkconf.out$n 2>&1 && ret=1 -grep "dnssec-policy: nsec3 iterations value 151 out of range" /dev/null || ret=1 +grep "dnssec-policy: nsec3 iterations value 1 not allowed, must be zero" /dev/null || ret=1 lines=$(wc -l <"checkconf.out$n") if [ $lines -ne $expect ]; then ret=1; fi if [ $ret -ne 0 ]; then echo_i "failed"; fi diff --git a/bin/tests/system/nsec3/ns3/named-fips.conf.in b/bin/tests/system/nsec3/ns3/named-fips.conf.in index 7890d4aa6d..4ed7cc0427 100644 --- a/bin/tests/system/nsec3/ns3/named-fips.conf.in +++ b/bin/tests/system/nsec3/ns3/named-fips.conf.in @@ -27,7 +27,7 @@ dnssec-policy "optout" { }; dnssec-policy "nsec3-other" { - nsec3param iterations 11 optout yes salt-length 8; + nsec3param iterations 0 optout yes salt-length 8; }; options { diff --git a/bin/tests/system/nsec3/ns3/named2-fips.conf.in b/bin/tests/system/nsec3/ns3/named2-fips.conf.in index 87e87f2e17..8b42abbcce 100644 --- a/bin/tests/system/nsec3/ns3/named2-fips.conf.in +++ b/bin/tests/system/nsec3/ns3/named2-fips.conf.in @@ -27,7 +27,7 @@ dnssec-policy "optout" { }; dnssec-policy "nsec3-other" { - nsec3param iterations 11 optout yes salt-length 0; + nsec3param iterations 0 optout yes salt-length 8; }; options { diff --git a/bin/tests/system/nsec3/tests.sh b/bin/tests/system/nsec3/tests.sh index 5be7fe33d4..ee49d63f47 100644 --- a/bin/tests/system/nsec3/tests.sh +++ b/bin/tests/system/nsec3/tests.sh @@ -46,12 +46,10 @@ set_zone_policy() { CDS_SHA256="yes" CDS_SHA384="no" } -# Set expected NSEC3 parameters: flags ($1), iterations ($2), and -# salt length ($3). +# Set expected NSEC3 parameters: flags ($1) and salt length ($2). set_nsec3param() { FLAGS=$1 - ITERATIONS=$2 - SALTLEN=$3 + SALTLEN=$2 # Reset salt. SALT="" } @@ -102,7 +100,7 @@ set_key_states() { # 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 - grep "${ZONE}\..*IN.*NSEC3PARAM.*1.*0.*${ITERATIONS}.*${SALT}" "dig.out.test$n.wait" >/dev/null || return 1 + grep "${ZONE}\..*IN.*NSEC3PARAM 1 0 0.*${SALT}" "dig.out.test$n.wait" >/dev/null || return 1 grep "${ZONE}\..*IN.*RRSIG" "dig.out.test$n.wait" >/dev/null || return 1 return 0 } @@ -188,7 +186,7 @@ check_nsec() { # Test: check NSEC3 parameters in answers _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 + grep "${ZONE}.*0.*IN.*NSEC3PARAM.*1.*0.*0.*${SALT}" "dig.out.test$n.nsec3param.$ZONE" >/dev/null || return 1 if [ -z "$SALT" ]; then SALT=$(awk '$4 == "NSEC3PARAM" { print $8 }' dig.out.test$n.nsec3param.$ZONE) @@ -198,7 +196,7 @@ _check_nsec3_nsec3param() { _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 + grep ".*\.${ZONE}.*IN.*NSEC3.*1.${FLAGS}.*0.*${SALT}" "dig.out.test$n.nxdomain.$ZONE" >/dev/null || return 1 return 0 } @@ -206,14 +204,14 @@ check_nsec3() { wait_for_zone_is_signed "nsec3" n=$((n + 1)) - echo_i "check that NSEC3PARAM 1 0 ${ITERATIONS} is published zone ${ZONE} ($n)" + echo_i "check that NSEC3PARAM 1 0 0 ${SALT} is published zone ${ZONE} ($n)" ret=0 retry_quiet 10 _check_nsec3_nsec3param || log_error "bad NSEC3PARAM response for ${ZONE}" test "$ret" -eq 0 || echo_i "failed" status=$((status + ret)) n=$((n + 1)) - echo_i "check NXDOMAIN response has correct NSEC3 1 ${FLAGS} ${ITERATIONS} ${SALT} for zone ${ZONE} ($n)" + echo_i "check NXDOMAIN response has correct NSEC3 1 ${FLAGS} 0 ${SALT} for zone ${ZONE} ($n)" ret=0 retry_quiet 10 _check_nsec3_nxdomain || log_error "bad NXDOMAIN response for zone ${ZONE}" test "$ret" -eq 0 || echo_i "failed" @@ -277,21 +275,21 @@ fi # Zone: nsec3.kasp. set_zone_policy "nsec3.kasp" "nsec3" 1 3600 -set_nsec3param "0" "0" "0" +set_nsec3param "0" "0" set_key_default_values "KEY1" echo_i "initial check zone ${ZONE}" check_nsec3 # Zone: nsec3-dynamic.kasp. set_zone_policy "nsec3-dynamic.kasp" "nsec3" 1 3600 -set_nsec3param "0" "0" "0" +set_nsec3param "0" "0" set_key_default_values "KEY1" echo_i "initial check zone ${ZONE}" check_nsec3 # Zone: nsec3-change.kasp. set_zone_policy "nsec3-change.kasp" "nsec3" 1 3600 -set_nsec3param "0" "0" "0" +set_nsec3param "0" "0" set_key_default_values "KEY1" echo_i "initial check zone ${ZONE}" check_nsec3 @@ -316,49 +314,49 @@ retry_quiet 10 _wait_for_new_soa || log_error "failed to update SOA record in zo # Zone: nsec3-dynamic-change.kasp. set_zone_policy "nsec3-dynamic-change.kasp" "nsec3" 1 3600 -set_nsec3param "0" "0" "0" +set_nsec3param "0" "0" set_key_default_values "KEY1" echo_i "initial check zone ${ZONE}" check_nsec3 # Zone: nsec3-dynamic-to-inline.kasp. set_zone_policy "nsec3-dynamic-to-inline.kasp" "nsec3" 1 3600 -set_nsec3param "0" "0" "0" +set_nsec3param "0" "0" set_key_default_values "KEY1" echo_i "initial check zone ${ZONE}" check_nsec3 # Zone: nsec3-inline-to-dynamic.kasp. set_zone_policy "nsec3-inline-to-dynamic.kasp" "nsec3" 1 3600 -set_nsec3param "0" "0" "0" +set_nsec3param "0" "0" set_key_default_values "KEY1" echo_i "initial check zone ${ZONE}" check_nsec3 # Zone: nsec3-to-nsec.kasp. set_zone_policy "nsec3-to-nsec.kasp" "nsec3" 1 3600 -set_nsec3param "0" "0" "0" +set_nsec3param "0" "0" set_key_default_values "KEY1" echo_i "initial check zone ${ZONE}" check_nsec3 # Zone: nsec3-to-optout.kasp. set_zone_policy "nsec3-to-optout.kasp" "nsec3" 1 3600 -set_nsec3param "0" "0" "0" +set_nsec3param "0" "0" set_key_default_values "KEY1" echo_i "initial check zone ${ZONE}" check_nsec3 # Zone: nsec3-from-optout.kasp. set_zone_policy "nsec3-from-optout.kasp" "optout" 1 3600 -set_nsec3param "1" "0" "0" +set_nsec3param "1" "0" set_key_default_values "KEY1" echo_i "initial check zone ${ZONE}" check_nsec3 # Zone: nsec3-other.kasp. set_zone_policy "nsec3-other.kasp" "nsec3-other" 1 3600 -set_nsec3param "1" "11" "8" +set_nsec3param "1" "8" set_key_default_values "KEY1" echo_i "initial check zone ${ZONE}" check_nsec3 @@ -403,7 +401,7 @@ rndc_reconfig ns3 10.53.0.3 # Zone: nsec-to-nsec3.kasp. (reconfigured) set_zone_policy "nsec-to-nsec3.kasp" "nsec3" 1 3600 -set_nsec3param "0" "0" "0" +set_nsec3param "0" "0" set_key_default_values "KEY1" echo_i "check zone ${ZONE} after reconfig" check_nsec3 @@ -431,7 +429,7 @@ if ($SHELL ../testcrypto.sh -q RSASHA1); then # Zone: nsec3-to-rsasha1.kasp. set_zone_policy "nsec3-to-rsasha1.kasp" "rsasha1" 2 3600 - set_nsec3param "1" "0" "0" + set_nsec3param "1" "0" set_server "ns3" "10.53.0.3" set_key_default_values "KEY1" set_key_states "KEY1" "hidden" "unretentive" "unretentive" "unretentive" "hidden" @@ -443,7 +441,7 @@ if ($SHELL ../testcrypto.sh -q RSASHA1); then # Zone: nsec3-to-rsasha1-ds.kasp. set_zone_policy "nsec3-to-rsasha1-ds.kasp" "rsasha1" 2 3600 - set_nsec3param "1" "0" "0" + set_nsec3param "1" "0" set_server "ns3" "10.53.0.3" set_key_default_values "KEY1" set_key_states "KEY1" "hidden" "omnipresent" "omnipresent" "omnipresent" "omnipresent" @@ -457,21 +455,21 @@ fi # Zone: nsec3.kasp. (same) set_zone_policy "nsec3.kasp" "nsec3" 1 3600 -set_nsec3param "0" "0" "0" +set_nsec3param "0" "0" set_key_default_values "KEY1" echo_i "check zone ${ZONE} after reconfig" check_nsec3 # Zone: nsec3-dyamic.kasp. (same) set_zone_policy "nsec3-dynamic.kasp" "nsec3" 1 3600 -set_nsec3param "0" "0" "0" +set_nsec3param "0" "0" set_key_default_values "KEY1" echo_i "check zone ${ZONE} after reconfig" check_nsec3 # Zone: nsec3-change.kasp. (reconfigured) set_zone_policy "nsec3-change.kasp" "nsec3-other" 1 3600 -set_nsec3param "1" "11" "8" +set_nsec3param "1" "8" set_key_default_values "KEY1" echo_i "check zone ${ZONE} after reconfig" check_nsec3 @@ -486,30 +484,36 @@ grep "${ZONE}\..*900.*IN.*NSEC3PARAM" "dig.out.nsec3param.test$n" >/dev/null || test "$ret" -eq 0 || echo_i "failed" status=$((status + ret)) +# Using rndc signing -nsec3param (should fail) +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 + # Zone: nsec3-dynamic-change.kasp. (reconfigured) set_zone_policy "nsec3-dynamic-change.kasp" "nsec3-other" 1 3600 -set_nsec3param "1" "11" "8" +set_nsec3param "1" "8" set_key_default_values "KEY1" echo_i "check zone ${ZONE} after reconfig" check_nsec3 # Zone: nsec3-dynamic-to-inline.kasp. (same) set_zone_policy "nsec3-dynamic-to-inline.kasp" "nsec3" 1 3600 -set_nsec3param "0" "0" "0" +set_nsec3param "0" "0" set_key_default_values "KEY1" echo_i "check zone ${ZONE} after reconfig" check_nsec3 # Zone: nsec3-inline-to-dynamic.kasp. (same) set_zone_policy "nsec3-inline-to-dynamic.kasp" "nsec3" 1 3600 -set_nsec3param "0" "0" "0" +set_nsec3param "0" "0" set_key_default_values "KEY1" echo_i "initial check zone ${ZONE}" check_nsec3 # Zone: nsec3-to-nsec.kasp. (reconfigured) set_zone_policy "nsec3-to-nsec.kasp" "nsec" 1 3600 -set_nsec3param "1" "11" "8" +set_nsec3param "1" "8" set_key_default_values "KEY1" echo_i "check zone ${ZONE} after reconfig" check_nsec @@ -519,7 +523,7 @@ check_nsec # 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" 1 3600 -#set_nsec3param "1" "0" "0" +#set_nsec3param "1" "0" #set_key_default_values "KEY1" #echo_i "check zone ${ZONE} after reconfig" #check_nsec3 @@ -529,28 +533,21 @@ check_nsec # 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" 1 3600 -#set_nsec3param "0" "0" "0" +#set_nsec3param "0" "0" #set_key_default_values "KEY1" #echo_i "check zone ${ZONE} after reconfig" #check_nsec3 # Zone: nsec3-other.kasp. (same) set_zone_policy "nsec3-other.kasp" "nsec3-other" 1 3600 -set_nsec3param "1" "11" "8" +set_nsec3param "1" "8" set_key_default_values "KEY1" echo_i "check zone ${ZONE} after reconfig" check_nsec3 -# Using rndc signing -nsec3param (should fail) -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 - # Test NSEC3 and NSEC3PARAM is the same after restart set_zone_policy "nsec3.kasp" "nsec3" 1 3600 -set_nsec3param "0" "0" "0" +set_nsec3param "0" "0" set_key_default_values "KEY1" echo_i "check zone ${ZONE} before restart" check_nsec3 @@ -570,7 +567,7 @@ status=$((status + ret)) prevsalt="${SALT}" set_zone_policy "nsec3.kasp" "nsec3" 1 3600 -set_nsec3param "0" "0" "0" +set_nsec3param "0" "0" set_key_default_values "KEY1" SALT="${prevsalt}" echo_i "check zone ${ZONE} after restart has salt ${SALT}" @@ -581,7 +578,7 @@ 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" 1 3600 -set_nsec3param "0" "0" "0" +set_nsec3param "0" "0" set_key_default_values "KEY1" echo_i "check zone ${ZONE} after reload" check_nsec3 From ff4201e3886afeea5b878c6d20debee7483f869e Mon Sep 17 00:00:00 2001 From: Matthijs Mekking Date: Wed, 22 Nov 2023 16:12:51 +0100 Subject: [PATCH 3/6] Lower the maximum allowed NSEC3 iterations to 50 BIND 9 will now treat the response as insecure when processing NSEC3 records with iterations larger than 50. Earlier, we limited the number of iterations to 150 (in #2445). RFC 9276 says: Because there has been a large growth of open (public) DNSSEC validating resolvers that are subject to compute resource constraints when handling requests from anonymous clients, this document recommends that validating resolvers reduce their iteration count limits over time. Specifically, validating resolver operators and validating resolver software implementers are encouraged to continue evaluating NSEC3 iteration count deployment trends and lower their acceptable iteration limits over time. After evaluation, we decided that the next major BIND release should lower the maximum allowed NSEC3 iterations to 50, which should be fine for 99,87% of the domain names. --- bin/dnssec/dnssec-signzone.c | 2 +- lib/dns/include/dns/nsec3.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/dnssec/dnssec-signzone.c b/bin/dnssec/dnssec-signzone.c index 2cf0a9bd83..83e3b9ee6a 100644 --- a/bin/dnssec/dnssec-signzone.c +++ b/bin/dnssec/dnssec-signzone.c @@ -3494,7 +3494,7 @@ main(int argc, char *argv[]) { set_iter = true; /* too-many is NOT DOCUMENTED */ if (strcmp(isc_commandline_argument, "too-many") == 0) { - nsec3iter = 151; + nsec3iter = 51; no_max_check = true; break; } diff --git a/lib/dns/include/dns/nsec3.h b/lib/dns/include/dns/nsec3.h index e4da790b06..3cd81cc616 100644 --- a/lib/dns/include/dns/nsec3.h +++ b/lib/dns/include/dns/nsec3.h @@ -26,7 +26,7 @@ #include #define DNS_NSEC3_SALTSIZE 255 -#define DNS_NSEC3_MAXITERATIONS 150U +#define DNS_NSEC3_MAXITERATIONS 50U /* * hash = 1, flags =1, iterations = 2, salt length = 1, salt = 255 (max) From abdaa77303cabca6c6d833ed93088d42ea4d1a30 Mon Sep 17 00:00:00 2001 From: Matthijs Mekking Date: Wed, 22 Nov 2023 16:29:44 +0100 Subject: [PATCH 4/6] Change max NSEC3 iterations in system tests to 50 The dnssec and nsupdate system tests need to be adjusted to accept a lower maximum value for NSEC3 iterations. --- bin/tests/system/dnssec/tests.sh | 8 ++++---- bin/tests/system/nsupdate/tests.sh | 6 +++--- bin/tests/system/nsupdate/update_test.pl | 4 ++-- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/bin/tests/system/dnssec/tests.sh b/bin/tests/system/dnssec/tests.sh index 0c73dcb69c..e98579b5b3 100644 --- a/bin/tests/system/dnssec/tests.sh +++ b/bin/tests/system/dnssec/tests.sh @@ -1467,7 +1467,7 @@ ret=0 ( cd signer/general || exit 0 rm -f signed.zone - $SIGNER -f signed.zone -3 - -H 151 -o example.com. test9.zone >signer.out.$n + $SIGNER -f signed.zone -3 - -H 51 -o example.com. test9.zone >signer.out.$n test -f signed.zone ) && ret=1 n=$((n + 1)) @@ -1492,7 +1492,7 @@ ret=0 ( cd signer/general || exit 1 rm -f signed.zone - $SIGNER -f signed.zone -3 - -H 150 -o example.com. test9.zone >signer.out.$n + $SIGNER -f signed.zone -3 - -H 50 -o example.com. test9.zone >signer.out.$n test -f signed.zone ) || ret=1 n=$((n + 1)) @@ -4317,8 +4317,8 @@ status=$((status + ret)) echo_i "checking excessive NSEC3 iteration warnings in named.run ($n)" ret=0 -grep "zone too-many-iterations/IN: excessive NSEC3PARAM iterations [0-9]* > 150" ns2/named.run >/dev/null 2>&1 || ret=1 -grep "zone too-many-iterations/IN: excessive NSEC3PARAM iterations [0-9]* > 150" ns3/named.run >/dev/null 2>&1 || ret=1 +grep "zone too-many-iterations/IN: excessive NSEC3PARAM iterations [0-9]* > 50" ns2/named.run >/dev/null 2>&1 || ret=1 +grep "zone too-many-iterations/IN: excessive NSEC3PARAM iterations [0-9]* > 50" ns3/named.run >/dev/null 2>&1 || ret=1 n=$((n + 1)) test "$ret" -eq 0 || echo_i "failed" status=$((status + ret)) diff --git a/bin/tests/system/nsupdate/tests.sh b/bin/tests/system/nsupdate/tests.sh index 775df666d1..9977552ef3 100755 --- a/bin/tests/system/nsupdate/tests.sh +++ b/bin/tests/system/nsupdate/tests.sh @@ -433,7 +433,7 @@ if $PERL -e 'use Net::DNS;' 2>/dev/null; then n=$((n + 1)) ret=0 echo_i "check for too many NSEC3 iterations log ($n)" - grep "updating zone 'update.nil/IN': too many NSEC3 iterations (151)" ns1/named.run >/dev/null || ret=1 + grep "updating zone 'update.nil/IN': too many NSEC3 iterations (51)" ns1/named.run >/dev/null || ret=1 [ $ret -eq 1 ] && { echo_i "failed" status=1 @@ -1899,9 +1899,9 @@ echo_i "check that excessive NSEC3PARAM iterations are rejected by nsupdate ($n) $NSUPDATE -d <nsupdate.out.test$n 2>&1 && ret=1 server 10.53.0.3 ${PORT} zone example -update add example 0 in NSEC3PARAM 1 0 151 - +update add example 0 in NSEC3PARAM 1 0 51 - END -grep "NSEC3PARAM has excessive iterations (> 150)" nsupdate.out.test$n >/dev/null || ret=1 +grep "NSEC3PARAM has excessive iterations (> 50)" nsupdate.out.test$n >/dev/null || ret=1 [ $ret = 0 ] || { echo_i "failed" status=1 diff --git a/bin/tests/system/nsupdate/update_test.pl b/bin/tests/system/nsupdate/update_test.pl index 835f1f88c7..066fa2ca15 100644 --- a/bin/tests/system/nsupdate/update_test.pl +++ b/bin/tests/system/nsupdate/update_test.pl @@ -417,8 +417,8 @@ if ($Net::DNS::VERSION < 1.01) { print "skipped Excessive NSEC3PARAM iterations; Net::DNS too old.\n"; } else { section("Excessive NSEC3PARAM iterations"); - test("REFUSED", ["update", rr_add("$zone 300 NSEC3PARAM 1 0 151 -")]); - test("NOERROR", ["update", rr_add("$zone 300 NSEC3PARAM 1 0 150 -")]); + test("REFUSED", ["update", rr_add("$zone 300 NSEC3PARAM 1 0 51 -")]); + test("NOERROR", ["update", rr_add("$zone 300 NSEC3PARAM 1 0 50 -")]); } if ($failures) { From 294943ba7ce037ae8ed161fc3eafda43876749fe Mon Sep 17 00:00:00 2001 From: Matthijs Mekking Date: Wed, 22 Nov 2023 16:39:40 +0100 Subject: [PATCH 5/6] Add release note and CHANGES for #4363 This protocol change is definitely worth mentioning. --- CHANGES | 6 ++++++ doc/notes/notes-current.rst | 7 ++++++- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/CHANGES b/CHANGES index 06772c24e6..83590f8445 100644 --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,9 @@ +6292. [func] Lower the maximum number of allowed NSEC3 iterations, + from 150 to 50. DNSSEC responses with a higher + iteration count are treated as insecure. For signing + with dnssec-policy, iterations must be set to zero. + [GL #4363] + 6291. [bug] SIGTERM failed to properly stop multiple outstanding lookup in dig. [GL #4457] diff --git a/doc/notes/notes-current.rst b/doc/notes/notes-current.rst index 7c0b9b30dc..9bb024fe9b 100644 --- a/doc/notes/notes-current.rst +++ b/doc/notes/notes-current.rst @@ -33,7 +33,12 @@ Removed Features Feature Changes ~~~~~~~~~~~~~~~ -- None. +- The maximum number of allowed NSEC3 iterations for validation has been + lowered from 150 to 50. DNSSEC responses containing NSEC3 records with + iteration counts greater than 50 are now treated as insecure. :gl:`#4363` + +- The number of NSEC3 iterations that can be configured for a zone must be 0. + :gl:`#4363` Bug Fixes ~~~~~~~~~ From a759f7f33c94509f3d6c313061f4e1d5e3d14438 Mon Sep 17 00:00:00 2001 From: Matthijs Mekking Date: Wed, 22 Nov 2023 17:30:00 +0100 Subject: [PATCH 6/6] Change max NSEC3 iterations in unit tests to 50 The nsec3 unit test needs to be adjusted to accept a lower maximum value for NSEC3 iterations. --- tests/dns/nsec3_test.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/tests/dns/nsec3_test.c b/tests/dns/nsec3_test.c index c2fcacd994..dd772d1cff 100644 --- a/tests/dns/nsec3_test.c +++ b/tests/dns/nsec3_test.c @@ -115,11 +115,11 @@ nsec3param_salttotext_test(const nsec3param_salttotext_test_params_t *params) { ISC_RUN_TEST_IMPL(max_iterations) { UNUSED(state); - iteration_test(TESTS_DIR "/testdata/nsec3/1024.db", 150); - iteration_test(TESTS_DIR "/testdata/nsec3/2048.db", 150); - iteration_test(TESTS_DIR "/testdata/nsec3/4096.db", 150); - iteration_test(TESTS_DIR "/testdata/nsec3/min-1024.db", 150); - iteration_test(TESTS_DIR "/testdata/nsec3/min-2048.db", 150); + iteration_test(TESTS_DIR "/testdata/nsec3/1024.db", 50); + iteration_test(TESTS_DIR "/testdata/nsec3/2048.db", 50); + iteration_test(TESTS_DIR "/testdata/nsec3/4096.db", 50); + iteration_test(TESTS_DIR "/testdata/nsec3/min-1024.db", 50); + iteration_test(TESTS_DIR "/testdata/nsec3/min-2048.db", 50); } /* check dns_nsec3param_salttotext() */