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