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