[v9_9] Prevent possible infinite signing loop after retransferring an inline-signed slave using NSEC3

4727.	[bug]		Retransferring an inline-signed slave using NSEC3
			around the time its NSEC3 salt was changed could result
			in an infinite signing loop. [RT #45080]

(cherry picked from commit 4ceebc8874)
This commit is contained in:
Michał Kępień
2017-09-18 09:30:56 +02:00
parent ecab2b21f1
commit c0ef11fb2e
12 changed files with 232 additions and 34 deletions
+4
View File
@@ -76,6 +76,10 @@ rm -f ns5/bits.bk
rm -f ns5/bits.bk.jnl
rm -f ns5/bits.bk.signed
rm -f ns5/bits.bk.signed.jnl
rm -f ns7/K*
rm -f ns7/nsec3-loop.db
rm -f ns7/nsec3-loop.db.signed
rm -f ns7/nsec3-loop.db.signed.jnl
rm -f */*.jbk
rm -f dig.out.ns*
rm -f signing.out*
+6
View File
@@ -55,3 +55,9 @@ zone "retransfer3" {
allow-update { any; };
notify no;
};
zone "nsec3-loop" {
type master;
file "nsec3-loop.db";
notify no;
};
+20
View File
@@ -0,0 +1,20 @@
; Copyright (C) 2017 Internet Systems Consortium, Inc. ("ISC")
;
; 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 http://mozilla.org/MPL/2.0/.
; NOTE: This zone's data has been crafted in order to reproduce a very specific
; scenario (see ns7/named.conf for more details). Please do not modify this
; file.
$TTL 300 ; 5 minutes
@ IN SOA ns2 . (
1 ; serial
20 ; refresh (20 seconds)
20 ; retry (20 seconds)
1814400 ; expire (3 weeks)
3600 ; minimum (1 hour)
)
NS ns2
ns2 A 10.53.0.2
+43
View File
@@ -0,0 +1,43 @@
/*
* Copyright (C) 2017 Internet Systems Consortium, Inc. ("ISC")
*
* 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 http://mozilla.org/MPL/2.0/.
*/
/*
* NS7
*
* NOTE: This named instance is used to reproduce a scenario which involves a
* number of functions getting called in a very specific order which results in
* an infinite loop while iterating over NSEC3 red-black tree. Ensuring this
* happens requires carefully setting the number of signing keys, NSEC3
* parameters (number of iterations and salt value), zone data and named
* configuration. Changing any of these and/or influencing this instance's
* behavior (e.g. by sending extra queries to it) might render this test moot
* as it will no longer be able to reproduce the exact scenario it attempts to.
*
* Given the above, please do not use this instance for any other test than the
* one it was meant for.
*/
include "../../common/rndc.key";
controls { inet 10.53.0.7 port 9953 allow { any; } keys { rndc_key; }; };
options {
query-source address 10.53.0.7;
notify-source 10.53.0.7;
transfer-source 10.53.0.7;
port 5300;
pid-file "named.pid";
listen-on { 10.53.0.7; };
listen-on-v6 { none; };
recursion no;
notify no;
try-tcp-refresh no;
allow-new-zones yes;
sig-signing-nodes 100;
sig-signing-signatures 10;
};
+20
View File
@@ -0,0 +1,20 @@
#!/bin/sh -e
#
# Copyright (C) 2017 Internet Systems Consortium, Inc. ("ISC")
#
# 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 http://mozilla.org/MPL/2.0/.
SYSTEMTESTTOP=../..
. $SYSTEMTESTTOP/conf.sh
# NOTE: The number of signing keys generated below is not coincidental. More
# details can be found in the comment inside ns7/named.conf.
zone=nsec3-loop
rm -f K${zone}.+*+*.key
rm -f K${zone}.+*+*.private
keyname=`$KEYGEN -q -r $RANDFILE -a NSEC3RSASHA1 -b 1024 -n zone $zone`
keyname=`$KEYGEN -q -r $RANDFILE -a NSEC3RSASHA1 -b 1024 -n zone $zone`
keyname=`$KEYGEN -q -r $RANDFILE -a NSEC3RSASHA1 -b 1024 -n zone -f KSK $zone`
+1
View File
@@ -43,3 +43,4 @@ cp ns5/named.conf.pre ns5/named.conf
(cd ns3; $SHELL -e sign.sh)
(cd ns1; $SHELL -e sign.sh)
(cd ns7; $SHELL -e sign.sh)
+55 -4
View File
@@ -49,7 +49,7 @@ do
done
n=`expr $n + 1`
echo "I:checking that rrsigs are replaced with ksk only"
echo "I:checking that rrsigs are replaced with ksk only ($n)"
ret=0
$DIG @10.53.0.3 -p 5300 axfr nsec3. |
awk '/RRSIG NSEC3/ {a[$1]++} END { for (i in a) {if (a[i] != 1) exit (1)}}' || ret=1
@@ -206,8 +206,8 @@ do
done
if [ $ret != 0 ]; then echo "I:failed"; fi
status=`expr $status + $ret`
n=`expr $n + 1`
n=`expr $n + 1`
echo "I:checking that the zone is signed on initial transfer, noixfr ($n)"
ret=0
for i in 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10
@@ -298,6 +298,7 @@ do
sleep 1
done
if [ $ret != 0 ]; then echo "I:failed"; fi
status=`expr $status + $ret`
n=`expr $n + 1`
echo "I:checking removal of private type record via 'rndc signing -clear' (master) ($n)"
@@ -420,6 +421,7 @@ do
sleep 1
done
if [ $ret != 0 ]; then echo "I:failed"; fi
status=`expr $status + $ret`
n=`expr $n + 1`
echo "I:checking master zone that was updated while offline is correct ($n)"
@@ -756,8 +758,8 @@ do
done
if [ $ans != 1 ]; then echo "I:failed"; ret=1; fi
status=`expr $status + $ret`
n=`expr $n + 1`
n=`expr $n + 1`
echo "I:check rndc retransfer of a inline slave zone works ($n)"
ret=0
$RNDC -c ../common/rndc.conf -s 10.53.0.3 -p 9953 retransfer retransfer 2>&1 || ret=1
@@ -771,10 +773,10 @@ do
sleep 1
done
[ $ans = 1 ] && ret=1
n=`expr $n + 1`
if [ $ret != 0 ]; then echo "I:failed"; fi
status=`expr $status + $ret`
n=`expr $n + 1`
echo "I:check rndc retransfer of a inline nsec3 slave retains nsec3 ($n)"
ret=0
for i in 0 1 2 3 4 5 6 7 8 9
@@ -797,7 +799,53 @@ do
sleep 1
done
[ $ans = 1 ] && ret=1
if [ $ret != 0 ]; then echo "I:failed"; fi
status=`expr $status + $ret`
# NOTE: The test below should be considered fragile. More details can be found
# in the comment inside ns7/named.conf.
n=`expr $n + 1`
echo "I:check rndc retransfer of a inline nsec3 slave does not trigger an infinite loop ($n)"
ret=0
zone=nsec3-loop
# Add slave zone using rndc
$RNDC -c ../common/rndc.conf -s 10.53.0.7 -p 9953 addzone $zone \
'{ type slave; masters { 10.53.0.2; }; file "'$zone'.db"; inline-signing yes; auto-dnssec maintain; };'
# Wait until slave zone is fully signed using NSEC
for i in 1 2 3 4 5 6 7 8 9 0
do
ret=1
$RNDC -c ../common/rndc.conf -s 10.53.0.7 -p 9953 signing -list $zone > signing.out.test$n 2>&1
keys=`grep '^Done signing' signing.out.test$n | wc -l`
[ $keys -eq 3 ] && ret=0 && break
sleep 1
done
# Switch slave zone to NSEC3
$RNDC -c ../common/rndc.conf -s 10.53.0.7 -p 9953 signing -nsec3param 1 0 2 12345678 $zone > /dev/null 2>&1
# Wait until slave zone is fully signed using NSEC3
for i in 1 2 3 4 5 6 7 8 9 0
do
ret=1
nsec3param=`$DIG +short @10.53.0.7 -p 5300 nsec3param $zone`
test "$nsec3param" = "1 0 2 12345678" && ret=0 && break
sleep 1
done
# Attempt to retransfer the slave zone from master
$RNDC -c ../common/rndc.conf -s 10.53.0.7 -p 9953 retransfer $zone
# Check whether the signer managed to fully sign the retransferred zone by
# waiting for a specific SOA serial number to appear in the logs; if this
# specific SOA serial number does not appear in the logs, it means the signer
# has either ran into an infinite loop or crashed; note that we check the logs
# instead of sending SOA queries to the signer as these may influence its
# behavior in a way which may prevent the desired scenario from being
# reproduced (see comment in ns7/named.conf)
for i in 1 2 3 4 5 6 7 8 9 0
do
ret=1
grep "ns2.$zone. . 10 20 20 1814400 3600" ns7/named.run > /dev/null 2>&1
[ $? -eq 0 ] && ret=0 && break
sleep 1
done
if [ $ret != 0 ]; then echo "I:failed"; fi
status=`expr $status + $ret`
@@ -848,6 +896,8 @@ $RNDC -c ../common/rndc.conf -s 10.53.0.3 -p 9953 addzone test-$zone \
'{ type slave; masters { 10.53.0.2; }; file "'test-$zone.bk'"; inline-signing yes; auto-dnssec maintain; allow-transfer { any; }; };'
$RNDC -c ../common/rndc.conf -s 10.53.0.3 -p 9953 delzone test-$zone > /dev/null 2>&1
done
if [ $ret != 0 ]; then echo "I:failed"; fi
status=`expr $status + $ret`
n=`expr $n + 1`
echo "I:testing adding external keys to a inline zone ($n)"
@@ -872,6 +922,7 @@ do
test ${dnskeys:-0} -eq 3 || { echo "I: failed $alg (dnskeys ${dnskeys:-0})"; ret=1; }
test ${rrsigs:-0} -eq 2 || { echo "I: failed $alg (rrsigs ${rrsigs:-0})"; ret=1; }
done
if [ $ret != 0 ]; then echo "I:failed"; fi
status=`expr $status + $ret`
n=`expr $n + 1`