From e5a5b23f410f60899453a713b98530f083647863 Mon Sep 17 00:00:00 2001
From: Matthijs Mekking <matthijs@isc.org>
Date: Mon, 10 Jan 2022 15:46:25 +0100
Subject: [PATCH] Test CDS DELETE persists after zone sign

Add a test case for a dynamically added CDS DELETE record and make
sure it is not removed when signing the zone. This happens because
BIND maintains CDS and CDNSKEY publishing and it will only allow
CDS DELETE records if the zone is transitioning to insecure. This is
a state that can be identified when using KASP through 'dnssec-policy',
but not when using 'auto-dnssec'.

(cherry picked from commit f08277f9fbbf3e38b855d6849c6d430d64bd3713)
Conflict: NA
Reference: https://gitlab.isc.org/isc-projects/bind9/-/commit/e5a5b23f410f60899453a713b98530f083647863
---
 bin/tests/system/autosign/clean.sh            |  2 +
 bin/tests/system/autosign/ns2/keygen.sh       |  5 +-
 .../autosign/ns3/cdnskey-delete.example.db.in | 28 +++++++
 .../autosign/ns3/cds-delete.example.db.in     | 28 +++++++
 bin/tests/system/autosign/ns3/keygen.sh       | 25 +++++-
 bin/tests/system/autosign/ns3/named.conf.in   | 14 ++++
 bin/tests/system/autosign/tests.sh            | 83 +++++++++++++++++++
 7 files changed, 180 insertions(+), 5 deletions(-)
 create mode 100644 bin/tests/system/autosign/ns3/cdnskey-delete.example.db.in
 create mode 100644 bin/tests/system/autosign/ns3/cds-delete.example.db.in

diff --git a/bin/tests/system/autosign/clean.sh b/bin/tests/system/autosign/clean.sh
index bb738af862..f4ab636e8e 100644
--- a/bin/tests/system/autosign/clean.sh
+++ b/bin/tests/system/autosign/clean.sh
@@ -35,6 +35,8 @@ rm -f ns2/private.secure.example.db ns2/bar.db
 rm -f ns3/*.nzd ns3/*.nzd-lock ns3/*.nzf
 rm -f ns3/*.nzf
 rm -f ns3/autonsec3.example.db
+rm -f ns3/cdnskey-delete.example.db
+rm -f ns3/cds-delete.example.db
 rm -f ns3/delzsk.example.db
 rm -f ns3/dname-at-apex-nsec3.example.db
 rm -f ns3/inacksk2.example.db
diff --git a/bin/tests/system/autosign/ns2/keygen.sh b/bin/tests/system/autosign/ns2/keygen.sh
index 8c9c80071c..383be7d3be 100644
--- a/bin/tests/system/autosign/ns2/keygen.sh
+++ b/bin/tests/system/autosign/ns2/keygen.sh
@@ -17,8 +17,9 @@ SYSTEMTESTTOP=../..
 # Have the child generate subdomain keys and pass DS sets to us.
 ( cd ../ns3 && $SHELL keygen.sh )
 
-for subdomain in secure nsec3 autonsec3 optout rsasha256 rsasha512 nsec3-to-nsec oldsigs sync \
-    dname-at-apex-nsec3
+for subdomain in secure nsec3 autonsec3 optout rsasha256 rsasha512 \
+		 nsec3-to-nsec oldsigs sync dname-at-apex-nsec3 cds-delete \
+		 cdnskey-delete
 do
 	cp ../ns3/dsset-$subdomain.example$TP .
 done
diff --git a/bin/tests/system/autosign/ns3/cdnskey-delete.example.db.in b/bin/tests/system/autosign/ns3/cdnskey-delete.example.db.in
new file mode 100644
index 0000000000..3083a79f7d
--- /dev/null
+++ b/bin/tests/system/autosign/ns3/cdnskey-delete.example.db.in
@@ -0,0 +1,28 @@
+; 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 http://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. . (
+				2009102722 ; 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
+b			A	10.0.0.2
+d			A	10.0.0.4
+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
diff --git a/bin/tests/system/autosign/ns3/cds-delete.example.db.in b/bin/tests/system/autosign/ns3/cds-delete.example.db.in
new file mode 100644
index 0000000000..3083a79f7d
--- /dev/null
+++ b/bin/tests/system/autosign/ns3/cds-delete.example.db.in
@@ -0,0 +1,28 @@
+; 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 http://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. . (
+				2009102722 ; 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
+b			A	10.0.0.2
+d			A	10.0.0.4
+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
diff --git a/bin/tests/system/autosign/ns3/keygen.sh b/bin/tests/system/autosign/ns3/keygen.sh
index 52b439f2bf..23d69f2fd5 100644
--- a/bin/tests/system/autosign/ns3/keygen.sh
+++ b/bin/tests/system/autosign/ns3/keygen.sh
@@ -333,7 +333,7 @@ $KEYGEN -a $DEFAULT_ALGORITHM -3 -q -P now -A now+3600 $zone > kg.out 2>&1 || du
 $DSFROMKEY $ksk.key > dsset-${zone}$TP
 
 #
-#  A zone that starts with a active KSK + ZSK and a inactive ZSK.
+# A zone that starts with a active KSK + ZSK and a inactive ZSK.
 #
 setup inacksk3.example
 cp $infile $zonefile
@@ -343,7 +343,7 @@ $KEYGEN -a $DEFAULT_ALGORITHM -3 -q $zone > kg.out 2>&1 || dumpit kg.out
 $DSFROMKEY $ksk.key > dsset-${zone}$TP
 
 #
-#  A zone that starts with a active KSK + ZSK and a inactive ZSK.
+# A zone that starts with a active KSK + ZSK and a inactive ZSK.
 #
 setup inaczsk3.example
 cp $infile $zonefile
@@ -364,10 +364,29 @@ zsk=`$KEYGEN -a $DEFAULT_ALGORITHM -3 -q -I now-1w $zone 2>kg.out` || dumpit kg.
 echo $zsk > ../delzsk.key
 
 #
-#  Check that NSEC3 are correctly signed and returned from below a DNAME
+# Check that NSEC3 are correctly signed and returned from below a DNAME
 #
 setup dname-at-apex-nsec3.example
 cp $infile $zonefile
 ksk=`$KEYGEN -q -a $DEFAULT_ALGORITHM -3 -fk $zone 2> kg.out` || dumpit kg.out
 $KEYGEN -q -a $DEFAULT_ALGORITHM -3 $zone > kg.out 2>&1 || dumpit kg.out
 $DSFROMKEY $ksk.key > dsset-${zone}$TP
+
+#
+# Check that dynamically added CDS (DELETE) is kept in the zone after signing.
+#
+setup cds-delete.example
+cp $infile $zonefile
+ksk=`$KEYGEN -q -a $DEFAULT_ALGORITHM -3 -fk $zone 2> kg.out` || dumpit kg.out
+$KEYGEN -q -a $DEFAULT_ALGORITHM -3 $zone > kg.out 2>&1 || dumpit kg.out
+$DSFROMKEY $ksk.key > dsset-${zone}$TP
+
+#
+# Check that dynamically added CDNSKEY (DELETE) is kept in the zone after
+# signing.
+#
+setup cdnskey-delete.example
+cp $infile $zonefile
+ksk=`$KEYGEN -q -a $DEFAULT_ALGORITHM -3 -fk $zone 2> kg.out` || dumpit kg.out
+$KEYGEN -q -a $DEFAULT_ALGORITHM -3 $zone > kg.out 2>&1 || dumpit kg.out
+$DSFROMKEY $ksk.key > dsset-${zone}$TP
diff --git a/bin/tests/system/autosign/ns3/named.conf.in b/bin/tests/system/autosign/ns3/named.conf.in
index 66d0e027a5..8f2eb5675a 100644
--- a/bin/tests/system/autosign/ns3/named.conf.in
+++ b/bin/tests/system/autosign/ns3/named.conf.in
@@ -317,4 +317,18 @@ zone "dname-at-apex-nsec3.example" {
 	auto-dnssec maintain;
 };
 
+zone "cds-delete.example" {
+	type primary;
+	file "cds-delete.example.db";
+	allow-update { any; };
+	auto-dnssec maintain;
+};
+
+zone "cdnskey-delete.example" {
+	type primary;
+	file "cdnskey-delete.example.db";
+	allow-update { any; };
+	auto-dnssec maintain;
+};
+
 include "trusted.conf";
diff --git a/bin/tests/system/autosign/tests.sh b/bin/tests/system/autosign/tests.sh
index 448de3c55c..962ca4e546 100755
--- a/bin/tests/system/autosign/tests.sh
+++ b/bin/tests/system/autosign/tests.sh
@@ -1638,6 +1638,89 @@ inac=`grep "DNSKEY .* is now inactive" ns1/named.run | wc -l`
 [ "$inac" -eq 1 ] || ret=1
 del=`grep "DNSKEY .* is now deleted" ns1/named.run | wc -l`
 [ "$del" -eq 1 ] || ret=1
+n=`expr $n + 1`
+if [ $ret != 0 ]; then echo_i "failed"; fi
+status=`expr $status + $ret`
+
+echo_i "checking that CDS (DELETE) persists after zone sign ($n)"
+echo_i "update add cds-delete.example. CDS 0 0 00"
+ret=0
+$NSUPDATE > nsupdate.out 2>&1 <<END
+server 10.53.0.3 ${PORT}
+zone cds-delete.example.
+update add cds-delete.example. 3600 CDS 0 0 0 00
+send
+END
+
+_cds_delete() (
+	$DIG $DIGOPTS +noall +answer $1 cds @10.53.0.3 > dig.out.ns3.test$n || return 1
+	grep "CDS.*0.*0.*0.*00" dig.out.ns3.test$n > /dev/null 2>&1 || return 1
+	return 0
+)
+_cdnskey_delete_nx() {
+	$DIG $DIGOPTS +noall +answer $1 cdnskey @10.53.0.3 > dig.out.ns3.test$n || return 1
+	grep "CDNSKEY.*0.*3.*0.*AA==" dig.out.ns3.test$n > /dev/null 2>&1 && return 1
+	return 0
+}
+
+echo_i "query cds-delete.example. CDS"
+retry_quiet 10 _cds_delete cds-delete.example. || ret=1
+echo_i "query cds-delete.example. CDNSKEY"
+retry_quiet 1 _cdnskey_delete_nx cds-delete.example. || ret=1
+
+echo_i "sign cds-delete.example."
+nextpart ns3/named.run >/dev/null
+$RNDCCMD 10.53.0.3 sign cds-delete.example > /dev/null 2>&1 || ret=1
+wait_for_log 10 "zone cds-delete.example/IN: next key event" ns3/named.run
+# The CDS (DELETE) record should still be here.
+echo_i "query cds-delete.example. CDS"
+retry_quiet 1 _cds_delete cds-delete.example. || ret=1
+# The CDNSKEY (DELETE) record should still not be added.
+echo_i "query cds-delete.example. CDNSKEY"
+retry_quiet 1 _cdnskey_delete_nx cds-delete.example. || ret=1
+
+n=`expr $n + 1`
+if [ $ret != 0 ]; then echo_i "failed"; fi
+status=`expr $status + $ret`
+
+echo_i "checking that CDNSKEY (DELETE) persists after zone sign ($n)"
+echo_i "update add cdnskey-delete.example. CDNSKEY 0 3 0 AA=="
+ret=0
+$NSUPDATE > nsupdate.out 2>&1 <<END
+server 10.53.0.3 ${PORT}
+zone cdnskey-delete.example.
+update add cdnskey-delete.example. 3600 CDNSKEY 0 3 0 AA==
+send
+END
+
+_cds_delete_nx() (
+	$DIG $DIGOPTS +noall +answer $1 cds @10.53.0.3 > dig.out.ns3.test$n || return 1
+	grep "CDS.*0.*0.*0.*00" dig.out.ns3.test$n > /dev/null 2>&1 && return 1
+	return 0
+)
+_cdnskey_delete() {
+	$DIG $DIGOPTS +noall +answer $1 cdnskey @10.53.0.3 > dig.out.ns3.test$n || return 1
+	grep "CDNSKEY.*0.*3.*0.*AA==" dig.out.ns3.test$n > /dev/null 2>&1 || return 1
+	return 0
+}
+
+echo_i "query cdnskey-delete.example. CDNSKEY"
+retry_quiet 10 _cdnskey_delete cdnskey-delete.example. || ret=1
+echo_i "query cdnskey-delete.example. CDS"
+retry_quiet 1 _cds_delete_nx cdnskey-delete.example. || ret=1
+
+echo_i "sign cdsnskey-delete.example."
+nextpart ns3/named.run >/dev/null
+$RNDCCMD 10.53.0.3 sign cdnskey-delete.example > /dev/null 2>&1 || ret=1
+wait_for_log 10 "zone cdnskey-delete.example/IN: next key event" ns3/named.run
+# The CDNSKEY (DELETE) record should still be here.
+echo_i "query cdnskey-delete.example. CDNSKEY"
+retry_quiet 1 _cdnskey_delete cdnskey-delete.example. || ret=1
+# The CDS (DELETE) record should still not be added.
+echo_i "query cdnskey-delete.example. CDS"
+retry_quiet 1 _cds_delete_nx cdnskey-delete.example. || ret=1
+
+n=`expr $n + 1`
 if [ $ret != 0 ]; then echo_i "failed"; fi
 status=`expr $status + $ret`
 
-- 
2.23.0

