xref: /netbsd-src/external/mpl/bind/dist/bin/tests/system/autosign/tests.sh (revision 901e7e84758515fbf39dfc064cb0b45ab146d8b0)
1#!/bin/sh
2
3# Copyright (C) Internet Systems Consortium, Inc. ("ISC")
4#
5# SPDX-License-Identifier: MPL-2.0
6#
7# This Source Code Form is subject to the terms of the Mozilla Public
8# License, v. 2.0.  If a copy of the MPL was not distributed with this
9# file, you can obtain one at https://mozilla.org/MPL/2.0/.
10#
11# See the COPYRIGHT file distributed with this work for additional
12# information regarding copyright ownership.
13
14SYSTEMTESTTOP=..
15. $SYSTEMTESTTOP/conf.sh
16
17status=0
18n=0
19
20DIGOPTS="+tcp +noadd +nosea +nostat +nocmd +dnssec -p ${PORT}"
21RNDCCMD="$RNDC -c $SYSTEMTESTTOP/common/rndc.conf -p ${CONTROLPORT} -s"
22
23# convert private-type records to readable form
24showprivate () {
25    echo "-- $@ --"
26    $DIG $DIGOPTS +nodnssec +short @$2 -t type65534 $1 | cut -f3 -d' ' |
27        while read record; do
28            $PERL -e 'my $rdata = pack("H*", @ARGV[0]);
29                die "invalid record" unless length($rdata) == 5;
30                my ($alg, $key, $remove, $complete) = unpack("CnCC", $rdata);
31                my $action = "signing";
32                $action = "removing" if $remove;
33                my $state = " (incomplete)";
34                $state = " (complete)" if $complete;
35                print ("$action: alg: $alg, key: $key$state\n");' $record
36        done
37}
38
39# check that signing records are marked as complete
40checkprivate () {
41    _ret=0
42    expected="${3:-0}"
43    x=$(showprivate "$@")
44    echo $x | grep incomplete > /dev/null && _ret=1
45
46    if [ $_ret = $expected ]; then
47        return 0
48    fi
49
50    echo "$x"
51    echo_i "failed"
52    return 1
53}
54
55# wait until notifies for zone $1 are sent by server $2. This is an indication
56# that the zone is signed with the active keys, and the changes have been
57# committed.
58wait_for_notifies () {
59	wait_for_log 10 "zone ${1}/IN: sending notifies" "${2}/named.run" || return 1
60}
61
62freq() {
63	_file=$1
64	# remove first and last line that has incomplete set and skews the distribution
65	awk '$4 == "RRSIG" {print substr($9,1,8)}' < "$_file" | sort | uniq -c | sed '1d;$d'
66}
67# Check the signatures expiration times.  First check how many signatures
68# there are in total ($rrsigs).  Then see what the distribution of signature
69# expiration times is ($expiretimes).  Ignore the time part for a better
70# modelled distribution.
71checkjitter () {
72	_file=$1
73	_ret=0
74
75	if ! command -v bc >/dev/null 2>&1; then
76		echo_i "skip: bc not available"
77		return 0
78	fi
79
80	freq "$_file" | cat_i
81	_expiretimes=$(freq "$_file" | awk '{print $1}')
82
83	_count=0
84	# Check if we have at least 4 days
85	# This number has been tuned for `sig-validity-interval 10 2`, as
86	# 1 signature expiration dates should be spread out across at most 8 (10-2) days
87	# 2. we remove first and last day to remove frequency outlier, we are left with 6 (8-2) days
88	# 3. we subtract two more days to allow test pass on day boundaries, etc. leaving us with 4 (6-2)
89	for _num in $_expiretimes
90	do
91		_count=$((_count+1))
92	done
93	if [ "$_count" -lt 4 ]; then
94		echo_i "error: not enough categories"
95		return 1
96	fi
97
98	# Calculate mean
99	_total=0
100	for _num in $_expiretimes
101	do
102		_total=$((_total+_num))
103	done
104	_mean=$(($_total / $_count))
105
106	# Calculate stddev
107	_stddev=0
108	for _num in $_expiretimes
109	do
110		_stddev=$(echo "$_stddev + (($_num - $_mean) * ($_num - $_mean))" | bc)
111	done
112	_stddev=$(echo "sqrt($_stddev/$_count)" | bc)
113
114	# We expect the number of signatures not to exceed the mean +- 3 * stddev.
115	_limit=$((_stddev*3))
116	_low=$((_mean-_limit))
117	_high=$((_mean+_limit))
118	# Find outliers.
119	echo_i "checking whether all frequencies fall into <$_low;$_high> range"
120	for _num in $_expiretimes
121	do
122		if [ $_num -gt $_high ]; then
123			echo_i "error: too many RRSIG records ($_num) in expiration bucket"
124			_ret=1
125		fi
126		if [ $_num -lt $_low ]; then
127			echo_i "error: too few RRSIG records ($_num) in expiration bucket"
128			_ret=1
129		fi
130	done
131
132	return $_ret
133}
134
135#
136#  The NSEC record at the apex of the zone and its RRSIG records are
137#  added as part of the last step in signing a zone.  We wait for the
138#  NSEC records to appear before proceeding with a counter to prevent
139#  infinite loops if there is a error.
140#
141echo_i "waiting for autosign changes to take effect"
142i=0
143while [ $i -lt 30 ]
144do
145	ret=0
146	#
147	# Wait for the root DNSKEY RRset to be fully signed.
148	#
149	$DIG $DIGOPTS . @10.53.0.1 dnskey > dig.out.ns1.test$n || ret=1
150	grep "ANSWER: 10," dig.out.ns1.test$n > /dev/null || ret=1
151	for z in .
152	do
153		$DIG $DIGOPTS $z @10.53.0.1 nsec > dig.out.ns1.test$n || ret=1
154		grep "NS SOA" dig.out.ns1.test$n > /dev/null || ret=1
155	done
156	for z in bar. example. private.secure.example. optout-with-ent.
157	do
158		$DIG $DIGOPTS $z @10.53.0.2 nsec > dig.out.ns2.test$n || ret=1
159		grep "NS SOA" dig.out.ns2.test$n > /dev/null || ret=1
160	done
161	for z in bar. example. inacksk2.example. inacksk3.example \
162		 inaczsk2.example. inaczsk3.example noksk.example nozsk.example
163	do
164		$DIG $DIGOPTS $z @10.53.0.3 nsec > dig.out.ns3.test$n || ret=1
165		grep "NS SOA" dig.out.ns3.test$n > /dev/null || ret=1
166	done
167	i=$((i + 1))
168	if [ $ret = 0 ]; then break; fi
169	echo_i "waiting ... ($i)"
170	sleep 2
171done
172n=$((n + 1))
173if [ $ret != 0 ]; then echo_i "done"; fi
174status=$((status + ret))
175
176echo_i "Convert optout-with-ent from nsec to nsec3"
177($RNDCCMD 10.53.0.2 signing -nsec3param 1 1 1 - optout-with-ent 2>&1 | sed 's/^/ns2 /' | cat_i) || ret=1
178
179echo_i "Initial counts of RRSIG expiry fields values for auto signed zones"
180for z in .
181do
182	echo_i zone $z
183	$DIG $DIGOPTS $z @10.53.0.1 axfr | awk '$4 == "RRSIG" {print $9}' | sort | uniq -c | cat_i
184done
185for z in bar. example. private.secure.example.
186do
187	echo_i zone $z
188	$DIG $DIGOPTS $z @10.53.0.2 axfr | awk '$4 == "RRSIG" {print $9}' | sort | uniq -c | cat_i
189done
190for z in inacksk2.example. inacksk3.example inaczsk2.example. inaczsk3.example
191do
192	echo_i zone $z
193	$DIG $DIGOPTS $z @10.53.0.3 axfr | awk '$4 == "RRSIG" {print $9}' | sort | uniq -c | cat_i
194done
195
196# Set logfile offset for wait_for_log usage.
197nextpartreset ns3/named.run
198
199#
200# Check that DNSKEY is initially signed with a KSK and not a ZSK.
201#
202echo_i "check that zone with active and inactive KSK and active ZSK is properly"
203echo_ic "resigned after the active KSK is deleted - stage 1: Verify that DNSKEY"
204echo_ic "is initially signed with a KSK and not a ZSK. ($n)"
205ret=0
206
207$DIG $DIGOPTS @10.53.0.3 axfr inacksk3.example > dig.out.ns3.test$n
208
209zskid=$(awk '$4 == "DNSKEY" && $5 == 256 { print }' dig.out.ns3.test$n |
210       $DSFROMKEY -A -2 -f - inacksk3.example | awk '{ print $4}')
211grep "DNSKEY ${DEFAULT_ALGORITHM_NUMBER} 2 " dig.out.ns3.test$n > /dev/null || ret=1
212
213pattern="DNSKEY ${DEFAULT_ALGORITHM_NUMBER} 2 [0-9]* [0-9]* [0-9]* ${zskid} "
214grep "${pattern}" dig.out.ns3.test$n > /dev/null && ret=1
215
216count=$(awk 'BEGIN { count = 0 }
217	    $4 == "RRSIG" && $5 == "DNSKEY" { count++ }
218	    END {print count}' dig.out.ns3.test$n)
219test $count -eq 1 || ret=1
220
221count=$(awk 'BEGIN { count = 0 }
222       $4 == "DNSKEY" { count++ }
223       END {print count}' dig.out.ns3.test$n)
224test $count -eq 3 || ret=1
225
226awk='$4 == "RRSIG" && $5 == "DNSKEY" { printf "%05u\n", $11 }'
227id=$(awk "${awk}" dig.out.ns3.test$n)
228
229keyfile=$(printf "ns3/Kinacksk3.example.+%03u+%s" "${DEFAULT_ALGORITHM_NUMBER}" "${id}")
230$SETTIME -D now+5 "${keyfile}" > settime.out.test$n || ret=1
231($RNDCCMD 10.53.0.3 loadkeys inacksk3.example 2>&1 | sed 's/^/ns3 /' | cat_i) || ret=1
232
233n=$((n + 1))
234if [ $ret != 0 ]; then echo_i "failed"; fi
235status=$((status + ret))
236
237#
238# Check that zone is initially signed with a ZSK and not a KSK.
239#
240echo_i "check that zone with active and inactive ZSK and active KSK is properly"
241echo_ic "resigned after the active ZSK is deleted - stage 1: Verify that zone"
242echo_ic "is initially signed with a ZSK and not a KSK. ($n)"
243ret=0
244$DIG $DIGOPTS @10.53.0.3 axfr inaczsk3.example > dig.out.ns3.test$n
245kskid=$(awk '$4 == "DNSKEY" && $5 == 257 { print }' dig.out.ns3.test$n |
246       $DSFROMKEY -2 -f - inaczsk3.example | awk '{ print $4}' )
247grep "CNAME ${DEFAULT_ALGORITHM_NUMBER} 3 " dig.out.ns3.test$n > /dev/null || ret=1
248grep "CNAME ${DEFAULT_ALGORITHM_NUMBER} 3 [0-9]* [0-9]* [0-9]* ${kskid} " dig.out.ns3.test$n > /dev/null && ret=1
249count=$(awk 'BEGIN { count = 0 }
250	    $4 == "RRSIG" && $5 == "CNAME" { count++ }
251	    END {print count}' dig.out.ns3.test$n)
252test $count -eq 1 || ret=1
253count=$(awk 'BEGIN { count = 0 }
254       $4 == "DNSKEY" { count++ }
255       END {print count}' dig.out.ns3.test$n)
256test $count -eq 3 || ret=1
257id=$(awk '$4 == "RRSIG" && $5 == "CNAME" { printf "%05u\n", $11 }' dig.out.ns3.test$n)
258
259keyfile=$(printf "ns3/Kinaczsk3.example.+%03u+%s" "${DEFAULT_ALGORITHM_NUMBER}" "${id}")
260$SETTIME -D now+5 "${keyfile}" > settime.out.test$n || ret=1
261($RNDCCMD 10.53.0.3 loadkeys inaczsk3.example 2>&1 | sed 's/^/ns3 /' | cat_i) || ret=1
262n=$((n + 1))
263if [ $ret != 0 ]; then echo_i "failed"; fi
264status=$((status + ret))
265
266echo_i "checking NSEC->NSEC3 conversion prerequisites ($n)"
267ret=0
268# these commands should result in an empty file:
269$DIG $DIGOPTS +noall +answer nsec3.example. nsec3param @10.53.0.3 > dig.out.ns3.1.test$n || ret=1
270grep "NSEC3PARAM" dig.out.ns3.1.test$n > /dev/null && ret=1
271$DIG $DIGOPTS +noall +answer autonsec3.example. nsec3param @10.53.0.3 > dig.out.ns3.2.test$n || ret=1
272grep "NSEC3PARAM" dig.out.ns3.2.test$n > /dev/null && ret=1
273n=$((n + 1))
274if [ $ret != 0 ]; then echo_i "failed"; fi
275status=$((status + ret))
276
277echo_i "checking NSEC3->NSEC conversion prerequisites ($n)"
278ret=0
279$DIG $DIGOPTS +noall +answer nsec3-to-nsec.example. nsec3param @10.53.0.3 > dig.out.ns3.test$n || ret=1
280grep "NSEC3PARAM" dig.out.ns3.test$n > /dev/null || ret=1
281n=$((n + 1))
282if [ $ret != 0 ]; then echo_i "failed"; fi
283status=$((status + ret))
284
285echo_i "converting zones from nsec to nsec3"
286$NSUPDATE > /dev/null 2>&1 <<END	|| status=1
287server 10.53.0.3 ${PORT}
288zone nsec3.nsec3.example.
289update add nsec3.nsec3.example. 3600 NSEC3PARAM 1 0 10 BEEF
290send
291zone optout.nsec3.example.
292update add optout.nsec3.example. 3600 NSEC3PARAM 1 1 10 BEEF
293send
294zone nsec3.example.
295update add nsec3.example. 3600 NSEC3PARAM 1 0 10 BEEF
296send
297zone autonsec3.example.
298update add autonsec3.example. 3600 NSEC3PARAM 1 0 20 DEAF
299send
300zone nsec3.optout.example.
301update add nsec3.optout.example. 3600 NSEC3PARAM 1 0 10 BEEF
302send
303zone optout.optout.example.
304update add optout.optout.example. 3600 NSEC3PARAM 1 1 10 BEEF
305send
306zone optout.example.
307update add optout.example. 3600 NSEC3PARAM 1 1 10 BEEF
308send
309END
310
311if $SHELL ../testcrypto.sh -q RSASHA1
312then
313    # try to convert nsec-only.example; this should fail due to
314    # non-NSEC3 compatible keys
315    echo_i "preset nsec3param in unsigned zone via nsupdate ($n)"
316    $NSUPDATE > nsupdate.out 2>&1 <<END
317server 10.53.0.3 ${PORT}
318zone nsec-only.example.
319update add nsec-only.example. 3600 NSEC3PARAM 1 0 10 BEEF
320send
321END
322fi
323
324echo_i "checking for nsec3param in unsigned zone ($n)"
325ret=0
326$DIG $DIGOPTS +noall +answer autonsec3.example. nsec3param @10.53.0.3 > dig.out.ns3.test$n || ret=1
327grep "NSEC3PARAM" dig.out.ns3.test$n > /dev/null && ret=1
328n=$((n + 1))
329if [ $ret != 0 ]; then echo_i "failed"; fi
330status=$((status + ret))
331
332echo_i "checking for nsec3param signing record ($n)"
333ret=0
334$RNDCCMD 10.53.0.3 signing -list autonsec3.example. > signing.out.test$n 2>&1
335grep "Pending NSEC3 chain 1 0 20 DEAF" signing.out.test$n > /dev/null || ret=1
336n=$((n + 1))
337if [ $ret != 0 ]; then echo_i "failed"; fi
338status=$((status + ret))
339
340echo_i "resetting nsec3param via rndc signing ($n)"
341ret=0
342$RNDCCMD 10.53.0.3 signing -clear all autonsec3.example. > /dev/null 2>&1
343$RNDCCMD 10.53.0.3 signing -nsec3param 1 1 10 beef autonsec3.example. > /dev/null 2>&1
344for i in 0 1 2 3 4 5 6 7 8 9; do
345	ret=0
346	$RNDCCMD 10.53.0.3 signing -list autonsec3.example. > signing.out.test$n 2>&1
347	grep "Pending NSEC3 chain 1 1 10 BEEF" signing.out.test$n > /dev/null || ret=1
348	num=$(grep "Pending " signing.out.test$n | wc -l)
349	[ $num -eq 1 ] || ret=1
350	[ $ret -eq 0 ] && break
351	echo_i "waiting ... ($i)"
352	sleep 2
353done
354n=$((n + 1))
355if [ $ret != 0 ]; then echo_i "failed"; fi
356status=$((status + ret))
357
358echo_i "signing preset nsec3 zone"
359zsk=$(cat autozsk.key)
360ksk=$(cat autoksk.key)
361$SETTIME -K ns3 -P now -A now $zsk > settime.out.test$n.zsk || ret=1
362$SETTIME -K ns3 -P now -A now $ksk > settime.out.test$n.ksk || ret=1
363($RNDCCMD 10.53.0.3 loadkeys autonsec3.example. 2>&1 | sed 's/^/ns3 /' | cat_i) || ret=1
364
365echo_i "waiting for changes to take effect"
366sleep 3
367
368echo_i "converting zone from nsec3 to nsec"
369$NSUPDATE > /dev/null 2>&1 << END	|| status=1
370server 10.53.0.3 ${PORT}
371zone nsec3-to-nsec.example.
372update delete nsec3-to-nsec.example. NSEC3PARAM
373send
374END
375
376echo_i "waiting for change to take effect"
377sleep 3
378
379missing=$(keyfile_to_key_id "$(cat noksk-ksk.key)")
380echo_i "checking that expired RRSIGs from missing KSK $missing are not deleted ($n)"
381ret=0
382$JOURNALPRINT ns3/noksk.example.db.jnl | \
383   awk '{if ($1 == "del" && $5 == "RRSIG" && $12 == id) {error=1}} END {exit error}' id=$missing || ret=1
384n=$((n + 1))
385if [ $ret != 0 ]; then echo_i "failed"; fi
386status=$((status + ret))
387
388missing=$(keyfile_to_key_id "$(cat nozsk-zsk.key)")
389ksk=$(keyfile_to_key_id "$(cat nozsk-ksk.key)")
390echo_i "checking that expired RRSIGs from missing ZSK $missing are replaced ($n)"
391ret=0
392$JOURNALPRINT ns3/nozsk.example.db.jnl | \
393   awk '{if ($1 == "del" && $5 == "RRSIG" && $12 == id) {ok=1}} END {exit ok?0:1}' id=$missing || ret=1
394$JOURNALPRINT ns3/nozsk.example.db.jnl | \
395   awk '{if ($1 == "add" && $5 == "RRSIG" && $12 == id) {ok=1}} END {exit ok?0:1}' id=$ksk || ret=1
396n=$((n + 1))
397if [ $ret != 0 ]; then echo_i "failed"; fi
398status=$((status + ret))
399
400inactive=$(keyfile_to_key_id "$(cat inaczsk-zsk.key)")
401ksk=$(keyfile_to_key_id "$(cat inaczsk-ksk.key)")
402echo_i "checking that expired RRSIGs from inactive ZSK $inactive are replaced ($n)"
403ret=0
404$JOURNALPRINT ns3/inaczsk.example.db.jnl | \
405   awk '{if ($1 == "del" && $5 == "RRSIG" && $12 == id) {ok=1}} END {exit ok?0:1}' id=$inactive || ret=1
406$JOURNALPRINT ns3/inaczsk.example.db.jnl | \
407   awk '{if ($1 == "add" && $5 == "RRSIG" && $12 == id) {ok=1}} END {exit ok?0:1}' id=$ksk || ret=1
408n=$((n + 1))
409if [ $ret != 0 ]; then echo_i "failed"; fi
410status=$((status + ret))
411
412echo_i "checking that replaced RRSIGs are not logged (missing ZSK private key) ($n)"
413ret=0
414loglines=$(grep "Key nozsk.example/$DEFAULT_ALGORITHM/$missing .* retaining signatures" ns3/named.run | wc -l)
415[ "$loglines" -eq 0 ] || ret=1
416n=$((n + 1))
417if [ $ret != 0 ]; then echo_i "failed"; fi
418status=$((status + ret))
419
420echo_i "checking that replaced RRSIGs are not logged (inactive ZSK private key) ($n)"
421ret=0
422loglines=$(grep "Key inaczsk.example/$DEFAULT_ALGORITHM/$inactive .* retaining signatures" ns3/named.run | wc -l)
423[ "$loglines" -eq 0 ] || ret=1
424n=$((n + 1))
425if [ $ret != 0 ]; then echo_i "failed"; fi
426status=$((status + ret))
427
428# Send rndc sync command to ns1, ns2 and ns3, to force the dynamically
429# signed zones to be dumped to their zone files
430echo_i "dumping zone files"
431($RNDCCMD 10.53.0.1 sync 2>&1 | sed 's/^/ns1 /' | cat_i) || ret=1
432($RNDCCMD 10.53.0.2 sync 2>&1 | sed 's/^/ns2 /' | cat_i) || ret=1
433($RNDCCMD 10.53.0.3 sync 2>&1 | sed 's/^/ns3 /' | cat_i) || ret=1
434
435now="$(TZ=UTC date +%Y%m%d%H%M%S)"
436check_expiry() (
437	$DIG $DIGOPTS AXFR oldsigs.example @10.53.0.3 > dig.out.test$n
438	nearest_expiration="$(awk '$4 == "RRSIG" { print $9 }' < dig.out.test$n | sort -n | head -1)"
439	if [ "$nearest_expiration" -le "$now" ]; then
440		echo_i "failed: $nearest_expiration <= $now"
441		return 1
442	fi
443)
444
445echo_i "checking expired signatures were updated ($n)"
446retry 10 check_expiry || ret=1
447$DIG $DIGOPTS +noauth a.oldsigs.example. @10.53.0.3 a > dig.out.ns3.test$n || ret=1
448$DIG $DIGOPTS +noauth a.oldsigs.example. @10.53.0.4 a > dig.out.ns4.test$n || ret=1
449digcomp dig.out.ns3.test$n dig.out.ns4.test$n || ret=1
450grep "flags:.*ad.*QUERY" dig.out.ns4.test$n > /dev/null || ret=1
451n=$((n + 1))
452if [ $ret != 0 ]; then echo_i "failed"; fi
453status=$((status + ret))
454
455# Check jitter distribution.
456echo_i "checking expired signatures were jittered correctly ($n)"
457ret=0
458$DIG $DIGOPTS axfr oldsigs.example @10.53.0.3 > dig.out.ns3.test$n || ret=1
459checkjitter dig.out.ns3.test$n || ret=1
460n=$((n + 1))
461if [ $ret != 0 ]; then echo_i "failed"; fi
462status=$((status + ret))
463
464echo_i "checking NSEC->NSEC3 conversion succeeded ($n)"
465ret=0
466$DIG $DIGOPTS nsec3.example. nsec3param @10.53.0.3 > dig.out.ns3.ok.test$n || ret=1
467grep "status: NOERROR" dig.out.ns3.ok.test$n > /dev/null || ret=1
468$DIG $DIGOPTS +noauth q.nsec3.example. @10.53.0.3 a > dig.out.ns3.test$n || ret=1
469$DIG $DIGOPTS +noauth q.nsec3.example. @10.53.0.4 a > dig.out.ns4.test$n || ret=1
470digcomp dig.out.ns3.test$n dig.out.ns4.test$n || ret=1
471grep "flags:.*ad.*QUERY" dig.out.ns4.test$n > /dev/null || ret=1
472grep "status: NXDOMAIN" dig.out.ns4.test$n > /dev/null || ret=1
473n=$((n + 1))
474if [ $ret != 0 ]; then echo_i "failed"; fi
475status=$((status + ret))
476
477echo_i "checking direct NSEC3 autosigning succeeded ($n)"
478ret=0
479$DIG $DIGOPTS +noall +answer autonsec3.example. nsec3param @10.53.0.3 > dig.out.ns3.ok.test$n || ret=1
480[ -s  dig.out.ns3.ok.test$n ] || ret=1
481grep "NSEC3PARAM" dig.out.ns3.ok.test$n > /dev/null || ret=1
482$DIG $DIGOPTS +noauth q.autonsec3.example. @10.53.0.3 a > dig.out.ns3.test$n || ret=1
483$DIG $DIGOPTS +noauth q.autonsec3.example. @10.53.0.4 a > dig.out.ns4.test$n || ret=1
484digcomp dig.out.ns3.test$n dig.out.ns4.test$n || ret=1
485grep "flags:.*ad.*QUERY" dig.out.ns4.test$n > /dev/null || ret=1
486grep "status: NXDOMAIN" dig.out.ns4.test$n > /dev/null || ret=1
487n=$((n + 1))
488if [ $ret != 0 ]; then echo_i "failed"; fi
489status=$((status + ret))
490
491echo_i "checking NSEC->NSEC3 conversion failed with NSEC-only key ($n)"
492ret=0
493if $SHELL ../testcrypto.sh -q RSASHA1
494then
495    grep "failed: REFUSED" nsupdate.out > /dev/null || ret=1
496else
497    echo_i "skip: RSASHA1 not supported"
498fi
499n=$((n + 1))
500if [ $ret != 0 ]; then echo_i "failed"; fi
501status=$((status + ret))
502
503echo_i "checking NSEC3->NSEC conversion succeeded ($n)"
504ret=0
505# this command should result in an empty file:
506$DIG $DIGOPTS +noall +answer nsec3-to-nsec.example. nsec3param @10.53.0.3 > dig.out.ns3.nx.test$n || ret=1
507grep "NSEC3PARAM" dig.out.ns3.nx.test$n > /dev/null && ret=1
508$DIG $DIGOPTS +noauth q.nsec3-to-nsec.example. @10.53.0.3 a > dig.out.ns3.test$n || ret=1
509$DIG $DIGOPTS +noauth q.nsec3-to-nsec.example. @10.53.0.4 a > dig.out.ns4.test$n || ret=1
510digcomp dig.out.ns3.test$n dig.out.ns4.test$n || ret=1
511grep "flags:.*ad.*QUERY" dig.out.ns4.test$n > /dev/null || ret=1
512grep "status: NXDOMAIN" dig.out.ns4.test$n > /dev/null || ret=1
513n=$((n + 1))
514if [ $ret != 0 ]; then echo_i "failed"; fi
515status=$((status + ret))
516
517echo_i "checking NSEC3->NSEC conversion with 'rndc signing -nsec3param none' ($n)"
518ret=0
519$RNDCCMD 10.53.0.3 signing -nsec3param none autonsec3.example. > /dev/null 2>&1
520# this command should result in an empty file:
521no_nsec3param() (
522 $DIG $DIGOPTS +noall +answer autonsec3.example. nsec3param @10.53.0.3 > dig.out.ns3.nx.test$n || return 1
523 grep "NSEC3PARAM" dig.out.ns3.nx.test$n > /dev/null && return 1
524 return 0
525)
526retry_quiet 10 no_nsec3param || ret=1
527$DIG $DIGOPTS +noauth q.autonsec3.example. @10.53.0.3 a > dig.out.ns3.test$n || ret=1
528$DIG $DIGOPTS +noauth q.autonsec3.example. @10.53.0.4 a > dig.out.ns4.test$n || ret=1
529digcomp dig.out.ns3.test$n dig.out.ns4.test$n || ret=1
530grep "flags:.*ad.*QUERY" dig.out.ns4.test$n > /dev/null || ret=1
531grep "status: NXDOMAIN" dig.out.ns4.test$n > /dev/null || ret=1
532n=$((n + 1))
533if [ $ret != 0 ]; then echo_i "failed"; fi
534status=$((status + ret))
535
536echo_i "checking TTLs of imported DNSKEYs (no default) ($n)"
537ret=0
538$DIG $DIGOPTS +tcp +noall +answer dnskey ttl1.example. @10.53.0.3 > dig.out.ns3.test$n || ret=1
539[ -s dig.out.ns3.test$n ] || ret=1
540(awk 'BEGIN {r=0} $2 != 300 {r=1; print "found TTL " $2} END {exit r}' dig.out.ns3.test$n | cat_i) || ret=1
541n=$((n + 1))
542if [ $ret != 0 ]; then echo_i "failed"; fi
543status=$((status + ret))
544
545echo_i "checking TTLs of imported DNSKEYs (with default) ($n)"
546ret=0
547$DIG $DIGOPTS +tcp +noall +answer dnskey ttl2.example. @10.53.0.3 > dig.out.ns3.test$n || ret=1
548[ -s dig.out.ns3.test$n ] || ret=1
549(awk 'BEGIN {r=0} $2 != 60 {r=1; print "found TTL " $2} END {exit r}' dig.out.ns3.test$n | cat_i) || ret=1
550n=$((n + 1))
551if [ $ret != 0 ]; then echo_i "failed"; fi
552status=$((status + ret))
553
554echo_i "checking TTLs of imported DNSKEYs (mismatched) ($n)"
555ret=0
556$DIG $DIGOPTS +tcp +noall +answer dnskey ttl3.example. @10.53.0.3 > dig.out.ns3.test$n || ret=1
557[ -s dig.out.ns3.test$n ] || ret=1
558(awk 'BEGIN {r=0} $2 != 30 {r=1; print "found TTL " $2} END {exit r}' dig.out.ns3.test$n | cat_i) || ret=1
559n=$((n + 1))
560if [ $ret != 0 ]; then echo_i "failed"; fi
561status=$((status + ret))
562
563echo_i "checking TTLs of imported DNSKEYs (existing RRset) ($n)"
564ret=0
565$DIG $DIGOPTS +tcp +noall +answer dnskey ttl4.example. @10.53.0.3 > dig.out.ns3.test$n || ret=1
566[ -s dig.out.ns3.test$n ] || ret=1
567(awk 'BEGIN {r=0} $2 != 30 {r=1; print "found TTL " $2} END {exit r}' dig.out.ns3.test$n | cat_i) || ret=1
568n=$((n + 1))
569if [ $ret != 0 ]; then echo_i "failed"; fi
570status=$((status + ret))
571
572echo_i "checking positive validation NSEC ($n)"
573ret=0
574$DIG $DIGOPTS +noauth a.example. @10.53.0.2 a > dig.out.ns2.test$n || ret=1
575$DIG $DIGOPTS +noauth a.example. @10.53.0.4 a > dig.out.ns4.test$n || ret=1
576digcomp dig.out.ns2.test$n dig.out.ns4.test$n || ret=1
577grep "flags:.*ad.*QUERY" dig.out.ns4.test$n > /dev/null || ret=1
578n=$((n + 1))
579if [ $ret != 0 ]; then echo_i "failed"; fi
580status=$((status + ret))
581
582echo_i "checking positive validation NSEC3 ($n)"
583ret=0
584$DIG $DIGOPTS +noauth a.nsec3.example. \
585	@10.53.0.3 a > dig.out.ns3.test$n || ret=1
586$DIG $DIGOPTS +noauth a.nsec3.example. \
587	@10.53.0.4 a > dig.out.ns4.test$n || ret=1
588digcomp dig.out.ns3.test$n dig.out.ns4.test$n || ret=1
589grep "flags:.*ad.*QUERY" dig.out.ns4.test$n > /dev/null || ret=1
590n=$((n + 1))
591if [ $ret != 0 ]; then echo_i "failed"; fi
592status=$((status + ret))
593
594echo_i "checking positive validation OPTOUT ($n)"
595ret=0
596$DIG $DIGOPTS +noauth a.optout.example. \
597	@10.53.0.3 a > dig.out.ns3.test$n || ret=1
598$DIG $DIGOPTS +noauth a.optout.example. \
599	@10.53.0.4 a > dig.out.ns4.test$n || ret=1
600digcomp dig.out.ns3.test$n dig.out.ns4.test$n || ret=1
601grep "flags:.*ad.*QUERY" dig.out.ns4.test$n > /dev/null || ret=1
602n=$((n + 1))
603if [ $ret != 0 ]; then echo_i "failed"; fi
604status=$((status + ret))
605
606echo_i "checking negative validation NXDOMAIN NSEC ($n)"
607ret=0
608$DIG $DIGOPTS +noauth q.example. @10.53.0.2 a > dig.out.ns2.test$n || ret=1
609$DIG $DIGOPTS +noauth q.example. @10.53.0.4 a > dig.out.ns4.test$n || ret=1
610digcomp dig.out.ns2.test$n dig.out.ns4.test$n || ret=1
611grep "flags:.*ad.*QUERY" dig.out.ns4.test$n > /dev/null || ret=1
612grep "status: NXDOMAIN" dig.out.ns4.test$n > /dev/null || ret=1
613n=$((n + 1))
614if [ $ret != 0 ]; then echo_i "failed"; fi
615status=$((status + ret))
616
617echo_i "checking negative validation NXDOMAIN NSEC3 ($n)"
618ret=0
619$DIG $DIGOPTS +noauth q.nsec3.example. \
620	@10.53.0.3 a > dig.out.ns3.test$n || ret=1
621$DIG $DIGOPTS +noauth q.nsec3.example. \
622	@10.53.0.4 a > dig.out.ns4.test$n || ret=1
623digcomp dig.out.ns3.test$n dig.out.ns4.test$n || ret=1
624grep "flags:.*ad.*QUERY" dig.out.ns4.test$n > /dev/null || ret=1
625grep "status: NXDOMAIN" dig.out.ns4.test$n > /dev/null || ret=1
626n=$((n + 1))
627if [ $ret != 0 ]; then echo_i "failed"; fi
628status=$((status + ret))
629
630echo_i "checking negative validation NXDOMAIN OPTOUT ($n)"
631ret=0
632$DIG $DIGOPTS +noauth q.optout.example. \
633	@10.53.0.3 a > dig.out.ns3.test$n || ret=1
634$DIG $DIGOPTS +noauth q.optout.example. \
635	@10.53.0.4 a > dig.out.ns4.test$n || ret=1
636digcomp dig.out.ns3.test$n dig.out.ns4.test$n || ret=1
637grep "status: NXDOMAIN" dig.out.ns4.test$n > /dev/null || ret=1
638# Note - this is looking for failure, hence the &&
639grep "flags:.*ad.*QUERY" dig.out.ns4.test$n > /dev/null && ret=1
640n=$((n + 1))
641if [ $ret != 0 ]; then echo_i "failed"; fi
642status=$((status + ret))
643
644echo_i "checking negative validation NODATA NSEC ($n)"
645ret=0
646$DIG $DIGOPTS +noauth a.example. @10.53.0.2 txt > dig.out.ns2.test$n || ret=1
647$DIG $DIGOPTS +noauth a.example. @10.53.0.4 txt > dig.out.ns4.test$n || ret=1
648digcomp dig.out.ns2.test$n dig.out.ns4.test$n || ret=1
649grep "flags:.*ad.*QUERY" dig.out.ns4.test$n > /dev/null || ret=1
650grep "status: NOERROR" dig.out.ns4.test$n > /dev/null || ret=1
651grep "ANSWER: 0" dig.out.ns4.test$n > /dev/null || ret=1
652n=$((n + 1))
653if [ $ret != 0 ]; then echo_i "failed"; fi
654status=$((status + ret))
655
656echo_i "checking negative validation NODATA NSEC3 ($n)"
657ret=0
658$DIG $DIGOPTS +noauth a.nsec3.example. \
659	@10.53.0.3 txt > dig.out.ns3.test$n || ret=1
660$DIG $DIGOPTS +noauth a.nsec3.example. \
661	@10.53.0.4 txt > dig.out.ns4.test$n || ret=1
662digcomp dig.out.ns3.test$n dig.out.ns4.test$n || ret=1
663grep "flags:.*ad.*QUERY" dig.out.ns4.test$n > /dev/null || ret=1
664grep "status: NOERROR" dig.out.ns4.test$n > /dev/null || ret=1
665grep "ANSWER: 0" dig.out.ns4.test$n > /dev/null || ret=1
666n=$((n + 1))
667if [ $ret != 0 ]; then echo_i "failed"; fi
668status=$((status + ret))
669
670echo_i "checking negative validation NODATA OPTOUT ($n)"
671ret=0
672$DIG $DIGOPTS +noauth a.optout.example. \
673	@10.53.0.3 txt > dig.out.ns3.test$n || ret=1
674$DIG $DIGOPTS +noauth a.optout.example. \
675	@10.53.0.4 txt > dig.out.ns4.test$n || ret=1
676digcomp dig.out.ns3.test$n dig.out.ns4.test$n || ret=1
677grep "flags:.*ad.*QUERY" dig.out.ns4.test$n > /dev/null || ret=1
678grep "status: NOERROR" dig.out.ns4.test$n > /dev/null || ret=1
679grep "ANSWER: 0" dig.out.ns4.test$n > /dev/null || ret=1
680n=$((n + 1))
681if [ $ret != 0 ]; then echo_i "failed"; fi
682status=$((status + ret))
683
684# Check the insecure.example domain
685
686echo_i "checking 1-server insecurity proof NSEC ($n)"
687ret=0
688$DIG $DIGOPTS +noauth a.insecure.example. @10.53.0.3 a > dig.out.ns3.test$n || ret=1
689$DIG $DIGOPTS +noauth a.insecure.example. @10.53.0.4 a > dig.out.ns4.test$n || ret=1
690digcomp dig.out.ns3.test$n dig.out.ns4.test$n || ret=1
691grep "status: NOERROR" dig.out.ns4.test$n > /dev/null || ret=1
692# Note - this is looking for failure, hence the &&
693grep "flags:.*ad.*QUERY" dig.out.ns4.test$n > /dev/null && ret=1
694n=$((n + 1))
695if [ $ret != 0 ]; then echo_i "failed"; fi
696status=$((status + ret))
697
698echo_i "checking 1-server negative insecurity proof NSEC ($n)"
699ret=0
700$DIG $DIGOPTS q.insecure.example. a @10.53.0.3 \
701	> dig.out.ns3.test$n || ret=1
702$DIG $DIGOPTS q.insecure.example. a @10.53.0.4 \
703	> dig.out.ns4.test$n || ret=1
704digcomp dig.out.ns3.test$n dig.out.ns4.test$n || ret=1
705grep "status: NXDOMAIN" dig.out.ns4.test$n > /dev/null || ret=1
706# Note - this is looking for failure, hence the &&
707grep "flags:.*ad.*QUERY" dig.out.ns4.test$n > /dev/null && ret=1
708n=$((n + 1))
709if [ $ret != 0 ]; then echo_i "failed"; fi
710status=$((status + ret))
711
712# Check the secure.example domain
713
714echo_i "checking multi-stage positive validation NSEC/NSEC ($n)"
715ret=0
716$DIG $DIGOPTS +noauth a.secure.example. \
717	@10.53.0.3 a > dig.out.ns3.test$n || ret=1
718$DIG $DIGOPTS +noauth a.secure.example. \
719	@10.53.0.4 a > dig.out.ns4.test$n || ret=1
720digcomp dig.out.ns3.test$n dig.out.ns4.test$n || ret=1
721grep "status: NOERROR" dig.out.ns4.test$n > /dev/null || ret=1
722grep "flags:.*ad.*QUERY" dig.out.ns4.test$n > /dev/null || ret=1
723n=$((n + 1))
724if [ $ret != 0 ]; then echo_i "failed"; fi
725status=$((status + ret))
726
727echo_i "checking multi-stage positive validation NSEC/NSEC3 ($n)"
728ret=0
729$DIG $DIGOPTS +noauth a.nsec3.example. \
730	@10.53.0.3 a > dig.out.ns3.test$n || ret=1
731$DIG $DIGOPTS +noauth a.nsec3.example. \
732	@10.53.0.4 a > dig.out.ns4.test$n || ret=1
733digcomp dig.out.ns3.test$n dig.out.ns4.test$n || ret=1
734grep "status: NOERROR" dig.out.ns4.test$n > /dev/null || ret=1
735grep "flags:.*ad.*QUERY" dig.out.ns4.test$n > /dev/null || ret=1
736n=$((n + 1))
737if [ $ret != 0 ]; then echo_i "failed"; fi
738status=$((status + ret))
739
740echo_i "checking multi-stage positive validation NSEC/OPTOUT ($n)"
741ret=0
742$DIG $DIGOPTS +noauth a.optout.example. \
743	@10.53.0.3 a > dig.out.ns3.test$n || ret=1
744$DIG $DIGOPTS +noauth a.optout.example. \
745	@10.53.0.4 a > dig.out.ns4.test$n || ret=1
746digcomp dig.out.ns3.test$n dig.out.ns4.test$n || ret=1
747grep "status: NOERROR" dig.out.ns4.test$n > /dev/null || ret=1
748grep "flags:.*ad.*QUERY" dig.out.ns4.test$n > /dev/null || ret=1
749n=$((n + 1))
750if [ $ret != 0 ]; then echo_i "failed"; fi
751status=$((status + ret))
752
753echo_i "checking multi-stage positive validation NSEC3/NSEC ($n)"
754ret=0
755$DIG $DIGOPTS +noauth a.secure.nsec3.example. \
756	@10.53.0.3 a > dig.out.ns3.test$n || ret=1
757$DIG $DIGOPTS +noauth a.secure.nsec3.example. \
758	@10.53.0.4 a > dig.out.ns4.test$n || ret=1
759digcomp dig.out.ns3.test$n dig.out.ns4.test$n || ret=1
760grep "status: NOERROR" dig.out.ns4.test$n > /dev/null || ret=1
761grep "flags:.*ad.*QUERY" dig.out.ns4.test$n > /dev/null || ret=1
762n=$((n + 1))
763if [ $ret != 0 ]; then echo_i "failed"; fi
764status=$((status + ret))
765
766echo_i "checking multi-stage positive validation NSEC3/NSEC3 ($n)"
767ret=0
768$DIG $DIGOPTS +noauth a.nsec3.nsec3.example. \
769	@10.53.0.3 a > dig.out.ns3.test$n || ret=1
770$DIG $DIGOPTS +noauth a.nsec3.nsec3.example. \
771	@10.53.0.4 a > dig.out.ns4.test$n || ret=1
772digcomp dig.out.ns3.test$n dig.out.ns4.test$n || ret=1
773grep "status: NOERROR" dig.out.ns4.test$n > /dev/null || ret=1
774grep "flags:.*ad.*QUERY" dig.out.ns4.test$n > /dev/null || ret=1
775n=$((n + 1))
776if [ $ret != 0 ]; then echo_i "failed"; fi
777status=$((status + ret))
778
779echo_i "checking multi-stage positive validation NSEC3/OPTOUT ($n)"
780ret=0
781$DIG $DIGOPTS +noauth a.optout.nsec3.example. \
782	@10.53.0.3 a > dig.out.ns3.test$n || ret=1
783$DIG $DIGOPTS +noauth a.optout.nsec3.example. \
784	@10.53.0.4 a > dig.out.ns4.test$n || ret=1
785digcomp dig.out.ns3.test$n dig.out.ns4.test$n || ret=1
786grep "status: NOERROR" dig.out.ns4.test$n > /dev/null || ret=1
787grep "flags:.*ad.*QUERY" dig.out.ns4.test$n > /dev/null || ret=1
788n=$((n + 1))
789if [ $ret != 0 ]; then echo_i "failed"; fi
790status=$((status + ret))
791
792echo_i "checking multi-stage positive validation OPTOUT/NSEC ($n)"
793ret=0
794$DIG $DIGOPTS +noauth a.secure.optout.example. \
795	@10.53.0.3 a > dig.out.ns3.test$n || ret=1
796$DIG $DIGOPTS +noauth a.secure.optout.example. \
797	@10.53.0.4 a > dig.out.ns4.test$n || ret=1
798digcomp dig.out.ns3.test$n dig.out.ns4.test$n || ret=1
799grep "status: NOERROR" dig.out.ns4.test$n > /dev/null || ret=1
800grep "flags:.*ad.*QUERY" dig.out.ns4.test$n > /dev/null || ret=1
801n=$((n + 1))
802if [ $ret != 0 ]; then echo_i "failed"; fi
803status=$((status + ret))
804
805echo_i "checking multi-stage positive validation OPTOUT/NSEC3 ($n)"
806ret=0
807$DIG $DIGOPTS +noauth a.nsec3.optout.example. \
808	@10.53.0.3 a > dig.out.ns3.test$n || ret=1
809$DIG $DIGOPTS +noauth a.nsec3.optout.example. \
810	@10.53.0.4 a > dig.out.ns4.test$n || ret=1
811digcomp dig.out.ns3.test$n dig.out.ns4.test$n || ret=1
812grep "status: NOERROR" dig.out.ns4.test$n > /dev/null || ret=1
813grep "flags:.*ad.*QUERY" dig.out.ns4.test$n > /dev/null || ret=1
814n=$((n + 1))
815if [ $ret != 0 ]; then echo_i "failed"; fi
816status=$((status + ret))
817
818echo_i "checking multi-stage positive validation OPTOUT/OPTOUT ($n)"
819ret=0
820$DIG $DIGOPTS +noauth a.optout.optout.example. \
821	@10.53.0.3 a > dig.out.ns3.test$n || ret=1
822$DIG $DIGOPTS +noauth a.optout.optout.example. \
823	@10.53.0.4 a > dig.out.ns4.test$n || ret=1
824digcomp dig.out.ns3.test$n dig.out.ns4.test$n || ret=1
825grep "status: NOERROR" dig.out.ns4.test$n > /dev/null || ret=1
826grep "flags:.*ad.*QUERY" dig.out.ns4.test$n > /dev/null || ret=1
827n=$((n + 1))
828if [ $ret != 0 ]; then echo_i "failed"; fi
829status=$((status + ret))
830
831echo_i "checking empty NODATA OPTOUT ($n)"
832ret=0
833$DIG $DIGOPTS +noauth empty.optout.example. \
834	@10.53.0.3 a > dig.out.ns3.test$n || ret=1
835$DIG $DIGOPTS +noauth empty.optout.example. \
836	@10.53.0.4 a > dig.out.ns4.test$n || ret=1
837digcomp dig.out.ns3.test$n dig.out.ns4.test$n || ret=1
838grep "status: NOERROR" dig.out.ns4.test$n > /dev/null || ret=1
839#grep "flags:.*ad.*QUERY" dig.out.ns4.test$n > /dev/null || ret=1
840n=$((n + 1))
841if [ $ret != 0 ]; then echo_i "failed"; fi
842status=$((status + ret))
843
844# Check the insecure.secure.example domain (insecurity proof)
845
846echo_i "checking 2-server insecurity proof ($n)"
847ret=0
848$DIG $DIGOPTS +noauth a.insecure.secure.example. @10.53.0.2 a \
849	> dig.out.ns2.test$n || ret=1
850$DIG $DIGOPTS +noauth a.insecure.secure.example. @10.53.0.4 a \
851	> dig.out.ns4.test$n || ret=1
852digcomp dig.out.ns2.test$n dig.out.ns4.test$n || ret=1
853grep "status: NOERROR" dig.out.ns4.test$n > /dev/null || ret=1
854# Note - this is looking for failure, hence the &&
855grep "flags:.*ad.*QUERY" dig.out.ns4.test$n > /dev/null && ret=1
856n=$((n + 1))
857if [ $ret != 0 ]; then echo_i "failed"; fi
858status=$((status + ret))
859
860# Check a negative response in insecure.secure.example
861
862echo_i "checking 2-server insecurity proof with a negative answer ($n)"
863ret=0
864$DIG $DIGOPTS q.insecure.secure.example. @10.53.0.2 a > dig.out.ns2.test$n \
865	|| ret=1
866$DIG $DIGOPTS q.insecure.secure.example. @10.53.0.4 a > dig.out.ns4.test$n \
867	|| ret=1
868digcomp dig.out.ns2.test$n dig.out.ns4.test$n || ret=1
869grep "status: NXDOMAIN" dig.out.ns4.test$n > /dev/null || ret=1
870# Note - this is looking for failure, hence the &&
871grep "flags:.*ad.*QUERY" dig.out.ns4.test$n > /dev/null && ret=1
872n=$((n + 1))
873if [ $ret != 0 ]; then echo_i "failed"; fi
874status=$((status + ret))
875
876echo_i "checking security root query ($n)"
877ret=0
878$DIG $DIGOPTS . @10.53.0.4 key > dig.out.ns4.test$n || ret=1
879grep "NOERROR" dig.out.ns4.test$n > /dev/null || ret=1
880grep "flags:.*ad.*QUERY" dig.out.ns4.test$n > /dev/null || ret=1
881n=$((n + 1))
882if [ $ret != 0 ]; then echo_i "failed"; fi
883status=$((status + ret))
884
885echo_i "checking positive validation RSASHA256 NSEC ($n)"
886ret=0
887$DIG $DIGOPTS +noauth a.rsasha256.example. @10.53.0.3 a > dig.out.ns3.test$n || ret=1
888$DIG $DIGOPTS +noauth a.rsasha256.example. @10.53.0.4 a > dig.out.ns4.test$n || ret=1
889digcomp dig.out.ns3.test$n dig.out.ns4.test$n || ret=1
890grep "flags:.*ad.*QUERY" dig.out.ns4.test$n > /dev/null || ret=1
891n=$((n + 1))
892if [ $ret != 0 ]; then echo_i "failed"; fi
893status=$((status + ret))
894
895echo_i "checking positive validation RSASHA512 NSEC ($n)"
896ret=0
897$DIG $DIGOPTS +noauth a.rsasha512.example. @10.53.0.3 a > dig.out.ns3.test$n || ret=1
898$DIG $DIGOPTS +noauth a.rsasha512.example. @10.53.0.4 a > dig.out.ns4.test$n || ret=1
899digcomp dig.out.ns3.test$n dig.out.ns4.test$n || ret=1
900grep "flags:.*ad.*QUERY" dig.out.ns4.test$n > /dev/null || ret=1
901n=$((n + 1))
902if [ $ret != 0 ]; then echo_i "failed"; fi
903status=$((status + ret))
904
905echo_i "checking that positive validation in a privately secure zone works ($n)"
906ret=0
907$DIG $DIGOPTS +noauth a.private.secure.example. a @10.53.0.2 \
908	> dig.out.ns2.test$n || ret=1
909$DIG $DIGOPTS +noauth a.private.secure.example. a @10.53.0.4 \
910	> dig.out.ns4.test$n || ret=1
911digcomp dig.out.ns2.test$n dig.out.ns4.test$n || ret=1
912grep "NOERROR" dig.out.ns4.test$n > /dev/null || ret=1
913grep "flags:.*ad.*QUERY" dig.out.ns4.test$n > /dev/null || ret=1
914n=$((n + 1))
915if [ $ret != 0 ]; then echo_i "failed"; fi
916status=$((status + ret))
917
918echo_i "checking that negative validation in a privately secure zone works ($n)"
919ret=0
920$DIG $DIGOPTS +noauth q.private.secure.example. a @10.53.0.2 \
921	> dig.out.ns2.test$n || ret=1
922$DIG $DIGOPTS +noauth q.private.secure.example. a @10.53.0.4 \
923	> dig.out.ns4.test$n || ret=1
924digcomp dig.out.ns2.test$n dig.out.ns4.test$n || ret=1
925grep "NXDOMAIN" dig.out.ns4.test$n > /dev/null || ret=1
926# Note - this is looking for failure, hence the &&
927grep "flags:.*ad.*QUERY" dig.out.ns4.test$n > /dev/null && ret=1
928n=$((n + 1))
929if [ $ret != 0 ]; then echo_i "failed"; fi
930status=$((status + ret))
931
932echo_i "checking privately secure to nxdomain works ($n)"
933ret=0
934$DIG $DIGOPTS +noauth private2secure-nxdomain.private.secure.example. SOA @10.53.0.4 > dig.out.ns4.test$n || ret=1
935grep "NXDOMAIN" dig.out.ns4.test$n > /dev/null || ret=1
936grep "flags:.*ad.*QUERY" dig.out.ns4.test$n > /dev/null || ret=1
937n=$((n + 1))
938if [ $ret != 0 ]; then echo_i "failed"; fi
939status=$((status + ret))
940
941# Try validating with a revoked trusted key.
942# This should fail.
943
944echo_i "checking that validation returns insecure due to revoked trusted key ($n)"
945ret=0
946$DIG $DIGOPTS example. soa @10.53.0.5 > dig.out.ns5.test$n || ret=1
947grep "flags:.*; QUERY" dig.out.ns5.test$n > /dev/null || ret=1
948grep "flags:.* ad.*; QUERY" dig.out.ns5.test$n > /dev/null && ret=1
949n=$((n + 1))
950if [ $ret != 0 ]; then echo_i "failed"; fi
951status=$((status + ret))
952
953echo_i "checking that revoked key is present ($n)"
954ret=0
955id=$(cat rev.key)
956$DIG $DIGOPTS +multi dnskey . @10.53.0.1 > dig.out.ns1.test$n || ret=1
957grep '; key id = '"$id"'$' dig.out.ns1.test$n > /dev/null || ret=1
958n=$((n + 1))
959if [ $ret != 0 ]; then echo_i "failed"; fi
960status=$((status + ret))
961
962echo_i "checking that revoked key self-signs ($n)"
963ret=0
964id=$(cat rev.key)
965$DIG $DIGOPTS dnskey . @10.53.0.1 > dig.out.ns1.test$n || ret=1
966grep 'RRSIG.*'" $id "'\. ' dig.out.ns1.test$n > /dev/null || ret=1
967n=$((n + 1))
968if [ $ret != 0 ]; then echo_i "failed"; fi
969status=$((status + ret))
970
971echo_i "checking for unpublished key ($n)"
972ret=0
973id=$(keyfile_to_key_id "$(cat unpub.key)")
974$DIG $DIGOPTS +multi dnskey . @10.53.0.1 > dig.out.ns1.test$n || ret=1
975grep '; key id = '"$id"'$' dig.out.ns1.test$n > /dev/null && ret=1
976n=$((n + 1))
977if [ $ret != 0 ]; then echo_i "failed"; fi
978status=$((status + ret))
979
980echo_i "checking for activated but unpublished key ($n)"
981ret=0
982id=$(keyfile_to_key_id "$(cat activate-now-publish-1day.key)")
983$DIG $DIGOPTS +multi dnskey . @10.53.0.1 > dig.out.ns1.test$n || ret=1
984grep '; key id = '"$id"'$' dig.out.ns1.test$n > /dev/null && ret=1
985n=$((n + 1))
986if [ $ret != 0 ]; then echo_i "failed"; fi
987status=$((status + ret))
988
989echo_i "checking that standby key does not sign records ($n)"
990ret=0
991id=$(keyfile_to_key_id "$(cat standby.key)")
992$DIG $DIGOPTS dnskey . @10.53.0.1 > dig.out.ns1.test$n || ret=1
993grep 'RRSIG.*'" $id "'\. ' dig.out.ns1.test$n > /dev/null && ret=1
994n=$((n + 1))
995if [ $ret != 0 ]; then echo_i "failed"; fi
996status=$((status + ret))
997
998echo_i "checking that deactivated key does not sign records  ($n)"
999ret=0
1000id=$(keyfile_to_key_id "$(cat inact.key)")
1001$DIG $DIGOPTS dnskey . @10.53.0.1 > dig.out.ns1.test$n || ret=1
1002grep 'RRSIG.*'" $id "'\. ' dig.out.ns1.test$n > /dev/null && ret=1
1003n=$((n + 1))
1004if [ $ret != 0 ]; then echo_i "failed"; fi
1005status=$((status + ret))
1006
1007echo_i "checking insertion of public-only key ($n)"
1008ret=0
1009id=$(keyfile_to_key_id "$(cat nopriv.key)")
1010file="ns1/$(cat nopriv.key).key"
1011keydata=$(grep DNSKEY $file)
1012$NSUPDATE > /dev/null 2>&1 <<END	|| status=1
1013server 10.53.0.1 ${PORT}
1014zone .
1015ttl 3600
1016update add $keydata
1017send
1018END
1019sleep 1
1020$DIG $DIGOPTS dnskey . @10.53.0.1 > dig.out.ns1.test$n || ret=1
1021grep 'RRSIG.*'" $id "'\. ' dig.out.ns1.test$n > /dev/null && ret=1
1022n=$((n + 1))
1023if [ $ret != 0 ]; then echo_i "failed"; fi
1024status=$((status + ret))
1025
1026echo_i "checking key deletion ($n)"
1027ret=0
1028id=$(keyfile_to_key_id "$(cat del.key)")
1029$DIG $DIGOPTS +multi dnskey . @10.53.0.1 > dig.out.ns1.test$n || ret=1
1030grep '; key id = '"$id"'$' dig.out.ns1.test$n > /dev/null && ret=1
1031n=$((n + 1))
1032if [ $ret != 0 ]; then echo_i "failed"; fi
1033status=$((status + ret))
1034
1035echo_i "checking secure-to-insecure transition, nsupdate ($n)"
1036ret=0
1037$NSUPDATE > /dev/null 2>&1 <<END	|| status=1
1038server 10.53.0.3 ${PORT}
1039zone secure-to-insecure.example
1040update delete secure-to-insecure.example dnskey
1041send
1042END
1043for i in 0 1 2 3 4 5 6 7 8 9; do
1044	ret=0
1045	$DIG $DIGOPTS axfr secure-to-insecure.example @10.53.0.3 > dig.out.ns3.test$n || ret=1
1046	grep -E '(RRSIG|DNSKEY|NSEC)' dig.out.ns3.test$n > /dev/null && ret=1
1047	[ $ret -eq 0 ] && break
1048	echo_i "waiting ... ($i)"
1049	sleep 2
1050done
1051n=$((n + 1))
1052if [ $ret != 0 ]; then echo_i "failed"; fi
1053status=$((status + ret))
1054
1055echo_i "checking secure-to-insecure transition, scheduled ($n)"
1056ret=0
1057file="ns3/$(cat del1.key).key"
1058$SETTIME -I now -D now $file > settime.out.test$n.1 || ret=1
1059file="ns3/$(cat del2.key).key"
1060$SETTIME -I now -D now $file > settime.out.test$n.2 || ret=1
1061($RNDCCMD 10.53.0.3 sign secure-to-insecure2.example. 2>&1 | sed 's/^/ns3 /' | cat_i) || ret=1
1062for i in 0 1 2 3 4 5 6 7 8 9; do
1063	ret=0
1064	$DIG $DIGOPTS axfr secure-to-insecure2.example @10.53.0.3 > dig.out.ns3.test$n || ret=1
1065	grep -E '(RRSIG|DNSKEY|NSEC3)' dig.out.ns3.test$n > /dev/null && ret=1
1066	[ $ret -eq 0 ] && break
1067	echo_i "waiting ... ($i)"
1068	sleep 2
1069done
1070n=$((n + 1))
1071if [ $ret != 0 ]; then echo_i "failed"; fi
1072status=$((status + ret))
1073
1074echo_i "checking jitter in a newly signed NSEC3 zone ($n)"
1075ret=0
1076# Use DNS UPDATE to add an NSEC3PARAM record into the zone.
1077$NSUPDATE > nsupdate.out.test$n 2>&1 <<END || ret=1
1078server 10.53.0.3 ${PORT}
1079zone jitter.nsec3.example.
1080update add jitter.nsec3.example. 3600 NSEC3PARAM 1 0 10 BEEF
1081send
1082END
1083[ $ret != 0 ] && echo_i "error: dynamic update add NSEC3PARAM failed"
1084# Create DNSSEC keys in the zone directory.
1085$KEYGEN -a $DEFAULT_ALGORITHM -3 -q -K ns3 jitter.nsec3.example > /dev/null
1086# Trigger zone signing.
1087($RNDCCMD 10.53.0.3 sign jitter.nsec3.example. 2>&1 | sed 's/^/ns3 /' | cat_i) || ret=1
1088# Wait until zone has been signed.
1089check_if_nsec3param_exists() {
1090	$DIG $DIGOPTS NSEC3PARAM jitter.nsec3.example @10.53.0.3 > dig.out.ns3.1.test$n || return 1
1091	grep -q "^jitter\.nsec3\.example\..*NSEC3PARAM" dig.out.ns3.1.test$n || return 1
1092}
1093retry_quiet 40 check_if_nsec3param_exists || {
1094	echo_i "error: NSEC3PARAM not present yet"
1095	ret=1
1096}
1097$DIG $DIGOPTS AXFR jitter.nsec3.example @10.53.0.3 > dig.out.ns3.2.test$n || ret=1
1098# Check jitter distribution.
1099checkjitter dig.out.ns3.2.test$n || ret=1
1100n=$((n + 1))
1101if [ $ret != 0 ]; then echo_i "failed"; fi
1102status=$((status + ret))
1103
1104echo_i "checking that serial number and RRSIGs are both updated (rt21045) ($n)"
1105ret=0
1106oldserial=$($DIG $DIGOPTS +short soa prepub.example @10.53.0.3 | awk '$0 !~ /SOA/ {print $3}')
1107oldinception=$($DIG $DIGOPTS +short soa prepub.example @10.53.0.3 | awk '/SOA/ {print $6}' | sort -u)
1108
1109$KEYGEN -a $DEFAULT_ALGORITHM -3 -q -K ns3 -P 0 -A +6d -I +38d -D +45d prepub.example > /dev/null
1110
1111($RNDCCMD 10.53.0.3 sign prepub.example 2>&1 | sed 's/^/ns1 /' | cat_i) || ret=1
1112newserial=$oldserial
1113try=0
1114while [ $oldserial -eq $newserial -a $try -lt 42 ]
1115do
1116	newserial=$($DIG $DIGOPTS +short soa prepub.example @10.53.0.3 |
1117		 awk '$0 !~ /SOA/ {print $3}')
1118	sleep 1
1119	try=$((try + 1))
1120done
1121newinception=$($DIG $DIGOPTS +short soa prepub.example @10.53.0.3 | awk '/SOA/ {print $6}' | sort -u)
1122#echo "$oldserial : $newserial"
1123#echo "$oldinception : $newinception"
1124
1125[ "$oldserial" = "$newserial" ] && ret=1
1126[ "$oldinception" = "$newinception" ] && ret=1
1127n=$((n + 1))
1128if [ $ret != 0 ]; then echo_i "failed"; fi
1129status=$((status + ret))
1130
1131echo_i "preparing to test key change corner cases"
1132echo_i "removing a private key file"
1133file="ns1/$(cat vanishing.key).private"
1134rm -f $file
1135
1136echo_i "preparing ZSK roll"
1137starttime=$($PERL -e 'print time(), "\n";')
1138oldfile=$(cat active.key)
1139oldid=$(keyfile_to_key_id "$(cat active.key)")
1140newfile=$(cat standby.key)
1141newid=$(keyfile_to_key_id "$(cat standby.key)")
1142$SETTIME -K ns1 -I now+2s -D now+25 $oldfile > settime.out.test$n.1 || ret=1
1143$SETTIME -K ns1 -i 0 -S $oldfile $newfile > settime.out.test$n.2 || ret=1
1144
1145# note previous zone serial number
1146oldserial=$($DIG $DIGOPTS +short soa . @10.53.0.1 | awk '{print $3}')
1147
1148($RNDCCMD 10.53.0.1 loadkeys . 2>&1 | sed 's/^/ns1 /' | cat_i) || ret=1
1149sleep 4
1150
1151echo_i "revoking key to duplicated key ID"
1152$SETTIME -R now -K ns2 Kbar.+013+59973.key > settime.out.test$n.3 || ret=1
1153
1154($RNDCCMD 10.53.0.2 loadkeys bar. 2>&1 | sed 's/^/ns2 /' | cat_i) || ret=1
1155
1156echo_i "waiting for changes to take effect"
1157sleep 5
1158
1159echo_i "checking former standby key $newid is now active ($n)"
1160ret=0
1161$DIG $DIGOPTS dnskey . @10.53.0.1 > dig.out.ns1.test$n || ret=1
1162grep 'RRSIG.*'" $newid "'\. ' dig.out.ns1.test$n > /dev/null || ret=1
1163n=$((n + 1))
1164if [ $ret != 0 ]; then echo_i "failed"; fi
1165status=$((status + ret))
1166
1167echo_i "checking former standby key has only signed incrementally ($n)"
1168ret=0
1169$DIG $DIGOPTS txt . @10.53.0.1 > dig.out.ns1.test$n || ret=1
1170grep 'RRSIG.*'" $newid "'\. ' dig.out.ns1.test$n > /dev/null && ret=1
1171grep 'RRSIG.*'" $oldid "'\. ' dig.out.ns1.test$n > /dev/null || ret=1
1172n=$((n + 1))
1173if [ $ret != 0 ]; then echo_i "failed"; fi
1174status=$((status + ret))
1175
1176echo_i "checking that signing records have been marked as complete ($n)"
1177ret=0
1178checkprivate . 10.53.0.1 || ret=1
1179checkprivate bar 10.53.0.2 || ret=1
1180checkprivate example 10.53.0.2 || ret=1
1181checkprivate private.secure.example 10.53.0.3 || ret=1
1182checkprivate nsec3.example 10.53.0.3 || ret=1
1183checkprivate nsec3.nsec3.example 10.53.0.3 || ret=1
1184checkprivate nsec3.optout.example 10.53.0.3 || ret=1
1185checkprivate nsec3-to-nsec.example 10.53.0.3 || ret=1
1186if $SHELL ../testcrypto.sh -q RSASHA1
1187then
1188    checkprivate nsec-only.example 10.53.0.3 || ret=1
1189fi
1190checkprivate oldsigs.example 10.53.0.3 || ret=1
1191checkprivate optout.example 10.53.0.3 || ret=1
1192checkprivate optout.nsec3.example 10.53.0.3 || ret=1
1193checkprivate optout.optout.example 10.53.0.3 || ret=1
1194checkprivate prepub.example 10.53.0.3 1 || ret=1
1195checkprivate rsasha256.example 10.53.0.3 || ret=1
1196checkprivate rsasha512.example 10.53.0.3 || ret=1
1197checkprivate secure.example 10.53.0.3 || ret=1
1198checkprivate secure.nsec3.example 10.53.0.3 || ret=1
1199checkprivate secure.optout.example 10.53.0.3 || ret=1
1200checkprivate secure-to-insecure2.example 10.53.0.3 || ret=1
1201checkprivate secure-to-insecure.example 10.53.0.3 || ret=1
1202checkprivate ttl1.example 10.53.0.3 || ret=1
1203checkprivate ttl2.example 10.53.0.3 || ret=1
1204checkprivate ttl3.example 10.53.0.3 || ret=1
1205checkprivate ttl4.example 10.53.0.3 || ret=1
1206n=$((n + 1))
1207status=$((status + ret))
1208
1209echo_i "forcing full sign"
1210($RNDCCMD 10.53.0.1 sign . 2>&1 | sed 's/^/ns1 /' | cat_i) || ret=1
1211
1212echo_i "waiting for change to take effect"
1213sleep 5
1214
1215echo_i "checking former standby key has now signed fully ($n)"
1216ret=0
1217$DIG $DIGOPTS txt . @10.53.0.1 > dig.out.ns1.test$n || ret=1
1218grep 'RRSIG.*'" $newid "'\. ' dig.out.ns1.test$n > /dev/null || ret=1
1219n=$((n + 1))
1220if [ $ret != 0 ]; then echo_i "failed"; fi
1221status=$((status + ret))
1222
1223echo_i "checking SOA serial number has been incremented ($n)"
1224ret=0
1225newserial=$($DIG $DIGOPTS +short soa . @10.53.0.1 | awk '{print $3}')
1226[ "$newserial" != "$oldserial" ] || ret=1
1227n=$((n + 1))
1228if [ $ret != 0 ]; then echo_i "failed"; fi
1229status=$((status + ret))
1230
1231echo_i "checking delayed key publication/activation ($n)"
1232ret=0
1233zsk=$(cat delayzsk.key)
1234ksk=$(cat delayksk.key)
1235# publication and activation times should be unset
1236$SETTIME -K ns3 -pA -pP $zsk > settime.out.test$n.zsk || ret=1
1237grep -v UNSET settime.out.test$n.zsk >/dev/null && ret=1
1238$SETTIME -K ns3 -pA -pP $ksk > settime.out.test$n.ksk || ret=1
1239grep -v UNSET settime.out.test$n.ksk >/dev/null && ret=1
1240$DIG $DIGOPTS +noall +answer dnskey delay.example. @10.53.0.3 > dig.out.ns3.test$n || ret=1
1241# DNSKEY not expected:
1242awk 'BEGIN {r=1} $4=="DNSKEY" {r=0} END {exit r}' dig.out.ns3.test$n && ret=1
1243n=$((n + 1))
1244if [ $ret != 0 ]; then echo_i "failed"; fi
1245status=$((status + ret))
1246
1247echo_i "checking scheduled key publication, not activation ($n)"
1248ret=0
1249# Ensure initial zone is loaded.
1250wait_for_notifies "delay.example" "ns3" || ret=1
1251$SETTIME -K ns3 -P now+3s -A none $zsk > settime.out.test$n.zsk || ret=1
1252$SETTIME -K ns3 -P now+3s -A none $ksk > settime.out.test$n.ksk || ret=1
1253($RNDCCMD 10.53.0.3 loadkeys delay.example. 2>&1 | sed 's/^/ns2 /' | cat_i) || ret=1
1254echo_i "waiting for changes to take effect"
1255sleep 3
1256wait_for_notifies "delay.example" "ns3" || ret=1
1257
1258$DIG $DIGOPTS +noall +answer dnskey delay.example. @10.53.0.3 > dig.out.ns3.test$n || ret=1
1259# DNSKEY expected:
1260awk 'BEGIN {r=1} $4=="DNSKEY" {r=0} END {exit r}' dig.out.ns3.test$n || ret=1
1261# RRSIG not expected:
1262awk 'BEGIN {r=1} $4=="RRSIG" {r=0} END {exit r}' dig.out.ns3.test$n && ret=1
1263n=$((n + 1))
1264if [ $ret != 0 ]; then echo_i "failed"; fi
1265status=$((status + ret))
1266
1267echo_i "checking scheduled key activation ($n)"
1268ret=0
1269$SETTIME -K ns3 -A now+3s $zsk > settime.out.test$n.zsk || ret=1
1270$SETTIME -K ns3 -A now+3s $ksk > settime.out.test$n.ksk || ret=1
1271($RNDCCMD 10.53.0.3 loadkeys delay.example. 2>&1 | sed 's/^/ns2 /' | cat_i) || ret=1
1272echo_i "waiting for changes to take effect"
1273sleep 3
1274wait_for_log 10 "add delay\.example\..*NSEC.a\.delay\.example\. NS SOA RRSIG NSEC DNSKEY" ns3/named.run
1275check_is_signed() {
1276  $DIG $DIGOPTS +noall +answer dnskey delay.example. @10.53.0.3 > dig.out.ns3.1.test$n || return 1
1277  # DNSKEY expected:
1278  awk 'BEGIN {r=1} $4=="DNSKEY" {r=0} END {exit r}' dig.out.ns3.1.test$n || return 1
1279  # RRSIG expected:
1280  awk 'BEGIN {r=1} $4=="RRSIG" {r=0} END {exit r}' dig.out.ns3.1.test$n || return 1
1281  $DIG $DIGOPTS +noall +answer a a.delay.example. @10.53.0.3 > dig.out.ns3.2.test$n || return 1
1282  # A expected:
1283  awk 'BEGIN {r=1} $4=="A" {r=0} END {exit r}' dig.out.ns3.2.test$n || return 1
1284  # RRSIG expected:
1285  awk 'BEGIN {r=1} $4=="RRSIG" {r=0} END {exit r}' dig.out.ns3.2.test$n || return 1
1286  return 0
1287}
1288retry_quiet 5 check_is_signed || ret=1
1289n=$((n + 1))
1290if [ $ret != 0 ]; then echo_i "failed"; fi
1291status=$((status + ret))
1292
1293echo_i "checking former active key was removed ($n)"
1294#
1295# Work out how long we need to sleep. Allow 4 seconds for the records
1296# to be removed.
1297#
1298now=$($PERL -e 'print time(), "\n";')
1299sleep=$((starttime + 29 - now))
1300case $sleep in
1301-*|0);;
1302*) echo_i "waiting for timer to have activated"; sleep $sleep;;
1303esac
1304ret=0
1305$DIG $DIGOPTS +multi dnskey . @10.53.0.1 > dig.out.ns1.test$n || ret=1
1306grep '; key id = '"$oldid"'$' dig.out.ns1.test$n > /dev/null && ret=1
1307n=$((n + 1))
1308if [ $ret != 0 ]; then echo_i "failed"; fi
1309status=$((status + ret))
1310
1311echo_i "checking private key file removal caused no immediate harm ($n)"
1312ret=0
1313id=$(keyfile_to_key_id "$(cat vanishing.key)")
1314$DIG $DIGOPTS dnskey . @10.53.0.1 > dig.out.ns1.test$n || ret=1
1315grep 'RRSIG.*'" $id "'\. ' dig.out.ns1.test$n > /dev/null || ret=1
1316n=$((n + 1))
1317if [ $ret != 0 ]; then echo_i "failed"; fi
1318status=$((status + ret))
1319
1320echo_i "checking revoked key with duplicate key ID ($n)"
1321ret=0
1322id=59973
1323rid=60101
1324$DIG $DIGOPTS +multi dnskey bar @10.53.0.2 > dig.out.ns2.test$n || ret=1
1325grep '; key id = '"$id"'$' dig.out.ns2.test$n > /dev/null && ret=1
1326keys=$(grep '; key id = '"$rid"'$' dig.out.ns2.test$n | wc -l)
1327test $keys -eq 2 || ret=1
1328$DIG $DIGOPTS dnskey bar @10.53.0.4 > dig.out.ns4.test$n || ret=1
1329grep "flags:.*ad.*QUERY" dig.out.ns4.test$n > /dev/null || ret=1
1330n=$((n + 1))
1331if [ $ret != 0 ]; then echo_i "failed"; fi
1332status=$((status + ret))
1333
1334echo_i "checking key event timers are always set ($n)"
1335ret=0
1336# this is a regression test for a bug in which the next key event could
1337# be scheduled for the present moment, and then never fire.  check for
1338# visible evidence of this error in the logs:
1339awk '/next key event/ {if ($1 == $8 && $2 == $9) exit 1}' */named.run || ret=1
1340n=$((n + 1))
1341if [ $ret != 0 ]; then echo_i "failed"; fi
1342status=$((status + ret))
1343
1344# this confirms that key events are never scheduled more than
1345# 'dnssec-loadkeys-interval' minutes in the future, and that the
1346# event scheduled is within 10 seconds of expected interval.
1347check_interval () {
1348        awk '/next key event/ {print $2 ":" $9}' $1/named.run |
1349	sed -e 's/\.//g' -e 's/:0\{1,4\}/:/g' |
1350            awk -F: '
1351                     {
1352                       x = ($6+ $5*60000 + $4*3600000) - ($3+ $2*60000 + $1*3600000);
1353		       # abs(x) < 1000 ms treat as 'now'
1354		       if (x < 1000 && x > -1000)
1355                         x = 0;
1356		       # convert to seconds
1357		       x = x/1000;
1358		       # handle end of day roll over
1359		       if (x < 0)
1360			 x = x + 24*3600;
1361		       # handle log timestamp being a few milliseconds later
1362                       if (x != int(x))
1363                         x = int(x + 1);
1364                       if (int(x) > int(interval))
1365                         exit (1);
1366                     }
1367                     END { if (int(x) > int(interval) || int(x) < int(interval-10)) exit(1) }' interval=$2
1368        return $?
1369}
1370
1371echo_i "checking automatic key reloading interval ($n)"
1372ret=0
1373check_interval ns1 3600 || ret=1
1374check_interval ns2 1800 || ret=1
1375check_interval ns3 600 || ret=1
1376n=$((n + 1))
1377if [ $ret != 0 ]; then echo_i "failed"; fi
1378status=$((status + ret))
1379
1380echo_i "checking for key reloading loops ($n)"
1381ret=0
1382# every key event should schedule a successor, so these should be equal
1383rekey_calls=$(grep "reconfiguring zone keys" ns*/named.run | wc -l)
1384rekey_events=$(grep "next key event" ns*/named.run | wc -l)
1385[ "$rekey_calls" = "$rekey_events" ] || ret=1
1386n=$((n + 1))
1387if [ $ret != 0 ]; then echo_i "failed"; fi
1388status=$((status + ret))
1389
1390echo_i "forcing full sign with unreadable keys ($n)"
1391ret=0
1392chmod 0 ns1/K.+*+*.key ns1/K.+*+*.private || ret=1
1393($RNDCCMD 10.53.0.1 sign . 2>&1 | sed 's/^/ns1 /' | cat_i) || ret=1
1394$DIG $DIGOPTS . @10.53.0.1 dnskey > dig.out.ns1.test$n || ret=1
1395grep "status: NOERROR" dig.out.ns1.test$n > /dev/null || ret=1
1396n=$((n + 1))
1397if [ $ret != 0 ]; then echo_i "failed"; fi
1398status=$((status + ret))
1399
1400echo_i "test turning on auto-dnssec during reconfig ($n)"
1401ret=0
1402# first create a zone that doesn't have auto-dnssec
1403($RNDCCMD 10.53.0.3 addzone reconf.example '{ type primary; file "reconf.example.db"; };' 2>&1 | sed 's/^/ns3 /' | cat_i) || ret=1
1404rekey_calls=$(grep "zone reconf.example.*next key event" ns3/named.run | wc -l)
1405[ "$rekey_calls" -eq 0 ] || ret=1
1406# ...then we add auto-dnssec and reconfigure
1407($RNDCCMD 10.53.0.3 modzone reconf.example '{ type primary; file "reconf.example.db"; allow-update { any; }; auto-dnssec maintain; };' 2>&1 | sed 's/^/ns3 /' | cat_i) || ret=1
1408rndc_reconfig ns3 10.53.0.3
1409for i in 0 1 2 3 4 5 6 7 8 9; do
1410    lret=0
1411    rekey_calls=$(grep "zone reconf.example.*next key event" ns3/named.run | wc -l)
1412    [ "$rekey_calls" -gt 0 ] || lret=1
1413    if [ "$lret" -eq 0 ]; then break; fi
1414    echo_i "waiting ... ($i)"
1415    sleep 1
1416done
1417n=$((n + 1))
1418if [ "$lret" != 0 ]; then ret=$lret; fi
1419if [ $ret != 0 ]; then echo_i "failed"; fi
1420status=$((status + ret))
1421
1422echo_i "test CDS and CDNSKEY auto generation ($n)"
1423ret=0
1424$DIG $DIGOPTS @10.53.0.3 sync.example cds > dig.out.ns3.cdstest$n
1425$DIG $DIGOPTS @10.53.0.3 sync.example cdnskey > dig.out.ns3.cdnskeytest$n
1426grep -i "sync.example.*in.cds.*[1-9][0-9]* " dig.out.ns3.cdstest$n > /dev/null || ret=1
1427grep -i "sync.example.*in.cdnskey.*257 " dig.out.ns3.cdnskeytest$n > /dev/null || ret=1
1428n=$((n + 1))
1429if [ $ret != 0 ]; then echo_i "failed"; fi
1430status=$((status + ret))
1431
1432echo_i "test 'dnssec-dnskey-kskonly no' affects DNSKEY/CDS/CDNSKEY ($n)"
1433ret=0
1434$DIG $DIGOPTS @10.53.0.3 sync.example dnskey > dig.out.ns3.dnskeytest$n
1435$DIG $DIGOPTS @10.53.0.3 sync.example cdnskey > dig.out.ns3.cdnskeytest$n
1436$DIG $DIGOPTS @10.53.0.3 sync.example cds > dig.out.ns3.cdstest$n
1437lines=$(awk '$4 == "RRSIG" && $5 == "DNSKEY" {print}' dig.out.ns3.dnskeytest$n | wc -l)
1438test ${lines:-0} -eq 2 || ret=1
1439lines=$(awk '$4 == "RRSIG" && $5 == "CDNSKEY" {print}' dig.out.ns3.cdnskeytest$n | wc -l)
1440test ${lines:-0} -eq 2 || ret=1
1441lines=$(awk '$4 == "RRSIG" && $5 == "CDS" {print}' dig.out.ns3.cdstest$n | wc -l)
1442test ${lines:-0} -eq 2 || ret=1
1443n=$((n + 1))
1444if [ $ret != 0 ]; then echo_i "failed"; fi
1445status=$((status + ret))
1446
1447echo_i "test 'dnssec-dnskey-kskonly yes' affects DNSKEY/CDS/CDNSKEY ($n)"
1448ret=0
1449$DIG $DIGOPTS @10.53.0.3 kskonly.example dnskey > dig.out.ns3.dnskeytest$n
1450$DIG $DIGOPTS @10.53.0.3 kskonly.example cdnskey > dig.out.ns3.cdnskeytest$n
1451$DIG $DIGOPTS @10.53.0.3 kskonly.example cds > dig.out.ns3.cdstest$n
1452lines=$(awk '$4 == "RRSIG" && $5 == "DNSKEY" {print}' dig.out.ns3.dnskeytest$n | wc -l)
1453test ${lines:-0} -eq 1 || ret=1
1454lines=$(awk '$4 == "RRSIG" && $5 == "CDNSKEY" {print}' dig.out.ns3.cdnskeytest$n | wc -l)
1455test ${lines:-0} -eq 1 || ret=1
1456lines=$(awk '$4 == "RRSIG" && $5 == "CDS" {print}' dig.out.ns3.cdstest$n | wc -l)
1457test ${lines:-0} -eq 1 || ret=1
1458n=$((n + 1))
1459if [ $ret != 0 ]; then echo_i "failed"; fi
1460status=$((status + ret))
1461
1462echo_i "setting CDS and CDNSKEY deletion times and calling 'rndc loadkeys'"
1463$SETTIME -D sync now $(cat sync.key) > settime.out.test$n || ret=1
1464($RNDCCMD 10.53.0.3 loadkeys sync.example | sed 's/^/ns3 /' | cat_i) || ret=1
1465
1466echo_i "checking that the CDS and CDNSKEY are deleted ($n)"
1467ret=0
1468ensure_cds_and_cdnskey_are_deleted() {
1469	$DIG $DIGOPTS @10.53.0.3 sync.example. CDS > dig.out.ns3.cdstest$n || return 1
1470	awk '$1 == "sync.example." && $4 == "CDS" { exit 1; }' dig.out.ns3.cdstest$n || return 1
1471	$DIG $DIGOPTS @10.53.0.3 sync.example. CDNSKEY > dig.out.ns3.cdnskeytest$n || return 1
1472	awk '$1 == "sync.example." && $4 == "CDNSKEY" { exit 1; }' dig.out.ns3.cdnskeytest$n || return 1
1473}
1474retry 10 ensure_cds_and_cdnskey_are_deleted || ret=1
1475n=$((n + 1))
1476if [ $ret != 0 ]; then echo_i "failed"; fi
1477status=$((status + ret))
1478
1479echo_i "check that dnssec-settime -p Dsync works ($n)"
1480ret=0
1481$SETTIME -p Dsync $(cat sync.key) > settime.out.test$n || ret=1
1482grep "SYNC Delete:" settime.out.test$n >/dev/null || ret=1
1483n=$((n + 1))
1484if [ $ret != 0 ]; then echo_i "failed"; fi
1485status=$((status + ret))
1486
1487echo_i "check that dnssec-settime -p Psync works ($n)"
1488ret=0
1489$SETTIME -p Psync $(cat sync.key) > settime.out.test$n || ret=1
1490grep "SYNC Publish:" settime.out.test$n >/dev/null || ret=1
1491n=$((n + 1))
1492if [ $ret != 0 ]; then echo_i "failed"; fi
1493status=$((status + ret))
1494
1495echo_i "check that zone with inactive KSK and active ZSK is properly autosigned ($n)"
1496ret=0
1497$DIG $DIGOPTS @10.53.0.3 axfr inacksk2.example > dig.out.ns3.test$n
1498
1499zskid=$(awk '$4 == "DNSKEY" && $5 == 256 { print }' dig.out.ns3.test$n |
1500       $DSFROMKEY -A -2 -f - inacksk2.example | awk '{ print $4}' )
1501pattern="DNSKEY ${DEFAULT_ALGORITHM_NUMBER} 2 [0-9]* [0-9]* [0-9]* ${zskid} "
1502grep "${pattern}" dig.out.ns3.test$n > /dev/null || ret=1
1503
1504kskid=$(awk '$4 == "DNSKEY" && $5 == 257 { print }' dig.out.ns3.test$n |
1505       $DSFROMKEY -2 -f - inacksk2.example | awk '{ print $4}' )
1506pattern="DNSKEY ${DEFAULT_ALGORITHM_NUMBER} 2 [0-9]* [0-9]* [0-9]* ${kskid} "
1507grep "${pattern}" dig.out.ns3.test$n > /dev/null && ret=1
1508
1509n=$((n + 1))
1510if [ $ret != 0 ]; then echo_i "failed"; fi
1511status=$((status + ret))
1512
1513echo_i "check that zone with inactive ZSK and active KSK is properly autosigned ($n)"
1514ret=0
1515$DIG $DIGOPTS @10.53.0.3 axfr inaczsk2.example > dig.out.ns3.test$n
1516grep "SOA ${DEFAULT_ALGORITHM_NUMBER} 2" dig.out.ns3.test$n > /dev/null || ret=1
1517n=$((n + 1))
1518if [ $ret != 0 ]; then echo_i "failed"; fi
1519status=$((status + ret))
1520
1521#
1522# Check that DNSKEY is now signed with the ZSK.
1523#
1524echo_i "check that zone with active and inactive KSK and active ZSK is properly"
1525echo_ic "resigned after the active KSK is deleted - stage 2: Verify that DNSKEY"
1526echo_ic "is now signed with the ZSK. ($n)"
1527ret=0
1528
1529$DIG $DIGOPTS @10.53.0.3 axfr inacksk3.example > dig.out.ns3.test$n
1530
1531zskid=$(awk '$4 == "DNSKEY" && $5 == 256 { print }' dig.out.ns3.test$n |
1532       $DSFROMKEY -A -2 -f - inacksk3.example | awk '{ print $4}' )
1533pattern="DNSKEY ${DEFAULT_ALGORITHM_NUMBER} 2 [0-9]* [0-9]* [0-9]* ${zskid} "
1534grep "${pattern}" dig.out.ns3.test$n > /dev/null || ret=1
1535
1536count=$(awk 'BEGIN { count = 0 }
1537       $4 == "RRSIG" && $5 == "DNSKEY" { count++ }
1538       END {print count}' dig.out.ns3.test$n)
1539test $count -eq 1 || ret=1
1540
1541count=$(awk 'BEGIN { count = 0 }
1542       $4 == "DNSKEY" { count++ }
1543       END {print count}' dig.out.ns3.test$n)
1544test $count -eq 2 || ret=1
1545
1546n=$((n + 1))
1547if [ $ret != 0 ]; then echo_i "failed"; fi
1548status=$((status + ret))
1549
1550#
1551# Check that zone is now signed with the KSK.
1552#
1553echo_i "check that zone with active and inactive ZSK and active KSK is properly"
1554echo_ic "resigned after the active ZSK is deleted - stage 2: Verify that zone"
1555echo_ic "is now signed with the KSK. ($n)"
1556ret=0
1557$DIG $DIGOPTS @10.53.0.3 axfr inaczsk3.example > dig.out.ns3.test$n
1558kskid=$(awk '$4 == "DNSKEY" && $5 == 257 { print }' dig.out.ns3.test$n |
1559       $DSFROMKEY -2 -f - inaczsk3.example | awk '{ print $4}' )
1560grep "CNAME ${DEFAULT_ALGORITHM_NUMBER} 3 [0-9]* [0-9]* [0-9]* ${kskid} " dig.out.ns3.test$n > /dev/null || ret=1
1561count=$(awk 'BEGIN { count = 0 }
1562       $4 == "RRSIG" && $5 == "CNAME" { count++ }
1563       END {print count}' dig.out.ns3.test$n)
1564test $count -eq 1 || ret=1
1565count=$(awk 'BEGIN { count = 0 }
1566       $4 == "DNSKEY" { count++ }
1567       END {print count}' dig.out.ns3.test$n)
1568test $count -eq 2 || ret=1
1569n=$((n + 1))
1570if [ $ret != 0 ]; then echo_i "failed"; fi
1571status=$((status + ret))
1572
1573echo_i "checking for out-of-zone NSEC3 records after ZSK removal ($n)"
1574ret=0
1575# Switch the zone over to NSEC3 and wait until the transition is complete.
1576$RNDCCMD 10.53.0.3 signing -nsec3param 1 1 10 12345678 delzsk.example. > signing.out.1.test$n 2>&1 || ret=1
1577for i in 0 1 2 3 4 5 6 7 8 9; do
1578	_ret=1
1579	$DIG $DIGOPTS delzsk.example NSEC3PARAM @10.53.0.3 > dig.out.ns3.1.test$n 2>&1 || ret=1
1580	grep "NSEC3PARAM.*12345678" dig.out.ns3.1.test$n > /dev/null 2>&1
1581	if [ $? -eq 0 ]; then
1582		$RNDCCMD 10.53.0.3 signing -list delzsk.example > signing.out.2.test$n 2>&1
1583		grep "Creating NSEC3 chain " signing.out.2.test$n > /dev/null 2>&1
1584		if [ $? -ne 0 ]; then
1585			_ret=0
1586			break
1587		fi
1588	fi
1589	sleep 1
1590done
1591if [ $_ret -ne 0 ]; then
1592	echo_i "timed out waiting for NSEC3 chain creation"
1593	ret=1
1594fi
1595# Mark the inactive ZSK as pending removal.
1596file="ns3/$(cat delzsk.key).key"
1597$SETTIME -D now-1h $file > settime.out.test$n || ret=1
1598# Trigger removal of the inactive ZSK and wait until its completion.
1599($RNDCCMD 10.53.0.3 loadkeys delzsk.example 2>&1 | sed 's/^/ns3 /' | cat_i) || ret=1
1600for i in 0 1 2 3 4 5 6 7 8 9; do
1601	_ret=1
1602	$RNDCCMD 10.53.0.3 signing -list delzsk.example > signing.out.3.test$n 2>&1
1603	grep "Signing " signing.out.3.test$n > /dev/null 2>&1
1604	if [ $? -ne 0 ]; then
1605		if [ $(grep "Done signing " signing.out.3.test$n | wc -l) -eq 2 ]; then
1606			_ret=0
1607			break
1608		fi
1609	fi
1610	sleep 1
1611done
1612if [ $_ret -ne 0 ]; then
1613	echo_i "timed out waiting for key removal"
1614	ret=1
1615fi
1616# Check whether key removal caused NSEC3 records to be erroneously created for
1617# glue records due to a secure delegation already being signed by the active key
1618# (i.e. a key other than the one being removed but using the same algorithm).
1619#
1620# For reference:
1621#
1622#     $ nsec3hash 12345678 1 10 ns.sub.delzsk.example.
1623#     589R358VSPJUFVAJU949JPVF74D9PTGH (salt=12345678, hash=1, iterations=10)
1624#
1625$DIG $DIGOPTS delzsk.example AXFR @10.53.0.3 > dig.out.ns3.3.test$n || ret=1
1626grep "589R358VSPJUFVAJU949JPVF74D9PTGH" dig.out.ns3.3.test$n > /dev/null 2>&1 && ret=1
1627n=$((n + 1))
1628if [ $ret != 0 ]; then echo_i "failed"; fi
1629status=$((status + ret))
1630
1631echo_i "check that DNAME at apex with NSEC3 is correctly signed (auto-dnssec maintain) ($n)"
1632ret=0
1633$DIG $DIGOPTS txt dname-at-apex-nsec3.example @10.53.0.3 > dig.out.ns3.test$n || ret=1
1634grep "RRSIG NSEC3 ${DEFAULT_ALGORITHM_NUMBER} 3 600" dig.out.ns3.test$n > /dev/null || ret=1
1635n=$((n + 1))
1636if [ $ret != 0 ]; then echo_i "failed"; fi
1637status=$((status + ret))
1638
1639echo_i "checking that DNAME is not treated as a delegation when signing ($n)"
1640ret=0
1641$DIG $DIGOPTS dname-and-txt.secure.example. DNAME @10.53.0.3 > dig.out.ns3.1.test$n || ret=1
1642grep "dname-and-txt.secure.example.*RRSIG.*DNAME" dig.out.ns3.1.test$n > /dev/null 2>&1 || ret=1
1643$DIG $DIGOPTS dname-and-txt.secure.example. TXT @10.53.0.3 > dig.out.ns3.2.test$n || ret=1
1644grep "dname-and-txt.secure.example.*RRSIG.*TXT" dig.out.ns3.2.test$n > /dev/null 2>&1 || ret=1
1645n=$((n + 1))
1646if [ $ret != 0 ]; then echo_i "failed"; fi
1647status=$((status + ret))
1648
1649echo_i "checking key maintenance events were logged correctly ($n)"
1650ret=0
1651pub=$(grep "DNSKEY .* is now published" ns1/named.run | wc -l)
1652[ "$pub" -eq 6 ] || ret=1
1653act=$(grep "DNSKEY .* is now active" ns1/named.run | wc -l)
1654[ "$act" -eq 5 ] || ret=1
1655rev=$(grep "DNSKEY .* is now revoked" ns1/named.run | wc -l)
1656[ "$rev" -eq 1 ] || ret=1
1657inac=$(grep "DNSKEY .* is now inactive" ns1/named.run | wc -l)
1658[ "$inac" -eq 1 ] || ret=1
1659del=$(grep "DNSKEY .* is now deleted" ns1/named.run | wc -l)
1660[ "$del" -eq 1 ] || ret=1
1661n=$((n + 1))
1662if [ $ret != 0 ]; then echo_i "failed"; fi
1663status=$((status + ret))
1664
1665echo_i "checking that CDS (DELETE) persists after zone sign ($n)"
1666echo_i "update add cds-delete.example. CDS 0 0 00"
1667ret=0
1668$NSUPDATE > nsupdate.out 2>&1 <<END
1669server 10.53.0.3 ${PORT}
1670zone cds-delete.example.
1671update add cds-delete.example. 3600 CDS 0 0 0 00
1672send
1673END
1674
1675_cds_delete() (
1676	$DIG $DIGOPTS +noall +answer $1 cds @10.53.0.3 > dig.out.ns3.test$n || return 1
1677	grep "CDS.*0.*0.*0.*00" dig.out.ns3.test$n > /dev/null 2>&1 || return 1
1678	return 0
1679)
1680_cdnskey_delete_nx() {
1681	$DIG $DIGOPTS +noall +answer $1 cdnskey @10.53.0.3 > dig.out.ns3.test$n || return 1
1682	grep "CDNSKEY.*0.*3.*0.*AA==" dig.out.ns3.test$n > /dev/null 2>&1 && return 1
1683	return 0
1684}
1685
1686echo_i "query cds-delete.example. CDS"
1687retry_quiet 10 _cds_delete cds-delete.example. || ret=1
1688echo_i "query cds-delete.example. CDNSKEY"
1689retry_quiet 1 _cdnskey_delete_nx cds-delete.example. || ret=1
1690
1691echo_i "sign cds-delete.example."
1692nextpart ns3/named.run >/dev/null
1693$RNDCCMD 10.53.0.3 sign cds-delete.example > /dev/null 2>&1 || ret=1
1694wait_for_log 10 "zone cds-delete.example/IN: next key event" ns3/named.run
1695# The CDS (DELETE) record should still be here.
1696echo_i "query cds-delete.example. CDS"
1697retry_quiet 1 _cds_delete cds-delete.example. || ret=1
1698# The CDNSKEY (DELETE) record should still not be added.
1699echo_i "query cds-delete.example. CDNSKEY"
1700retry_quiet 1 _cdnskey_delete_nx cds-delete.example. || ret=1
1701
1702n=$((n + 1))
1703if [ $ret != 0 ]; then echo_i "failed"; fi
1704status=$((status + ret))
1705
1706echo_i "checking that CDNSKEY (DELETE) persists after zone sign ($n)"
1707echo_i "update add cdnskey-delete.example. CDNSKEY 0 3 0 AA=="
1708ret=0
1709$NSUPDATE > nsupdate.out 2>&1 <<END
1710server 10.53.0.3 ${PORT}
1711zone cdnskey-delete.example.
1712update add cdnskey-delete.example. 3600 CDNSKEY 0 3 0 AA==
1713send
1714END
1715
1716_cds_delete_nx() (
1717	$DIG $DIGOPTS +noall +answer $1 cds @10.53.0.3 > dig.out.ns3.test$n || return 1
1718	grep "CDS.*0.*0.*0.*00" dig.out.ns3.test$n > /dev/null 2>&1 && return 1
1719	return 0
1720)
1721_cdnskey_delete() {
1722	$DIG $DIGOPTS +noall +answer $1 cdnskey @10.53.0.3 > dig.out.ns3.test$n || return 1
1723	grep "CDNSKEY.*0.*3.*0.*AA==" dig.out.ns3.test$n > /dev/null 2>&1 || return 1
1724	return 0
1725}
1726
1727echo_i "query cdnskey-delete.example. CDNSKEY"
1728retry_quiet 10 _cdnskey_delete cdnskey-delete.example. || ret=1
1729echo_i "query cdnskey-delete.example. CDS"
1730retry_quiet 1 _cds_delete_nx cdnskey-delete.example. || ret=1
1731
1732echo_i "sign cdsnskey-delete.example."
1733nextpart ns3/named.run >/dev/null
1734$RNDCCMD 10.53.0.3 sign cdnskey-delete.example > /dev/null 2>&1 || ret=1
1735wait_for_log 10 "zone cdnskey-delete.example/IN: next key event" ns3/named.run
1736# The CDNSKEY (DELETE) record should still be here.
1737echo_i "query cdnskey-delete.example. CDNSKEY"
1738retry_quiet 1 _cdnskey_delete cdnskey-delete.example. || ret=1
1739# The CDS (DELETE) record should still not be added.
1740echo_i "query cdnskey-delete.example. CDS"
1741retry_quiet 1 _cds_delete_nx cdnskey-delete.example. || ret=1
1742
1743n=$((n + 1))
1744if [ $ret != 0 ]; then echo_i "failed"; fi
1745status=$((status + ret))
1746
1747echo_i "check removal of ENT NSEC3 records when opt out delegations are removed ($n)"
1748ret=0
1749zone=optout-with-ent
1750hash=JTR8R6AVFULU0DQH9I6HNN2KUK5956EL
1751# check that NSEC3 for ENT is present
1752$DIG $DIGOPTS @10.53.0.2 a "ent.${zone}" > dig.out.pre.ns2.test$n
1753grep "status: NOERROR" dig.out.pre.ns2.test$n >/dev/null || ret=1
1754grep "ANSWER: 0, AUTHORITY: 4, " dig.out.pre.ns2.test$n > /dev/null || ret=1
1755grep "^${hash}.${zone}." dig.out.pre.ns2.test$n > /dev/null || ret=1
1756# remove first delegation of two delegations, NSEC3 for ENT should remain.
1757(
1758echo zone $zone
1759echo server 10.53.0.2 "$PORT"
1760echo update del sub1.ent.$zone NS
1761echo send
1762) | $NSUPDATE
1763# check that NSEC3 for ENT is still present
1764$DIG $DIGOPTS @10.53.0.2 a "ent.${zone}" > dig.out.pre.ns2.test$n
1765$DIG $DIGOPTS @10.53.0.2 a "ent.${zone}" > dig.out.mid.ns2.test$n
1766grep "status: NOERROR" dig.out.mid.ns2.test$n >/dev/null || ret=1
1767grep "ANSWER: 0, AUTHORITY: 4, " dig.out.mid.ns2.test$n > /dev/null || ret=1
1768grep "^${hash}.${zone}." dig.out.mid.ns2.test$n > /dev/null || ret=1
1769# remove second delegation of two delegations, NSEC3 for ENT should be deleted.
1770(
1771echo zone $zone
1772echo server 10.53.0.2 "$PORT"
1773echo update del sub2.ent.$zone NS
1774echo send
1775) | $NSUPDATE
1776# check that NSEC3 for ENT is gone present
1777$DIG $DIGOPTS @10.53.0.2 a "ent.${zone}" > dig.out.post.ns2.test$n
1778grep "status: NXDOMAIN" dig.out.post.ns2.test$n >/dev/null || ret=1
1779grep "ANSWER: 0, AUTHORITY: 4, " dig.out.post.ns2.test$n > /dev/null || ret=1
1780grep "^${hash}.${zone}." dig.out.post.ns2.test$n > /dev/null && ret=1
1781$DIG $DIGOPTS @10.53.0.2 axfr "${zone}" > dig.out.axfr.ns2.test$n
1782grep "^${hash}.${zone}." dig.out.axfr.ns2.test$n > /dev/null && ret=1
1783n=$((n+1))
1784if [ "$ret" -ne 0 ]; then echo_i "failed"; fi
1785status=$((status+ret))
1786
1787echo_i "exit status: $status"
1788[ $status -eq 0 ] || exit 1
1789