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