summaryrefslogtreecommitdiffstats
path: root/bin/tests/system/dnssec
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 15:59:48 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 15:59:48 +0000
commit3b9b6d0b8e7f798023c9d109c490449d528fde80 (patch)
tree2e1c188dd7b8d7475cd163de9ae02c428343669b /bin/tests/system/dnssec
parentInitial commit. (diff)
downloadbind9-3b9b6d0b8e7f798023c9d109c490449d528fde80.tar.xz
bind9-3b9b6d0b8e7f798023c9d109c490449d528fde80.zip
Adding upstream version 1:9.18.19.upstream/1%9.18.19upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'bin/tests/system/dnssec')
-rw-r--r--bin/tests/system/dnssec/README32
-rw-r--r--bin/tests/system/dnssec/ans10/ans.py158
-rw-r--r--bin/tests/system/dnssec/clean.sh117
-rw-r--r--bin/tests/system/dnssec/dnssec_update_test.pl99
-rw-r--r--bin/tests/system/dnssec/ns1/named.conf.in36
-rw-r--r--bin/tests/system/dnssec/ns1/root.db.in37
-rw-r--r--bin/tests/system/dnssec/ns1/sign.sh62
-rw-r--r--bin/tests/system/dnssec/ns2/algroll.db.in26
-rw-r--r--bin/tests/system/dnssec/ns2/badparam.db.in21
-rw-r--r--bin/tests/system/dnssec/ns2/cdnskey-auto.secure.db.in14
-rw-r--r--bin/tests/system/dnssec/ns2/cdnskey-kskonly.secure.db.in14
-rw-r--r--bin/tests/system/dnssec/ns2/cdnskey-update.secure.db.in14
-rw-r--r--bin/tests/system/dnssec/ns2/cdnskey.secure.db.in14
-rw-r--r--bin/tests/system/dnssec/ns2/cds-auto.secure.db.in14
-rw-r--r--bin/tests/system/dnssec/ns2/cds-kskonly.secure.db.in14
-rw-r--r--bin/tests/system/dnssec/ns2/cds-update.secure.db.in14
-rw-r--r--bin/tests/system/dnssec/ns2/cds.secure.db.in14
-rw-r--r--bin/tests/system/dnssec/ns2/child.nsec3.example.db20
-rw-r--r--bin/tests/system/dnssec/ns2/child.optout.example.db20
-rw-r--r--bin/tests/system/dnssec/ns2/corp.db23
-rw-r--r--bin/tests/system/dnssec/ns2/dst.example.db.in21
-rw-r--r--bin/tests/system/dnssec/ns2/example.db.in171
-rw-r--r--bin/tests/system/dnssec/ns2/hours-vs-days.db.in167
-rw-r--r--bin/tests/system/dnssec/ns2/in-addr.arpa.db.in19
-rw-r--r--bin/tests/system/dnssec/ns2/insecure.secure.example.db26
-rw-r--r--bin/tests/system/dnssec/ns2/key.db.in45
-rw-r--r--bin/tests/system/dnssec/ns2/named.conf.in205
-rw-r--r--bin/tests/system/dnssec/ns2/private.secure.example.db.in28
-rw-r--r--bin/tests/system/dnssec/ns2/rfc2335.example.db114
-rw-r--r--bin/tests/system/dnssec/ns2/sign.sh332
-rw-r--r--bin/tests/system/dnssec/ns2/single-nsec3.db.in21
-rw-r--r--bin/tests/system/dnssec/ns2/template.secure.db.in14
-rw-r--r--bin/tests/system/dnssec/ns2/too-many-iterations.db.in27
-rw-r--r--bin/tests/system/dnssec/ns3/auto-nsec.example.db.in40
-rw-r--r--bin/tests/system/dnssec/ns3/auto-nsec3.example.db.in40
-rw-r--r--bin/tests/system/dnssec/ns3/bogus.example.db.in27
-rw-r--r--bin/tests/system/dnssec/ns3/dname-at-apex-nsec3.example.db.in15
-rw-r--r--bin/tests/system/dnssec/ns3/dnskey-nsec3-unknown.example.db.in29
-rw-r--r--bin/tests/system/dnssec/ns3/dnskey-unknown.example.db.in29
-rw-r--r--bin/tests/system/dnssec/ns3/dnskey-unsupported-2.example.db.in29
-rw-r--r--bin/tests/system/dnssec/ns3/dnskey-unsupported.example.db.in29
-rw-r--r--bin/tests/system/dnssec/ns3/dynamic.example.db.in25
-rw-r--r--bin/tests/system/dnssec/ns3/expired.example.db.in44
-rw-r--r--bin/tests/system/dnssec/ns3/expiring.example.db.in40
-rw-r--r--bin/tests/system/dnssec/ns3/future.example.db.in40
-rw-r--r--bin/tests/system/dnssec/ns3/generic.example.db.in23
-rw-r--r--bin/tests/system/dnssec/ns3/inline.example.db26
-rw-r--r--bin/tests/system/dnssec/ns3/insecure.below-cname.example.db26
-rw-r--r--bin/tests/system/dnssec/ns3/insecure.example.db27
-rw-r--r--bin/tests/system/dnssec/ns3/insecure.nsec3.example.db26
-rw-r--r--bin/tests/system/dnssec/ns3/insecure.optout.example.db26
-rw-r--r--bin/tests/system/dnssec/ns3/insecure2.example.db27
-rw-r--r--bin/tests/system/dnssec/ns3/key.db.in26
-rw-r--r--bin/tests/system/dnssec/ns3/kskonly.example.db.in26
-rw-r--r--bin/tests/system/dnssec/ns3/lower.example.db.in21
-rw-r--r--bin/tests/system/dnssec/ns3/managed-future.example.db.in40
-rw-r--r--bin/tests/system/dnssec/ns3/multiple.example.db.in29
-rw-r--r--bin/tests/system/dnssec/ns3/named.conf.in383
-rw-r--r--bin/tests/system/dnssec/ns3/nosign.example.db.in23
-rw-r--r--bin/tests/system/dnssec/ns3/nsec3-unknown.example.db.in29
-rw-r--r--bin/tests/system/dnssec/ns3/nsec3.example.db.in38
-rw-r--r--bin/tests/system/dnssec/ns3/nsec3.nsec3.example.db.in35
-rw-r--r--bin/tests/system/dnssec/ns3/nsec3.optout.example.db.in35
-rw-r--r--bin/tests/system/dnssec/ns3/occluded.example.db.in26
-rw-r--r--bin/tests/system/dnssec/ns3/optout-unknown.example.db.in29
-rw-r--r--bin/tests/system/dnssec/ns3/optout.example.db.in40
-rw-r--r--bin/tests/system/dnssec/ns3/optout.nsec3.example.db.in35
-rw-r--r--bin/tests/system/dnssec/ns3/optout.optout.example.db.in35
-rw-r--r--bin/tests/system/dnssec/ns3/publish-inactive.example.db.in26
-rw-r--r--bin/tests/system/dnssec/ns3/rsasha256.example.db.in28
-rw-r--r--bin/tests/system/dnssec/ns3/rsasha512.example.db.in28
-rw-r--r--bin/tests/system/dnssec/ns3/secure.below-cname.example.db.in26
-rw-r--r--bin/tests/system/dnssec/ns3/secure.example.db.in49
-rw-r--r--bin/tests/system/dnssec/ns3/secure.nsec3.example.db.in35
-rw-r--r--bin/tests/system/dnssec/ns3/secure.optout.example.db.in35
-rw-r--r--bin/tests/system/dnssec/ns3/siginterval.example.db.in21
-rw-r--r--bin/tests/system/dnssec/ns3/siginterval1.conf21
-rw-r--r--bin/tests/system/dnssec/ns3/siginterval2.conf21
-rw-r--r--bin/tests/system/dnssec/ns3/sign.sh674
-rw-r--r--bin/tests/system/dnssec/ns3/split-dnssec.example.db.in38
-rw-r--r--bin/tests/system/dnssec/ns3/split-smart.example.db.in38
-rw-r--r--bin/tests/system/dnssec/ns3/ttlpatch.example.db.in26
-rw-r--r--bin/tests/system/dnssec/ns3/unsupported-algorithm.key1
-rw-r--r--bin/tests/system/dnssec/ns3/update-nsec3.example.db.in40
-rw-r--r--bin/tests/system/dnssec/ns3/upper.example.db.in21
-rw-r--r--bin/tests/system/dnssec/ns4/managed-keys.bind.in21
-rw-r--r--bin/tests/system/dnssec/ns4/named1.conf.in61
-rw-r--r--bin/tests/system/dnssec/ns4/named2.conf.in42
-rw-r--r--bin/tests/system/dnssec/ns4/named3.conf.in43
-rw-r--r--bin/tests/system/dnssec/ns4/named4.conf.in78
-rw-r--r--bin/tests/system/dnssec/ns4/named5.conf.in40
-rw-r--r--bin/tests/system/dnssec/ns5/named1.conf.in43
-rw-r--r--bin/tests/system/dnssec/ns5/named2.conf.in53
-rw-r--r--bin/tests/system/dnssec/ns5/sign.sh39
-rw-r--r--bin/tests/system/dnssec/ns6/named.args1
-rw-r--r--bin/tests/system/dnssec/ns6/named.conf.in40
-rw-r--r--bin/tests/system/dnssec/ns6/optout-tld.db.in22
-rw-r--r--bin/tests/system/dnssec/ns6/sign.sh29
-rw-r--r--bin/tests/system/dnssec/ns7/named.conf.in76
-rw-r--r--bin/tests/system/dnssec/ns7/named.nosoa12
-rw-r--r--bin/tests/system/dnssec/ns7/nosoa.secure.example.db22
-rw-r--r--bin/tests/system/dnssec/ns7/sign.sh44
-rw-r--r--bin/tests/system/dnssec/ns7/split-rrsig.db.in21
-rw-r--r--bin/tests/system/dnssec/ns8/named.conf.in47
-rw-r--r--bin/tests/system/dnssec/ns9/named.conf.in39
-rwxr-xr-xbin/tests/system/dnssec/ntadiff.pl24
-rw-r--r--bin/tests/system/dnssec/setup.sh52
-rw-r--r--bin/tests/system/dnssec/signer/example.db.in17
-rw-r--r--bin/tests/system/dnssec/signer/general/Kexample.com.+008+15002.key5
-rw-r--r--bin/tests/system/dnssec/signer/general/Kexample.com.+008+15002.private13
-rw-r--r--bin/tests/system/dnssec/signer/general/Kexample.com.+008+63613.key5
-rw-r--r--bin/tests/system/dnssec/signer/general/Kexample.com.+008+63613.private13
-rw-r--r--bin/tests/system/dnssec/signer/general/Kexample.com.+010+18240.key5
-rw-r--r--bin/tests/system/dnssec/signer/general/Kexample.com.+010+18240.private13
-rw-r--r--bin/tests/system/dnssec/signer/general/Kexample.com.+010+28633.key5
-rw-r--r--bin/tests/system/dnssec/signer/general/Kexample.com.+010+28633.private13
-rw-r--r--bin/tests/system/dnssec/signer/general/bogus-ksk.key6
-rw-r--r--bin/tests/system/dnssec/signer/general/bogus-zsk.key6
-rw-r--r--bin/tests/system/dnssec/signer/general/test1.zone19
-rw-r--r--bin/tests/system/dnssec/signer/general/test2.zone18
-rw-r--r--bin/tests/system/dnssec/signer/general/test3.zone18
-rw-r--r--bin/tests/system/dnssec/signer/general/test4.zone20
-rw-r--r--bin/tests/system/dnssec/signer/general/test5.zone19
-rw-r--r--bin/tests/system/dnssec/signer/general/test6.zone21
-rw-r--r--bin/tests/system/dnssec/signer/general/test7.zone19
-rw-r--r--bin/tests/system/dnssec/signer/general/test8.zone19
-rw-r--r--bin/tests/system/dnssec/signer/general/test9.zone19
-rw-r--r--bin/tests/system/dnssec/signer/prepub.db.in17
-rw-r--r--bin/tests/system/dnssec/signer/remove.db.in18
-rw-r--r--bin/tests/system/dnssec/signer/remove2.db.in16
-rw-r--r--bin/tests/system/dnssec/tests.sh4446
-rw-r--r--bin/tests/system/dnssec/tests_sh_dnssec.py14
132 files changed, 10132 insertions, 0 deletions
diff --git a/bin/tests/system/dnssec/README b/bin/tests/system/dnssec/README
new file mode 100644
index 0000000..fcaa3b6
--- /dev/null
+++ b/bin/tests/system/dnssec/README
@@ -0,0 +1,32 @@
+Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+
+SPDX-License-Identifier: MPL-2.0
+
+This Source Code Form is subject to the terms of the Mozilla Public
+License, v. 2.0. If a copy of the MPL was not distributed with this
+file, you can obtain one at https://mozilla.org/MPL/2.0/.
+
+See the COPYRIGHT file distributed with this work for additional
+information regarding copyright ownership.
+
+The test setup for the DNSSEC tests has a secure root.
+
+ns1 is the root server.
+
+ns2 and ns3 are authoritative servers for the various test domains.
+
+ns4 is a caching-only server, configured with the correct trusted key
+for the root.
+
+ns5 is a caching-only server, configured with the an incorrect trusted
+key for the root. It is used for testing failure cases.
+
+ns6 is an caching and authoritative server used for testing unusual
+server behaviors such as disabled DNSSEC algorithms.
+
+ns7 is used for checking non-cacheable answers.
+
+ns8 is a caching-only server, configured with unsupported and disabled
+algorithms. It is used for testing failure cases.
+
+ns9 is a forwarding-only server.
diff --git a/bin/tests/system/dnssec/ans10/ans.py b/bin/tests/system/dnssec/ans10/ans.py
new file mode 100644
index 0000000..dbe49e5
--- /dev/null
+++ b/bin/tests/system/dnssec/ans10/ans.py
@@ -0,0 +1,158 @@
+# Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+#
+# SPDX-License-Identifier: MPL-2.0
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, you can obtain one at https://mozilla.org/MPL/2.0/.
+#
+# See the COPYRIGHT file distributed with this work for additional
+# information regarding copyright ownership.
+
+from __future__ import print_function
+import os
+import sys
+import signal
+import socket
+import select
+from datetime import datetime, timedelta
+import time
+import functools
+
+import dns, dns.message, dns.query, dns.flags
+from dns.rdatatype import *
+from dns.rdataclass import *
+from dns.rcode import *
+from dns.name import *
+
+
+# Log query to file
+def logquery(type, qname):
+ with open("qlog", "a") as f:
+ f.write("%s %s\n", type, qname)
+
+
+############################################################################
+# Respond to a DNS query.
+# SOA gets a unsigned response.
+# NS gets a unsigned response.
+# DNSKEY get a unsigned NODATA response.
+# A gets a signed response.
+# All other types get a unsigned NODATA response.
+############################################################################
+def create_response(msg):
+ m = dns.message.from_wire(msg)
+ qname = m.question[0].name.to_text()
+ rrtype = m.question[0].rdtype
+ typename = dns.rdatatype.to_text(rrtype)
+
+ with open("query.log", "a") as f:
+ f.write("%s %s\n" % (typename, qname))
+ print("%s %s" % (typename, qname), end=" ")
+
+ r = dns.message.make_response(m)
+ r.set_rcode(NOERROR)
+ if rrtype == A:
+ now = datetime.today()
+ expire = now + timedelta(days=30)
+ inception = now - timedelta(days=1)
+ rrsig = (
+ "A 13 2 60 "
+ + expire.strftime("%Y%m%d%H%M%S")
+ + " "
+ + inception.strftime("%Y%m%d%H%M%S")
+ + " 12345 "
+ + qname
+ + " gB+eISXAhSPZU2i/II0W9ZUhC2SCIrb94mlNvP5092WAeXxqN/vG43/1nmDl"
+ + "y2Qs7y5VCjSMOGn85bnaMoAc7w=="
+ )
+ r.answer.append(dns.rrset.from_text(qname, 1, IN, A, "10.53.0.10"))
+ r.answer.append(dns.rrset.from_text(qname, 1, IN, RRSIG, rrsig))
+ elif rrtype == NS:
+ r.answer.append(dns.rrset.from_text(qname, 1, IN, NS, "."))
+ elif rrtype == SOA:
+ r.answer.append(dns.rrset.from_text(qname, 1, IN, SOA, ". . 0 0 0 0 0"))
+ else:
+ r.authority.append(dns.rrset.from_text(qname, 1, IN, SOA, ". . 0 0 0 0 0"))
+ r.flags |= dns.flags.AA
+ return r
+
+
+def sigterm(signum, frame):
+ print("Shutting down now...")
+ os.remove("ans.pid")
+ running = False
+ sys.exit(0)
+
+
+############################################################################
+# Main
+#
+# Set up responder and control channel, open the pid file, and start
+# the main loop, listening for queries on the query channel or commands
+# on the control channel and acting on them.
+############################################################################
+ip4 = "10.53.0.10"
+ip6 = "fd92:7065:b8e:ffff::10"
+
+try:
+ port = int(os.environ["PORT"])
+except:
+ port = 5300
+
+query4_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
+query4_socket.bind((ip4, port))
+havev6 = True
+try:
+ query6_socket = socket.socket(socket.AF_INET6, socket.SOCK_DGRAM)
+ try:
+ query6_socket.bind((ip6, port))
+ except:
+ query6_socket.close()
+ havev6 = False
+except:
+ havev6 = False
+signal.signal(signal.SIGTERM, sigterm)
+
+f = open("ans.pid", "w")
+pid = os.getpid()
+print(pid, file=f)
+f.close()
+
+running = True
+
+print("Listening on %s port %d" % (ip4, port))
+if havev6:
+ print("Listening on %s port %d" % (ip6, port))
+print("Ctrl-c to quit")
+
+if havev6:
+ input = [query4_socket, query6_socket]
+else:
+ input = [query4_socket]
+
+while running:
+ try:
+ inputready, outputready, exceptready = select.select(input, [], [])
+ except select.error as e:
+ break
+ except socket.error as e:
+ break
+ except KeyboardInterrupt:
+ break
+
+ for s in inputready:
+ if s == query4_socket or s == query6_socket:
+ print(
+ "Query received on %s" % (ip4 if s == query4_socket else ip6), end=" "
+ )
+ # Handle incoming queries
+ msg = s.recvfrom(65535)
+ rsp = create_response(msg[0])
+ if rsp:
+ print(dns.rcode.to_text(rsp.rcode()))
+ s.sendto(rsp.to_wire(), msg[1])
+ else:
+ print("NO RESPONSE")
+ if not running:
+ break
diff --git a/bin/tests/system/dnssec/clean.sh b/bin/tests/system/dnssec/clean.sh
new file mode 100644
index 0000000..1a933ad
--- /dev/null
+++ b/bin/tests/system/dnssec/clean.sh
@@ -0,0 +1,117 @@
+#!/bin/sh
+
+# Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+#
+# SPDX-License-Identifier: MPL-2.0
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, you can obtain one at https://mozilla.org/MPL/2.0/.
+#
+# See the COPYRIGHT file distributed with this work for additional
+# information regarding copyright ownership.
+
+set -e
+
+rm -f ./*/K* ./*/keyset-* ./*/dsset-* ./*/signedkey-* ./*/*.signed
+rm -f ./*/example.bk
+rm -f ./*/named.conf
+rm -f ./*/named.memstats
+rm -f ./*/named.run ./*/named.run.prev
+rm -f ./*/named.secroots
+rm -f ./*/tmp* ./*/*.jnl ./*/*.bk ./*/*.jbk
+rm -f ./*/trusted.conf ./*/managed.conf ./*/revoked.conf
+rm -f ./Kexample.* ./Kkeygen* ./keygen*.err
+rm -f ./ans10/query.log ./ans10/ans.run
+rm -f ./canonical?.*
+rm -f ./delv.out*
+rm -f ./delve.out*
+rm -f ./dig.out.*
+rm -f ./ns2/too-many-iterations.db
+rm -f ./dnssectools.out*
+rm -f ./dsfromkey.out.*
+rm -f ./keygen.err
+rm -f ./named.secroots.test*
+rm -f ./nosign.before
+rm -f ./ns*/*.nta
+rm -f ./ns*/managed-keys.bind ./ns*/managed-keys.bind.jnl ./ns*/*.mkeys*
+rm -f ./ns*/named.lock
+rm -f ./ns1/managed.key.id
+rm -f ./ns1/root.db ./ns2/example.db ./ns2/managed.db ./ns2/trusted.db
+rm -f ./ns1/trusted.keys
+rm -f ./ns2/algroll.db
+rm -f ./ns2/badparam.db ./ns2/badparam.db.bad
+rm -f ./ns2/cdnskey-kskonly.secure.db
+rm -f ./ns2/cdnskey-kskonly.secure.id
+rm -f ./ns2/cdnskey-update.secure.db
+rm -f ./ns2/cdnskey-x.secure.db
+rm -f ./ns2/cdnskey.secure.db
+rm -f ./ns2/cds-auto.secure.db ./ns2/cds-auto.secure.db.jnl
+rm -f ./ns2/cds-kskonly.secure.db
+rm -f ./ns2/cds-kskonly.secure.id
+rm -f ./ns2/cds-update.secure.db ./ns2/cds-update.secure.db.jnl
+rm -f ./ns2/cds.secure.db ./ns2/cds-x.secure.db
+rm -f ./ns2/in-addr.arpa.db
+rm -f ./ns2/nsec3chain-test.db
+rm -f ./ns2/single-nsec3.db
+rm -f ./ns2/updatecheck-kskonly.secure.*
+rm -f ./ns3/auto-nsec.example.db ./ns3/auto-nsec3.example.db
+rm -f ./ns3/badds.example.db
+rm -f ./ns3/dname-at-apex-nsec3.example.db
+rm -f ./ns3/dnskey-nsec3-unknown.example.db
+rm -f ./ns3/dnskey-nsec3-unknown.example.db.tmp
+rm -f ./ns3/dnskey-unknown.example.db
+rm -f ./ns3/dnskey-unknown.example.db.tmp
+rm -f ./ns3/dnskey-unsupported-2.example.db
+rm -f ./ns3/dnskey-unsupported-2.example.db.tmp
+rm -f ./ns3/dnskey-unsupported.example.db
+rm -f ./ns3/dnskey-unsupported.example.db.tmp
+rm -f ./ns3/dynamic.example.db ./ns3/dynamic.example.db.signed.jnl
+rm -f ./ns3/expired.example.db ./ns3/update-nsec3.example.db
+rm -f ./ns3/expiring.example.db ./ns3/nosign.example.db
+rm -f ./ns3/future.example.db ./ns3/trusted-future.key
+rm -f ./ns3/inline.example.db.signed
+rm -f ./ns3/kskonly.example.db
+rm -f ./ns3/lower.example.db ./ns3/upper.example.db ./ns3/upper.example.db.lower
+rm -f ./ns3/managed-future.example.db
+rm -f ./ns3/multiple.example.db ./ns3/nsec3-unknown.example.db ./ns3/nsec3.example.db
+rm -f ./ns3/nsec3.nsec3.example.db
+rm -f ./ns3/nsec3.optout.example.db
+rm -f ./ns3/occluded.example.db
+rm -f ./ns3/optout-unknown.example.db ./ns3/optout.example.db
+rm -f ./ns3/optout.nsec3.example.db
+rm -f ./ns3/optout.optout.example.db
+rm -f ./ns3/publish-inactive.example.db
+rm -f ./ns3/revkey.example.db
+rm -f ./ns3/rsasha256.example.db ./ns3/rsasha512.example.db
+rm -f ./ns3/secure.below-cname.example.db
+rm -f ./ns3/secure.example.db ./ns3/*.managed.db ./ns3/*.trusted.db
+rm -f ./ns3/secure.nsec3.example.db
+rm -f ./ns3/secure.optout.example.db
+rm -f ./ns3/siginterval.conf
+rm -f ./ns3/siginterval.example.db
+rm -f ./ns3/split-dnssec.example.db
+rm -f ./ns3/split-smart.example.db
+rm -f ./ns3/ttlpatch.example.db ./ns3/ttlpatch.example.db.signed
+rm -f ./ns3/ttlpatch.example.db.patched
+rm -f ./ns3/unsecure.example.db ./ns3/bogus.example.db ./ns3/keyless.example.db
+rm -f ./ns3/unsupported.managed.db.tmp ./ns3/unsupported.trusted.db.tmp
+rm -f ./ns3/NSEC ./ns3/NSEC3
+rm -f ./ns4/named_dump.db*
+rm -f ./ns6/optout-tld.db
+rm -f ./ns7/multiple.example.bk ./ns7/nsec3.example.bk ./ns7/optout.example.bk
+rm -f ./ns7/split-rrsig.db ./ns7/split-rrsig.db.unsplit
+rm -f ./nsupdate.out*
+rm -f ./python.out.*
+rm -f ./rndc.out.*
+rm -f ./signer/*.db
+rm -f ./signer/*.signed.post*
+rm -f ./signer/*.signed.pre*
+rm -f ./signer/example.db.after ./signer/example.db.before
+rm -f ./signer/example.db.changed
+rm -f ./signer/general/dsset*
+rm -f ./signer/general/signed.zone
+rm -f ./signer/general/signer.out.*
+rm -f ./signer/nsec3param.out
+rm -f ./signer/signer.out.*
+rm -f ./signing.out*
diff --git a/bin/tests/system/dnssec/dnssec_update_test.pl b/bin/tests/system/dnssec/dnssec_update_test.pl
new file mode 100644
index 0000000..a06c563
--- /dev/null
+++ b/bin/tests/system/dnssec/dnssec_update_test.pl
@@ -0,0 +1,99 @@
+#!/usr/bin/perl
+
+# Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+#
+# SPDX-License-Identifier: MPL-2.0
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, you can obtain one at https://mozilla.org/MPL/2.0/.
+#
+# See the COPYRIGHT file distributed with this work for additional
+# information regarding copyright ownership.
+
+#
+# DNSSEC Dynamic update test suite.
+#
+# Usage:
+#
+# perl update_test.pl [-s server] [-p port] zone
+#
+# The server defaults to 127.0.0.1.
+# The port defaults to 53.
+#
+# Installation notes:
+#
+# This program uses the Net::DNS::Resolver module.
+# You can install it by saying
+#
+# perl -MCPAN -e "install Net::DNS"
+#
+
+use Getopt::Std;
+use Net::DNS;
+use Net::DNS::Update;
+use Net::DNS::Resolver;
+
+$opt_s = "127.0.0.1";
+$opt_p = 53;
+
+getopt('s:p:');
+
+$res = new Net::DNS::Resolver;
+$res->nameservers($opt_s);
+$res->port($opt_p);
+$res->defnames(0); # Do not append default domain.
+
+@ARGV == 1 or die
+ "usage: perl update_test.pl [-s server] [-p port] zone\n";
+
+$zone = shift @ARGV;
+
+my $failures = 0;
+
+sub assert {
+ my ($cond, $explanation) = @_;
+ if (!$cond) {
+ print "Test Failed: $explanation ***\n";
+ $failures++
+ }
+}
+
+sub test {
+ my ($expected, @records) = @_;
+
+ my $update = new Net::DNS::Update("$zone");
+
+ foreach $rec (@records) {
+ $update->push(@$rec);
+ }
+
+ $reply = $res->send($update);
+
+ # Did it work?
+ if (defined $reply) {
+ my $rcode = $reply->header->rcode;
+ assert($rcode eq $expected, "expected $expected, got $rcode");
+ } else {
+ print "Update failed: ", $res->errorstring, "\n";
+ }
+}
+
+sub section {
+ my ($msg) = @_;
+ print "$msg\n";
+}
+
+section("Add a name");
+test("NOERROR", ["update", rr_add("a.$zone 300 A 73.80.65.49")]);
+
+section("Delete the name");
+test("NOERROR", ["update", rr_del("a.$zone")]);
+
+if ($failures) {
+ print "$failures update tests failed.\n";
+} else {
+ print "All update tests successful.\n";
+}
+
+exit $failures;
diff --git a/bin/tests/system/dnssec/ns1/named.conf.in b/bin/tests/system/dnssec/ns1/named.conf.in
new file mode 100644
index 0000000..bd1ccc4
--- /dev/null
+++ b/bin/tests/system/dnssec/ns1/named.conf.in
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * SPDX-License-Identifier: MPL-2.0
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, you can obtain one at https://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+// NS1
+
+options {
+ query-source address 10.53.0.1;
+ notify-source 10.53.0.1;
+ transfer-source 10.53.0.1;
+ port @PORT@;
+ pid-file "named.pid";
+ listen-on { 10.53.0.1; };
+ listen-on-v6 { none; };
+ recursion no;
+ notify yes;
+ dnssec-validation yes;
+ /* test that we can turn off trust-anchor-telemetry */
+ trust-anchor-telemetry no;
+};
+
+zone "." {
+ type primary;
+ file "root.db.signed";
+};
+
+include "trusted.conf";
diff --git a/bin/tests/system/dnssec/ns1/root.db.in b/bin/tests/system/dnssec/ns1/root.db.in
new file mode 100644
index 0000000..526e36c
--- /dev/null
+++ b/bin/tests/system/dnssec/ns1/root.db.in
@@ -0,0 +1,37 @@
+; Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+;
+; SPDX-License-Identifier: MPL-2.0
+;
+; This Source Code Form is subject to the terms of the Mozilla Public
+; License, v. 2.0. If a copy of the MPL was not distributed with this
+; file, you can obtain one at https://mozilla.org/MPL/2.0/.
+;
+; See the COPYRIGHT file distributed with this work for additional
+; information regarding copyright ownership.
+
+$TTL 300
+. IN SOA gson.nominum.com. a.root.servers.nil. (
+ 2000042100 ; serial
+ 600 ; refresh
+ 600 ; retry
+ 1200 ; expire
+ 600 ; minimum
+ )
+. NS a.root-servers.nil.
+a.root-servers.nil. A 10.53.0.1
+
+example. NS ns2.example.
+ns2.example. A 10.53.0.2
+algroll. NS ns2.algroll.
+ns2.algroll. A 10.53.0.2
+managed. NS ns2.managed.
+ns2.managed. A 10.53.0.2
+trusted. NS ns2.trusted.
+ns2.trusted. A 10.53.0.2
+optout-tld NS ns6.optout-tld.
+ns6.optout-tld. A 10.53.0.6
+in-addr.arpa. NS ns2.example.
+inprogress. NS ns10.inprogress.
+ns10.inprogress. A 10.53.0.10
+too-many-iterations. NS ns2.too-many-iterations.
+ns2.too-many-iterations. A 10.53.0.2
diff --git a/bin/tests/system/dnssec/ns1/sign.sh b/bin/tests/system/dnssec/ns1/sign.sh
new file mode 100644
index 0000000..21c6d71
--- /dev/null
+++ b/bin/tests/system/dnssec/ns1/sign.sh
@@ -0,0 +1,62 @@
+#!/bin/sh -e
+
+# Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+#
+# SPDX-License-Identifier: MPL-2.0
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, you can obtain one at https://mozilla.org/MPL/2.0/.
+#
+# See the COPYRIGHT file distributed with this work for additional
+# information regarding copyright ownership.
+
+# shellcheck source=conf.sh
+. ../../conf.sh
+
+set -e
+
+zone=.
+infile=root.db.in
+zonefile=root.db
+
+(cd ../ns2 && $SHELL sign.sh )
+(cd ../ns6 && $SHELL sign.sh )
+(cd ../ns7 && $SHELL sign.sh )
+
+echo_i "ns1/sign.sh"
+
+cp "../ns2/dsset-example." .
+cp "../ns2/dsset-in-addr.arpa." .
+cp "../ns2/dsset-too-many-iterations." .
+
+grep "$DEFAULT_ALGORITHM_NUMBER [12] " "../ns2/dsset-algroll." > "dsset-algroll."
+cp "../ns6/dsset-optout-tld." .
+
+ksk=$("$KEYGEN" -q -fk -a "$DEFAULT_ALGORITHM" -b "$DEFAULT_BITS" -n zone "$zone")
+zsk=$("$KEYGEN" -q -a "$DEFAULT_ALGORITHM" -b "$DEFAULT_BITS" -n zone "$zone")
+
+cat "$infile" "$ksk.key" "$zsk.key" > "$zonefile"
+
+"$SIGNER" -g -o "$zone" "$zonefile" > /dev/null 2>&1
+
+# Configure the resolving server with a staitc key.
+keyfile_to_static_ds "$ksk" > trusted.conf
+cp trusted.conf ../ns2/trusted.conf
+cp trusted.conf ../ns3/trusted.conf
+cp trusted.conf ../ns4/trusted.conf
+cp trusted.conf ../ns6/trusted.conf
+cp trusted.conf ../ns7/trusted.conf
+cp trusted.conf ../ns9/trusted.conf
+
+keyfile_to_trusted_keys "$ksk" > trusted.keys
+
+# ...or with an initializing key.
+keyfile_to_initial_ds "$ksk" > managed.conf
+cp managed.conf ../ns4/managed.conf
+
+#
+# Save keyid for managed key id test.
+#
+
+keyfile_to_key_id "$ksk" > managed.key.id
diff --git a/bin/tests/system/dnssec/ns2/algroll.db.in b/bin/tests/system/dnssec/ns2/algroll.db.in
new file mode 100644
index 0000000..6f66fc9
--- /dev/null
+++ b/bin/tests/system/dnssec/ns2/algroll.db.in
@@ -0,0 +1,26 @@
+; Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+;
+; SPDX-License-Identifier: MPL-2.0
+;
+; This Source Code Form is subject to the terms of the Mozilla Public
+; License, v. 2.0. If a copy of the MPL was not distributed with this
+; file, you can obtain one at https://mozilla.org/MPL/2.0/.
+;
+; See the COPYRIGHT file distributed with this work for additional
+; information regarding copyright ownership.
+
+$TTL 30 ; 5 minutes
+@ IN SOA mname1. . (
+ 2000042407 ; serial
+ 20 ; refresh (20 seconds)
+ 20 ; retry (20 seconds)
+ 1814400 ; expire (3 weeks)
+ 30 ; minimum (1 hour)
+ )
+ NS ns2
+ns2 A 10.53.0.2
+ns3 A 10.53.0.3
+
+a A 10.0.0.1
+b A 10.0.0.2
+d A 10.0.0.4
diff --git a/bin/tests/system/dnssec/ns2/badparam.db.in b/bin/tests/system/dnssec/ns2/badparam.db.in
new file mode 100644
index 0000000..b18d186
--- /dev/null
+++ b/bin/tests/system/dnssec/ns2/badparam.db.in
@@ -0,0 +1,21 @@
+; Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+;
+; SPDX-License-Identifier: MPL-2.0
+;
+; This Source Code Form is subject to the terms of the Mozilla Public
+; License, v. 2.0. If a copy of the MPL was not distributed with this
+; file, you can obtain one at https://mozilla.org/MPL/2.0/.
+;
+; See the COPYRIGHT file distributed with this work for additional
+; information regarding copyright ownership.
+
+$TTL 300 ; 5 minutes
+@ IN SOA mname1. . (
+ 2010081000 ; serial
+ 20 ; refresh (20 seconds)
+ 20 ; retry (20 seconds)
+ 1814400 ; expire (3 weeks)
+ 3600 ; minimum (1 hour)
+ )
+ NS ns2
+ns2 A 10.53.0.2
diff --git a/bin/tests/system/dnssec/ns2/cdnskey-auto.secure.db.in b/bin/tests/system/dnssec/ns2/cdnskey-auto.secure.db.in
new file mode 100644
index 0000000..aa3aaab
--- /dev/null
+++ b/bin/tests/system/dnssec/ns2/cdnskey-auto.secure.db.in
@@ -0,0 +1,14 @@
+; Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+;
+; SPDX-License-Identifier: MPL-2.0
+;
+; This Source Code Form is subject to the terms of the Mozilla Public
+; License, v. 2.0. If a copy of the MPL was not distributed with this
+; file, you can obtain one at https://mozilla.org/MPL/2.0/.
+;
+; See the COPYRIGHT file distributed with this work for additional
+; information regarding copyright ownership.
+
+$TTL 3600
+@ SOA ns2.example. . 1 3600 1200 86400 1200
+@ NS ns2.example.
diff --git a/bin/tests/system/dnssec/ns2/cdnskey-kskonly.secure.db.in b/bin/tests/system/dnssec/ns2/cdnskey-kskonly.secure.db.in
new file mode 100644
index 0000000..aa3aaab
--- /dev/null
+++ b/bin/tests/system/dnssec/ns2/cdnskey-kskonly.secure.db.in
@@ -0,0 +1,14 @@
+; Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+;
+; SPDX-License-Identifier: MPL-2.0
+;
+; This Source Code Form is subject to the terms of the Mozilla Public
+; License, v. 2.0. If a copy of the MPL was not distributed with this
+; file, you can obtain one at https://mozilla.org/MPL/2.0/.
+;
+; See the COPYRIGHT file distributed with this work for additional
+; information regarding copyright ownership.
+
+$TTL 3600
+@ SOA ns2.example. . 1 3600 1200 86400 1200
+@ NS ns2.example.
diff --git a/bin/tests/system/dnssec/ns2/cdnskey-update.secure.db.in b/bin/tests/system/dnssec/ns2/cdnskey-update.secure.db.in
new file mode 100644
index 0000000..aa3aaab
--- /dev/null
+++ b/bin/tests/system/dnssec/ns2/cdnskey-update.secure.db.in
@@ -0,0 +1,14 @@
+; Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+;
+; SPDX-License-Identifier: MPL-2.0
+;
+; This Source Code Form is subject to the terms of the Mozilla Public
+; License, v. 2.0. If a copy of the MPL was not distributed with this
+; file, you can obtain one at https://mozilla.org/MPL/2.0/.
+;
+; See the COPYRIGHT file distributed with this work for additional
+; information regarding copyright ownership.
+
+$TTL 3600
+@ SOA ns2.example. . 1 3600 1200 86400 1200
+@ NS ns2.example.
diff --git a/bin/tests/system/dnssec/ns2/cdnskey.secure.db.in b/bin/tests/system/dnssec/ns2/cdnskey.secure.db.in
new file mode 100644
index 0000000..aa3aaab
--- /dev/null
+++ b/bin/tests/system/dnssec/ns2/cdnskey.secure.db.in
@@ -0,0 +1,14 @@
+; Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+;
+; SPDX-License-Identifier: MPL-2.0
+;
+; This Source Code Form is subject to the terms of the Mozilla Public
+; License, v. 2.0. If a copy of the MPL was not distributed with this
+; file, you can obtain one at https://mozilla.org/MPL/2.0/.
+;
+; See the COPYRIGHT file distributed with this work for additional
+; information regarding copyright ownership.
+
+$TTL 3600
+@ SOA ns2.example. . 1 3600 1200 86400 1200
+@ NS ns2.example.
diff --git a/bin/tests/system/dnssec/ns2/cds-auto.secure.db.in b/bin/tests/system/dnssec/ns2/cds-auto.secure.db.in
new file mode 100644
index 0000000..aa3aaab
--- /dev/null
+++ b/bin/tests/system/dnssec/ns2/cds-auto.secure.db.in
@@ -0,0 +1,14 @@
+; Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+;
+; SPDX-License-Identifier: MPL-2.0
+;
+; This Source Code Form is subject to the terms of the Mozilla Public
+; License, v. 2.0. If a copy of the MPL was not distributed with this
+; file, you can obtain one at https://mozilla.org/MPL/2.0/.
+;
+; See the COPYRIGHT file distributed with this work for additional
+; information regarding copyright ownership.
+
+$TTL 3600
+@ SOA ns2.example. . 1 3600 1200 86400 1200
+@ NS ns2.example.
diff --git a/bin/tests/system/dnssec/ns2/cds-kskonly.secure.db.in b/bin/tests/system/dnssec/ns2/cds-kskonly.secure.db.in
new file mode 100644
index 0000000..aa3aaab
--- /dev/null
+++ b/bin/tests/system/dnssec/ns2/cds-kskonly.secure.db.in
@@ -0,0 +1,14 @@
+; Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+;
+; SPDX-License-Identifier: MPL-2.0
+;
+; This Source Code Form is subject to the terms of the Mozilla Public
+; License, v. 2.0. If a copy of the MPL was not distributed with this
+; file, you can obtain one at https://mozilla.org/MPL/2.0/.
+;
+; See the COPYRIGHT file distributed with this work for additional
+; information regarding copyright ownership.
+
+$TTL 3600
+@ SOA ns2.example. . 1 3600 1200 86400 1200
+@ NS ns2.example.
diff --git a/bin/tests/system/dnssec/ns2/cds-update.secure.db.in b/bin/tests/system/dnssec/ns2/cds-update.secure.db.in
new file mode 100644
index 0000000..aa3aaab
--- /dev/null
+++ b/bin/tests/system/dnssec/ns2/cds-update.secure.db.in
@@ -0,0 +1,14 @@
+; Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+;
+; SPDX-License-Identifier: MPL-2.0
+;
+; This Source Code Form is subject to the terms of the Mozilla Public
+; License, v. 2.0. If a copy of the MPL was not distributed with this
+; file, you can obtain one at https://mozilla.org/MPL/2.0/.
+;
+; See the COPYRIGHT file distributed with this work for additional
+; information regarding copyright ownership.
+
+$TTL 3600
+@ SOA ns2.example. . 1 3600 1200 86400 1200
+@ NS ns2.example.
diff --git a/bin/tests/system/dnssec/ns2/cds.secure.db.in b/bin/tests/system/dnssec/ns2/cds.secure.db.in
new file mode 100644
index 0000000..aa3aaab
--- /dev/null
+++ b/bin/tests/system/dnssec/ns2/cds.secure.db.in
@@ -0,0 +1,14 @@
+; Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+;
+; SPDX-License-Identifier: MPL-2.0
+;
+; This Source Code Form is subject to the terms of the Mozilla Public
+; License, v. 2.0. If a copy of the MPL was not distributed with this
+; file, you can obtain one at https://mozilla.org/MPL/2.0/.
+;
+; See the COPYRIGHT file distributed with this work for additional
+; information regarding copyright ownership.
+
+$TTL 3600
+@ SOA ns2.example. . 1 3600 1200 86400 1200
+@ NS ns2.example.
diff --git a/bin/tests/system/dnssec/ns2/child.nsec3.example.db b/bin/tests/system/dnssec/ns2/child.nsec3.example.db
new file mode 100644
index 0000000..8fc3bc8
--- /dev/null
+++ b/bin/tests/system/dnssec/ns2/child.nsec3.example.db
@@ -0,0 +1,20 @@
+; Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+;
+; SPDX-License-Identifier: MPL-2.0
+;
+; This Source Code Form is subject to the terms of the Mozilla Public
+; License, v. 2.0. If a copy of the MPL was not distributed with this
+; file, you can obtain one at https://mozilla.org/MPL/2.0/.
+;
+; See the COPYRIGHT file distributed with this work for additional
+; information regarding copyright ownership.
+
+$TTL 300 ; 5 minutes
+@ IN SOA mname1. . (
+ 2006081400 ; serial
+ 20 ; refresh (20 seconds)
+ 20 ; retry (20 seconds)
+ 1814400 ; expire (3 weeks)
+ 3600 ; minimum (1 hour)
+ )
+@ IN NS ns2.example.
diff --git a/bin/tests/system/dnssec/ns2/child.optout.example.db b/bin/tests/system/dnssec/ns2/child.optout.example.db
new file mode 100644
index 0000000..8fc3bc8
--- /dev/null
+++ b/bin/tests/system/dnssec/ns2/child.optout.example.db
@@ -0,0 +1,20 @@
+; Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+;
+; SPDX-License-Identifier: MPL-2.0
+;
+; This Source Code Form is subject to the terms of the Mozilla Public
+; License, v. 2.0. If a copy of the MPL was not distributed with this
+; file, you can obtain one at https://mozilla.org/MPL/2.0/.
+;
+; See the COPYRIGHT file distributed with this work for additional
+; information regarding copyright ownership.
+
+$TTL 300 ; 5 minutes
+@ IN SOA mname1. . (
+ 2006081400 ; serial
+ 20 ; refresh (20 seconds)
+ 20 ; retry (20 seconds)
+ 1814400 ; expire (3 weeks)
+ 3600 ; minimum (1 hour)
+ )
+@ IN NS ns2.example.
diff --git a/bin/tests/system/dnssec/ns2/corp.db b/bin/tests/system/dnssec/ns2/corp.db
new file mode 100644
index 0000000..b2912bc
--- /dev/null
+++ b/bin/tests/system/dnssec/ns2/corp.db
@@ -0,0 +1,23 @@
+; Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+;
+; SPDX-License-Identifier: MPL-2.0
+;
+; This Source Code Form is subject to the terms of the Mozilla Public
+; License, v. 2.0. If a copy of the MPL was not distributed with this
+; file, you can obtain one at https://mozilla.org/MPL/2.0/.
+;
+; See the COPYRIGHT file distributed with this work for additional
+; information regarding copyright ownership.
+
+$TTL 30 ; 5 minutes
+@ IN SOA mname1. . (
+ 2000042407 ; serial
+ 20 ; refresh (20 seconds)
+ 20 ; retry (20 seconds)
+ 1814400 ; expire (3 weeks)
+ 30 ; minimum (1 hour)
+ )
+ NS ns2
+ns2 A 10.53.0.2
+
+www A 10.0.0.1
diff --git a/bin/tests/system/dnssec/ns2/dst.example.db.in b/bin/tests/system/dnssec/ns2/dst.example.db.in
new file mode 100644
index 0000000..0039484
--- /dev/null
+++ b/bin/tests/system/dnssec/ns2/dst.example.db.in
@@ -0,0 +1,21 @@
+; Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+;
+; SPDX-License-Identifier: MPL-2.0
+;
+; This Source Code Form is subject to the terms of the Mozilla Public
+; License, v. 2.0. If a copy of the MPL was not distributed with this
+; file, you can obtain one at https://mozilla.org/MPL/2.0/.
+;
+; See the COPYRIGHT file distributed with this work for additional
+; information regarding copyright ownership.
+
+$TTL 300 ; 5 minutes
+@ IN SOA mname1. . (
+ 2000042407 ; serial
+ 20 ; refresh (20 seconds)
+ 20 ; retry (20 seconds)
+ 1814400 ; expire (3 weeks)
+ 3600 ; minimum (1 hour)
+ )
+ NS ns2.example.
+a A 10.0.0.1
diff --git a/bin/tests/system/dnssec/ns2/example.db.in b/bin/tests/system/dnssec/ns2/example.db.in
new file mode 100644
index 0000000..f711f58
--- /dev/null
+++ b/bin/tests/system/dnssec/ns2/example.db.in
@@ -0,0 +1,171 @@
+; Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+;
+; SPDX-License-Identifier: MPL-2.0
+;
+; This Source Code Form is subject to the terms of the Mozilla Public
+; License, v. 2.0. If a copy of the MPL was not distributed with this
+; file, you can obtain one at https://mozilla.org/MPL/2.0/.
+;
+; See the COPYRIGHT file distributed with this work for additional
+; information regarding copyright ownership.
+
+$TTL 300 ; 5 minutes
+@ IN SOA mname1. . (
+ 2000042407 ; serial
+ 20 ; refresh (20 seconds)
+ 20 ; retry (20 seconds)
+ 1814400 ; expire (3 weeks)
+ 3600 ; minimum (1 hour)
+ )
+ NS ns2
+ NS ns3
+ns2 A 10.53.0.2
+ns3 A 10.53.0.3
+
+a A 10.0.0.1
+b A 10.0.0.2
+d A 10.0.0.4
+
+; Used for testing ANY queries
+foo TXT "testing"
+foo A 10.0.1.0
+
+bad-cname CNAME a
+bad-dname DNAME @
+
+; Used for testing CNAME queries
+cname1 CNAME cname1-target
+cname1-target TXT "testing cname"
+
+cname2 CNAME cname2-target
+cname2-target TXT "testing cname"
+
+; Used for testing DNAME queries
+dname1 DNAME dname1-target
+foo.dname1-target TXT "testing dname"
+
+dname2 DNAME dname2-target
+foo.dname2-target TXT "testing dname"
+
+; A secure subdomain
+secure NS ns3.secure
+ns3.secure A 10.53.0.3
+
+; An insecure subdomain
+insecure NS ns.insecure
+ns.insecure A 10.53.0.3
+
+; A second insecure subdomain
+insecure2 NS ns.insecure2
+ns.insecure2 A 10.53.0.3
+
+; A secure subdomain we're going to inject bogus data into
+bogus NS ns.bogus
+ns.bogus A 10.53.0.3
+
+; A subdomain with a corrupt DS
+badds NS ns.badds
+ns.badds A 10.53.0.3
+
+; A dynamic secure subdomain
+dynamic NS dynamic
+dynamic A 10.53.0.3
+
+; A insecure subdomain
+mustbesecure NS ns.mustbesecure
+ns.mustbesecure A 10.53.0.3
+
+; A subdomain with expired signatures
+expired NS ns.expired
+ns.expired A 10.53.0.3
+
+; A rfc2535 signed zone w/ CNAME
+rfc2535 NS ns.rfc2535
+ns.rfc2535 A 10.53.0.3
+
+z A 10.0.0.26
+
+keyless NS ns.keyless
+ns.keyless A 10.53.0.3
+
+nsec3 NS ns.nsec3
+ns.nsec3 A 10.53.0.3
+
+optout NS ns.optout
+ns.optout A 10.53.0.3
+
+nsec3-unknown NS ns.nsec3-unknown
+ns.nsec3-unknown A 10.53.0.3
+
+optout-unknown NS ns.optout-unknown
+ns.optout-unknown A 10.53.0.3
+
+dnskey-unknown NS ns.dnskey-unknown
+ns.dnskey-unknown A 10.53.0.3
+
+dnskey-unsupported NS ns.dnskey-unsupported
+ns.dnskey-unsupported A 10.53.0.3
+
+dnskey-nsec3-unknown NS ns.dnskey-nsec3-unknown
+ns.dnskey-nsec3-unknown A 10.53.0.3
+
+multiple NS ns.multiple
+ns.multiple A 10.53.0.3
+
+*.wild A 10.0.0.27
+
+rsasha256 NS ns.rsasha256
+ns.rsasha256 A 10.53.0.3
+
+rsasha512 NS ns.rsasha512
+ns.rsasha512 A 10.53.0.3
+
+kskonly NS ns.kskonly
+ns.kskonly A 10.53.0.3
+
+update-nsec3 NS ns.update-nsec3
+ns.update-nsec3 A 10.53.0.3
+
+auto-nsec NS ns.auto-nsec
+ns.auto-nsec A 10.53.0.3
+
+auto-nsec3 NS ns.auto-nsec3
+ns.auto-nsec3 A 10.53.0.3
+
+
+below-cname CNAME some.where.else.
+
+insecure.below-cname NS ns.insecure.below-cname
+ns.insecure.below-cname A 10.53.0.3
+
+secure.below-cname NS ns.secure.below-cname
+ns.secure.below-cname A 10.53.0.3
+
+ttlpatch NS ns.ttlpatch
+ns.ttlpatch A 10.53.0.3
+
+split-dnssec NS ns.split-dnssec
+ns.split-dnssec A 10.53.0.3
+
+split-smart NS ns.split-smart
+ns.split-smart A 10.53.0.3
+
+upper NS ns.upper
+ns.upper A 10.53.0.3
+
+LOWER NS NS.LOWER
+NS.LOWER A 10.53.0.3
+
+expiring NS ns.expiring
+ns.expiring A 10.53.0.3
+
+future NS ns.future
+ns.future A 10.53.0.3
+
+managed-future NS ns.managed-future
+ns.managed-future A 10.53.0.3
+
+revkey NS ns.revkey
+ns.revkey A 10.53.0.3
+
+dname-at-apex-nsec3 NS ns3
diff --git a/bin/tests/system/dnssec/ns2/hours-vs-days.db.in b/bin/tests/system/dnssec/ns2/hours-vs-days.db.in
new file mode 100644
index 0000000..5ec8801
--- /dev/null
+++ b/bin/tests/system/dnssec/ns2/hours-vs-days.db.in
@@ -0,0 +1,167 @@
+; Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+;
+; SPDX-License-Identifier: MPL-2.0
+;
+; This Source Code Form is subject to the terms of the Mozilla Public
+; License, v. 2.0. If a copy of the MPL was not distributed with this
+; file, you can obtain one at https://mozilla.org/MPL/2.0/.
+;
+; See the COPYRIGHT file distributed with this work for additional
+; information regarding copyright ownership.
+
+$TTL 300 ; 5 minutes
+@ IN SOA mname1. . (
+ 2000042407 ; serial
+ 20 ; refresh (20 seconds)
+ 20 ; retry (20 seconds)
+ 1814400 ; expire (3 weeks)
+ 3600 ; minimum (1 hour)
+ )
+ NS ns2
+ NS ns3
+ns2 A 10.53.0.2
+ns3 A 10.53.0.3
+
+a A 10.0.0.1
+b A 10.0.0.2
+d A 10.0.0.4
+
+; Used for testing ANY queries
+foo TXT "testing"
+foo A 10.0.1.0
+
+bad-cname CNAME a
+bad-dname DNAME @
+
+; Used for testing CNAME queries
+cname1 CNAME cname1-target
+cname1-target TXT "testing cname"
+
+cname2 CNAME cname2-target
+cname2-target TXT "testing cname"
+
+; Used for testing DNAME queries
+dname1 DNAME dname1-target
+foo.dname1-target TXT "testing dname"
+
+dname2 DNAME dname2-target
+foo.dname2-target TXT "testing dname"
+
+; A secure subdomain
+secure NS ns3.secure
+ns3.secure A 10.53.0.3
+
+; An insecure subdomain
+insecure NS ns.insecure
+ns.insecure A 10.53.0.3
+
+; A secure subdomain we're going to inject bogus data into
+bogus NS ns.bogus
+ns.bogus A 10.53.0.3
+
+; A subdomain with a corrupt DS
+badds NS ns.badds
+ns.badds A 10.53.0.3
+
+; A dynamic secure subdomain
+dynamic NS dynamic
+dynamic A 10.53.0.3
+
+; A insecure subdomain
+mustbesecure NS ns.mustbesecure
+ns.mustbesecure A 10.53.0.3
+
+; A subdomain with expired signatures
+expired NS ns.expired
+ns.expired A 10.53.0.3
+
+; A rfc2535 signed zone w/ CNAME
+rfc2535 NS ns.rfc2535
+ns.rfc2535 A 10.53.0.3
+
+z A 10.0.0.26
+
+keyless NS ns.keyless
+ns.keyless A 10.53.0.3
+
+nsec3 NS ns.nsec3
+ns.nsec3 A 10.53.0.3
+
+optout NS ns.optout
+ns.optout A 10.53.0.3
+
+nsec3-unknown NS ns.nsec3-unknown
+ns.nsec3-unknown A 10.53.0.3
+
+optout-unknown NS ns.optout-unknown
+ns.optout-unknown A 10.53.0.3
+
+dnskey-unknown NS ns.dnskey-unknown
+ns.dnskey-unknown A 10.53.0.3
+
+dnskey-unsupported NS ns.dnskey-unsupported
+ns.dnskey-unsupported A 10.53.0.3
+
+dnskey-nsec3-unknown NS ns.dnskey-nsec3-unknown
+ns.dnskey-nsec3-unknown A 10.53.0.3
+
+multiple NS ns.multiple
+ns.multiple A 10.53.0.3
+
+*.wild A 10.0.0.27
+
+rsasha256 NS ns.rsasha256
+ns.rsasha256 A 10.53.0.3
+
+rsasha512 NS ns.rsasha512
+ns.rsasha512 A 10.53.0.3
+
+kskonly NS ns.kskonly
+ns.kskonly A 10.53.0.3
+
+update-nsec3 NS ns.update-nsec3
+ns.update-nsec3 A 10.53.0.3
+
+auto-nsec NS ns.auto-nsec
+ns.auto-nsec A 10.53.0.3
+
+auto-nsec3 NS ns.auto-nsec3
+ns.auto-nsec3 A 10.53.0.3
+
+
+below-cname CNAME some.where.else.
+
+insecure.below-cname NS ns.insecure.below-cname
+ns.insecure.below-cname A 10.53.0.3
+
+secure.below-cname NS ns.secure.below-cname
+ns.secure.below-cname A 10.53.0.3
+
+ttlpatch NS ns.ttlpatch
+ns.ttlpatch A 10.53.0.3
+
+split-dnssec NS ns.split-dnssec
+ns.split-dnssec A 10.53.0.3
+
+split-smart NS ns.split-smart
+ns.split-smart A 10.53.0.3
+
+upper NS ns.upper
+ns.upper A 10.53.0.3
+
+LOWER NS NS.LOWER
+NS.LOWER A 10.53.0.3
+
+expiring NS ns.expiring
+ns.expiring A 10.53.0.3
+
+future NS ns.future
+ns.future A 10.53.0.3
+
+managed-future NS ns.managed-future
+ns.managed-future A 10.53.0.3
+
+revkey NS ns.revkey
+ns.revkey A 10.53.0.3
+
+dname-at-apex-nsec3 NS ns3
diff --git a/bin/tests/system/dnssec/ns2/in-addr.arpa.db.in b/bin/tests/system/dnssec/ns2/in-addr.arpa.db.in
new file mode 100644
index 0000000..874b915
--- /dev/null
+++ b/bin/tests/system/dnssec/ns2/in-addr.arpa.db.in
@@ -0,0 +1,19 @@
+; Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+;
+; SPDX-License-Identifier: MPL-2.0
+;
+; This Source Code Form is subject to the terms of the Mozilla Public
+; License, v. 2.0. If a copy of the MPL was not distributed with this
+; file, you can obtain one at https://mozilla.org/MPL/2.0/.
+;
+; See the COPYRIGHT file distributed with this work for additional
+; information regarding copyright ownership.
+
+$TTL 3600
+@ SOA ns2.example. . 1 3600 1200 86400 1200
+@ NS ns2.example.
+;
+; As we are testing empty zone behaviour ns3 doesn't need to be
+; configured to serve 10.in-addr.arpa.
+;
+10 NS ns3.example.
diff --git a/bin/tests/system/dnssec/ns2/insecure.secure.example.db b/bin/tests/system/dnssec/ns2/insecure.secure.example.db
new file mode 100644
index 0000000..62862f5
--- /dev/null
+++ b/bin/tests/system/dnssec/ns2/insecure.secure.example.db
@@ -0,0 +1,26 @@
+; Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+;
+; SPDX-License-Identifier: MPL-2.0
+;
+; This Source Code Form is subject to the terms of the Mozilla Public
+; License, v. 2.0. If a copy of the MPL was not distributed with this
+; file, you can obtain one at https://mozilla.org/MPL/2.0/.
+;
+; See the COPYRIGHT file distributed with this work for additional
+; information regarding copyright ownership.
+
+$TTL 300 ; 5 minutes
+@ IN SOA mname1. . (
+ 2000042407 ; serial
+ 20 ; refresh (20 seconds)
+ 20 ; retry (20 seconds)
+ 1814400 ; expire (3 weeks)
+ 3600 ; minimum (1 hour)
+ )
+ NS ns2
+ns2 A 10.53.0.2
+
+a A 10.0.0.1
+b A 10.0.0.2
+d A 10.0.0.4
+z A 10.0.0.26
diff --git a/bin/tests/system/dnssec/ns2/key.db.in b/bin/tests/system/dnssec/ns2/key.db.in
new file mode 100644
index 0000000..2ff5df4
--- /dev/null
+++ b/bin/tests/system/dnssec/ns2/key.db.in
@@ -0,0 +1,45 @@
+; Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+;
+; SPDX-License-Identifier: MPL-2.0
+;
+; This Source Code Form is subject to the terms of the Mozilla Public
+; License, v. 2.0. If a copy of the MPL was not distributed with this
+; file, you can obtain one at https://mozilla.org/MPL/2.0/.
+;
+; See the COPYRIGHT file distributed with this work for additional
+; information regarding copyright ownership.
+
+$TTL 300 ; 5 minutes
+@ IN SOA mname1. . (
+ 2000042407 ; serial
+ 20 ; refresh (20 seconds)
+ 20 ; retry (20 seconds)
+ 1814400 ; expire (3 weeks)
+ 3600 ; minimum (1 hour)
+ )
+ NS ns2
+ns2 A 10.53.0.2
+
+a A 10.0.0.1
+b A 10.0.0.2
+d A 10.0.0.4
+
+; A secure subdomain
+secure NS ns3.secure
+ns3.secure A 10.53.0.3
+
+; A subdomain that is signed with an unsupported algorithm
+unsupported NS ns3.unsupported
+ns3.unsupported A 10.53.0.3
+
+; A secure subdomain with a disabled algorithm
+disabled NS ns3.disabled
+ns3.disabled A 10.53.0.3
+
+; A secure subdomain with a disabled algorithm, but not in bailiwick
+enabled NS ns3.enabled
+ns3.enabled A 10.53.0.3
+
+; A secure subdomain with a revoked trust anchor
+revoked NS ns3.revoked
+ns3.revoked A 10.53.0.3
diff --git a/bin/tests/system/dnssec/ns2/named.conf.in b/bin/tests/system/dnssec/ns2/named.conf.in
new file mode 100644
index 0000000..94928c1
--- /dev/null
+++ b/bin/tests/system/dnssec/ns2/named.conf.in
@@ -0,0 +1,205 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * SPDX-License-Identifier: MPL-2.0
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, you can obtain one at https://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+// NS2
+
+options {
+ query-source address 10.53.0.2;
+ notify-source 10.53.0.2;
+ transfer-source 10.53.0.2;
+ port @PORT@;
+ pid-file "named.pid";
+ listen-on { 10.53.0.2; };
+ listen-on-v6 { none; };
+ recursion no;
+ notify yes;
+ dnssec-validation yes;
+ notify-delay 1;
+ minimal-responses no;
+};
+
+key rndc_key {
+ secret "1234abcd8765";
+ algorithm @DEFAULT_HMAC@;
+};
+
+controls {
+ inet 10.53.0.2 port @CONTROLPORT@ allow { any; } keys { rndc_key; };
+};
+
+zone "." {
+ type hint;
+ file "../../common/root.hint";
+};
+
+zone "trusted" {
+ type primary;
+ file "trusted.db.signed";
+};
+
+zone "managed" {
+ type primary;
+ file "managed.db.signed";
+};
+
+zone "example" {
+ type primary;
+ file "example.db.signed";
+ allow-update { any; };
+};
+
+zone "insecure.secure.example" {
+ type primary;
+ file "insecure.secure.example.db";
+ allow-update { any; };
+};
+
+zone "rfc2335.example" {
+ type primary;
+ file "rfc2335.example.db";
+};
+
+zone "child.nsec3.example" {
+ type primary;
+ file "child.nsec3.example.db";
+ allow-update { none; };
+};
+
+zone "child.optout.example" {
+ type primary;
+ file "child.optout.example.db";
+ allow-update { none; };
+};
+
+zone "badparam" {
+ type primary;
+ file "badparam.db.bad";
+};
+
+zone "single-nsec3" {
+ type primary;
+ file "single-nsec3.db.signed";
+};
+
+zone "algroll" {
+ type primary;
+ file "algroll.db.signed";
+};
+
+zone "nsec3chain-test" {
+ type primary;
+ file "nsec3chain-test.db.signed";
+ allow-update {any;};
+};
+
+zone "in-addr.arpa" {
+ type primary;
+ file "in-addr.arpa.db.signed";
+};
+
+zone "cds.secure" {
+ type primary;
+ file "cds.secure.db.signed";
+};
+
+zone "cds-x.secure" {
+ type primary;
+ file "cds-x.secure.db.signed";
+};
+
+zone "cds-update.secure" {
+ type primary;
+ dnssec-dnskey-kskonly no;
+ file "cds-update.secure.db.signed";
+ allow-update { any; };
+};
+
+zone "cds-kskonly.secure" {
+ type primary;
+ dnssec-dnskey-kskonly yes;
+ file "cds-kskonly.secure.db.signed";
+ allow-update { any; };
+};
+
+zone "cds-auto.secure" {
+ type primary;
+ dnssec-dnskey-kskonly no;
+ file "cds-auto.secure.db.signed";
+ auto-dnssec maintain;
+ allow-update { any; };
+};
+
+zone "cdnskey.secure" {
+ type primary;
+ file "cdnskey.secure.db.signed";
+};
+
+zone "cdnskey-x.secure" {
+ type primary;
+ file "cdnskey-x.secure.db.signed";
+};
+
+zone "cdnskey-update.secure" {
+ type primary;
+ dnssec-dnskey-kskonly no;
+ file "cdnskey-update.secure.db.signed";
+ allow-update { any; };
+};
+
+zone "cdnskey-kskonly.secure" {
+ type primary;
+ dnssec-dnskey-kskonly yes;
+ file "cdnskey-kskonly.secure.db.signed";
+ allow-update { any; };
+};
+
+zone "cdnskey-auto.secure" {
+ type primary;
+ dnssec-dnskey-kskonly no;
+ file "cdnskey-auto.secure.db.signed";
+ auto-dnssec maintain;
+ allow-update { any; };
+};
+
+zone "updatecheck-kskonly.secure" {
+ type primary;
+ auto-dnssec maintain;
+ key-directory ".";
+ dnssec-dnskey-kskonly yes;
+ update-check-ksk yes;
+ sig-validity-interval 10;
+ dnskey-sig-validity 40;
+ file "updatecheck-kskonly.secure.db.signed";
+ allow-update { any; };
+};
+
+zone "corp" {
+ type primary;
+ file "corp.db";
+};
+
+zone "hours-vs-days" {
+ type primary;
+ file "hours-vs-days.db.signed";
+ auto-dnssec maintain;
+ /* validity 500 days, resign in 499 days */
+ sig-validity-interval 500 499;
+ allow-update { any; };
+};
+
+zone "too-many-iterations" {
+ type primary;
+ file "too-many-iterations.db.signed";
+};
+
+include "trusted.conf";
diff --git a/bin/tests/system/dnssec/ns2/private.secure.example.db.in b/bin/tests/system/dnssec/ns2/private.secure.example.db.in
new file mode 100644
index 0000000..94042ae
--- /dev/null
+++ b/bin/tests/system/dnssec/ns2/private.secure.example.db.in
@@ -0,0 +1,28 @@
+; Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+;
+; SPDX-License-Identifier: MPL-2.0
+;
+; This Source Code Form is subject to the terms of the Mozilla Public
+; License, v. 2.0. If a copy of the MPL was not distributed with this
+; file, you can obtain one at https://mozilla.org/MPL/2.0/.
+;
+; See the COPYRIGHT file distributed with this work for additional
+; information regarding copyright ownership.
+
+$TTL 300 ; 5 minutes
+@ IN SOA mname1. . (
+ 2000042407 ; serial
+ 20 ; refresh (20 seconds)
+ 20 ; retry (20 seconds)
+ 1814400 ; expire (3 weeks)
+ 3600 ; minimum (1 hour)
+ )
+ NS ns
+ns A 10.53.0.2
+
+a A 10.0.0.1
+b A 10.0.0.2
+d A 10.0.0.4
+z A 10.0.0.26
+private2secure-nxdomain CNAME r.example.
+*.wild CNAME s.example.
diff --git a/bin/tests/system/dnssec/ns2/rfc2335.example.db b/bin/tests/system/dnssec/ns2/rfc2335.example.db
new file mode 100644
index 0000000..78e9326
--- /dev/null
+++ b/bin/tests/system/dnssec/ns2/rfc2335.example.db
@@ -0,0 +1,114 @@
+; Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+;
+; SPDX-License-Identifier: MPL-2.0
+;
+; This Source Code Form is subject to the terms of the Mozilla Public
+; License, v. 2.0. If a copy of the MPL was not distributed with this
+; file, you can obtain one at https://mozilla.org/MPL/2.0/.
+;
+; See the COPYRIGHT file distributed with this work for additional
+; information regarding copyright ownership.
+
+; File written on Fri Apr 30 12:19:15 2004
+; dnssec_signzone version 9.2.4rc3
+rfc2335.example. 300 IN SOA mname1. . (
+ 2000042407 ; serial
+ 20 ; refresh (20 seconds)
+ 20 ; retry (20 seconds)
+ 1814400 ; expire (3 weeks)
+ 3600 ; minimum (1 hour)
+ )
+ 300 SIG SOA 1 2 300 20040530021915 (
+ 20040430021915 47799 rfc2335.example.
+ nGPJKIzF7X/hMJbZURRz59UeEi/6HRxCn9Er
+ GqSnpw0Ea9Yx5Axu6sLKnF7jXlkZ6NHMCIpJ
+ +Lv+FDHXTs/dQg== )
+ 300 NS ns.rfc2335.example.
+ 300 SIG NS 1 2 300 20040530021915 (
+ 20040430021915 47799 rfc2335.example.
+ Q234AL9dJYMvxdWG33lpww6AJ3GplKp+ace7
+ MUaj0oqDdkx4DtJF2XaP2xcqq7kTOObdQ8ES
+ vVxNThqOx7LFzg== )
+ 300 KEY 256 3 1 (
+ AQPZhzXIabI8y5ihWUw7F0WxN2MabnYWkOcV
+ Fn11NgaGSdjBSYPRMMwMCasD5N2KYPRUP83W
+ y8mj+ofcoW1FurcZ
+ ) ; key id = 47799
+ 300 NXT a.rfc2335.example. NS SOA SIG KEY NXT
+ 300 SIG NXT 1 2 300 20040530021915 (
+ 20040430021915 47799 rfc2335.example.
+ Y587mqNy6pBEfbsU6+weM2XRSqLwLwRT9Sl7
+ oNuOK9kV3TR4R2M54m2S0MgJCXbRAwU+fF8Q
+ UbZkSTVe2N8Nyg== )
+a.rfc2335.example. 300 IN A 10.0.0.1
+ 300 SIG A 1 3 300 20040530021915 (
+ 20040430021915 47799 rfc2335.example.
+ FnfWrcw5ire8ut25504zti5l///BdDMUAkJZ
+ UCLFiTW4lBGMcq1pqz64zltDZXCgJ3xUeQ2i
+ nRt19/ZxO6Z1KA== )
+ 300 NXT b.rfc2335.example. A SIG NXT
+ 300 SIG NXT 1 3 300 20040530021915 (
+ 20040430021915 47799 rfc2335.example.
+ R6SpC3ndMVg4u/eZaaUsXSuMHV/hZXeaM/Op
+ bJLAe3KxMiOHfb6XgLy7wflAiC1xt6A9bWpy
+ kTc5T5gfic33kA== )
+b.rfc2335.example. 300 IN A 10.0.0.2
+ 300 SIG A 1 3 300 20040530021915 (
+ 20040430021915 47799 rfc2335.example.
+ zjRsYXMGyhDI6ipDtu8YXC9XPN+3hGamzzxL
+ 8uPE/LPo+x19MNdbzEgWzlajAf1/mkSGr2jN
+ BDMVBA5NMKpwAA== )
+ 300 NXT d.rfc2335.example. A SIG NXT
+ 300 SIG NXT 1 3 300 20040530021915 (
+ 20040430021915 47799 rfc2335.example.
+ aV87iZCYsC5Tqop827Zzb18TNqopGt0QynkR
+ gIF/lIHqZasNFRfaS1/nTnXdDKD8JS5IqxKb
+ oTJr5zswDAtCEw== )
+d.rfc2335.example. 300 IN A 10.0.0.4
+ 300 SIG A 1 3 300 20040530021915 (
+ 20040430021915 47799 rfc2335.example.
+ NsKyvhUYZxTbOTBX4YwxTxevI5iGBpULKwmt
+ +D4l00ME4XRygOVmiqVDTT9dF1EgjDxOdfMT
+ hSjtCh5M1b2f6g== )
+ 300 NXT ns.rfc2335.example. A SIG NXT
+ 300 SIG NXT 1 3 300 20040530021915 (
+ 20040430021915 47799 rfc2335.example.
+ OGqlvSDZIZdHYigh4UAFzXfPze7vcQfgj7sN
+ +cAeoh4BL1gpa00DqANCxowNCYluDk3ZCDwt
+ UHZEJa8ZjNvv4g== )
+ns.rfc2335.example. 300 IN A 10.53.0.3
+ 300 SIG A 1 3 300 20040530021915 (
+ 20040430021915 47799 rfc2335.example.
+ T6ZGeUWflLTku8jO23x/TeAPeUl8t0I18FCh
+ qHUZaHomLQasQ2jlZQn6cLpFd2uFJkBNxZ0G
+ I39aG7G1bObXdA== )
+ 300 NXT x.rfc2335.example. A SIG NXT
+ 300 SIG NXT 1 3 300 20040530021915 (
+ 20040430021915 47799 rfc2335.example.
+ l46mrf3/Ii5iRm3AiDjYeMg4ZXBgitHxXA2y
+ e/NhKpkxRRpCs7UQ94wT/RiSCjjK49E5FBe6
+ 5bRxtWq0GI7zlg== )
+x.rfc2335.example. 300 IN CNAME a.rfc2335.example.
+ 300 SIG CNAME 1 3 300 20040530021915 (
+ 20040430021915 47799 rfc2335.example.
+ L3IOluq+kboBd2gR2Mu54uJKCUzfmyHRiWKl
+ kfx+vuFr0I8mEHQRmJtouxNDrBzmzGp5vybK
+ SdabLWw0n6uQEA== )
+ 300 NXT z.rfc2335.example. CNAME SIG NXT
+ 300 SIG NXT 1 3 300 20040530021915 (
+ 20040430021915 47799 rfc2335.example.
+ CBKoJSkZzdpwiON7JS4yPFY5VVeBjfT19x/O
+ vx+5UK1JZUNKhTXWWgW1er+JlLzNf4Ot40+l
+ z9HUTyaeS0eWyw== )
+z.rfc2335.example. 300 IN A 10.0.0.26
+ 300 SIG A 1 3 300 20040530021915 (
+ 20040430021915 47799 rfc2335.example.
+ ccqjVHnehvVwlNNd4+7n/GzGlRjj+ul0gCT3
+ X3950LTccxHsOFyjNNm8v/Ho/aurSYdqXEjY
+ jwmjC6elwkzB7A== )
+ 300 NXT rfc2335.example. A SIG NXT
+ 300 SIG NXT 1 3 300 20040530021915 (
+ 20040430021915 47799 rfc2335.example.
+ W42WoFyd9erysv8HjKo+CpHIH1x6+pAKwCDO
+ /hHnkEpQI3brewxl7cWOPYeA92Ns80Ody/ui
+ m2E28A5gnmWqPw== )
diff --git a/bin/tests/system/dnssec/ns2/sign.sh b/bin/tests/system/dnssec/ns2/sign.sh
new file mode 100644
index 0000000..47248a4
--- /dev/null
+++ b/bin/tests/system/dnssec/ns2/sign.sh
@@ -0,0 +1,332 @@
+#!/bin/sh -e
+
+# Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+#
+# SPDX-License-Identifier: MPL-2.0
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, you can obtain one at https://mozilla.org/MPL/2.0/.
+#
+# See the COPYRIGHT file distributed with this work for additional
+# information regarding copyright ownership.
+
+# shellcheck source=conf.sh
+. ../../conf.sh
+
+set -e
+
+# Sign child zones (served by ns3).
+( cd ../ns3 && $SHELL sign.sh )
+
+echo_i "ns2/sign.sh"
+
+# Get the DS records for the "trusted." and "managed." zones.
+for subdomain in secure unsupported disabled enabled
+do
+ cp "../ns3/dsset-$subdomain.managed." .
+ cp "../ns3/dsset-$subdomain.trusted." .
+done
+
+# Sign the "trusted." and "managed." zones.
+zone=managed.
+infile=key.db.in
+zonefile=managed.db
+
+keyname1=$("$KEYGEN" -q -a "$ALTERNATIVE_ALGORITHM" -b "$ALTERNATIVE_BITS" -n zone -f KSK "$zone")
+keyname2=$("$KEYGEN" -q -a "$ALTERNATIVE_ALGORITHM" -b "$ALTERNATIVE_BITS" -n zone "$zone")
+
+cat "$infile" "$keyname1.key" "$keyname2.key" > "$zonefile"
+
+"$SIGNER" -g -o "$zone" -k "$keyname1" "$zonefile" "$keyname2" > /dev/null 2>&1
+
+zone=trusted.
+infile=key.db.in
+zonefile=trusted.db
+
+keyname1=$("$KEYGEN" -q -a "$ALTERNATIVE_ALGORITHM" -b "$ALTERNATIVE_BITS" -n zone -f KSK "$zone")
+keyname2=$("$KEYGEN" -q -a "$ALTERNATIVE_ALGORITHM" -b "$ALTERNATIVE_BITS" -n zone "$zone")
+
+cat "$infile" "$keyname1.key" "$keyname2.key" > "$zonefile"
+
+"$SIGNER" -g -o "$zone" -k "$keyname1" "$zonefile" "$keyname2" > /dev/null 2>&1
+
+# The "example." zone.
+zone=example.
+infile=example.db.in
+zonefile=example.db
+
+# Get the DS records for the "example." zone.
+for subdomain in secure badds bogus dynamic keyless nsec3 optout \
+ nsec3-unknown optout-unknown multiple rsasha256 rsasha512 \
+ kskonly update-nsec3 auto-nsec auto-nsec3 secure.below-cname \
+ ttlpatch split-dnssec split-smart expired expiring upper lower \
+ dnskey-unknown dnskey-unsupported dnskey-unsupported-2 \
+ dnskey-nsec3-unknown managed-future revkey \
+ dname-at-apex-nsec3 occluded
+do
+ cp "../ns3/dsset-$subdomain.example." .
+done
+
+# Sign the "example." zone.
+keyname1=$("$KEYGEN" -q -a "$ALTERNATIVE_ALGORITHM" -b "$ALTERNATIVE_BITS" -n zone -f KSK "$zone")
+keyname2=$("$KEYGEN" -q -a "$ALTERNATIVE_ALGORITHM" -b "$ALTERNATIVE_BITS" -n zone "$zone")
+
+cat "$infile" "$keyname1.key" "$keyname2.key" > "$zonefile"
+
+"$SIGNER" -g -o "$zone" -k "$keyname1" "$zonefile" "$keyname2" > /dev/null 2>&1
+
+#
+# lower/uppercase the signature bits with the exception of the last characters
+# changing the last 4 characters will lead to a bad base64 encoding.
+#
+
+zonefiletmp=$(mktemp "$zonefile.XXXXXX") || exit 1
+"$CHECKZONE" -D -q -i local "$zone" "$zonefile.signed" |
+awk '
+tolower($1) == "bad-cname.example." && $4 == "RRSIG" && $5 == "CNAME" {
+ for (i = 1; i <= NF; i++ ) {
+ if (i <= 12) {
+ printf("%s ", $i);
+ continue;
+ }
+ prefix = substr($i, 1, length($i) - 4);
+ suffix = substr($i, length($i) - 4, 4);
+ if (i > 12 && tolower(prefix) != prefix)
+ printf("%s%s", tolower(prefix), suffix);
+ else if (i > 12 && toupper(prefix) != prefix)
+ printf("%s%s", toupper(prefix), suffix);
+ else
+ printf("%s%s ", prefix, suffix);
+ }
+ printf("\n");
+ next;
+}
+
+tolower($1) == "bad-dname.example." && $4 == "RRSIG" && $5 == "DNAME" {
+ for (i = 1; i <= NF; i++ ) {
+ if (i <= 12) {
+ printf("%s ", $i);
+ continue;
+ }
+ prefix = substr($i, 1, length($i) - 4);
+ suffix = substr($i, length($i) - 4, 4);
+ if (i > 12 && tolower(prefix) != prefix)
+ printf("%s%s", tolower(prefix), suffix);
+ else if (i > 12 && toupper(prefix) != prefix)
+ printf("%s%s", toupper(prefix), suffix);
+ else
+ printf("%s%s ", prefix, suffix);
+ }
+ printf("\n");
+ next;
+}
+
+{ print; }' > "$zonefiletmp" && mv "$zonefiletmp" "$zonefile.signed"
+
+#
+# signed in-addr.arpa w/ a delegation for 10.in-addr.arpa which is unsigned.
+#
+zone=in-addr.arpa.
+infile=in-addr.arpa.db.in
+zonefile=in-addr.arpa.db
+
+keyname1=$("$KEYGEN" -q -a "$DEFAULT_ALGORITHM" -b "$DEFAULT_BITS" -n zone -f KSK "$zone")
+keyname2=$("$KEYGEN" -q -a "$DEFAULT_ALGORITHM" -b "$DEFAULT_BITS" -n zone "$zone")
+
+cat "$infile" "$keyname1.key" "$keyname2.key" > "$zonefile"
+"$SIGNER" -g -o "$zone" -k "$keyname1" "$zonefile" "$keyname2" > /dev/null 2>&1
+
+# Sign the badparam secure file
+
+zone=badparam.
+infile=badparam.db.in
+zonefile=badparam.db
+
+keyname1=$("$KEYGEN" -q -a "$DEFAULT_ALGORITHM" -b "$DEFAULT_BITS" -n zone -f KSK "$zone")
+keyname2=$("$KEYGEN" -q -a "$DEFAULT_ALGORITHM" -b "$DEFAULT_BITS" -n zone "$zone")
+
+cat "$infile" "$keyname1.key" "$keyname2.key" > "$zonefile"
+
+"$SIGNER" -3 - -H 1 -g -o "$zone" -k "$keyname1" "$zonefile" "$keyname2" > /dev/null 2>&1
+
+sed -e 's/IN NSEC3 1 0 1 /IN NSEC3 1 0 10 /' "$zonefile.signed" > "$zonefile.bad"
+
+# Sign the single-nsec3 secure zone with optout
+
+zone=single-nsec3.
+infile=single-nsec3.db.in
+zonefile=single-nsec3.db
+
+keyname1=$("$KEYGEN" -q -a "$DEFAULT_ALGORITHM" -b "$DEFAULT_BITS" -n zone -f KSK "$zone")
+keyname2=$("$KEYGEN" -q -a "$DEFAULT_ALGORITHM" -b "$DEFAULT_BITS" -n zone "$zone")
+
+cat "$infile" "$keyname1.key" "$keyname2.key" > "$zonefile"
+
+"$SIGNER" -3 - -A -H 1 -g -o "$zone" -k "$keyname1" "$zonefile" "$keyname2" > /dev/null 2>&1
+
+#
+# algroll has just has the old DNSKEY records removed and is waiting
+# for them to be flushed from caches. We still need to generate
+# RRSIGs for the old DNSKEY.
+#
+zone=algroll.
+infile=algroll.db.in
+zonefile=algroll.db
+
+keyold1=$("$KEYGEN" -q -a "$ALTERNATIVE_ALGORITHM" -b "$ALTERNATIVE_BITS" -n zone -f KSK "$zone")
+keyold2=$("$KEYGEN" -q -a "$ALTERNATIVE_ALGORITHM" -b "$ALTERNATIVE_BITS" -n zone "$zone")
+keynew1=$("$KEYGEN" -q -a "$DEFAULT_ALGORITHM" -b "$DEFAULT_BITS" -n zone -f KSK "$zone")
+keynew2=$("$KEYGEN" -q -a "$DEFAULT_ALGORITHM" -b "$DEFAULT_BITS" -n zone "$zone")
+
+cat "$infile" "$keynew1.key" "$keynew2.key" > "$zonefile"
+
+"$SIGNER" -o "$zone" -k "$keyold1" -k "$keynew1" "$zonefile" "$keyold1" "$keyold2" "$keynew1" "$keynew2" > /dev/null 2>&1
+
+#
+# Make a zone big enough that it takes several seconds to generate a new
+# nsec3 chain.
+#
+zone=nsec3chain-test
+zonefile=nsec3chain-test.db
+cat > "$zonefile" << EOF
+\$TTL 10
+@ 10 SOA ns2 hostmaster 0 3600 1200 864000 1200
+@ 10 NS ns2
+@ 10 NS ns3
+ns2 10 A 10.53.0.2
+ns3 10 A 10.53.0.3
+EOF
+i=1
+while [ $i -le 300 ]; do
+ echo "host$i 10 IN NS ns.elsewhere"
+ i=$((i+1))
+done >> "$zonefile"
+key1=$("$KEYGEN" -q -a "$DEFAULT_ALGORITHM" -b "$DEFAULT_BITS" -n zone -f KSK "$zone")
+key2=$("$KEYGEN" -q -a "$DEFAULT_ALGORITHM" -b "$DEFAULT_BITS" -n zone "$zone")
+cat "$key1.key" "$key2.key" >> "$zonefile"
+"$SIGNER" -3 - -A -H 1 -g -o "$zone" -k "$key1" "$zonefile" "$key2" > /dev/null 2>&1
+
+zone=cds.secure
+infile=cds.secure.db.in
+zonefile=cds.secure.db
+key1=$("$KEYGEN" -q -a "$DEFAULT_ALGORITHM" -b "$DEFAULT_BITS" -n zone -f KSK "$zone")
+key2=$("$KEYGEN" -q -a "$DEFAULT_ALGORITHM" -b "$DEFAULT_BITS" -n zone "$zone")
+"$DSFROMKEY" -C "$key1.key" > "$key1.cds"
+cat "$infile" "$key1.key" "$key2.key" "$key1.cds" >$zonefile
+"$SIGNER" -g -o "$zone" "$zonefile" > /dev/null 2>&1
+
+zone=cds-x.secure
+infile=cds.secure.db.in
+zonefile=cds-x.secure.db
+key1=$("$KEYGEN" -q -a "$DEFAULT_ALGORITHM" -b "$DEFAULT_BITS" -n zone -f KSK "$zone")
+key2=$("$KEYGEN" -q -a "$DEFAULT_ALGORITHM" -b "$DEFAULT_BITS" -n zone -f KSK "$zone")
+key3=$("$KEYGEN" -q -a "$DEFAULT_ALGORITHM" -b "$DEFAULT_BITS" -n zone "$zone")
+"$DSFROMKEY" -C "$key2.key" > "$key2.cds"
+cat "$infile" "$key1.key" "$key2.key" "$key3.key" "$key2.cds" > "$zonefile"
+"$SIGNER" -g -x -o "$zone" "$zonefile" > /dev/null 2>&1
+
+zone=cds-update.secure
+infile=cds-update.secure.db.in
+zonefile=cds-update.secure.db
+key1=$("$KEYGEN" -q -a "$DEFAULT_ALGORITHM" -b "$DEFAULT_BITS" -n zone -f KSK "$zone")
+key2=$("$KEYGEN" -q -a "$DEFAULT_ALGORITHM" -b "$DEFAULT_BITS" -n zone "$zone")
+cat "$infile" "$key1.key" "$key2.key" > "$zonefile"
+"$SIGNER" -g -o "$zone" "$zonefile" > /dev/null 2>&1
+
+zone=cds-kskonly.secure
+infile=cds-kskonly.secure.db.in
+zonefile=cds-kskonly.secure.db
+key1=$("$KEYGEN" -q -a "$DEFAULT_ALGORITHM" -b "$DEFAULT_BITS" -n zone -f KSK "$zone")
+key2=$("$KEYGEN" -q -a "$DEFAULT_ALGORITHM" -b "$DEFAULT_BITS" -n zone "$zone")
+cat "$infile" "$key1.key" "$key2.key" > "$zonefile"
+"$SIGNER" -g -o "$zone" "$zonefile" > /dev/null 2>&1
+keyfile_to_key_id "$key1" > cds-kskonly.secure.id
+
+zone=cds-auto.secure
+infile=cds-auto.secure.db.in
+zonefile=cds-auto.secure.db
+key1=$("$KEYGEN" -q -a "$DEFAULT_ALGORITHM" -b "$DEFAULT_BITS" -n zone -f KSK "$zone")
+key2=$("$KEYGEN" -q -a "$DEFAULT_ALGORITHM" -b "$DEFAULT_BITS" -n zone "$zone")
+$SETTIME -P sync now "$key1" > /dev/null
+cat "$infile" > "$zonefile.signed"
+
+zone=cdnskey.secure
+infile=cdnskey.secure.db.in
+zonefile=cdnskey.secure.db
+key1=$("$KEYGEN" -q -a "$DEFAULT_ALGORITHM" -b "$DEFAULT_BITS" -n zone -f KSK "$zone")
+key2=$("$KEYGEN" -q -a "$DEFAULT_ALGORITHM" -b "$DEFAULT_BITS" -n zone "$zone")
+sed 's/DNSKEY/CDNSKEY/' "$key1.key" > "$key1.cds"
+cat "$infile" "$key1.key" "$key2.key" "$key1.cds" > "$zonefile"
+"$SIGNER" -g -o "$zone" "$zonefile" > /dev/null 2>&1
+
+zone=cdnskey-x.secure
+infile=cdnskey.secure.db.in
+zonefile=cdnskey-x.secure.db
+key1=$("$KEYGEN" -q -a "$DEFAULT_ALGORITHM" -b "$DEFAULT_BITS" -n zone -f KSK "$zone")
+key2=$("$KEYGEN" -q -a "$DEFAULT_ALGORITHM" -b "$DEFAULT_BITS" -n zone -f KSK "$zone")
+key3=$("$KEYGEN" -q -a "$DEFAULT_ALGORITHM" -b "$DEFAULT_BITS" -n zone "$zone")
+sed 's/DNSKEY/CDNSKEY/' "$key1.key" > "$key1.cds"
+cat "$infile" "$key1.key" "$key2.key" "$key3.key" "$key1.cds" > "$zonefile"
+"$SIGNER" -g -x -o "$zone" "$zonefile" > /dev/null 2>&1
+
+zone=cdnskey-update.secure
+infile=cdnskey-update.secure.db.in
+zonefile=cdnskey-update.secure.db
+key1=$("$KEYGEN" -q -a "$DEFAULT_ALGORITHM" -b "$DEFAULT_BITS" -n zone -f KSK "$zone")
+key2=$("$KEYGEN" -q -a "$DEFAULT_ALGORITHM" -b "$DEFAULT_BITS" -n zone "$zone")
+cat "$infile" "$key1.key" "$key2.key" > "$zonefile"
+"$SIGNER" -g -o "$zone" "$zonefile" > /dev/null 2>&1
+
+zone=cdnskey-kskonly.secure
+infile=cdnskey-kskonly.secure.db.in
+zonefile=cdnskey-kskonly.secure.db
+key1=$("$KEYGEN" -q -a "$DEFAULT_ALGORITHM" -b "$DEFAULT_BITS" -n zone -f KSK "$zone")
+key2=$("$KEYGEN" -q -a "$DEFAULT_ALGORITHM" -b "$DEFAULT_BITS" -n zone "$zone")
+cat "$infile" "$key1.key" "$key2.key" > "$zonefile"
+"$SIGNER" -g -o "$zone" "$zonefile" > /dev/null 2>&1
+keyfile_to_key_id "$key1" > cdnskey-kskonly.secure.id
+
+zone=cdnskey-auto.secure
+infile=cdnskey-auto.secure.db.in
+zonefile=cdnskey-auto.secure.db
+key1=$("$KEYGEN" -q -a "$DEFAULT_ALGORITHM" -b "$DEFAULT_BITS" -n zone -f KSK "$zone")
+key2=$("$KEYGEN" -q -a "$DEFAULT_ALGORITHM" -b "$DEFAULT_BITS" -n zone "$zone")
+$SETTIME -P sync now "$key1" > /dev/null
+cat "$infile" > "$zonefile.signed"
+
+zone=updatecheck-kskonly.secure
+infile=template.secure.db.in
+zonefile=${zone}.db
+key1=$("$KEYGEN" -q -a "$DEFAULT_ALGORITHM" -b "$DEFAULT_BITS" -n zone -f KSK "$zone")
+key2=$("$KEYGEN" -q -a "$DEFAULT_ALGORITHM" -b "$DEFAULT_BITS" -n zone "$zone")
+# Save key id's for checking active key usage
+keyfile_to_key_id "$key1" > $zone.ksk.id
+keyfile_to_key_id "$key2" > $zone.zsk.id
+echo "${key1}" > $zone.ksk.key
+echo "${key2}" > $zone.zsk.key
+# Add CDS and CDNSKEY records
+sed 's/DNSKEY/CDNSKEY/' "$key1.key" > "$key1.cdnskey"
+"$DSFROMKEY" -C "$key1.key" > "$key1.cds"
+cat "$infile" "$key1.key" "$key2.key" "$key1.cdnskey" "$key1.cds" > "$zonefile"
+# Don't sign, let auto-dnssec maintain do it.
+mv $zonefile "$zonefile.signed"
+
+zone=hours-vs-days
+infile=hours-vs-days.db.in
+zonefile=hours-vs-days.db
+key1=$("$KEYGEN" -q -a "$DEFAULT_ALGORITHM" -b "$DEFAULT_BITS" -n zone -f KSK "$zone")
+key2=$("$KEYGEN" -q -a "$DEFAULT_ALGORITHM" -b "$DEFAULT_BITS" -n zone "$zone")
+$SETTIME -P sync now "$key1" > /dev/null
+cat "$infile" > "$zonefile.signed"
+
+#
+# Negative result from this zone should come back as insecure.
+#
+zone=too-many-iterations
+infile=too-many-iterations.db.in
+zonefile=too-many-iterations.db
+key1=$("$KEYGEN" -q -a "$DEFAULT_ALGORITHM" -b "$DEFAULT_BITS" -n zone -f KSK "$zone")
+key2=$("$KEYGEN" -q -a "$DEFAULT_ALGORITHM" -b "$DEFAULT_BITS" -n zone "$zone")
+cat "$infile" "$key1.key" "$key2.key" > "$zonefile"
+"$SIGNER" -P -3 - -H too-many -g -o "$zone" "$zonefile" > /dev/null 2>&1
diff --git a/bin/tests/system/dnssec/ns2/single-nsec3.db.in b/bin/tests/system/dnssec/ns2/single-nsec3.db.in
new file mode 100644
index 0000000..b2e3c13
--- /dev/null
+++ b/bin/tests/system/dnssec/ns2/single-nsec3.db.in
@@ -0,0 +1,21 @@
+; Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+;
+; SPDX-License-Identifier: MPL-2.0
+;
+; This Source Code Form is subject to the terms of the Mozilla Public
+; License, v. 2.0. If a copy of the MPL was not distributed with this
+; file, you can obtain one at https://mozilla.org/MPL/2.0/.
+;
+; See the COPYRIGHT file distributed with this work for additional
+; information regarding copyright ownership.
+
+$TTL 300 ; 5 minutes
+@ IN SOA ns2.example. . (
+ 2010042407 ; serial
+ 20 ; refresh (20 seconds)
+ 20 ; retry (20 seconds)
+ 1814400 ; expire (3 weeks)
+ 3600 ; minimum (1 hour)
+ )
+ NS ns2.example.
+delegation NS ns3.example.
diff --git a/bin/tests/system/dnssec/ns2/template.secure.db.in b/bin/tests/system/dnssec/ns2/template.secure.db.in
new file mode 100644
index 0000000..aa3aaab
--- /dev/null
+++ b/bin/tests/system/dnssec/ns2/template.secure.db.in
@@ -0,0 +1,14 @@
+; Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+;
+; SPDX-License-Identifier: MPL-2.0
+;
+; This Source Code Form is subject to the terms of the Mozilla Public
+; License, v. 2.0. If a copy of the MPL was not distributed with this
+; file, you can obtain one at https://mozilla.org/MPL/2.0/.
+;
+; See the COPYRIGHT file distributed with this work for additional
+; information regarding copyright ownership.
+
+$TTL 3600
+@ SOA ns2.example. . 1 3600 1200 86400 1200
+@ NS ns2.example.
diff --git a/bin/tests/system/dnssec/ns2/too-many-iterations.db.in b/bin/tests/system/dnssec/ns2/too-many-iterations.db.in
new file mode 100644
index 0000000..1527e07
--- /dev/null
+++ b/bin/tests/system/dnssec/ns2/too-many-iterations.db.in
@@ -0,0 +1,27 @@
+; Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+;
+; SPDX-License-Identifier: MPL-2.0
+;
+; This Source Code Form is subject to the terms of the Mozilla Public
+; License, v. 2.0. If a copy of the MPL was not distributed with this
+; file, you can obtain one at https://mozilla.org/MPL/2.0/.
+;
+; See the COPYRIGHT file distributed with this work for additional
+; information regarding copyright ownership.
+
+$TTL 30 ; 5 minutes
+@ IN SOA mname1. . (
+ 2000042407 ; serial
+ 20 ; refresh (20 seconds)
+ 20 ; retry (20 seconds)
+ 1814400 ; expire (3 weeks)
+ 30 ; minimum (1 hour)
+ )
+ NS ns2
+ns2 A 10.53.0.2
+ns3 A 10.53.0.3
+
+a A 10.0.0.1
+*.a A 10.0.0.3
+b A 10.0.0.2
+d A 10.0.0.4
diff --git a/bin/tests/system/dnssec/ns3/auto-nsec.example.db.in b/bin/tests/system/dnssec/ns3/auto-nsec.example.db.in
new file mode 100644
index 0000000..a7792fd
--- /dev/null
+++ b/bin/tests/system/dnssec/ns3/auto-nsec.example.db.in
@@ -0,0 +1,40 @@
+; Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+;
+; SPDX-License-Identifier: MPL-2.0
+;
+; This Source Code Form is subject to the terms of the Mozilla Public
+; License, v. 2.0. If a copy of the MPL was not distributed with this
+; file, you can obtain one at https://mozilla.org/MPL/2.0/.
+;
+; See the COPYRIGHT file distributed with this work for additional
+; information regarding copyright ownership.
+
+$TTL 300 ; 5 minutes
+@ IN SOA mname1. . (
+ 2000042407 ; serial
+ 20 ; refresh (20 seconds)
+ 20 ; retry (20 seconds)
+ 1814400 ; expire (3 weeks)
+ 3600 ; minimum (1 hour)
+ )
+ NS ns
+ns A 10.53.0.3
+
+a A 10.0.0.1
+b A 10.0.0.2
+d A 10.0.0.4
+z A 10.0.0.26
+a.a.a.a.a.a.a.a.a.a.e A 10.0.0.27
+x CNAME a
+
+private NS ns.private
+ns.private A 10.53.0.2
+
+insecure NS ns.insecure
+ns.insecure A 10.53.0.2
+
+nosoa NS ns.nosoa
+ns.nosoa A 10.53.0.7
+
+normalthenrrsig A 10.0.0.28
+rrsigonly A 10.0.0.29
diff --git a/bin/tests/system/dnssec/ns3/auto-nsec3.example.db.in b/bin/tests/system/dnssec/ns3/auto-nsec3.example.db.in
new file mode 100644
index 0000000..a7792fd
--- /dev/null
+++ b/bin/tests/system/dnssec/ns3/auto-nsec3.example.db.in
@@ -0,0 +1,40 @@
+; Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+;
+; SPDX-License-Identifier: MPL-2.0
+;
+; This Source Code Form is subject to the terms of the Mozilla Public
+; License, v. 2.0. If a copy of the MPL was not distributed with this
+; file, you can obtain one at https://mozilla.org/MPL/2.0/.
+;
+; See the COPYRIGHT file distributed with this work for additional
+; information regarding copyright ownership.
+
+$TTL 300 ; 5 minutes
+@ IN SOA mname1. . (
+ 2000042407 ; serial
+ 20 ; refresh (20 seconds)
+ 20 ; retry (20 seconds)
+ 1814400 ; expire (3 weeks)
+ 3600 ; minimum (1 hour)
+ )
+ NS ns
+ns A 10.53.0.3
+
+a A 10.0.0.1
+b A 10.0.0.2
+d A 10.0.0.4
+z A 10.0.0.26
+a.a.a.a.a.a.a.a.a.a.e A 10.0.0.27
+x CNAME a
+
+private NS ns.private
+ns.private A 10.53.0.2
+
+insecure NS ns.insecure
+ns.insecure A 10.53.0.2
+
+nosoa NS ns.nosoa
+ns.nosoa A 10.53.0.7
+
+normalthenrrsig A 10.0.0.28
+rrsigonly A 10.0.0.29
diff --git a/bin/tests/system/dnssec/ns3/bogus.example.db.in b/bin/tests/system/dnssec/ns3/bogus.example.db.in
new file mode 100644
index 0000000..0feb441
--- /dev/null
+++ b/bin/tests/system/dnssec/ns3/bogus.example.db.in
@@ -0,0 +1,27 @@
+; Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+;
+; SPDX-License-Identifier: MPL-2.0
+;
+; This Source Code Form is subject to the terms of the Mozilla Public
+; License, v. 2.0. If a copy of the MPL was not distributed with this
+; file, you can obtain one at https://mozilla.org/MPL/2.0/.
+;
+; See the COPYRIGHT file distributed with this work for additional
+; information regarding copyright ownership.
+
+$TTL 300 ; 5 minutes
+@ IN SOA mname1. . (
+ 2000042407 ; serial
+ 20 ; refresh (20 seconds)
+ 20 ; retry (20 seconds)
+ 1814400 ; expire (3 weeks)
+ 3600 ; minimum (1 hour)
+ )
+ NS ns
+ns A 10.53.0.3
+
+a A 10.0.0.1
+b A 10.0.0.2
+c A 10.0.0.3
+d A 10.0.0.4
+z A 10.0.0.26
diff --git a/bin/tests/system/dnssec/ns3/dname-at-apex-nsec3.example.db.in b/bin/tests/system/dnssec/ns3/dname-at-apex-nsec3.example.db.in
new file mode 100644
index 0000000..e758cdd
--- /dev/null
+++ b/bin/tests/system/dnssec/ns3/dname-at-apex-nsec3.example.db.in
@@ -0,0 +1,15 @@
+; Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+;
+; SPDX-License-Identifier: MPL-2.0
+;
+; This Source Code Form is subject to the terms of the Mozilla Public
+; License, v. 2.0. If a copy of the MPL was not distributed with this
+; file, you can obtain one at https://mozilla.org/MPL/2.0/.
+;
+; See the COPYRIGHT file distributed with this work for additional
+; information regarding copyright ownership.
+
+$TTL 600
+@ SOA ns3.example. . 1 1200 1200 1814400 3600
+@ NS ns3.example.
+@ DNAME example.
diff --git a/bin/tests/system/dnssec/ns3/dnskey-nsec3-unknown.example.db.in b/bin/tests/system/dnssec/ns3/dnskey-nsec3-unknown.example.db.in
new file mode 100644
index 0000000..f37dd75
--- /dev/null
+++ b/bin/tests/system/dnssec/ns3/dnskey-nsec3-unknown.example.db.in
@@ -0,0 +1,29 @@
+; Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+;
+; SPDX-License-Identifier: MPL-2.0
+;
+; This Source Code Form is subject to the terms of the Mozilla Public
+; License, v. 2.0. If a copy of the MPL was not distributed with this
+; file, you can obtain one at https://mozilla.org/MPL/2.0/.
+;
+; See the COPYRIGHT file distributed with this work for additional
+; information regarding copyright ownership.
+
+$TTL 300 ; 5 minutes
+@ IN SOA mname1. . (
+ 2000042407 ; serial
+ 20 ; refresh (20 seconds)
+ 20 ; retry (20 seconds)
+ 1814400 ; expire (3 weeks)
+ 3600 ; minimum (1 hour)
+ )
+ NS ns
+ns A 10.53.0.3
+
+a A 10.0.0.1
+b A 10.0.0.2
+d A 10.0.0.4
+z A 10.0.0.26
+a.a.a.a A 10.0.0.3
+*.e A 10.0.0.6
+child NS ns2.example.
diff --git a/bin/tests/system/dnssec/ns3/dnskey-unknown.example.db.in b/bin/tests/system/dnssec/ns3/dnskey-unknown.example.db.in
new file mode 100644
index 0000000..f37dd75
--- /dev/null
+++ b/bin/tests/system/dnssec/ns3/dnskey-unknown.example.db.in
@@ -0,0 +1,29 @@
+; Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+;
+; SPDX-License-Identifier: MPL-2.0
+;
+; This Source Code Form is subject to the terms of the Mozilla Public
+; License, v. 2.0. If a copy of the MPL was not distributed with this
+; file, you can obtain one at https://mozilla.org/MPL/2.0/.
+;
+; See the COPYRIGHT file distributed with this work for additional
+; information regarding copyright ownership.
+
+$TTL 300 ; 5 minutes
+@ IN SOA mname1. . (
+ 2000042407 ; serial
+ 20 ; refresh (20 seconds)
+ 20 ; retry (20 seconds)
+ 1814400 ; expire (3 weeks)
+ 3600 ; minimum (1 hour)
+ )
+ NS ns
+ns A 10.53.0.3
+
+a A 10.0.0.1
+b A 10.0.0.2
+d A 10.0.0.4
+z A 10.0.0.26
+a.a.a.a A 10.0.0.3
+*.e A 10.0.0.6
+child NS ns2.example.
diff --git a/bin/tests/system/dnssec/ns3/dnskey-unsupported-2.example.db.in b/bin/tests/system/dnssec/ns3/dnskey-unsupported-2.example.db.in
new file mode 100644
index 0000000..f37dd75
--- /dev/null
+++ b/bin/tests/system/dnssec/ns3/dnskey-unsupported-2.example.db.in
@@ -0,0 +1,29 @@
+; Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+;
+; SPDX-License-Identifier: MPL-2.0
+;
+; This Source Code Form is subject to the terms of the Mozilla Public
+; License, v. 2.0. If a copy of the MPL was not distributed with this
+; file, you can obtain one at https://mozilla.org/MPL/2.0/.
+;
+; See the COPYRIGHT file distributed with this work for additional
+; information regarding copyright ownership.
+
+$TTL 300 ; 5 minutes
+@ IN SOA mname1. . (
+ 2000042407 ; serial
+ 20 ; refresh (20 seconds)
+ 20 ; retry (20 seconds)
+ 1814400 ; expire (3 weeks)
+ 3600 ; minimum (1 hour)
+ )
+ NS ns
+ns A 10.53.0.3
+
+a A 10.0.0.1
+b A 10.0.0.2
+d A 10.0.0.4
+z A 10.0.0.26
+a.a.a.a A 10.0.0.3
+*.e A 10.0.0.6
+child NS ns2.example.
diff --git a/bin/tests/system/dnssec/ns3/dnskey-unsupported.example.db.in b/bin/tests/system/dnssec/ns3/dnskey-unsupported.example.db.in
new file mode 100644
index 0000000..f37dd75
--- /dev/null
+++ b/bin/tests/system/dnssec/ns3/dnskey-unsupported.example.db.in
@@ -0,0 +1,29 @@
+; Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+;
+; SPDX-License-Identifier: MPL-2.0
+;
+; This Source Code Form is subject to the terms of the Mozilla Public
+; License, v. 2.0. If a copy of the MPL was not distributed with this
+; file, you can obtain one at https://mozilla.org/MPL/2.0/.
+;
+; See the COPYRIGHT file distributed with this work for additional
+; information regarding copyright ownership.
+
+$TTL 300 ; 5 minutes
+@ IN SOA mname1. . (
+ 2000042407 ; serial
+ 20 ; refresh (20 seconds)
+ 20 ; retry (20 seconds)
+ 1814400 ; expire (3 weeks)
+ 3600 ; minimum (1 hour)
+ )
+ NS ns
+ns A 10.53.0.3
+
+a A 10.0.0.1
+b A 10.0.0.2
+d A 10.0.0.4
+z A 10.0.0.26
+a.a.a.a A 10.0.0.3
+*.e A 10.0.0.6
+child NS ns2.example.
diff --git a/bin/tests/system/dnssec/ns3/dynamic.example.db.in b/bin/tests/system/dnssec/ns3/dynamic.example.db.in
new file mode 100644
index 0000000..babf54c
--- /dev/null
+++ b/bin/tests/system/dnssec/ns3/dynamic.example.db.in
@@ -0,0 +1,25 @@
+; Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+;
+; SPDX-License-Identifier: MPL-2.0
+;
+; This Source Code Form is subject to the terms of the Mozilla Public
+; License, v. 2.0. If a copy of the MPL was not distributed with this
+; file, you can obtain one at https://mozilla.org/MPL/2.0/.
+;
+; See the COPYRIGHT file distributed with this work for additional
+; information regarding copyright ownership.
+
+; This has the NS and glue at the apex because testing RT #2399
+; requires we have only one name in the zone at a certain point
+; during the test.
+
+$TTL 300 ; 5 minutes
+@ IN SOA mname1. . (
+ 2000042407 ; serial
+ 20 ; refresh (20 seconds)
+ 20 ; retry (20 seconds)
+ 1814400 ; expire (3 weeks)
+ 3600 ; minimum (1 hour)
+ )
+@ NS @
+@ A 10.53.0.3
diff --git a/bin/tests/system/dnssec/ns3/expired.example.db.in b/bin/tests/system/dnssec/ns3/expired.example.db.in
new file mode 100644
index 0000000..b7706d3
--- /dev/null
+++ b/bin/tests/system/dnssec/ns3/expired.example.db.in
@@ -0,0 +1,44 @@
+; Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+;
+; SPDX-License-Identifier: MPL-2.0
+;
+; This Source Code Form is subject to the terms of the Mozilla Public
+; License, v. 2.0. If a copy of the MPL was not distributed with this
+; file, you can obtain one at https://mozilla.org/MPL/2.0/.
+;
+; See the COPYRIGHT file distributed with this work for additional
+; information regarding copyright ownership.
+
+$TTL 300 ; 5 minutes
+@ IN SOA mname1. . (
+ 2000042407 ; serial
+ 20 ; refresh (20 seconds)
+ 20 ; retry (20 seconds)
+ 1814400 ; expire (3 weeks)
+ 3600 ; minimum (1 hour)
+ )
+ NS ns
+ MX 10 mx
+ns A 10.53.0.3
+mx A 10.0.0.30
+
+a A 10.0.0.1
+b A 10.0.0.2
+d A 10.0.0.4
+z A 10.0.0.26
+a.a.a.a.a.a.a.a.a.a.e A 10.0.0.27
+x CNAME a
+
+private NS ns.private
+ns.private A 10.53.0.2
+
+insecure NS ns.insecure
+ns.insecure A 10.53.0.2
+
+nosoa NS ns.nosoa
+ns.nosoa A 10.53.0.7
+
+normalthenrrsig A 10.0.0.28
+rrsigonly A 10.0.0.29
+
+
diff --git a/bin/tests/system/dnssec/ns3/expiring.example.db.in b/bin/tests/system/dnssec/ns3/expiring.example.db.in
new file mode 100644
index 0000000..8acf7b1
--- /dev/null
+++ b/bin/tests/system/dnssec/ns3/expiring.example.db.in
@@ -0,0 +1,40 @@
+; Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+;
+; SPDX-License-Identifier: MPL-2.0
+;
+; This Source Code Form is subject to the terms of the Mozilla Public
+; License, v. 2.0. If a copy of the MPL was not distributed with this
+; file, you can obtain one at https://mozilla.org/MPL/2.0/.
+;
+; See the COPYRIGHT file distributed with this work for additional
+; information regarding copyright ownership.
+
+$TTL 300 ; 5 minutes
+@ IN SOA mname1. . (
+ 2000042407 ; serial
+ 20 ; refresh (20 seconds)
+ 20 ; retry (20 seconds)
+ 1814400 ; expire (3 weeks)
+ 3600 ; minimum (1 hour)
+ )
+ NS ns
+ MX 10 mx
+ns A 10.53.0.3
+mx A 10.0.0.30
+
+a A 10.0.0.1
+b A 10.0.0.2
+d A 10.0.0.4
+z A 10.0.0.26
+a.a.a.a A 10.0.0.3
+*.wild A 10.0.0.6
+child NS ns2.example.
+insecure NS ns.insecure
+ns.insecure A 10.53.0.3
+secure NS ns.secure
+ns.secure A 10.53.0.3
+nsec3 NS ns.nsec3
+ns.nsec3 A 10.53.0.3
+optout NS ns.optout
+ns.optout A 10.53.0.3
+02HC3EM7BDD011A0GMS3HKKJT2IF5VP8 A 10.0.0.17
diff --git a/bin/tests/system/dnssec/ns3/future.example.db.in b/bin/tests/system/dnssec/ns3/future.example.db.in
new file mode 100644
index 0000000..20c19c5
--- /dev/null
+++ b/bin/tests/system/dnssec/ns3/future.example.db.in
@@ -0,0 +1,40 @@
+; Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+;
+; SPDX-License-Identifier: MPL-2.0
+;
+; This Source Code Form is subject to the terms of the Mozilla Public
+; License, v. 2.0. If a copy of the MPL was not distributed with this
+; file, you can obtain one at https://mozilla.org/MPL/2.0/.
+;
+; See the COPYRIGHT file distributed with this work for additional
+; information regarding copyright ownership.
+
+$TTL 300 ; 5 minutes
+@ IN SOA mname1. . (
+ 2000042407 ; serial
+ 20 ; refresh (20 seconds)
+ 20 ; retry (20 seconds)
+ 1814400 ; expire (3 weeks)
+ 3600 ; minimum (1 hour)
+ )
+ NS ns
+ns A 10.53.0.3
+
+a A 10.0.0.1
+b A 10.0.0.2
+d A 10.0.0.4
+z A 10.0.0.26
+a.a.a.a A 10.0.0.3
+*.wild A 10.0.0.6
+insecure NS ns.insecure
+ns.insecure A 10.53.0.3
+secure NS ns.secure
+ns.secure A 10.53.0.3
+nsec3 NS ns.nsec3
+ns.nsec3 A 10.53.0.3
+optout NS ns.optout
+ns.optout A 10.53.0.3
+child NS ns2.example.
+insecure.empty NS ns.insecure.empty
+ns.insecure.empty A 10.53.0.3
+foo.*.empty-wild NS ns
diff --git a/bin/tests/system/dnssec/ns3/generic.example.db.in b/bin/tests/system/dnssec/ns3/generic.example.db.in
new file mode 100644
index 0000000..5cc3ecc
--- /dev/null
+++ b/bin/tests/system/dnssec/ns3/generic.example.db.in
@@ -0,0 +1,23 @@
+; Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+;
+; SPDX-License-Identifier: MPL-2.0
+;
+; This Source Code Form is subject to the terms of the Mozilla Public
+; License, v. 2.0. If a copy of the MPL was not distributed with this
+; file, you can obtain one at https://mozilla.org/MPL/2.0/.
+;
+; See the COPYRIGHT file distributed with this work for additional
+; information regarding copyright ownership.
+
+$TTL 300 ; 5 minutes
+@ IN SOA mname1. . (
+ 2000042407 ; serial
+ 20 ; refresh (20 seconds)
+ 20 ; retry (20 seconds)
+ 1814400 ; expire (3 weeks)
+ 3600 ; minimum (1 hour)
+ )
+ NS ns
+ns A 10.53.0.3
+
+a.b A 10.0.0.1
diff --git a/bin/tests/system/dnssec/ns3/inline.example.db b/bin/tests/system/dnssec/ns3/inline.example.db
new file mode 100644
index 0000000..14971bd
--- /dev/null
+++ b/bin/tests/system/dnssec/ns3/inline.example.db
@@ -0,0 +1,26 @@
+; Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+;
+; SPDX-License-Identifier: MPL-2.0
+;
+; This Source Code Form is subject to the terms of the Mozilla Public
+; License, v. 2.0. If a copy of the MPL was not distributed with this
+; file, you can obtain one at https://mozilla.org/MPL/2.0/.
+;
+; See the COPYRIGHT file distributed with this work for additional
+; information regarding copyright ownership.
+
+$TTL 300 ; 5 minutes
+@ IN SOA mname1. . (
+ 2000042407 ; serial
+ 20 ; refresh (20 seconds)
+ 20 ; retry (20 seconds)
+ 1814400 ; expire (3 weeks)
+ 3600 ; minimum (1 hour)
+ )
+ NS ns
+ns A 10.53.0.3
+
+a A 10.0.0.1
+b A 10.0.0.2
+d A 10.0.0.4
+z A 10.0.0.26
diff --git a/bin/tests/system/dnssec/ns3/insecure.below-cname.example.db b/bin/tests/system/dnssec/ns3/insecure.below-cname.example.db
new file mode 100644
index 0000000..14971bd
--- /dev/null
+++ b/bin/tests/system/dnssec/ns3/insecure.below-cname.example.db
@@ -0,0 +1,26 @@
+; Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+;
+; SPDX-License-Identifier: MPL-2.0
+;
+; This Source Code Form is subject to the terms of the Mozilla Public
+; License, v. 2.0. If a copy of the MPL was not distributed with this
+; file, you can obtain one at https://mozilla.org/MPL/2.0/.
+;
+; See the COPYRIGHT file distributed with this work for additional
+; information regarding copyright ownership.
+
+$TTL 300 ; 5 minutes
+@ IN SOA mname1. . (
+ 2000042407 ; serial
+ 20 ; refresh (20 seconds)
+ 20 ; retry (20 seconds)
+ 1814400 ; expire (3 weeks)
+ 3600 ; minimum (1 hour)
+ )
+ NS ns
+ns A 10.53.0.3
+
+a A 10.0.0.1
+b A 10.0.0.2
+d A 10.0.0.4
+z A 10.0.0.26
diff --git a/bin/tests/system/dnssec/ns3/insecure.example.db b/bin/tests/system/dnssec/ns3/insecure.example.db
new file mode 100644
index 0000000..76e3f47
--- /dev/null
+++ b/bin/tests/system/dnssec/ns3/insecure.example.db
@@ -0,0 +1,27 @@
+; Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+;
+; SPDX-License-Identifier: MPL-2.0
+;
+; This Source Code Form is subject to the terms of the Mozilla Public
+; License, v. 2.0. If a copy of the MPL was not distributed with this
+; file, you can obtain one at https://mozilla.org/MPL/2.0/.
+;
+; See the COPYRIGHT file distributed with this work for additional
+; information regarding copyright ownership.
+
+$TTL 300 ; 5 minutes
+@ IN SOA mname1. . (
+ 2000042407 ; serial
+ 20 ; refresh (20 seconds)
+ 20 ; retry (20 seconds)
+ 1814400 ; expire (3 weeks)
+ 3600 ; minimum (1 hour)
+ )
+ NS ns
+ns A 10.53.0.3
+
+a A 10.0.0.1
+b A 10.0.0.2
+d A 10.0.0.4
+x DNSKEY 258 3 5 Cg==
+z A 10.0.0.26
diff --git a/bin/tests/system/dnssec/ns3/insecure.nsec3.example.db b/bin/tests/system/dnssec/ns3/insecure.nsec3.example.db
new file mode 100644
index 0000000..14971bd
--- /dev/null
+++ b/bin/tests/system/dnssec/ns3/insecure.nsec3.example.db
@@ -0,0 +1,26 @@
+; Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+;
+; SPDX-License-Identifier: MPL-2.0
+;
+; This Source Code Form is subject to the terms of the Mozilla Public
+; License, v. 2.0. If a copy of the MPL was not distributed with this
+; file, you can obtain one at https://mozilla.org/MPL/2.0/.
+;
+; See the COPYRIGHT file distributed with this work for additional
+; information regarding copyright ownership.
+
+$TTL 300 ; 5 minutes
+@ IN SOA mname1. . (
+ 2000042407 ; serial
+ 20 ; refresh (20 seconds)
+ 20 ; retry (20 seconds)
+ 1814400 ; expire (3 weeks)
+ 3600 ; minimum (1 hour)
+ )
+ NS ns
+ns A 10.53.0.3
+
+a A 10.0.0.1
+b A 10.0.0.2
+d A 10.0.0.4
+z A 10.0.0.26
diff --git a/bin/tests/system/dnssec/ns3/insecure.optout.example.db b/bin/tests/system/dnssec/ns3/insecure.optout.example.db
new file mode 100644
index 0000000..14971bd
--- /dev/null
+++ b/bin/tests/system/dnssec/ns3/insecure.optout.example.db
@@ -0,0 +1,26 @@
+; Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+;
+; SPDX-License-Identifier: MPL-2.0
+;
+; This Source Code Form is subject to the terms of the Mozilla Public
+; License, v. 2.0. If a copy of the MPL was not distributed with this
+; file, you can obtain one at https://mozilla.org/MPL/2.0/.
+;
+; See the COPYRIGHT file distributed with this work for additional
+; information regarding copyright ownership.
+
+$TTL 300 ; 5 minutes
+@ IN SOA mname1. . (
+ 2000042407 ; serial
+ 20 ; refresh (20 seconds)
+ 20 ; retry (20 seconds)
+ 1814400 ; expire (3 weeks)
+ 3600 ; minimum (1 hour)
+ )
+ NS ns
+ns A 10.53.0.3
+
+a A 10.0.0.1
+b A 10.0.0.2
+d A 10.0.0.4
+z A 10.0.0.26
diff --git a/bin/tests/system/dnssec/ns3/insecure2.example.db b/bin/tests/system/dnssec/ns3/insecure2.example.db
new file mode 100644
index 0000000..76e3f47
--- /dev/null
+++ b/bin/tests/system/dnssec/ns3/insecure2.example.db
@@ -0,0 +1,27 @@
+; Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+;
+; SPDX-License-Identifier: MPL-2.0
+;
+; This Source Code Form is subject to the terms of the Mozilla Public
+; License, v. 2.0. If a copy of the MPL was not distributed with this
+; file, you can obtain one at https://mozilla.org/MPL/2.0/.
+;
+; See the COPYRIGHT file distributed with this work for additional
+; information regarding copyright ownership.
+
+$TTL 300 ; 5 minutes
+@ IN SOA mname1. . (
+ 2000042407 ; serial
+ 20 ; refresh (20 seconds)
+ 20 ; retry (20 seconds)
+ 1814400 ; expire (3 weeks)
+ 3600 ; minimum (1 hour)
+ )
+ NS ns
+ns A 10.53.0.3
+
+a A 10.0.0.1
+b A 10.0.0.2
+d A 10.0.0.4
+x DNSKEY 258 3 5 Cg==
+z A 10.0.0.26
diff --git a/bin/tests/system/dnssec/ns3/key.db.in b/bin/tests/system/dnssec/ns3/key.db.in
new file mode 100644
index 0000000..0165e3f
--- /dev/null
+++ b/bin/tests/system/dnssec/ns3/key.db.in
@@ -0,0 +1,26 @@
+; Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+;
+; SPDX-License-Identifier: MPL-2.0
+;
+; This Source Code Form is subject to the terms of the Mozilla Public
+; License, v. 2.0. If a copy of the MPL was not distributed with this
+; file, you can obtain one at https://mozilla.org/MPL/2.0/.
+;
+; See the COPYRIGHT file distributed with this work for additional
+; information regarding copyright ownership.
+
+$TTL 300 ; 5 minutes
+@ IN SOA mname1. . (
+ 2000042407 ; serial
+ 20 ; refresh (20 seconds)
+ 20 ; retry (20 seconds)
+ 1814400 ; expire (3 weeks)
+ 3600 ; minimum (1 hour)
+ )
+ NS ns3
+ns3 A 10.53.0.3
+
+a A 10.0.0.1
+b A 10.0.0.2
+c A 10.0.0.3
+
diff --git a/bin/tests/system/dnssec/ns3/kskonly.example.db.in b/bin/tests/system/dnssec/ns3/kskonly.example.db.in
new file mode 100644
index 0000000..0b11a00
--- /dev/null
+++ b/bin/tests/system/dnssec/ns3/kskonly.example.db.in
@@ -0,0 +1,26 @@
+; Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+;
+; SPDX-License-Identifier: MPL-2.0
+;
+; This Source Code Form is subject to the terms of the Mozilla Public
+; License, v. 2.0. If a copy of the MPL was not distributed with this
+; file, you can obtain one at https://mozilla.org/MPL/2.0/.
+;
+; See the COPYRIGHT file distributed with this work for additional
+; information regarding copyright ownership.
+
+$TTL 300 ; 5 minutes
+@ IN SOA mname1. . (
+ 2009102722 ; serial
+ 20 ; refresh (20 seconds)
+ 20 ; retry (20 seconds)
+ 1814400 ; expire (3 weeks)
+ 3600 ; minimum (1 hour)
+ )
+ NS ns
+ns A 10.53.0.3
+
+a A 10.0.0.1
+b A 10.0.0.2
+d A 10.0.0.4
+x CNAME a
diff --git a/bin/tests/system/dnssec/ns3/lower.example.db.in b/bin/tests/system/dnssec/ns3/lower.example.db.in
new file mode 100644
index 0000000..a04793e
--- /dev/null
+++ b/bin/tests/system/dnssec/ns3/lower.example.db.in
@@ -0,0 +1,21 @@
+; Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+;
+; SPDX-License-Identifier: MPL-2.0
+;
+; This Source Code Form is subject to the terms of the Mozilla Public
+; License, v. 2.0. If a copy of the MPL was not distributed with this
+; file, you can obtain one at https://mozilla.org/MPL/2.0/.
+;
+; See the COPYRIGHT file distributed with this work for additional
+; information regarding copyright ownership.
+
+$TTL 300 ; 5 minutes
+@ IN SOA MNAME1. . (
+ 2012042407 ; serial
+ 20 ; refresh (20 seconds)
+ 20 ; retry (20 seconds)
+ 1814400 ; expire (3 weeks)
+ 3600 ; minimum (1 hour)
+ )
+@ NS NS
+NS A 10.53.0.3
diff --git a/bin/tests/system/dnssec/ns3/managed-future.example.db.in b/bin/tests/system/dnssec/ns3/managed-future.example.db.in
new file mode 100644
index 0000000..20c19c5
--- /dev/null
+++ b/bin/tests/system/dnssec/ns3/managed-future.example.db.in
@@ -0,0 +1,40 @@
+; Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+;
+; SPDX-License-Identifier: MPL-2.0
+;
+; This Source Code Form is subject to the terms of the Mozilla Public
+; License, v. 2.0. If a copy of the MPL was not distributed with this
+; file, you can obtain one at https://mozilla.org/MPL/2.0/.
+;
+; See the COPYRIGHT file distributed with this work for additional
+; information regarding copyright ownership.
+
+$TTL 300 ; 5 minutes
+@ IN SOA mname1. . (
+ 2000042407 ; serial
+ 20 ; refresh (20 seconds)
+ 20 ; retry (20 seconds)
+ 1814400 ; expire (3 weeks)
+ 3600 ; minimum (1 hour)
+ )
+ NS ns
+ns A 10.53.0.3
+
+a A 10.0.0.1
+b A 10.0.0.2
+d A 10.0.0.4
+z A 10.0.0.26
+a.a.a.a A 10.0.0.3
+*.wild A 10.0.0.6
+insecure NS ns.insecure
+ns.insecure A 10.53.0.3
+secure NS ns.secure
+ns.secure A 10.53.0.3
+nsec3 NS ns.nsec3
+ns.nsec3 A 10.53.0.3
+optout NS ns.optout
+ns.optout A 10.53.0.3
+child NS ns2.example.
+insecure.empty NS ns.insecure.empty
+ns.insecure.empty A 10.53.0.3
+foo.*.empty-wild NS ns
diff --git a/bin/tests/system/dnssec/ns3/multiple.example.db.in b/bin/tests/system/dnssec/ns3/multiple.example.db.in
new file mode 100644
index 0000000..f37dd75
--- /dev/null
+++ b/bin/tests/system/dnssec/ns3/multiple.example.db.in
@@ -0,0 +1,29 @@
+; Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+;
+; SPDX-License-Identifier: MPL-2.0
+;
+; This Source Code Form is subject to the terms of the Mozilla Public
+; License, v. 2.0. If a copy of the MPL was not distributed with this
+; file, you can obtain one at https://mozilla.org/MPL/2.0/.
+;
+; See the COPYRIGHT file distributed with this work for additional
+; information regarding copyright ownership.
+
+$TTL 300 ; 5 minutes
+@ IN SOA mname1. . (
+ 2000042407 ; serial
+ 20 ; refresh (20 seconds)
+ 20 ; retry (20 seconds)
+ 1814400 ; expire (3 weeks)
+ 3600 ; minimum (1 hour)
+ )
+ NS ns
+ns A 10.53.0.3
+
+a A 10.0.0.1
+b A 10.0.0.2
+d A 10.0.0.4
+z A 10.0.0.26
+a.a.a.a A 10.0.0.3
+*.e A 10.0.0.6
+child NS ns2.example.
diff --git a/bin/tests/system/dnssec/ns3/named.conf.in b/bin/tests/system/dnssec/ns3/named.conf.in
new file mode 100644
index 0000000..cdc6e02
--- /dev/null
+++ b/bin/tests/system/dnssec/ns3/named.conf.in
@@ -0,0 +1,383 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * SPDX-License-Identifier: MPL-2.0
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, you can obtain one at https://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+// NS3
+
+options {
+ query-source address 10.53.0.3;
+ notify-source 10.53.0.3;
+ transfer-source 10.53.0.3;
+ port @PORT@;
+ pid-file "named.pid";
+ listen-on { 10.53.0.3; };
+ listen-on-v6 { none; };
+ recursion no;
+ notify yes;
+ dnssec-validation yes;
+ session-keyfile "session.key";
+ minimal-responses no;
+};
+
+key rndc_key {
+ secret "1234abcd8765";
+ algorithm @DEFAULT_HMAC@;
+};
+
+controls {
+ inet 10.53.0.3 port @CONTROLPORT@ allow { any; } keys { rndc_key; };
+};
+
+zone "." {
+ type hint;
+ file "../../common/root.hint";
+};
+
+zone "example" {
+ type secondary;
+ primaries { 10.53.0.2; };
+ file "example.bk";
+};
+
+zone "secure.example" {
+ type primary;
+ file "secure.example.db.signed";
+ allow-update { any; };
+};
+
+zone "bogus.example" {
+ type primary;
+ file "bogus.example.db.signed";
+ allow-update { any; };
+};
+
+zone "badds.example" {
+ type primary;
+ file "badds.example.db.signed";
+ allow-update { any; };
+};
+
+zone "dynamic.example" {
+ type primary;
+ file "dynamic.example.db.signed";
+ allow-update { any; };
+};
+
+zone "insecure.example" {
+ type primary;
+ file "insecure.example.db";
+ allow-update { any; };
+};
+
+zone "insecure2.example" {
+ type primary;
+ file "insecure2.example.db";
+ allow-update { any; };
+};
+
+zone "insecure.nsec3.example" {
+ type primary;
+ file "insecure.nsec3.example.db";
+ allow-update { any; };
+};
+
+zone "insecure.optout.example" {
+ type primary;
+ file "insecure.optout.example.db";
+ allow-update { any; };
+};
+
+zone "keyless.example" {
+ type primary;
+ file "keyless.example.db.signed";
+};
+
+zone "nsec3.example" {
+ type primary;
+ file "nsec3.example.db.signed";
+};
+
+zone "optout.nsec3.example" {
+ type primary;
+ file "optout.nsec3.example.db.signed";
+};
+
+zone "nsec3.nsec3.example" {
+ type primary;
+ file "nsec3.nsec3.example.db.signed";
+};
+
+zone "secure.nsec3.example" {
+ type primary;
+ file "secure.nsec3.example.db.signed";
+};
+
+zone "optout.example" {
+ type primary;
+ file "optout.example.db.signed";
+};
+
+zone "secure.optout.example" {
+ type primary;
+ file "secure.optout.example.db.signed";
+};
+
+zone "nsec3.optout.example" {
+ type primary;
+ file "nsec3.optout.example.db.signed";
+};
+
+zone "optout.optout.example" {
+ type primary;
+ file "optout.optout.example.db.signed";
+};
+
+zone "nsec3-unknown.example" {
+ type primary;
+ nsec3-test-zone yes;
+ file "nsec3-unknown.example.db.signed";
+};
+
+zone "optout-unknown.example" {
+ type primary;
+ nsec3-test-zone yes;
+ file "optout-unknown.example.db.signed";
+};
+
+zone "dnskey-unknown.example" {
+ type primary;
+ file "dnskey-unknown.example.db.signed";
+};
+
+zone "dnskey-unsupported.example" {
+ type primary;
+ file "dnskey-unsupported.example.db.signed";
+};
+
+zone "dnskey-unsupported-2.example" {
+ type primary;
+ file "dnskey-unsupported-2.example.db.signed";
+};
+
+zone "dnskey-nsec3-unknown.example" {
+ type primary;
+ nsec3-test-zone yes;
+ file "dnskey-nsec3-unknown.example.db.signed";
+};
+
+zone "multiple.example" {
+ type primary;
+ file "multiple.example.db.signed";
+ allow-update { any; };
+};
+
+zone "rfc2335.example" {
+ type secondary;
+ primaries { 10.53.0.2; };
+ file "rfc2335.example.bk";
+};
+
+zone "rsasha256.example" {
+ type primary;
+ file "rsasha256.example.db.signed";
+};
+
+zone "rsasha512.example" {
+ type primary;
+ file "rsasha512.example.db.signed";
+};
+
+zone "kskonly.example" {
+ type primary;
+ file "kskonly.example.db.signed";
+};
+
+zone "expired.example" {
+ type primary;
+ allow-update { none; };
+ file "expired.example.db.signed";
+};
+
+zone "update-nsec3.example" {
+ type primary;
+ allow-update { any; };
+ file "update-nsec3.example.db.signed";
+};
+
+zone "auto-nsec.example" {
+ type primary;
+ auto-dnssec maintain;
+ allow-update { !0.0.0.0; };
+ file "auto-nsec.example.db.signed";
+};
+
+zone "auto-nsec3.example" {
+ type primary;
+ auto-dnssec maintain;
+ allow-update { !0.0.0.0; };
+ file "auto-nsec3.example.db.signed";
+};
+
+zone "insecure.below-cname.example" {
+ type primary;
+ file "insecure.below-cname.example.db";
+};
+
+zone "secure.below-cname.example" {
+ type primary;
+ file "secure.below-cname.example.db.signed";
+};
+
+zone "ttlpatch.example" {
+ type primary;
+ file "ttlpatch.example.db.patched";
+};
+
+zone "split-dnssec.example" {
+ type primary;
+ file "split-dnssec.example.db";
+};
+
+zone "split-smart.example" {
+ type primary;
+ file "split-smart.example.db";
+};
+
+zone "nsec3chain-test" {
+ type secondary;
+ file "nsec3chain-test.bk";
+ primaries { 10.53.0.2; };
+};
+
+zone "expiring.example" {
+ type primary;
+ allow-update { any; };
+ file "expiring.example.db.signed";
+};
+
+zone "nosign.example" {
+ type primary;
+ allow-update { any; };
+ dnssec-update-mode no-resign;
+ file "nosign.example.db.signed";
+};
+
+zone "upper.example" {
+ type primary;
+ file "upper.example.db.signed";
+};
+
+zone "LOWER.EXAMPLE" {
+ type primary;
+ file "lower.example.db.signed";
+};
+
+zone "inline.example" {
+ type primary;
+ file "inline.example.db";
+ inline-signing yes;
+ auto-dnssec maintain;
+};
+
+zone "publish-inactive.example" {
+ type primary;
+ file "publish-inactive.example.db";
+ auto-dnssec maintain;
+ dnssec-dnskey-kskonly no;
+ update-policy local;
+};
+
+zone "future.example" {
+ type primary;
+ file "future.example.db.signed";
+};
+
+zone "managed-future.example" {
+ type primary;
+ file "managed-future.example.db.signed";
+ allow-update { any; };
+};
+
+zone "revkey.example" {
+ type primary;
+ file "revkey.example.db.signed";
+};
+
+zone "dname-at-apex-nsec3.example" {
+ type primary;
+ file "dname-at-apex-nsec3.example.db.signed";
+};
+
+zone "occluded.example" {
+ type primary;
+ file "occluded.example.db.signed";
+};
+
+zone "secure.managed" {
+ type primary;
+ file "secure.managed.db.signed";
+};
+
+zone "disabled.managed" {
+ type primary;
+ file "disabled.managed.db.signed";
+};
+
+zone "enabled.managed" {
+ type primary;
+ file "enabled.managed.db.signed";
+};
+
+zone "unsupported.managed" {
+ type primary;
+ file "unsupported.managed.db.signed";
+};
+
+zone "revoked.managed" {
+ type primary;
+ file "revoked.managed.db.signed";
+};
+
+zone "secure.trusted" {
+ type primary;
+ file "secure.trusted.db.signed";
+};
+
+zone "disabled.trusted" {
+ type primary;
+ file "disabled.trusted.db.signed";
+};
+
+zone "enabled.trusted" {
+ type primary;
+ file "enabled.trusted.db.signed";
+};
+
+zone "unsupported.trusted" {
+ type primary;
+ file "unsupported.trusted.db.signed";
+};
+
+zone "revoked.trusted" {
+ type primary;
+ file "revoked.trusted.db.signed";
+};
+
+zone "too-many-iterations" {
+ type secondary;
+ primaries { 10.53.0.2; };
+ file "too-many-iterations.bk";
+};
+
+include "siginterval.conf";
+
+include "trusted.conf";
diff --git a/bin/tests/system/dnssec/ns3/nosign.example.db.in b/bin/tests/system/dnssec/ns3/nosign.example.db.in
new file mode 100644
index 0000000..2be8a28
--- /dev/null
+++ b/bin/tests/system/dnssec/ns3/nosign.example.db.in
@@ -0,0 +1,23 @@
+; Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+;
+; SPDX-License-Identifier: MPL-2.0
+;
+; This Source Code Form is subject to the terms of the Mozilla Public
+; License, v. 2.0. If a copy of the MPL was not distributed with this
+; file, you can obtain one at https://mozilla.org/MPL/2.0/.
+;
+; See the COPYRIGHT file distributed with this work for additional
+; information regarding copyright ownership.
+
+$TTL 300 ; 5 minutes
+@ IN SOA mname1. . (
+ 2000042407 ; serial
+ 20 ; refresh (20 seconds)
+ 20 ; retry (20 seconds)
+ 1814400 ; expire (3 weeks)
+ 3600 ; minimum (1 hour)
+ )
+ NS ns
+ns A 10.53.0.3
+
+a A 10.0.0.1
diff --git a/bin/tests/system/dnssec/ns3/nsec3-unknown.example.db.in b/bin/tests/system/dnssec/ns3/nsec3-unknown.example.db.in
new file mode 100644
index 0000000..f37dd75
--- /dev/null
+++ b/bin/tests/system/dnssec/ns3/nsec3-unknown.example.db.in
@@ -0,0 +1,29 @@
+; Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+;
+; SPDX-License-Identifier: MPL-2.0
+;
+; This Source Code Form is subject to the terms of the Mozilla Public
+; License, v. 2.0. If a copy of the MPL was not distributed with this
+; file, you can obtain one at https://mozilla.org/MPL/2.0/.
+;
+; See the COPYRIGHT file distributed with this work for additional
+; information regarding copyright ownership.
+
+$TTL 300 ; 5 minutes
+@ IN SOA mname1. . (
+ 2000042407 ; serial
+ 20 ; refresh (20 seconds)
+ 20 ; retry (20 seconds)
+ 1814400 ; expire (3 weeks)
+ 3600 ; minimum (1 hour)
+ )
+ NS ns
+ns A 10.53.0.3
+
+a A 10.0.0.1
+b A 10.0.0.2
+d A 10.0.0.4
+z A 10.0.0.26
+a.a.a.a A 10.0.0.3
+*.e A 10.0.0.6
+child NS ns2.example.
diff --git a/bin/tests/system/dnssec/ns3/nsec3.example.db.in b/bin/tests/system/dnssec/ns3/nsec3.example.db.in
new file mode 100644
index 0000000..55b3877
--- /dev/null
+++ b/bin/tests/system/dnssec/ns3/nsec3.example.db.in
@@ -0,0 +1,38 @@
+; Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+;
+; SPDX-License-Identifier: MPL-2.0
+;
+; This Source Code Form is subject to the terms of the Mozilla Public
+; License, v. 2.0. If a copy of the MPL was not distributed with this
+; file, you can obtain one at https://mozilla.org/MPL/2.0/.
+;
+; See the COPYRIGHT file distributed with this work for additional
+; information regarding copyright ownership.
+
+$TTL 300 ; 5 minutes
+@ IN SOA mname1. . (
+ 2000042407 ; serial
+ 20 ; refresh (20 seconds)
+ 20 ; retry (20 seconds)
+ 1814400 ; expire (3 weeks)
+ 3600 ; minimum (1 hour)
+ )
+ NS ns
+ns A 10.53.0.3
+
+a A 10.0.0.1
+b A 10.0.0.2
+d A 10.0.0.4
+z A 10.0.0.26
+a.a.a.a A 10.0.0.3
+*.wild A 10.0.0.6
+child NS ns2.example.
+insecure NS ns.insecure
+ns.insecure A 10.53.0.3
+secure NS ns.secure
+ns.secure A 10.53.0.3
+nsec3 NS ns.nsec3
+ns.nsec3 A 10.53.0.3
+optout NS ns.optout
+ns.optout A 10.53.0.3
+02HC3EM7BDD011A0GMS3HKKJT2IF5VP8 A 10.0.0.17
diff --git a/bin/tests/system/dnssec/ns3/nsec3.nsec3.example.db.in b/bin/tests/system/dnssec/ns3/nsec3.nsec3.example.db.in
new file mode 100644
index 0000000..15fe621
--- /dev/null
+++ b/bin/tests/system/dnssec/ns3/nsec3.nsec3.example.db.in
@@ -0,0 +1,35 @@
+; Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+;
+; SPDX-License-Identifier: MPL-2.0
+;
+; This Source Code Form is subject to the terms of the Mozilla Public
+; License, v. 2.0. If a copy of the MPL was not distributed with this
+; file, you can obtain one at https://mozilla.org/MPL/2.0/.
+;
+; See the COPYRIGHT file distributed with this work for additional
+; information regarding copyright ownership.
+
+$TTL 300 ; 5 minutes
+@ IN SOA mname1. . (
+ 2000042407 ; serial
+ 20 ; refresh (20 seconds)
+ 20 ; retry (20 seconds)
+ 1814400 ; expire (3 weeks)
+ 3600 ; minimum (1 hour)
+ )
+ NS ns
+ns A 10.53.0.3
+
+a A 10.0.0.1
+b A 10.0.0.2
+d A 10.0.0.4
+z A 10.0.0.26
+a.a.a.a.a.a.a.a.a.a.e A 10.0.0.27
+x CNAME a
+
+private NS ns.private
+ns.private A 10.53.0.2
+
+insecure NS ns.insecure
+ns.insecure A 10.53.0.2
+
diff --git a/bin/tests/system/dnssec/ns3/nsec3.optout.example.db.in b/bin/tests/system/dnssec/ns3/nsec3.optout.example.db.in
new file mode 100644
index 0000000..15fe621
--- /dev/null
+++ b/bin/tests/system/dnssec/ns3/nsec3.optout.example.db.in
@@ -0,0 +1,35 @@
+; Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+;
+; SPDX-License-Identifier: MPL-2.0
+;
+; This Source Code Form is subject to the terms of the Mozilla Public
+; License, v. 2.0. If a copy of the MPL was not distributed with this
+; file, you can obtain one at https://mozilla.org/MPL/2.0/.
+;
+; See the COPYRIGHT file distributed with this work for additional
+; information regarding copyright ownership.
+
+$TTL 300 ; 5 minutes
+@ IN SOA mname1. . (
+ 2000042407 ; serial
+ 20 ; refresh (20 seconds)
+ 20 ; retry (20 seconds)
+ 1814400 ; expire (3 weeks)
+ 3600 ; minimum (1 hour)
+ )
+ NS ns
+ns A 10.53.0.3
+
+a A 10.0.0.1
+b A 10.0.0.2
+d A 10.0.0.4
+z A 10.0.0.26
+a.a.a.a.a.a.a.a.a.a.e A 10.0.0.27
+x CNAME a
+
+private NS ns.private
+ns.private A 10.53.0.2
+
+insecure NS ns.insecure
+ns.insecure A 10.53.0.2
+
diff --git a/bin/tests/system/dnssec/ns3/occluded.example.db.in b/bin/tests/system/dnssec/ns3/occluded.example.db.in
new file mode 100644
index 0000000..ee9c900
--- /dev/null
+++ b/bin/tests/system/dnssec/ns3/occluded.example.db.in
@@ -0,0 +1,26 @@
+; Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+;
+; SPDX-License-Identifier: MPL-2.0
+;
+; This Source Code Form is subject to the terms of the Mozilla Public
+; License, v. 2.0. If a copy of the MPL was not distributed with this
+; file, you can obtain one at https://mozilla.org/MPL/2.0/.
+;
+; See the COPYRIGHT file distributed with this work for additional
+; information regarding copyright ownership.
+
+$TTL 300 ; 5 minutes
+@ IN SOA mname1. . (
+ 2000042407 ; serial
+ 20 ; refresh (20 seconds)
+ 20 ; retry (20 seconds)
+ 1814400 ; expire (3 weeks)
+ 3600 ; minimum (1 hour)
+ )
+ NS ns
+ns A 10.53.0.3
+
+a.b A 10.0.0.1
+delegation NS ns
+ A 10.53.0.3
+ AAAA 2002::
diff --git a/bin/tests/system/dnssec/ns3/optout-unknown.example.db.in b/bin/tests/system/dnssec/ns3/optout-unknown.example.db.in
new file mode 100644
index 0000000..f37dd75
--- /dev/null
+++ b/bin/tests/system/dnssec/ns3/optout-unknown.example.db.in
@@ -0,0 +1,29 @@
+; Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+;
+; SPDX-License-Identifier: MPL-2.0
+;
+; This Source Code Form is subject to the terms of the Mozilla Public
+; License, v. 2.0. If a copy of the MPL was not distributed with this
+; file, you can obtain one at https://mozilla.org/MPL/2.0/.
+;
+; See the COPYRIGHT file distributed with this work for additional
+; information regarding copyright ownership.
+
+$TTL 300 ; 5 minutes
+@ IN SOA mname1. . (
+ 2000042407 ; serial
+ 20 ; refresh (20 seconds)
+ 20 ; retry (20 seconds)
+ 1814400 ; expire (3 weeks)
+ 3600 ; minimum (1 hour)
+ )
+ NS ns
+ns A 10.53.0.3
+
+a A 10.0.0.1
+b A 10.0.0.2
+d A 10.0.0.4
+z A 10.0.0.26
+a.a.a.a A 10.0.0.3
+*.e A 10.0.0.6
+child NS ns2.example.
diff --git a/bin/tests/system/dnssec/ns3/optout.example.db.in b/bin/tests/system/dnssec/ns3/optout.example.db.in
new file mode 100644
index 0000000..20c19c5
--- /dev/null
+++ b/bin/tests/system/dnssec/ns3/optout.example.db.in
@@ -0,0 +1,40 @@
+; Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+;
+; SPDX-License-Identifier: MPL-2.0
+;
+; This Source Code Form is subject to the terms of the Mozilla Public
+; License, v. 2.0. If a copy of the MPL was not distributed with this
+; file, you can obtain one at https://mozilla.org/MPL/2.0/.
+;
+; See the COPYRIGHT file distributed with this work for additional
+; information regarding copyright ownership.
+
+$TTL 300 ; 5 minutes
+@ IN SOA mname1. . (
+ 2000042407 ; serial
+ 20 ; refresh (20 seconds)
+ 20 ; retry (20 seconds)
+ 1814400 ; expire (3 weeks)
+ 3600 ; minimum (1 hour)
+ )
+ NS ns
+ns A 10.53.0.3
+
+a A 10.0.0.1
+b A 10.0.0.2
+d A 10.0.0.4
+z A 10.0.0.26
+a.a.a.a A 10.0.0.3
+*.wild A 10.0.0.6
+insecure NS ns.insecure
+ns.insecure A 10.53.0.3
+secure NS ns.secure
+ns.secure A 10.53.0.3
+nsec3 NS ns.nsec3
+ns.nsec3 A 10.53.0.3
+optout NS ns.optout
+ns.optout A 10.53.0.3
+child NS ns2.example.
+insecure.empty NS ns.insecure.empty
+ns.insecure.empty A 10.53.0.3
+foo.*.empty-wild NS ns
diff --git a/bin/tests/system/dnssec/ns3/optout.nsec3.example.db.in b/bin/tests/system/dnssec/ns3/optout.nsec3.example.db.in
new file mode 100644
index 0000000..15fe621
--- /dev/null
+++ b/bin/tests/system/dnssec/ns3/optout.nsec3.example.db.in
@@ -0,0 +1,35 @@
+; Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+;
+; SPDX-License-Identifier: MPL-2.0
+;
+; This Source Code Form is subject to the terms of the Mozilla Public
+; License, v. 2.0. If a copy of the MPL was not distributed with this
+; file, you can obtain one at https://mozilla.org/MPL/2.0/.
+;
+; See the COPYRIGHT file distributed with this work for additional
+; information regarding copyright ownership.
+
+$TTL 300 ; 5 minutes
+@ IN SOA mname1. . (
+ 2000042407 ; serial
+ 20 ; refresh (20 seconds)
+ 20 ; retry (20 seconds)
+ 1814400 ; expire (3 weeks)
+ 3600 ; minimum (1 hour)
+ )
+ NS ns
+ns A 10.53.0.3
+
+a A 10.0.0.1
+b A 10.0.0.2
+d A 10.0.0.4
+z A 10.0.0.26
+a.a.a.a.a.a.a.a.a.a.e A 10.0.0.27
+x CNAME a
+
+private NS ns.private
+ns.private A 10.53.0.2
+
+insecure NS ns.insecure
+ns.insecure A 10.53.0.2
+
diff --git a/bin/tests/system/dnssec/ns3/optout.optout.example.db.in b/bin/tests/system/dnssec/ns3/optout.optout.example.db.in
new file mode 100644
index 0000000..15fe621
--- /dev/null
+++ b/bin/tests/system/dnssec/ns3/optout.optout.example.db.in
@@ -0,0 +1,35 @@
+; Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+;
+; SPDX-License-Identifier: MPL-2.0
+;
+; This Source Code Form is subject to the terms of the Mozilla Public
+; License, v. 2.0. If a copy of the MPL was not distributed with this
+; file, you can obtain one at https://mozilla.org/MPL/2.0/.
+;
+; See the COPYRIGHT file distributed with this work for additional
+; information regarding copyright ownership.
+
+$TTL 300 ; 5 minutes
+@ IN SOA mname1. . (
+ 2000042407 ; serial
+ 20 ; refresh (20 seconds)
+ 20 ; retry (20 seconds)
+ 1814400 ; expire (3 weeks)
+ 3600 ; minimum (1 hour)
+ )
+ NS ns
+ns A 10.53.0.3
+
+a A 10.0.0.1
+b A 10.0.0.2
+d A 10.0.0.4
+z A 10.0.0.26
+a.a.a.a.a.a.a.a.a.a.e A 10.0.0.27
+x CNAME a
+
+private NS ns.private
+ns.private A 10.53.0.2
+
+insecure NS ns.insecure
+ns.insecure A 10.53.0.2
+
diff --git a/bin/tests/system/dnssec/ns3/publish-inactive.example.db.in b/bin/tests/system/dnssec/ns3/publish-inactive.example.db.in
new file mode 100644
index 0000000..14971bd
--- /dev/null
+++ b/bin/tests/system/dnssec/ns3/publish-inactive.example.db.in
@@ -0,0 +1,26 @@
+; Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+;
+; SPDX-License-Identifier: MPL-2.0
+;
+; This Source Code Form is subject to the terms of the Mozilla Public
+; License, v. 2.0. If a copy of the MPL was not distributed with this
+; file, you can obtain one at https://mozilla.org/MPL/2.0/.
+;
+; See the COPYRIGHT file distributed with this work for additional
+; information regarding copyright ownership.
+
+$TTL 300 ; 5 minutes
+@ IN SOA mname1. . (
+ 2000042407 ; serial
+ 20 ; refresh (20 seconds)
+ 20 ; retry (20 seconds)
+ 1814400 ; expire (3 weeks)
+ 3600 ; minimum (1 hour)
+ )
+ NS ns
+ns A 10.53.0.3
+
+a A 10.0.0.1
+b A 10.0.0.2
+d A 10.0.0.4
+z A 10.0.0.26
diff --git a/bin/tests/system/dnssec/ns3/rsasha256.example.db.in b/bin/tests/system/dnssec/ns3/rsasha256.example.db.in
new file mode 100644
index 0000000..f6c4fab
--- /dev/null
+++ b/bin/tests/system/dnssec/ns3/rsasha256.example.db.in
@@ -0,0 +1,28 @@
+; Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+;
+; SPDX-License-Identifier: MPL-2.0
+;
+; This Source Code Form is subject to the terms of the Mozilla Public
+; License, v. 2.0. If a copy of the MPL was not distributed with this
+; file, you can obtain one at https://mozilla.org/MPL/2.0/.
+;
+; See the COPYRIGHT file distributed with this work for additional
+; information regarding copyright ownership.
+
+$TTL 300 ; 5 minutes
+@ IN SOA mname1. . (
+ 2009102722 ; serial
+ 20 ; refresh (20 seconds)
+ 20 ; retry (20 seconds)
+ 1814400 ; expire (3 weeks)
+ 3600 ; minimum (1 hour)
+ )
+ NS ns
+ns A 10.53.0.3
+
+a A 10.0.0.1
+b A 10.0.0.2
+d A 10.0.0.4
+z A 10.0.0.26
+a.a.a.a.a.a.a.a.a.a.e A 10.0.0.27
+x CNAME a
diff --git a/bin/tests/system/dnssec/ns3/rsasha512.example.db.in b/bin/tests/system/dnssec/ns3/rsasha512.example.db.in
new file mode 100644
index 0000000..f6c4fab
--- /dev/null
+++ b/bin/tests/system/dnssec/ns3/rsasha512.example.db.in
@@ -0,0 +1,28 @@
+; Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+;
+; SPDX-License-Identifier: MPL-2.0
+;
+; This Source Code Form is subject to the terms of the Mozilla Public
+; License, v. 2.0. If a copy of the MPL was not distributed with this
+; file, you can obtain one at https://mozilla.org/MPL/2.0/.
+;
+; See the COPYRIGHT file distributed with this work for additional
+; information regarding copyright ownership.
+
+$TTL 300 ; 5 minutes
+@ IN SOA mname1. . (
+ 2009102722 ; serial
+ 20 ; refresh (20 seconds)
+ 20 ; retry (20 seconds)
+ 1814400 ; expire (3 weeks)
+ 3600 ; minimum (1 hour)
+ )
+ NS ns
+ns A 10.53.0.3
+
+a A 10.0.0.1
+b A 10.0.0.2
+d A 10.0.0.4
+z A 10.0.0.26
+a.a.a.a.a.a.a.a.a.a.e A 10.0.0.27
+x CNAME a
diff --git a/bin/tests/system/dnssec/ns3/secure.below-cname.example.db.in b/bin/tests/system/dnssec/ns3/secure.below-cname.example.db.in
new file mode 100644
index 0000000..14971bd
--- /dev/null
+++ b/bin/tests/system/dnssec/ns3/secure.below-cname.example.db.in
@@ -0,0 +1,26 @@
+; Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+;
+; SPDX-License-Identifier: MPL-2.0
+;
+; This Source Code Form is subject to the terms of the Mozilla Public
+; License, v. 2.0. If a copy of the MPL was not distributed with this
+; file, you can obtain one at https://mozilla.org/MPL/2.0/.
+;
+; See the COPYRIGHT file distributed with this work for additional
+; information regarding copyright ownership.
+
+$TTL 300 ; 5 minutes
+@ IN SOA mname1. . (
+ 2000042407 ; serial
+ 20 ; refresh (20 seconds)
+ 20 ; retry (20 seconds)
+ 1814400 ; expire (3 weeks)
+ 3600 ; minimum (1 hour)
+ )
+ NS ns
+ns A 10.53.0.3
+
+a A 10.0.0.1
+b A 10.0.0.2
+d A 10.0.0.4
+z A 10.0.0.26
diff --git a/bin/tests/system/dnssec/ns3/secure.example.db.in b/bin/tests/system/dnssec/ns3/secure.example.db.in
new file mode 100644
index 0000000..ec39308
--- /dev/null
+++ b/bin/tests/system/dnssec/ns3/secure.example.db.in
@@ -0,0 +1,49 @@
+; Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+;
+; SPDX-License-Identifier: MPL-2.0
+;
+; This Source Code Form is subject to the terms of the Mozilla Public
+; License, v. 2.0. If a copy of the MPL was not distributed with this
+; file, you can obtain one at https://mozilla.org/MPL/2.0/.
+;
+; See the COPYRIGHT file distributed with this work for additional
+; information regarding copyright ownership.
+
+$TTL 300 ; 5 minutes
+@ IN SOA mname1. . (
+ 2000042407 ; serial
+ 20 ; refresh (20 seconds)
+ 20 ; retry (20 seconds)
+ 1814400 ; expire (3 weeks)
+ 3600 ; minimum (1 hour)
+ )
+ NS ns3
+ns3 A 10.53.0.3
+
+a A 10.0.0.1
+b A 10.0.0.2
+c A 10.0.0.3
+d A 10.0.0.4
+e A 10.0.0.5
+f A 10.0.0.6
+g A 10.0.0.7
+z A 10.0.0.26
+a.a.a.a.a.a.a.a.a.a.e A 10.0.0.27
+x CNAME a
+zz DNSKEY 258 3 5 Cg==
+
+private NS ns.private
+ns.private A 10.53.0.2
+
+insecure NS ns2.insecure
+ns2.insecure A 10.53.0.2
+
+nosoa NS ns.nosoa
+ns.nosoa A 10.53.0.7
+
+normalthenrrsig A 10.0.0.28
+rrsigonly A 10.0.0.29
+
+cnameandkey CNAME @
+cnamenokey CNAME @
+dnameandkey DNAME @
diff --git a/bin/tests/system/dnssec/ns3/secure.nsec3.example.db.in b/bin/tests/system/dnssec/ns3/secure.nsec3.example.db.in
new file mode 100644
index 0000000..15fe621
--- /dev/null
+++ b/bin/tests/system/dnssec/ns3/secure.nsec3.example.db.in
@@ -0,0 +1,35 @@
+; Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+;
+; SPDX-License-Identifier: MPL-2.0
+;
+; This Source Code Form is subject to the terms of the Mozilla Public
+; License, v. 2.0. If a copy of the MPL was not distributed with this
+; file, you can obtain one at https://mozilla.org/MPL/2.0/.
+;
+; See the COPYRIGHT file distributed with this work for additional
+; information regarding copyright ownership.
+
+$TTL 300 ; 5 minutes
+@ IN SOA mname1. . (
+ 2000042407 ; serial
+ 20 ; refresh (20 seconds)
+ 20 ; retry (20 seconds)
+ 1814400 ; expire (3 weeks)
+ 3600 ; minimum (1 hour)
+ )
+ NS ns
+ns A 10.53.0.3
+
+a A 10.0.0.1
+b A 10.0.0.2
+d A 10.0.0.4
+z A 10.0.0.26
+a.a.a.a.a.a.a.a.a.a.e A 10.0.0.27
+x CNAME a
+
+private NS ns.private
+ns.private A 10.53.0.2
+
+insecure NS ns.insecure
+ns.insecure A 10.53.0.2
+
diff --git a/bin/tests/system/dnssec/ns3/secure.optout.example.db.in b/bin/tests/system/dnssec/ns3/secure.optout.example.db.in
new file mode 100644
index 0000000..15fe621
--- /dev/null
+++ b/bin/tests/system/dnssec/ns3/secure.optout.example.db.in
@@ -0,0 +1,35 @@
+; Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+;
+; SPDX-License-Identifier: MPL-2.0
+;
+; This Source Code Form is subject to the terms of the Mozilla Public
+; License, v. 2.0. If a copy of the MPL was not distributed with this
+; file, you can obtain one at https://mozilla.org/MPL/2.0/.
+;
+; See the COPYRIGHT file distributed with this work for additional
+; information regarding copyright ownership.
+
+$TTL 300 ; 5 minutes
+@ IN SOA mname1. . (
+ 2000042407 ; serial
+ 20 ; refresh (20 seconds)
+ 20 ; retry (20 seconds)
+ 1814400 ; expire (3 weeks)
+ 3600 ; minimum (1 hour)
+ )
+ NS ns
+ns A 10.53.0.3
+
+a A 10.0.0.1
+b A 10.0.0.2
+d A 10.0.0.4
+z A 10.0.0.26
+a.a.a.a.a.a.a.a.a.a.e A 10.0.0.27
+x CNAME a
+
+private NS ns.private
+ns.private A 10.53.0.2
+
+insecure NS ns.insecure
+ns.insecure A 10.53.0.2
+
diff --git a/bin/tests/system/dnssec/ns3/siginterval.example.db.in b/bin/tests/system/dnssec/ns3/siginterval.example.db.in
new file mode 100644
index 0000000..ec6603a
--- /dev/null
+++ b/bin/tests/system/dnssec/ns3/siginterval.example.db.in
@@ -0,0 +1,21 @@
+; Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+;
+; SPDX-License-Identifier: MPL-2.0
+;
+; This Source Code Form is subject to the terms of the Mozilla Public
+; License, v. 2.0. If a copy of the MPL was not distributed with this
+; file, you can obtain one at https://mozilla.org/MPL/2.0/.
+;
+; See the COPYRIGHT file distributed with this work for additional
+; information regarding copyright ownership.
+
+$TTL 300 ; 5 minutes
+@ IN SOA mname1. . (
+ 2012042407 ; serial
+ 20 ; refresh (20 seconds)
+ 20 ; retry (20 seconds)
+ 1814400 ; expire (3 weeks)
+ 3600 ; minimum (1 hour)
+ )
+@ NS ns
+ns A 10.53.0.3
diff --git a/bin/tests/system/dnssec/ns3/siginterval1.conf b/bin/tests/system/dnssec/ns3/siginterval1.conf
new file mode 100644
index 0000000..4674cf3
--- /dev/null
+++ b/bin/tests/system/dnssec/ns3/siginterval1.conf
@@ -0,0 +1,21 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * SPDX-License-Identifier: MPL-2.0
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, you can obtain one at https://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+zone "siginterval.example" {
+ type primary;
+ allow-update { any; };
+ sig-validity-interval 1 23;
+ dnskey-sig-validity 90;
+ auto-dnssec maintain;
+ file "siginterval.example.db";
+};
diff --git a/bin/tests/system/dnssec/ns3/siginterval2.conf b/bin/tests/system/dnssec/ns3/siginterval2.conf
new file mode 100644
index 0000000..46a2007
--- /dev/null
+++ b/bin/tests/system/dnssec/ns3/siginterval2.conf
@@ -0,0 +1,21 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * SPDX-License-Identifier: MPL-2.0
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, you can obtain one at https://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+zone "siginterval.example" {
+ type primary;
+ allow-update { any; };
+ sig-validity-interval 35 28;
+ dnskey-sig-validity 90;
+ auto-dnssec maintain;
+ file "siginterval.example.db";
+};
diff --git a/bin/tests/system/dnssec/ns3/sign.sh b/bin/tests/system/dnssec/ns3/sign.sh
new file mode 100644
index 0000000..f56edb2
--- /dev/null
+++ b/bin/tests/system/dnssec/ns3/sign.sh
@@ -0,0 +1,674 @@
+#!/bin/sh -e
+
+# Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+#
+# SPDX-License-Identifier: MPL-2.0
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, you can obtain one at https://mozilla.org/MPL/2.0/.
+#
+# See the COPYRIGHT file distributed with this work for additional
+# information regarding copyright ownership.
+
+# shellcheck source=conf.sh
+. ../../conf.sh
+
+set -e
+
+echo_i "ns3/sign.sh"
+
+infile=key.db.in
+for tld in managed trusted
+do
+ # A secure zone to test.
+ zone=secure.${tld}
+ zonefile=${zone}.db
+
+ keyname1=$("$KEYGEN" -f KSK -q -a "$DEFAULT_ALGORITHM" -b "$DEFAULT_BITS" -n zone "$zone")
+ cat "$infile" "$keyname1.key" > "$zonefile"
+ "$SIGNER" -z -P -3 - -o "$zone" -O full -f ${zonefile}.signed "$zonefile" > /dev/null
+
+ # Zone to test trust anchor that matches disabled algorithm.
+ zone=disabled.${tld}
+ zonefile=${zone}.db
+
+ keyname2=$("$KEYGEN" -f KSK -q -a "$DISABLED_ALGORITHM" -b "$DISABLED_BITS" -n zone "$zone")
+ cat "$infile" "$keyname2.key" > "$zonefile"
+ "$SIGNER" -z -P -3 - -o "$zone" -O full -f ${zonefile}.signed "$zonefile" > /dev/null
+
+ # Zone to test trust anchor that has disabled algorithm for other domain.
+ zone=enabled.${tld}
+ zonefile=${zone}.db
+
+ keyname3=$("$KEYGEN" -f KSK -q -a "$DISABLED_ALGORITHM" -b "$DISABLED_BITS" -n zone "$zone")
+ cat "$infile" "$keyname3.key" > "$zonefile"
+ "$SIGNER" -z -P -3 - -o "$zone" -O full -f ${zonefile}.signed "$zonefile" > /dev/null
+
+ # Zone to test trust anchor with unsupported algorithm.
+ zone=unsupported.${tld}
+ zonefile=${zone}.db
+
+ keyname4=$("$KEYGEN" -f KSK -q -a "$DEFAULT_ALGORITHM" -b "$DEFAULT_BITS" -n zone "$zone")
+ cat "$infile" "$keyname4.key" > "$zonefile"
+ "$SIGNER" -z -3 - -o "$zone" -O full -f ${zonefile}.tmp "$zonefile" > /dev/null
+ awk '$4 == "DNSKEY" { $7 = 255 } $4 == "RRSIG" { $6 = 255 } { print }' ${zonefile}.tmp > ${zonefile}.signed
+
+ # Make trusted-keys and managed keys conf sections for ns8.
+ mv ${keyname4}.key ${keyname4}.tmp
+ awk '$1 == "unsupported.'"${tld}"'." { $6 = 255 } { print }' ${keyname4}.tmp > ${keyname4}.key
+
+ # Zone to test trust anchor that is revoked.
+ zone=revoked.${tld}
+ zonefile=${zone}.db
+
+ keyname5=$("$KEYGEN" -f KSK -f REVOKE -q -a "$DEFAULT_ALGORITHM" -b "$DEFAULT_BITS" -n zone "$zone")
+ cat "$infile" "$keyname5.key" > "$zonefile"
+ "$SIGNER" -z -P -3 - -o "$zone" -O full -f ${zonefile}.signed "$zonefile" > /dev/null
+
+ case $tld in
+ "managed")
+ keyfile_to_initial_keys $keyname1 $keyname2 $keyname3 $keyname4 $keyname5 > ../ns8/managed.conf
+ ;;
+ "trusted")
+ keyfile_to_static_keys $keyname1 $keyname2 $keyname3 $keyname4 $keyname5 > ../ns8/trusted.conf
+ ;;
+ esac
+done
+
+echo_i "ns3/sign.sh: example zones"
+
+zone=secure.example.
+infile=secure.example.db.in
+zonefile=secure.example.db
+
+cnameandkey=$("$KEYGEN" -T KEY -q -a "$DEFAULT_ALGORITHM" -b "$DEFAULT_BITS" -n host "cnameandkey.$zone")
+dnameandkey=$("$KEYGEN" -T KEY -q -a "$DEFAULT_ALGORITHM" -b "$DEFAULT_BITS" -n host "dnameandkey.$zone")
+keyname=$("$KEYGEN" -q -a "$DEFAULT_ALGORITHM" -b "$DEFAULT_BITS" -n zone "$zone")
+
+cat "$infile" "$cnameandkey.key" "$dnameandkey.key" "$keyname.key" > "$zonefile"
+
+"$SIGNER" -z -o "$zone" "$zonefile" > /dev/null
+
+zone=bogus.example.
+infile=bogus.example.db.in
+zonefile=bogus.example.db
+
+keyname=$("$KEYGEN" -q -a "$DEFAULT_ALGORITHM" -b "$DEFAULT_BITS" -n zone "$zone")
+
+cat "$infile" "$keyname.key" > "$zonefile"
+
+"$SIGNER" -z -o "$zone" "$zonefile" > /dev/null
+
+zone=dynamic.example.
+infile=dynamic.example.db.in
+zonefile=dynamic.example.db
+
+keyname1=$("$KEYGEN" -q -a "$DEFAULT_ALGORITHM" -b "$DEFAULT_BITS" -n zone "$zone")
+keyname2=$("$KEYGEN" -q -a "$DEFAULT_ALGORITHM" -b "$DEFAULT_BITS" -n zone -f KSK "$zone")
+
+cat "$infile" "$keyname1.key" "$keyname2.key" > "$zonefile"
+
+"$SIGNER" -o "$zone" "$zonefile" > /dev/null
+
+zone=keyless.example.
+infile=generic.example.db.in
+zonefile=keyless.example.db
+
+keyname=$("$KEYGEN" -q -a "$DEFAULT_ALGORITHM" -b "$DEFAULT_BITS" -n zone "$zone")
+
+cat "$infile" "$keyname.key" > "$zonefile"
+
+"$SIGNER" -z -o "$zone" "$zonefile" > /dev/null
+
+# Change the signer field of the a.b.keyless.example RRSIG A
+# to point to a provably nonexistent DNSKEY record.
+zonefiletmp=$(mktemp "$zonefile.XXXXXX") || exit 1
+mv "$zonefile.signed" "$zonefiletmp"
+<"$zonefiletmp" "$PERL" -p -e 's/ keyless.example/ b.keyless.example/
+ if /^a.b.keyless.example/../A RRSIG NSEC/;' > "$zonefile.signed"
+rm -f "$zonefiletmp"
+
+#
+# NSEC3/NSEC test zone
+#
+zone=secure.nsec3.example.
+infile=secure.nsec3.example.db.in
+zonefile=secure.nsec3.example.db
+
+keyname=$("$KEYGEN" -q -a "$DEFAULT_ALGORITHM" -b "$DEFAULT_BITS" -n zone "$zone")
+
+cat "$infile" "$keyname.key" > "$zonefile"
+
+"$SIGNER" -z -o "$zone" "$zonefile" > /dev/null
+
+#
+# NSEC3/NSEC3 test zone
+#
+zone=nsec3.nsec3.example.
+infile=nsec3.nsec3.example.db.in
+zonefile=nsec3.nsec3.example.db
+
+keyname=$("$KEYGEN" -q -a "$DEFAULT_ALGORITHM" -b "$DEFAULT_BITS" -n zone "$zone")
+
+cat "$infile" "$keyname.key" > "$zonefile"
+
+"$SIGNER" -z -3 - -o "$zone" "$zonefile" > /dev/null
+
+#
+# OPTOUT/NSEC3 test zone
+#
+zone=optout.nsec3.example.
+infile=optout.nsec3.example.db.in
+zonefile=optout.nsec3.example.db
+
+keyname=$("$KEYGEN" -q -a "$DEFAULT_ALGORITHM" -b "$DEFAULT_BITS" -n zone "$zone")
+
+cat "$infile" "$keyname.key" > "$zonefile"
+
+"$SIGNER" -z -3 - -A -o "$zone" "$zonefile" > /dev/null
+
+#
+# A nsec3 zone (non-optout).
+#
+zone=nsec3.example.
+infile=nsec3.example.db.in
+zonefile=nsec3.example.db
+
+keyname=$("$KEYGEN" -q -a "$DEFAULT_ALGORITHM" -b "$DEFAULT_BITS" -n zone "$zone")
+
+cat "$infile" "$keyname.key" > "$zonefile"
+
+"$SIGNER" -z -g -3 - -o "$zone" "$zonefile" > /dev/null
+
+#
+# OPTOUT/NSEC test zone
+#
+zone=secure.optout.example.
+infile=secure.optout.example.db.in
+zonefile=secure.optout.example.db
+
+keyname=$("$KEYGEN" -q -a "$DEFAULT_ALGORITHM" -b "$DEFAULT_BITS" -n zone "$zone")
+
+cat "$infile" "$keyname.key" > "$zonefile"
+
+"$SIGNER" -z -o "$zone" "$zonefile" > /dev/null
+
+#
+# OPTOUT/NSEC3 test zone
+#
+zone=nsec3.optout.example.
+infile=nsec3.optout.example.db.in
+zonefile=nsec3.optout.example.db
+
+keyname=$("$KEYGEN" -q -a "$DEFAULT_ALGORITHM" -b "$DEFAULT_BITS" -n zone "$zone")
+
+cat "$infile" "$keyname.key" > "$zonefile"
+
+"$SIGNER" -z -3 - -o "$zone" "$zonefile" > /dev/null
+
+#
+# OPTOUT/OPTOUT test zone
+#
+zone=optout.optout.example.
+infile=optout.optout.example.db.in
+zonefile=optout.optout.example.db
+
+keyname=$("$KEYGEN" -q -a "$DEFAULT_ALGORITHM" -b "$DEFAULT_BITS" -n zone "$zone")
+
+cat "$infile" "$keyname.key" > "$zonefile"
+
+"$SIGNER" -z -3 - -A -o "$zone" "$zonefile" > /dev/null
+
+#
+# A optout nsec3 zone.
+#
+zone=optout.example.
+infile=optout.example.db.in
+zonefile=optout.example.db
+
+keyname=$("$KEYGEN" -q -a "$DEFAULT_ALGORITHM" -b "$DEFAULT_BITS" -n zone "$zone")
+
+cat "$infile" "$keyname.key" > "$zonefile"
+
+"$SIGNER" -z -g -3 - -A -o "$zone" "$zonefile" > /dev/null
+
+#
+# A nsec3 zone (non-optout) with unknown nsec3 hash algorithm (-U).
+#
+zone=nsec3-unknown.example.
+infile=nsec3-unknown.example.db.in
+zonefile=nsec3-unknown.example.db
+
+keyname=$("$KEYGEN" -q -a "$DEFAULT_ALGORITHM" -b "$DEFAULT_BITS" -n zone "$zone")
+
+cat "$infile" "$keyname.key" > "$zonefile"
+
+"$SIGNER" -z -3 - -PU -o "$zone" "$zonefile" > /dev/null
+
+#
+# A optout nsec3 zone with a unknown nsec3 hash algorithm (-U).
+#
+zone=optout-unknown.example.
+infile=optout-unknown.example.db.in
+zonefile=optout-unknown.example.db
+
+keyname=$("$KEYGEN" -q -a "$DEFAULT_ALGORITHM" -b "$DEFAULT_BITS" -n zone "$zone")
+
+cat "$infile" "$keyname.key" > "$zonefile"
+
+"$SIGNER" -z -3 - -PU -A -o "$zone" "$zonefile" > /dev/null
+
+#
+# A zone that is signed with an unknown DNSKEY algorithm.
+# Algorithm 7 is replaced by 100 in the zone and dsset.
+#
+zone=dnskey-unknown.example
+infile=dnskey-unknown.example.db.in
+zonefile=dnskey-unknown.example.db
+
+keyname=$("$KEYGEN" -q -a "$DEFAULT_ALGORITHM" -b "$DEFAULT_BITS" -n zone "$zone")
+
+cat "$infile" "$keyname.key" > "$zonefile"
+
+"$SIGNER" -z -3 - -o "$zone" -O full -f ${zonefile}.tmp "$zonefile" > /dev/null
+
+awk '$4 == "DNSKEY" { $7 = 100 } $4 == "RRSIG" { $6 = 100 } { print }' ${zonefile}.tmp > ${zonefile}.signed
+
+DSFILE="dsset-${zone}."
+$DSFROMKEY -A -f ${zonefile}.signed "$zone" > "$DSFILE"
+
+#
+# A zone that is signed with an unsupported DNSKEY algorithm (3).
+# Algorithm 7 is replaced by 255 in the zone and dsset.
+#
+zone=dnskey-unsupported.example
+infile=dnskey-unsupported.example.db.in
+zonefile=dnskey-unsupported.example.db
+
+keyname=$("$KEYGEN" -q -a "$DEFAULT_ALGORITHM" -b "$DEFAULT_BITS" -n zone "$zone")
+
+cat "$infile" "$keyname.key" > "$zonefile"
+
+"$SIGNER" -z -3 - -o "$zone" -O full -f ${zonefile}.tmp "$zonefile" > /dev/null
+
+awk '$4 == "DNSKEY" { $7 = 255 } $4 == "RRSIG" { $6 = 255 } { print }' ${zonefile}.tmp > ${zonefile}.signed
+
+DSFILE="dsset-${zone}."
+$DSFROMKEY -A -f ${zonefile}.signed "$zone" > "$DSFILE"
+
+#
+# A zone with a published unsupported DNSKEY algorithm (Reserved).
+# Different from above because this key is not intended for signing.
+#
+zone=dnskey-unsupported-2.example
+infile=dnskey-unsupported-2.example.db.in
+zonefile=dnskey-unsupported-2.example.db
+
+ksk=$("$KEYGEN" -f KSK -q -a "$DEFAULT_ALGORITHM" -b "$DEFAULT_BITS" -n zone "$zone")
+zsk=$("$KEYGEN" -q -a "$DEFAULT_ALGORITHM" -b "$DEFAULT_BITS" -n zone "$zone")
+
+cat "$infile" "$ksk.key" "$zsk.key" unsupported-algorithm.key > "$zonefile"
+
+"$SIGNER" -3 - -o "$zone" -f ${zonefile}.signed "$zonefile" > /dev/null
+
+#
+# A zone with a unknown DNSKEY algorithm + unknown NSEC3 hash algorithm (-U).
+# Algorithm 7 is replaced by 100 in the zone and dsset.
+#
+zone=dnskey-nsec3-unknown.example
+infile=dnskey-nsec3-unknown.example.db.in
+zonefile=dnskey-nsec3-unknown.example.db
+
+keyname=$("$KEYGEN" -q -a "$DEFAULT_ALGORITHM" -b "$DEFAULT_BITS" -n zone "$zone")
+
+cat "$infile" "$keyname.key" > "$zonefile"
+
+"$SIGNER" -z -3 - -o "$zone" -PU -O full -f ${zonefile}.tmp "$zonefile" > /dev/null
+
+awk '$4 == "DNSKEY" { $7 = 100; print } $4 == "RRSIG" { $6 = 100; print } { print }' ${zonefile}.tmp > ${zonefile}.signed
+
+DSFILE="dsset-${zone}."
+$DSFROMKEY -A -f ${zonefile}.signed "$zone" > "$DSFILE"
+
+#
+# A multiple parameter nsec3 zone.
+#
+zone=multiple.example.
+infile=multiple.example.db.in
+zonefile=multiple.example.db
+
+keyname=$("$KEYGEN" -q -a "$DEFAULT_ALGORITHM" -b "$DEFAULT_BITS" -n zone "$zone")
+
+cat "$infile" "$keyname.key" > "$zonefile"
+
+"$SIGNER" -z -O full -o "$zone" "$zonefile" > /dev/null
+awk '$4 == "NSEC" || ( $4 == "RRSIG" && $5 == "NSEC" ) { print }' "$zonefile".signed > NSEC
+"$SIGNER" -z -O full -u3 - -o "$zone" "$zonefile" > /dev/null
+awk '$4 == "NSEC3" || ( $4 == "RRSIG" && $5 == "NSEC3" ) { print }' "$zonefile".signed > NSEC3
+"$SIGNER" -z -O full -u3 AAAA -o "$zone" "$zonefile" > /dev/null
+awk '$4 == "NSEC3" || ( $4 == "RRSIG" && $5 == "NSEC3" ) { print }' "$zonefile".signed >> NSEC3
+"$SIGNER" -z -O full -u3 BBBB -o "$zone" "$zonefile" > /dev/null
+awk '$4 == "NSEC3" || ( $4 == "RRSIG" && $5 == "NSEC3" ) { print }' "$zonefile".signed >> NSEC3
+"$SIGNER" -z -O full -u3 CCCC -o "$zone" "$zonefile" > /dev/null
+awk '$4 == "NSEC3" || ( $4 == "RRSIG" && $5 == "NSEC3" ) { print }' "$zonefile".signed >> NSEC3
+"$SIGNER" -z -O full -u3 DDDD -o "$zone" "$zonefile" > /dev/null
+cat NSEC NSEC3 >> "$zonefile".signed
+
+#
+# A RSASHA256 zone.
+#
+zone=rsasha256.example.
+infile=rsasha256.example.db.in
+zonefile=rsasha256.example.db
+
+keyname=$("$KEYGEN" -q -a RSASHA256 -n zone "$zone")
+
+cat "$infile" "$keyname.key" > "$zonefile"
+
+"$SIGNER" -P -o "$zone" "$zonefile" > /dev/null
+
+#
+# A RSASHA512 zone.
+#
+zone=rsasha512.example.
+infile=rsasha512.example.db.in
+zonefile=rsasha512.example.db
+
+keyname=$("$KEYGEN" -q -a RSASHA512 -n zone "$zone")
+
+cat "$infile" "$keyname.key" > "$zonefile"
+
+"$SIGNER" -P -o "$zone" "$zonefile" > /dev/null
+
+#
+# A zone with the DNSKEY set only signed by the KSK
+#
+zone=kskonly.example.
+infile=kskonly.example.db.in
+zonefile=kskonly.example.db
+
+kskname=$("$KEYGEN" -q -a "$DEFAULT_ALGORITHM" -b "$DEFAULT_BITS" -f KSK "$zone")
+zskname=$("$KEYGEN" -q -a "$DEFAULT_ALGORITHM" -b "$DEFAULT_BITS" "$zone")
+cat "$infile" "$kskname.key" "$zskname.key" > "$zonefile"
+"$SIGNER" -x -o "$zone" "$zonefile" > /dev/null
+
+#
+# A zone with the expired signatures
+#
+zone=expired.example.
+infile=expired.example.db.in
+zonefile=expired.example.db
+
+kskname=$("$KEYGEN" -q -a "$DEFAULT_ALGORITHM" -b "$DEFAULT_BITS" -fk "$zone")
+zskname=$("$KEYGEN" -q -a "$DEFAULT_ALGORITHM" -b "$DEFAULT_BITS" "$zone")
+cat "$infile" "$kskname.key" "$zskname.key" > "$zonefile"
+"$SIGNER" -P -o "$zone" -s -1d -e +1h "$zonefile" > /dev/null
+rm -f "$kskname.*" "$zskname.*"
+
+#
+# A NSEC3 signed zone that will have a DNSKEY added to it via UPDATE.
+#
+zone=update-nsec3.example.
+infile=update-nsec3.example.db.in
+zonefile=update-nsec3.example.db
+
+kskname=$("$KEYGEN" -q -3 -a "$DEFAULT_ALGORITHM" -b "$DEFAULT_BITS" -fk "$zone")
+zskname=$("$KEYGEN" -q -3 -a "$DEFAULT_ALGORITHM" -b "$DEFAULT_BITS" "$zone")
+cat "$infile" "$kskname.key" "$zskname.key" > "$zonefile"
+"$SIGNER" -P -3 - -o "$zone" "$zonefile" > /dev/null
+
+#
+# A NSEC signed zone that will have auto-dnssec enabled and
+# extra keys not in the initial signed zone.
+#
+zone=auto-nsec.example.
+infile=auto-nsec.example.db.in
+zonefile=auto-nsec.example.db
+
+kskname=$("$KEYGEN" -q -a "$DEFAULT_ALGORITHM" -b "$DEFAULT_BITS" -fk "$zone")
+zskname=$("$KEYGEN" -q -a "$DEFAULT_ALGORITHM" -b "$DEFAULT_BITS" "$zone")
+kskname=$("$KEYGEN" -q -a "$DEFAULT_ALGORITHM" -b "$DEFAULT_BITS" -fk "$zone")
+zskname=$("$KEYGEN" -q -a "$DEFAULT_ALGORITHM" -b "$DEFAULT_BITS" "$zone")
+cat "$infile" "$kskname.key" "$zskname.key" > "$zonefile"
+"$SIGNER" -P -o "$zone" "$zonefile" > /dev/null
+
+#
+# A NSEC3 signed zone that will have auto-dnssec enabled and
+# extra keys not in the initial signed zone.
+#
+zone=auto-nsec3.example.
+infile=auto-nsec3.example.db.in
+zonefile=auto-nsec3.example.db
+
+kskname=$("$KEYGEN" -q -3 -a "$DEFAULT_ALGORITHM" -b "$DEFAULT_BITS" -fk "$zone")
+zskname=$("$KEYGEN" -q -3 -a "$DEFAULT_ALGORITHM" -b "$DEFAULT_BITS" "$zone")
+kskname=$("$KEYGEN" -q -3 -a "$DEFAULT_ALGORITHM" -b "$DEFAULT_BITS" -fk "$zone")
+zskname=$("$KEYGEN" -q -3 -a "$DEFAULT_ALGORITHM" -b "$DEFAULT_BITS" "$zone")
+cat "$infile" "$kskname.key" "$zskname.key" > "$zonefile"
+"$SIGNER" -P -3 - -o "$zone" "$zonefile" > /dev/null
+
+#
+# Secure below cname test zone.
+#
+zone=secure.below-cname.example.
+infile=secure.below-cname.example.db.in
+zonefile=secure.below-cname.example.db
+keyname=$("$KEYGEN" -q -a "$DEFAULT_ALGORITHM" -b "$DEFAULT_BITS" -n zone "$zone")
+cat "$infile" "$keyname.key" > "$zonefile"
+"$SIGNER" -P -o "$zone" "$zonefile" > /dev/null
+
+#
+# Patched TTL test zone.
+#
+zone=ttlpatch.example.
+infile=ttlpatch.example.db.in
+zonefile=ttlpatch.example.db
+signedfile=ttlpatch.example.db.signed
+patchedfile=ttlpatch.example.db.patched
+
+keyname=$("$KEYGEN" -q -a "$DEFAULT_ALGORITHM" -b "$DEFAULT_BITS" -n zone "$zone")
+cat "$infile" "$keyname.key" > "$zonefile"
+
+"$SIGNER" -P -f $signedfile -o "$zone" "$zonefile" > /dev/null
+$CHECKZONE -D -s full "$zone" $signedfile 2> /dev/null | \
+ awk '{$2 = "3600"; print}' > $patchedfile
+
+#
+# Separate DNSSEC records.
+#
+zone=split-dnssec.example.
+infile=split-dnssec.example.db.in
+zonefile=split-dnssec.example.db
+signedfile=split-dnssec.example.db.signed
+
+keyname=$("$KEYGEN" -q -a "$DEFAULT_ALGORITHM" -b "$DEFAULT_BITS" -n zone "$zone")
+cat "$infile" "$keyname.key" > "$zonefile"
+echo "\$INCLUDE \"$signedfile\"" >> "$zonefile"
+: > "$signedfile"
+"$SIGNER" -P -D -o "$zone" "$zonefile" > /dev/null
+
+#
+# Separate DNSSEC records smart signing.
+#
+zone=split-smart.example.
+infile=split-smart.example.db.in
+zonefile=split-smart.example.db
+signedfile=split-smart.example.db.signed
+
+keyname=$("$KEYGEN" -q -a "$DEFAULT_ALGORITHM" -b "$DEFAULT_BITS" -n zone "$zone")
+cp "$infile" "$zonefile"
+# shellcheck disable=SC2016
+echo "\$INCLUDE \"$signedfile\"" >> "$zonefile"
+: > "$signedfile"
+"$SIGNER" -P -S -D -o "$zone" "$zonefile" > /dev/null
+
+#
+# Zone with signatures about to expire, but no private key to replace them
+#
+zone="expiring.example."
+infile="expiring.example.db.in"
+zonefile="expiring.example.db"
+signedfile="expiring.example.db.signed"
+kskname=$("$KEYGEN" -q -a "$DEFAULT_ALGORITHM" -b "$DEFAULT_BITS" "$zone")
+zskname=$("$KEYGEN" -q -a "$DEFAULT_ALGORITHM" -b "$DEFAULT_BITS" -f KSK "$zone")
+cp "$infile" "$zonefile"
+"$SIGNER" -S -e now+1mi -o "$zone" "$zonefile" > /dev/null
+mv -f "${zskname}.private" "${zskname}.private.moved"
+mv -f "${kskname}.private" "${kskname}.private.moved"
+
+#
+# A zone where the signer's name has been forced to uppercase.
+#
+zone="upper.example."
+infile="upper.example.db.in"
+zonefile="upper.example.db"
+lower="upper.example.db.lower"
+signedfile="upper.example.db.signed"
+kskname=$("$KEYGEN" -q -a "$DEFAULT_ALGORITHM" -b "$DEFAULT_BITS" "$zone")
+zskname=$("$KEYGEN" -q -a "$DEFAULT_ALGORITHM" -b "$DEFAULT_BITS" -f KSK "$zone")
+cp "$infile" "$zonefile"
+"$SIGNER" -P -S -o "$zone" -f $lower "$zonefile" > /dev/null
+$CHECKZONE -D upper.example $lower 2>/dev/null | \
+ sed '/RRSIG/s/ upper.example. / UPPER.EXAMPLE. /' > $signedfile
+
+#
+# Check that the signer's name is in lower case when zone name is in
+# upper case.
+#
+zone="LOWER.EXAMPLE."
+infile="lower.example.db.in"
+zonefile="lower.example.db"
+signedfile="lower.example.db.signed"
+kskname=$("$KEYGEN" -q -a "$DEFAULT_ALGORITHM" -b "$DEFAULT_BITS" "$zone")
+zskname=$("$KEYGEN" -q -a "$DEFAULT_ALGORITHM" -b "$DEFAULT_BITS" -f KSK "$zone")
+cp "$infile" "$zonefile"
+"$SIGNER" -P -S -o "$zone" "$zonefile" > /dev/null
+
+#
+# Zone with signatures about to expire, and dynamic, but configured
+# not to resign with 'auto-resign no;'
+#
+zone="nosign.example."
+infile="nosign.example.db.in"
+zonefile="nosign.example.db"
+signedfile="nosign.example.db.signed"
+kskname=$("$KEYGEN" -q -a "$DEFAULT_ALGORITHM" -b "$DEFAULT_BITS" "$zone")
+zskname=$("$KEYGEN" -q -a "$DEFAULT_ALGORITHM" -b "$DEFAULT_BITS" -f KSK "$zone")
+cp "$infile" "$zonefile"
+"$SIGNER" -S -e "now+1mi" -o "$zone" "$zonefile" > /dev/null
+# preserve a normalized copy of the NS RRSIG for comparison later
+$CHECKZONE -D nosign.example nosign.example.db.signed 2>/dev/null | \
+ awk '$4 == "RRSIG" && $5 == "NS" {$2 = ""; print}' | \
+ sed 's/[ ][ ]*/ /g'> ../nosign.before
+
+#
+# An inline signing zone
+#
+zone=inline.example.
+kskname=$("$KEYGEN" -q -3 -a "$DEFAULT_ALGORITHM" -b "$DEFAULT_BITS" -fk "$zone")
+zskname=$("$KEYGEN" -q -3 -a "$DEFAULT_ALGORITHM" -b "$DEFAULT_BITS" "$zone")
+
+#
+# publish a new key while deactivating another key at the same time.
+#
+zone=publish-inactive.example
+infile=publish-inactive.example.db.in
+zonefile=publish-inactive.example.db
+now=$(date -u +%Y%m%d%H%M%S)
+kskname=$("$KEYGEN" -q -a "$DEFAULT_ALGORITHM" -b "$DEFAULT_BITS" -f KSK "$zone")
+kskname=$("$KEYGEN" -P "$now+90s" -A "$now+3600s" -q -a "$DEFAULT_ALGORITHM" -b "$DEFAULT_BITS" -f KSK "$zone")
+kskname=$("$KEYGEN" -I "$now+90s" -q -a "$DEFAULT_ALGORITHM" -b "$DEFAULT_BITS" -f KSK "$zone")
+zskname=$("$KEYGEN" -q -a "$DEFAULT_ALGORITHM" -b "$DEFAULT_BITS" "$zone")
+cp "$infile" "$zonefile"
+"$SIGNER" -S -o "$zone" "$zonefile" > /dev/null
+
+#
+# A zone which will change its sig-validity-interval
+#
+zone=siginterval.example
+infile=siginterval.example.db.in
+zonefile=siginterval.example.db
+kskname=$("$KEYGEN" -q -3 -a "$DEFAULT_ALGORITHM" -b "$DEFAULT_BITS" -fk "$zone")
+zskname=$("$KEYGEN" -q -3 -a "$DEFAULT_ALGORITHM" -b "$DEFAULT_BITS" "$zone")
+cp "$infile" "$zonefile"
+
+#
+# A zone with a bad DS in the parent
+# (sourced from bogus.example.db.in)
+#
+zone=badds.example.
+infile=bogus.example.db.in
+zonefile=badds.example.db
+
+keyname=$("$KEYGEN" -q -a "$DEFAULT_ALGORITHM" -b "$DEFAULT_BITS" -n zone "$zone")
+
+cat "$infile" "$keyname.key" > "$zonefile"
+
+"$SIGNER" -P -o "$zone" "$zonefile" > /dev/null
+sed -e 's/bogus/badds/g' < dsset-bogus.example. > dsset-badds.example.
+
+#
+# A zone with future signatures.
+#
+zone=future.example
+infile=future.example.db.in
+zonefile=future.example.db
+kskname=$("$KEYGEN" -q -a "$DEFAULT_ALGORITHM" -b "$DEFAULT_BITS" -f KSK "$zone")
+zskname=$("$KEYGEN" -q -a "$DEFAULT_ALGORITHM" -b "$DEFAULT_BITS" "$zone")
+cat "$infile" "$kskname.key" "$zskname.key" > "$zonefile"
+"$SIGNER" -P -s +3600 -o "$zone" "$zonefile" > /dev/null
+cp -f "$kskname.key" trusted-future.key
+
+#
+# A zone with future signatures.
+#
+zone=managed-future.example
+infile=managed-future.example.db.in
+zonefile=managed-future.example.db
+kskname=$("$KEYGEN" -q -a "$DEFAULT_ALGORITHM" -b "$DEFAULT_BITS" -f KSK "$zone")
+zskname=$("$KEYGEN" -q -a "$DEFAULT_ALGORITHM" -b "$DEFAULT_BITS" "$zone")
+cat "$infile" "$kskname.key" "$zskname.key" > "$zonefile"
+"$SIGNER" -P -s +3600 -o "$zone" "$zonefile" > /dev/null
+
+#
+# A zone with a revoked key
+#
+zone=revkey.example.
+infile=generic.example.db.in
+zonefile=revkey.example.db
+
+ksk1=$("$KEYGEN" -q -a "$DEFAULT_ALGORITHM" -b "$DEFAULT_BITS" -3fk "$zone")
+ksk1=$("$REVOKE" "$ksk1")
+ksk2=$("$KEYGEN" -q -a "$DEFAULT_ALGORITHM" -b "$DEFAULT_BITS" -3fk "$zone")
+zsk1=$("$KEYGEN" -q -a "$DEFAULT_ALGORITHM" -b "$DEFAULT_BITS" -3 "$zone")
+
+cat "$infile" "${ksk1}.key" "${ksk2}.key" "${zsk1}.key" > "$zonefile"
+"$SIGNER" -P -o "$zone" "$zonefile" > /dev/null
+
+#
+# Check that NSEC3 are correctly signed and returned from below a DNAME
+#
+zone=dname-at-apex-nsec3.example
+infile=dname-at-apex-nsec3.example.db.in
+zonefile=dname-at-apex-nsec3.example.db
+
+kskname=$("$KEYGEN" -q -a "$DEFAULT_ALGORITHM" -3fk "$zone")
+zskname=$("$KEYGEN" -q -a "$DEFAULT_ALGORITHM" -3 "$zone")
+cat "$infile" "${kskname}.key" "${zskname}.key" >"$zonefile"
+"$SIGNER" -P -3 - -o "$zone" "$zonefile" > /dev/null
+
+#
+# A NSEC zone with occuded data at the delegation
+#
+zone=occluded.example
+infile=occluded.example.db.in
+zonefile=occluded.example.db
+kskname=$("$KEYGEN" -q -a "$DEFAULT_ALGORITHM" -fk "$zone")
+zskname=$("$KEYGEN" -q -a "$DEFAULT_ALGORITHM" "$zone")
+dnskeyname=$("$KEYGEN" -q -a "$DEFAULT_ALGORITHM" -fk "delegation.$zone")
+keyname=$("$KEYGEN" -q -a DH -b 1024 -n HOST -T KEY "delegation.$zone")
+$DSFROMKEY "$dnskeyname.key" > "dsset-delegation.${zone}."
+cat "$infile" "${kskname}.key" "${zskname}.key" "${keyname}.key" \
+ "${dnskeyname}.key" "dsset-delegation.${zone}." >"$zonefile"
+"$SIGNER" -P -o "$zone" "$zonefile" > /dev/null
diff --git a/bin/tests/system/dnssec/ns3/split-dnssec.example.db.in b/bin/tests/system/dnssec/ns3/split-dnssec.example.db.in
new file mode 100644
index 0000000..55b3877
--- /dev/null
+++ b/bin/tests/system/dnssec/ns3/split-dnssec.example.db.in
@@ -0,0 +1,38 @@
+; Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+;
+; SPDX-License-Identifier: MPL-2.0
+;
+; This Source Code Form is subject to the terms of the Mozilla Public
+; License, v. 2.0. If a copy of the MPL was not distributed with this
+; file, you can obtain one at https://mozilla.org/MPL/2.0/.
+;
+; See the COPYRIGHT file distributed with this work for additional
+; information regarding copyright ownership.
+
+$TTL 300 ; 5 minutes
+@ IN SOA mname1. . (
+ 2000042407 ; serial
+ 20 ; refresh (20 seconds)
+ 20 ; retry (20 seconds)
+ 1814400 ; expire (3 weeks)
+ 3600 ; minimum (1 hour)
+ )
+ NS ns
+ns A 10.53.0.3
+
+a A 10.0.0.1
+b A 10.0.0.2
+d A 10.0.0.4
+z A 10.0.0.26
+a.a.a.a A 10.0.0.3
+*.wild A 10.0.0.6
+child NS ns2.example.
+insecure NS ns.insecure
+ns.insecure A 10.53.0.3
+secure NS ns.secure
+ns.secure A 10.53.0.3
+nsec3 NS ns.nsec3
+ns.nsec3 A 10.53.0.3
+optout NS ns.optout
+ns.optout A 10.53.0.3
+02HC3EM7BDD011A0GMS3HKKJT2IF5VP8 A 10.0.0.17
diff --git a/bin/tests/system/dnssec/ns3/split-smart.example.db.in b/bin/tests/system/dnssec/ns3/split-smart.example.db.in
new file mode 100644
index 0000000..55b3877
--- /dev/null
+++ b/bin/tests/system/dnssec/ns3/split-smart.example.db.in
@@ -0,0 +1,38 @@
+; Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+;
+; SPDX-License-Identifier: MPL-2.0
+;
+; This Source Code Form is subject to the terms of the Mozilla Public
+; License, v. 2.0. If a copy of the MPL was not distributed with this
+; file, you can obtain one at https://mozilla.org/MPL/2.0/.
+;
+; See the COPYRIGHT file distributed with this work for additional
+; information regarding copyright ownership.
+
+$TTL 300 ; 5 minutes
+@ IN SOA mname1. . (
+ 2000042407 ; serial
+ 20 ; refresh (20 seconds)
+ 20 ; retry (20 seconds)
+ 1814400 ; expire (3 weeks)
+ 3600 ; minimum (1 hour)
+ )
+ NS ns
+ns A 10.53.0.3
+
+a A 10.0.0.1
+b A 10.0.0.2
+d A 10.0.0.4
+z A 10.0.0.26
+a.a.a.a A 10.0.0.3
+*.wild A 10.0.0.6
+child NS ns2.example.
+insecure NS ns.insecure
+ns.insecure A 10.53.0.3
+secure NS ns.secure
+ns.secure A 10.53.0.3
+nsec3 NS ns.nsec3
+ns.nsec3 A 10.53.0.3
+optout NS ns.optout
+ns.optout A 10.53.0.3
+02HC3EM7BDD011A0GMS3HKKJT2IF5VP8 A 10.0.0.17
diff --git a/bin/tests/system/dnssec/ns3/ttlpatch.example.db.in b/bin/tests/system/dnssec/ns3/ttlpatch.example.db.in
new file mode 100644
index 0000000..14971bd
--- /dev/null
+++ b/bin/tests/system/dnssec/ns3/ttlpatch.example.db.in
@@ -0,0 +1,26 @@
+; Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+;
+; SPDX-License-Identifier: MPL-2.0
+;
+; This Source Code Form is subject to the terms of the Mozilla Public
+; License, v. 2.0. If a copy of the MPL was not distributed with this
+; file, you can obtain one at https://mozilla.org/MPL/2.0/.
+;
+; See the COPYRIGHT file distributed with this work for additional
+; information regarding copyright ownership.
+
+$TTL 300 ; 5 minutes
+@ IN SOA mname1. . (
+ 2000042407 ; serial
+ 20 ; refresh (20 seconds)
+ 20 ; retry (20 seconds)
+ 1814400 ; expire (3 weeks)
+ 3600 ; minimum (1 hour)
+ )
+ NS ns
+ns A 10.53.0.3
+
+a A 10.0.0.1
+b A 10.0.0.2
+d A 10.0.0.4
+z A 10.0.0.26
diff --git a/bin/tests/system/dnssec/ns3/unsupported-algorithm.key b/bin/tests/system/dnssec/ns3/unsupported-algorithm.key
new file mode 100644
index 0000000..cc8bb9a
--- /dev/null
+++ b/bin/tests/system/dnssec/ns3/unsupported-algorithm.key
@@ -0,0 +1 @@
+dnskey-unsupported-2.example. IN DNSKEY 257 3 255 BJ0eV4dQC0pihdFXiVdlXjPDkzbv4fC+opEvK0RaDU7LLwFXPAi6DOc6tm7vcSr5Tgdnpoal3S4WqHuVw6I1pzy5mPPIZ3OpLSY/QeOyGc2QRAZtOXxiGxERHRjyAk7emlgGscM0Vty2oJVYRgTPX0lTwKX/V2H+mjEgp7u3tyG3cj5XBUQ8J0KUoqkrn1ZKrizH27aWiDaBUvqxJUcotaDhnydkNtcHoQIedm2b4qbyTQsdRkddJiSWxpveEcj3AMdt2PjU6Q4rgSWOc5ylPnW/O+GqqCEAkalGSF7ud0Nl3FVVR9iGwV/73FHzpBLawfkcHaODFmKRjzGqok8giKCih2vdNsxlx7gdJWJIPYYx/ZqNGc2ewzuAnnleJpZdXFo8uL3HYk6Pl51sSkfVUmcn/SM+ ;{id = 38688 (ksk), size = 768b}
diff --git a/bin/tests/system/dnssec/ns3/update-nsec3.example.db.in b/bin/tests/system/dnssec/ns3/update-nsec3.example.db.in
new file mode 100644
index 0000000..a7792fd
--- /dev/null
+++ b/bin/tests/system/dnssec/ns3/update-nsec3.example.db.in
@@ -0,0 +1,40 @@
+; Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+;
+; SPDX-License-Identifier: MPL-2.0
+;
+; This Source Code Form is subject to the terms of the Mozilla Public
+; License, v. 2.0. If a copy of the MPL was not distributed with this
+; file, you can obtain one at https://mozilla.org/MPL/2.0/.
+;
+; See the COPYRIGHT file distributed with this work for additional
+; information regarding copyright ownership.
+
+$TTL 300 ; 5 minutes
+@ IN SOA mname1. . (
+ 2000042407 ; serial
+ 20 ; refresh (20 seconds)
+ 20 ; retry (20 seconds)
+ 1814400 ; expire (3 weeks)
+ 3600 ; minimum (1 hour)
+ )
+ NS ns
+ns A 10.53.0.3
+
+a A 10.0.0.1
+b A 10.0.0.2
+d A 10.0.0.4
+z A 10.0.0.26
+a.a.a.a.a.a.a.a.a.a.e A 10.0.0.27
+x CNAME a
+
+private NS ns.private
+ns.private A 10.53.0.2
+
+insecure NS ns.insecure
+ns.insecure A 10.53.0.2
+
+nosoa NS ns.nosoa
+ns.nosoa A 10.53.0.7
+
+normalthenrrsig A 10.0.0.28
+rrsigonly A 10.0.0.29
diff --git a/bin/tests/system/dnssec/ns3/upper.example.db.in b/bin/tests/system/dnssec/ns3/upper.example.db.in
new file mode 100644
index 0000000..ec6603a
--- /dev/null
+++ b/bin/tests/system/dnssec/ns3/upper.example.db.in
@@ -0,0 +1,21 @@
+; Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+;
+; SPDX-License-Identifier: MPL-2.0
+;
+; This Source Code Form is subject to the terms of the Mozilla Public
+; License, v. 2.0. If a copy of the MPL was not distributed with this
+; file, you can obtain one at https://mozilla.org/MPL/2.0/.
+;
+; See the COPYRIGHT file distributed with this work for additional
+; information regarding copyright ownership.
+
+$TTL 300 ; 5 minutes
+@ IN SOA mname1. . (
+ 2012042407 ; serial
+ 20 ; refresh (20 seconds)
+ 20 ; retry (20 seconds)
+ 1814400 ; expire (3 weeks)
+ 3600 ; minimum (1 hour)
+ )
+@ NS ns
+ns A 10.53.0.3
diff --git a/bin/tests/system/dnssec/ns4/managed-keys.bind.in b/bin/tests/system/dnssec/ns4/managed-keys.bind.in
new file mode 100644
index 0000000..570669d
--- /dev/null
+++ b/bin/tests/system/dnssec/ns4/managed-keys.bind.in
@@ -0,0 +1,21 @@
+; Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+;
+; SPDX-License-Identifier: MPL-2.0
+;
+; This Source Code Form is subject to the terms of the Mozilla Public
+; License, v. 2.0. If a copy of the MPL was not distributed with this
+; file, you can obtain one at https://mozilla.org/MPL/2.0/.
+;
+; See the COPYRIGHT file distributed with this work for additional
+; information regarding copyright ownership.
+
+$ORIGIN .
+$TTL 0 ; 0 seconds
+@ IN SOA . . (
+ 2 ; serial
+ 0 ; refresh (0 seconds)
+ 0 ; retry (0 seconds)
+ 0 ; expire (0 seconds)
+ 0 ; minimum (0 seconds)
+ )
+ KEYDATA 20221028094934 19700101000000 19700101000000 0 0 0 ; placeholder
diff --git a/bin/tests/system/dnssec/ns4/named1.conf.in b/bin/tests/system/dnssec/ns4/named1.conf.in
new file mode 100644
index 0000000..280217e
--- /dev/null
+++ b/bin/tests/system/dnssec/ns4/named1.conf.in
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * SPDX-License-Identifier: MPL-2.0
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, you can obtain one at https://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+// NS4
+
+options {
+ query-source address 10.53.0.4;
+ notify-source 10.53.0.4;
+ transfer-source 10.53.0.4;
+ port @PORT@;
+ pid-file "named.pid";
+ listen-on { 10.53.0.4; };
+ listen-on-v6 { none; };
+ recursion yes;
+ dnssec-validation yes;
+ dnssec-must-be-secure mustbesecure.example yes;
+ minimal-responses no;
+
+ nta-lifetime 12s;
+ nta-recheck 9s;
+
+ validate-except { corp; };
+
+ # Note: We only reference the bind.keys file here to confirm that it
+ # is *not* being used. It contains the real root key, and we're
+ # using a local toy root zone for the tests, so it wouldn't work.
+ # But since dnssec-validation is set to "yes" not "auto", that
+ # won't matter.
+ bindkeys-file "../../../../../bind.keys";
+};
+
+key rndc_key {
+ secret "1234abcd8765";
+ algorithm @DEFAULT_HMAC@;
+};
+
+controls {
+ inet 10.53.0.4 port @CONTROLPORT@ allow { any; } keys { rndc_key; };
+};
+
+zone "." {
+ type hint;
+ file "../../common/root.hint";
+};
+
+zone "corp" {
+ type static-stub;
+ server-addresses { 10.53.0.2; };
+};
+
+include "trusted.conf";
diff --git a/bin/tests/system/dnssec/ns4/named2.conf.in b/bin/tests/system/dnssec/ns4/named2.conf.in
new file mode 100644
index 0000000..b01979b
--- /dev/null
+++ b/bin/tests/system/dnssec/ns4/named2.conf.in
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * SPDX-License-Identifier: MPL-2.0
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, you can obtain one at https://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+// NS4
+
+options {
+ query-source address 10.53.0.4;
+ notify-source 10.53.0.4;
+ transfer-source 10.53.0.4;
+ port @PORT@;
+ pid-file "named.pid";
+ listen-on { 10.53.0.4; };
+ listen-on-v6 { none; };
+ recursion yes;
+ dnssec-validation auto;
+ bindkeys-file "managed.conf";
+ minimal-responses no;
+};
+
+key rndc_key {
+ secret "1234abcd8765";
+ algorithm @DEFAULT_HMAC@;
+};
+
+controls {
+ inet 10.53.0.4 port @CONTROLPORT@ allow { any; } keys { rndc_key; };
+};
+
+zone "." {
+ type hint;
+ file "../../common/root.hint";
+};
diff --git a/bin/tests/system/dnssec/ns4/named3.conf.in b/bin/tests/system/dnssec/ns4/named3.conf.in
new file mode 100644
index 0000000..3a64e9d
--- /dev/null
+++ b/bin/tests/system/dnssec/ns4/named3.conf.in
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * SPDX-License-Identifier: MPL-2.0
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, you can obtain one at https://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+// NS4
+
+options {
+ query-source address 10.53.0.4;
+ notify-source 10.53.0.4;
+ transfer-source 10.53.0.4;
+ port @PORT@;
+ pid-file "named.pid";
+ listen-on { 10.53.0.4; };
+ listen-on-v6 { none; };
+ recursion yes;
+ dnssec-validation auto;
+ bindkeys-file "managed.conf";
+ dnssec-accept-expired yes;
+ minimal-responses no;
+};
+
+key rndc_key {
+ secret "1234abcd8765";
+ algorithm @DEFAULT_HMAC@;
+};
+
+controls {
+ inet 10.53.0.4 port @CONTROLPORT@ allow { any; } keys { rndc_key; };
+};
+
+zone "." {
+ type hint;
+ file "../../common/root.hint";
+};
diff --git a/bin/tests/system/dnssec/ns4/named4.conf.in b/bin/tests/system/dnssec/ns4/named4.conf.in
new file mode 100644
index 0000000..5d3bf3f
--- /dev/null
+++ b/bin/tests/system/dnssec/ns4/named4.conf.in
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * SPDX-License-Identifier: MPL-2.0
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, you can obtain one at https://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+// NS4
+
+options {
+ query-source address 10.53.0.4;
+ notify-source 10.53.0.4;
+ transfer-source 10.53.0.4;
+ port @PORT@;
+ pid-file "named.pid";
+ listen-on { 10.53.0.4; };
+ listen-on-v6 { none; };
+};
+
+key rndc_key {
+ secret "1234abcd8765";
+ algorithm @DEFAULT_HMAC@;
+};
+
+controls {
+ inet 10.53.0.4 port @CONTROLPORT@ allow { any; } keys { rndc_key; };
+};
+
+key auth {
+ secret "1234abcd8765";
+ algorithm @DEFAULT_HMAC@;
+};
+
+include "trusted.conf";
+
+view rec {
+ match-recursive-only yes;
+ recursion yes;
+ dnssec-validation yes;
+ dnssec-accept-expired yes;
+ minimal-responses no;
+
+ zone "." {
+ type hint;
+ file "../../common/root.hint";
+ };
+
+ zone secure.example {
+ type static-stub;
+ server-addresses { 10.53.0.4; };
+ };
+
+ zone insecure.secure.example {
+ type static-stub;
+ server-addresses { 10.53.0.4; };
+ };
+};
+
+view auth {
+ recursion no;
+ allow-recursion { none; };
+
+ zone secure.example {
+ type secondary;
+ primaries { 10.53.0.3; };
+ };
+
+ zone insecure.secure.example {
+ type secondary;
+ primaries { 10.53.0.2; };
+ };
+};
diff --git a/bin/tests/system/dnssec/ns4/named5.conf.in b/bin/tests/system/dnssec/ns4/named5.conf.in
new file mode 100644
index 0000000..88caaca
--- /dev/null
+++ b/bin/tests/system/dnssec/ns4/named5.conf.in
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * SPDX-License-Identifier: MPL-2.0
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, you can obtain one at https://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+// NS4
+
+options {
+ query-source address 10.53.0.4;
+ notify-source 10.53.0.4;
+ transfer-source 10.53.0.4;
+ port @PORT@;
+ pid-file "named.pid";
+ listen-on { 10.53.0.4; };
+ listen-on-v6 { none; };
+ bindkeys-file "managed.conf";
+ dnssec-validation no;
+};
+
+key rndc_key {
+ secret "1234abcd8765";
+ algorithm @DEFAULT_HMAC@;
+};
+
+controls {
+ inet 10.53.0.4 port @CONTROLPORT@ allow { any; } keys { rndc_key; };
+};
+
+key auth {
+ secret "1234abcd8765";
+ algorithm hmac-sha256;
+};
diff --git a/bin/tests/system/dnssec/ns5/named1.conf.in b/bin/tests/system/dnssec/ns5/named1.conf.in
new file mode 100644
index 0000000..ccb3de9
--- /dev/null
+++ b/bin/tests/system/dnssec/ns5/named1.conf.in
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * SPDX-License-Identifier: MPL-2.0
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, you can obtain one at https://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+// NS5
+
+options {
+ query-source address 10.53.0.5;
+ notify-source 10.53.0.5;
+ transfer-source 10.53.0.5;
+ port @PORT@;
+ pid-file "named.pid";
+ listen-on { 10.53.0.5; };
+ listen-on-v6 { none; };
+ recursion yes;
+ dnssec-validation yes;
+};
+
+key rndc_key {
+ secret "1234abcd8765";
+ algorithm @DEFAULT_HMAC@;
+};
+
+controls {
+ inet 10.53.0.5 port @CONTROLPORT@ allow { any; } keys { rndc_key; };
+};
+
+
+zone "." {
+ type hint;
+ file "../../common/root.hint";
+};
+
+include "trusted.conf";
diff --git a/bin/tests/system/dnssec/ns5/named2.conf.in b/bin/tests/system/dnssec/ns5/named2.conf.in
new file mode 100644
index 0000000..6d0474b
--- /dev/null
+++ b/bin/tests/system/dnssec/ns5/named2.conf.in
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * SPDX-License-Identifier: MPL-2.0
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, you can obtain one at https://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+// NS5
+
+key rndc_key {
+ secret "1234abcd8765";
+ algorithm @DEFAULT_HMAC@;
+};
+
+controls {
+ inet 10.53.0.5 port @CONTROLPORT@ allow { any; } keys { rndc_key; };
+};
+
+options {
+ query-source address 10.53.0.5;
+ notify-source 10.53.0.5;
+ transfer-source 10.53.0.5;
+ port @PORT@;
+ pid-file "named.pid";
+ listen-on { 10.53.0.5; 127.0.0.1; };
+ listen-on-v6 { none; };
+ recursion yes;
+ dnssec-validation yes;
+};
+
+view root {
+ match-destinations { 127.0.0.1; };
+
+ zone "." {
+ type primary;
+ file "root.db.signed";
+ };
+};
+
+view other {
+include "revoked.conf";
+
+ zone "." {
+ type static-stub;
+ server-addresses { 127.0.0.1; };
+ };
+};
diff --git a/bin/tests/system/dnssec/ns5/sign.sh b/bin/tests/system/dnssec/ns5/sign.sh
new file mode 100644
index 0000000..df0b208
--- /dev/null
+++ b/bin/tests/system/dnssec/ns5/sign.sh
@@ -0,0 +1,39 @@
+#!/bin/sh -e
+
+# Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+#
+# SPDX-License-Identifier: MPL-2.0
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, you can obtain one at https://mozilla.org/MPL/2.0/.
+#
+# See the COPYRIGHT file distributed with this work for additional
+# information regarding copyright ownership.
+
+# shellcheck source=conf.sh
+. ../../conf.sh
+
+set -e
+
+echo_i "ns5/sign.sh"
+
+zone=.
+infile=../ns1/root.db.in
+zonefile=root.db.signed
+
+keyname=$("$KEYGEN" -q -a "$DEFAULT_ALGORITHM" -b "$DEFAULT_BITS" -f KSK "$zone")
+
+# copy the KSK out first, then revoke it
+keyfile_to_initial_ds "$keyname" > revoked.conf
+
+"$SETTIME" -R now "${keyname}.key" > /dev/null
+
+# create a current set of keys, and sign the root zone
+"$KEYGEN" -q -a "$DEFAULT_ALGORITHM" -b "$DEFAULT_BITS" $zone > /dev/null
+"$KEYGEN" -q -a "$DEFAULT_ALGORITHM" -b "$DEFAULT_BITS" -f KSK $zone > /dev/null
+"$SIGNER" -S -o "$zone" -f "$zonefile" "$infile" > /dev/null 2>&1
+
+keyname=$("$KEYGEN" -q -a "$DEFAULT_ALGORITHM" -b "$DEFAULT_BITS" -n zone ".")
+
+keyfile_to_static_ds "$keyname" > trusted.conf
diff --git a/bin/tests/system/dnssec/ns6/named.args b/bin/tests/system/dnssec/ns6/named.args
new file mode 100644
index 0000000..4b96405
--- /dev/null
+++ b/bin/tests/system/dnssec/ns6/named.args
@@ -0,0 +1 @@
+-m record -c named.conf -d 99 -D dnssec-ns6 -X named.lock -g -T maxcachesize=2097152 -T nonearest -T tat=1
diff --git a/bin/tests/system/dnssec/ns6/named.conf.in b/bin/tests/system/dnssec/ns6/named.conf.in
new file mode 100644
index 0000000..4bdc79c
--- /dev/null
+++ b/bin/tests/system/dnssec/ns6/named.conf.in
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * SPDX-License-Identifier: MPL-2.0
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, you can obtain one at https://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+// NS6
+
+options {
+ query-source address 10.53.0.6;
+ notify-source 10.53.0.6;
+ transfer-source 10.53.0.6;
+ port @PORT@;
+ pid-file "named.pid";
+ listen-on { 10.53.0.6; };
+ listen-on-v6 { none; };
+ recursion yes;
+ notify yes;
+ disable-algorithms . { @ALTERNATIVE_ALGORITHM@; };
+ dnssec-validation yes;
+};
+
+zone "." {
+ type hint;
+ file "../../common/root.hint";
+};
+
+zone "optout-tld" {
+ type primary;
+ file "optout-tld.db.signed";
+};
+
+include "trusted.conf";
diff --git a/bin/tests/system/dnssec/ns6/optout-tld.db.in b/bin/tests/system/dnssec/ns6/optout-tld.db.in
new file mode 100644
index 0000000..b2aa393
--- /dev/null
+++ b/bin/tests/system/dnssec/ns6/optout-tld.db.in
@@ -0,0 +1,22 @@
+; Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+;
+; SPDX-License-Identifier: MPL-2.0
+;
+; This Source Code Form is subject to the terms of the Mozilla Public
+; License, v. 2.0. If a copy of the MPL was not distributed with this
+; file, you can obtain one at https://mozilla.org/MPL/2.0/.
+;
+; See the COPYRIGHT file distributed with this work for additional
+; information regarding copyright ownership.
+
+$TTL 60
+optout-tld. 60 IN SOA example. . 0 0 0 0 0
+optout-tld. 60 IN NS ns6.optout-tld.
+ns6.optout-tld. 60 IN A 10.53.0.6
+a 60 PTR example.
+b 60 PTR example.
+a.b.c.d 60 NS example.
+e 60 PTR example.
+f 60 PTR example.
+g 60 PTR example.
+h 60 PTR example.
diff --git a/bin/tests/system/dnssec/ns6/sign.sh b/bin/tests/system/dnssec/ns6/sign.sh
new file mode 100644
index 0000000..6102e52
--- /dev/null
+++ b/bin/tests/system/dnssec/ns6/sign.sh
@@ -0,0 +1,29 @@
+#!/bin/sh -e
+
+# Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+#
+# SPDX-License-Identifier: MPL-2.0
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, you can obtain one at https://mozilla.org/MPL/2.0/.
+#
+# See the COPYRIGHT file distributed with this work for additional
+# information regarding copyright ownership.
+
+# shellcheck source=conf.sh
+. ../../conf.sh
+
+set -e
+
+echo_i "ns6/sign.sh"
+
+zone=optout-tld
+infile=optout-tld.db.in
+zonefile=optout-tld.db
+
+keyname=$("$KEYGEN" -q -a "$DEFAULT_ALGORITHM" -b "$DEFAULT_BITS" -n zone "$zone")
+
+cat "$infile" "$keyname.key" > "$zonefile"
+
+"$SIGNER" -z -3 - -A -o "$zone" "$zonefile" > /dev/null 2>&1
diff --git a/bin/tests/system/dnssec/ns7/named.conf.in b/bin/tests/system/dnssec/ns7/named.conf.in
new file mode 100644
index 0000000..55cbec9
--- /dev/null
+++ b/bin/tests/system/dnssec/ns7/named.conf.in
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * SPDX-License-Identifier: MPL-2.0
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, you can obtain one at https://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+// NS3
+
+options {
+ query-source address 10.53.0.7;
+ notify-source 10.53.0.7;
+ transfer-source 10.53.0.7;
+ port @PORT@;
+ pid-file "named.pid";
+ listen-on { 10.53.0.7; };
+ listen-on-v6 { none; };
+ recursion no;
+ notify yes;
+ dnssec-validation yes;
+ minimal-responses yes;
+};
+
+zone "." {
+ type hint;
+ file "../../common/root.hint";
+};
+
+zone "nsec3.example" {
+ type secondary;
+ primaries { 10.53.0.3; };
+ file "nsec3.example.bk";
+};
+
+zone "optout.example" {
+ type secondary;
+ primaries { 10.53.0.3; };
+ file "optout.example.bk";
+};
+
+zone "nsec3-unknown.example" {
+ type secondary;
+ primaries { 10.53.0.3; };
+ file "nsec3-unknown.example.bk";
+};
+
+zone "optout-unknown.example" {
+ type secondary;
+ primaries { 10.53.0.3; };
+ file "optout-unknown.example.bk";
+};
+
+zone "multiple.example" {
+ type secondary;
+ primaries { 10.53.0.3; };
+ file "multiple.example.bk";
+};
+
+zone "nosoa.secure.example" {
+ type primary;
+ file "nosoa.secure.example.db";
+};
+
+zone "split-rrsig" {
+ type primary;
+ file "split-rrsig.db.signed";
+ allow-update { any; };
+};
+
+include "trusted.conf";
diff --git a/bin/tests/system/dnssec/ns7/named.nosoa b/bin/tests/system/dnssec/ns7/named.nosoa
new file mode 100644
index 0000000..caefbbb
--- /dev/null
+++ b/bin/tests/system/dnssec/ns7/named.nosoa
@@ -0,0 +1,12 @@
+Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+
+SPDX-License-Identifier: MPL-2.0
+
+This Source Code Form is subject to the terms of the Mozilla Public
+License, v. 2.0. If a copy of the MPL was not distributed with this
+file, you can obtain one at https://mozilla.org/MPL/2.0/.
+
+See the COPYRIGHT file distributed with this work for additional
+information regarding copyright ownership.
+
+Add -T nosoa.
diff --git a/bin/tests/system/dnssec/ns7/nosoa.secure.example.db b/bin/tests/system/dnssec/ns7/nosoa.secure.example.db
new file mode 100644
index 0000000..d3c9878
--- /dev/null
+++ b/bin/tests/system/dnssec/ns7/nosoa.secure.example.db
@@ -0,0 +1,22 @@
+; Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+;
+; SPDX-License-Identifier: MPL-2.0
+;
+; This Source Code Form is subject to the terms of the Mozilla Public
+; License, v. 2.0. If a copy of the MPL was not distributed with this
+; file, you can obtain one at https://mozilla.org/MPL/2.0/.
+;
+; See the COPYRIGHT file distributed with this work for additional
+; information regarding copyright ownership.
+
+$TTL 300 ; 5 minutes
+@ IN SOA mname1. . (
+ 2010062400 ; serial
+ 20 ; refresh (20 seconds)
+ 20 ; retry (20 seconds)
+ 1814400 ; expire (3 weeks)
+ 3600 ; minimum (1 hour)
+ )
+@ IN NS ns
+ns IN A 10.53.0.7
+a IN A 1.2.3.4
diff --git a/bin/tests/system/dnssec/ns7/sign.sh b/bin/tests/system/dnssec/ns7/sign.sh
new file mode 100644
index 0000000..551b217
--- /dev/null
+++ b/bin/tests/system/dnssec/ns7/sign.sh
@@ -0,0 +1,44 @@
+#!/bin/sh -e
+
+# Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+#
+# SPDX-License-Identifier: MPL-2.0
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, you can obtain one at https://mozilla.org/MPL/2.0/.
+#
+# See the COPYRIGHT file distributed with this work for additional
+# information regarding copyright ownership.
+
+# shellcheck source=conf.sh
+. ../../conf.sh
+
+set -e
+
+echo_i "ns7/sign.sh"
+
+zone=split-rrsig
+infile=split-rrsig.db.in
+zonefile=split-rrsig.db
+
+k1=$("$KEYGEN" -q -a "$DEFAULT_ALGORITHM" -b "$DEFAULT_BITS" -n zone "$zone")
+k2=$("$KEYGEN" -q -a "$DEFAULT_ALGORITHM" -b "$DEFAULT_BITS" -n zone "$zone")
+
+cat "$infile" "$k1.key" "$k2.key" > "$zonefile"
+
+# The awk script below achieves two goals:
+#
+# - it puts one of the two RRSIG(SOA) records at the end of the zone file, so
+# that these two records (forming a single RRset) are not placed immediately
+# next to each other; the test then checks if RRSIG RRsets split this way are
+# correctly added to resigning heaps,
+#
+# - it places a copy of one of the RRSIG(SOA) records somewhere else than at the
+# zone apex; the test then checks whether such signatures are automatically
+# removed from the zone after it is loaded.
+"$SIGNER" -P -3 - -A -o "$zone" -O full -f "$zonefile.unsplit" -e now-3600 -s now-7200 "$zonefile" > /dev/null 2>&1
+awk 'BEGIN { r = ""; }
+ $4 == "RRSIG" && $5 == "SOA" && r == "" { r = $0; next; }
+ { print }
+ END { print r; print "not-at-zone-apex." r; }' "$zonefile.unsplit" > "$zonefile.signed"
diff --git a/bin/tests/system/dnssec/ns7/split-rrsig.db.in b/bin/tests/system/dnssec/ns7/split-rrsig.db.in
new file mode 100644
index 0000000..48c2f87
--- /dev/null
+++ b/bin/tests/system/dnssec/ns7/split-rrsig.db.in
@@ -0,0 +1,21 @@
+; Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+;
+; SPDX-License-Identifier: MPL-2.0
+;
+; This Source Code Form is subject to the terms of the Mozilla Public
+; License, v. 2.0. If a copy of the MPL was not distributed with this
+; file, you can obtain one at https://mozilla.org/MPL/2.0/.
+;
+; See the COPYRIGHT file distributed with this work for additional
+; information regarding copyright ownership.
+
+split-rrsig. 3660 IN SOA . . (
+ 1 ; serial
+ 3600 ; refresh (1 hour)
+ 3600 ; retry (1 hour)
+ 3600 ; expire (1 hour)
+ 3600 ; minimum (1 hour)
+ )
+ 3660 NS ns.example.
+a.split-rrsig. 3660 IN A 192.0.2.2
+b.split-rrsig. 3660 IN A 192.0.2.2
diff --git a/bin/tests/system/dnssec/ns8/named.conf.in b/bin/tests/system/dnssec/ns8/named.conf.in
new file mode 100644
index 0000000..d0278ca
--- /dev/null
+++ b/bin/tests/system/dnssec/ns8/named.conf.in
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * SPDX-License-Identifier: MPL-2.0
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, you can obtain one at https://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+// NS8
+
+options {
+ query-source address 10.53.0.8;
+ notify-source 10.53.0.8;
+ transfer-source 10.53.0.8;
+ port @PORT@;
+ pid-file "named.pid";
+ listen-on { 10.53.0.8; };
+ listen-on-v6 { none; };
+ recursion yes;
+ dnssec-validation yes;
+ minimal-responses no;
+ disable-algorithms "disabled.managed." { @DISABLED_ALGORITHM@; };
+ disable-algorithms "disabled.trusted." { @DISABLED_ALGORITHM@; };
+};
+
+key rndc_key {
+ secret "1234abcd8765";
+ algorithm @DEFAULT_HMAC@;
+};
+
+controls {
+ inet 10.53.0.8 port @CONTROLPORT@ allow { any; } keys { rndc_key; };
+};
+
+zone "." {
+ type hint;
+ file "../../common/root.hint";
+};
+
+include "managed.conf";
+include "trusted.conf";
+
diff --git a/bin/tests/system/dnssec/ns9/named.conf.in b/bin/tests/system/dnssec/ns9/named.conf.in
new file mode 100644
index 0000000..06530a0
--- /dev/null
+++ b/bin/tests/system/dnssec/ns9/named.conf.in
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * SPDX-License-Identifier: MPL-2.0
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, you can obtain one at https://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+// NS9
+
+options {
+ query-source address 10.53.0.9;
+ notify-source 10.53.0.9;
+ transfer-source 10.53.0.9;
+ port @PORT@;
+ pid-file "named.pid";
+ listen-on { 10.53.0.9; };
+ listen-on-v6 { none; };
+ recursion yes;
+ dnssec-validation yes;
+ forward only;
+ forwarders { 10.53.0.4; };
+};
+
+key rndc_key {
+ secret "1234abcd8765";
+ algorithm @DEFAULT_HMAC@;
+};
+
+controls {
+ inet 10.53.0.9 port @CONTROLPORT@ allow { any; } keys { rndc_key; };
+};
+
+include "trusted.conf";
diff --git a/bin/tests/system/dnssec/ntadiff.pl b/bin/tests/system/dnssec/ntadiff.pl
new file mode 100755
index 0000000..ca80eac
--- /dev/null
+++ b/bin/tests/system/dnssec/ntadiff.pl
@@ -0,0 +1,24 @@
+#!/usr/bin/perl -w
+
+# Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+#
+# SPDX-License-Identifier: MPL-2.0
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, you can obtain one at https://mozilla.org/MPL/2.0/.
+#
+# See the COPYRIGHT file distributed with this work for additional
+# information regarding copyright ownership.
+
+use strict;
+use Time::Piece;
+use Time::Seconds;
+
+exit 1 if (scalar(@ARGV) != 2);
+
+my $actual = Time::Piece->strptime($ARGV[0], '%d-%b-%Y %H:%M:%S.000 %z');
+my $expected = Time::Piece->strptime($ARGV[1], '%s') + ONE_WEEK;
+my $diff = abs($actual - $expected);
+
+print($diff . "\n");
diff --git a/bin/tests/system/dnssec/setup.sh b/bin/tests/system/dnssec/setup.sh
new file mode 100644
index 0000000..6aa0cd0
--- /dev/null
+++ b/bin/tests/system/dnssec/setup.sh
@@ -0,0 +1,52 @@
+#!/bin/sh -e
+
+# Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+#
+# SPDX-License-Identifier: MPL-2.0
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, you can obtain one at https://mozilla.org/MPL/2.0/.
+#
+# See the COPYRIGHT file distributed with this work for additional
+# information regarding copyright ownership.
+
+# shellcheck source=conf.sh
+. ../conf.sh
+
+set -e
+
+$SHELL clean.sh
+
+copy_setports ns1/named.conf.in ns1/named.conf
+copy_setports ns2/named.conf.in ns2/named.conf
+copy_setports ns3/named.conf.in ns3/named.conf
+
+copy_setports ns4/named1.conf.in ns4/named.conf
+copy_setports ns5/named1.conf.in ns5/named.conf
+
+copy_setports ns6/named.conf.in ns6/named.conf
+copy_setports ns7/named.conf.in ns7/named.conf
+copy_setports ns8/named.conf.in ns8/named.conf
+
+copy_setports ns9/named.conf.in ns9/named.conf
+
+(
+ cd ns1
+ $SHELL sign.sh
+ {
+ echo "a.bogus.example. A 10.0.0.22"
+ echo "b.bogus.example. A 10.0.0.23"
+ echo "c.bogus.example. A 10.0.0.23"
+ } >>../ns3/bogus.example.db.signed
+)
+
+(
+ cd ns3
+ cp -f siginterval1.conf siginterval.conf
+)
+
+(
+ cd ns5
+ $SHELL sign.sh
+)
diff --git a/bin/tests/system/dnssec/signer/example.db.in b/bin/tests/system/dnssec/signer/example.db.in
new file mode 100644
index 0000000..3ab6aa2
--- /dev/null
+++ b/bin/tests/system/dnssec/signer/example.db.in
@@ -0,0 +1,17 @@
+; Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+;
+; SPDX-License-Identifier: MPL-2.0
+;
+; This Source Code Form is subject to the terms of the Mozilla Public
+; License, v. 2.0. If a copy of the MPL was not distributed with this
+; file, you can obtain one at https://mozilla.org/MPL/2.0/.
+;
+; See the COPYRIGHT file distributed with this work for additional
+; information regarding copyright ownership.
+
+$TTL 60
+example. 60 IN SOA example. . 0 0 0 0 0
+example. 60 IN NS example.
+example. 60 IN A 1.2.3.4
+; out of zone record
+out-of-zone. 60 IN A 1.2.3.4
diff --git a/bin/tests/system/dnssec/signer/general/Kexample.com.+008+15002.key b/bin/tests/system/dnssec/signer/general/Kexample.com.+008+15002.key
new file mode 100644
index 0000000..d4b8efb
--- /dev/null
+++ b/bin/tests/system/dnssec/signer/general/Kexample.com.+008+15002.key
@@ -0,0 +1,5 @@
+; This is a key-signing key, keyid 15002, for example.com.
+; Created: 20210423012926 (Fri Apr 23 11:29:26 2021)
+; Publish: 20210423012926 (Fri Apr 23 11:29:26 2021)
+; Activate: 20210423012926 (Fri Apr 23 11:29:26 2021)
+example.com. IN DNSKEY 257 3 8 AwEAAdp+oCXl7vpKA3Mmyndx6/iA+wLrtxeMUiWL7uWJ9ZF24EdS8Dye 63p0lGlyvjvM9T5dTiyEpTAdutEBr79H0MlDqIBqpadrCdJRI2S4kC+0 nq5+Aj2CEyiAamPGujwWeXwtfLAvVPfBqs42PBr6wPQIJOByFYDaZBU3 enUEWgHYy/7OnJDrt0QlswKphR6SvYtyuixiUR8J/WouWXglUY5qlC7Z vVDxs9E4q7B1mfKCyoqcFMKPh9lzEBH+IfUZ543xXEYf2BEztKB1SZ2R QnpYedjATGDcgPis46uA2gHMfvDYJTQ5UqTBtveGb3Wsqc0oRXVPMEoY 3WnWhaKDzkk=
diff --git a/bin/tests/system/dnssec/signer/general/Kexample.com.+008+15002.private b/bin/tests/system/dnssec/signer/general/Kexample.com.+008+15002.private
new file mode 100644
index 0000000..72b8e2e
--- /dev/null
+++ b/bin/tests/system/dnssec/signer/general/Kexample.com.+008+15002.private
@@ -0,0 +1,13 @@
+Private-key-format: v1.3
+Algorithm: 8 (RSASHA256)
+Modulus: 2n6gJeXu+koDcybKd3Hr+ID7Auu3F4xSJYvu5Yn1kXbgR1LwPJ7renSUaXK+O8z1Pl1OLISlMB260QGvv0fQyUOogGqlp2sJ0lEjZLiQL7Sern4CPYITKIBqY8a6PBZ5fC18sC9U98GqzjY8GvrA9Agk4HIVgNpkFTd6dQRaAdjL/s6ckOu3RCWzAqmFHpK9i3K6LGJRHwn9ai5ZeCVRjmqULtm9UPGz0TirsHWZ8oLKipwUwo+H2XMQEf4h9RnnjfFcRh/YETO0oHVJnZFCelh52MBMYNyA+Kzjq4DaAcx+8NglNDlSpMG294ZvdaypzShFdU8wShjdadaFooPOSQ==
+PublicExponent: AQAB
+PrivateExponent: SD4X64/0DTONonRP+2Biej8DP7r6RcHyo1F6QtDzrg4VJ+AHaLPO/iUvsRHsTk99QwqMv3F4QMmDrHmXR3KSWQmS3Crm7M0aaTzErBfOLMfWs7EcQoQQm5KiGq1phFaWAnXzxTlRKb4SIK6T/wOr6sQKlV+DNqB++Pjn92rh67vLM8kZBUzWI14Vl9N0ib+xOOFH1oYFo7ynDgMfJhpnQSkuRfyQls3aD1eKQsNazRtZ7lFi2S0HR/V0AKYH2AQi7SdL5wH6hYba5cHfpKSw7PebI0lYkUJ4PAg3Xw7DPMkg8O0hkpLICpU8x7MPqQQ74eKDaEY+fjbL0KLL0Dy9UQ==
+Prime1: /IDRb7WzMY6wp14LqDORULoUnmiQOqkRjOQnCoEXT2KVpYwPmGMG+GR40hrMFgqqAZFVmi56VBoasWpYbSBEqM4aJv1JVimMPREk23v5i+TY93kxICO/ee9/v0hXgLmrKUkS1Kwu4a1PxLX5U/LAzXPR6zF+EHP9OKFjDRWHqN0=
+Prime2: 3YU9QdtsXofjNmlDETRwemKv45pa0oVNPmNvS1vtzIpQ3m/QSuhJxzyTgSP9x1XMiIsg63er3LOCtkRifXVE1IBrfIUgchp8YD5LsyesRl2ielE8Hw8PwSA1YjUVu90yRHcVfbZJ8lm2KyRKHgDWXz94t2Xnm/9M5XjUGuNW7l0=
+Exponent1: 7KIkpJYZyvW4ZAFk10sMgiUBMbs4f2D2i509YUC9ga4YJD7wVpVncN1nxS9L19RCopl7KbUo+yxDm8TX/dzhu3j7VVLFqbPiM1Cfw/mZUhszoii3ezFFPpbOl4rKRl66I0TSGvEKNoDfYrBPavby7Rf/wHRveifZRXspgpeMvRk=
+Exponent2: yvvtjuxW2CRiopg/+YL40lyd2cy2DpRRnKqW8BHzzGquAbWpwwopmOS8MSjewgqv2irK5pmJJTpku0nciiOsB6EJXVfLzGLSt4o96ZOf+/aPDNBla/xsLkaqRCxqlvPwvOX2DnS8O9PS5qNhOy7/QNYzcrJxUfPV7awTh/Pr040=
+Coefficient: PHxU1tqPKTpI/8nABvso0SRerc1m+RPWGRk7s/SVcADSBvEW7fUDcwiZeRfK9MdlwPvLiVozbYnRbgRQl8GuKSqAD1+Cnvn2yOQk81AgNKbuKPwF7UvKIdq/c/xnhj2bvZUVSavJ91ux/RlZNP50378Ks8bj5HJl1xzAMVHXB5o=
+Created: 20210423012926
+Publish: 20210423012926
+Activate: 20210423012926
diff --git a/bin/tests/system/dnssec/signer/general/Kexample.com.+008+63613.key b/bin/tests/system/dnssec/signer/general/Kexample.com.+008+63613.key
new file mode 100644
index 0000000..990b837
--- /dev/null
+++ b/bin/tests/system/dnssec/signer/general/Kexample.com.+008+63613.key
@@ -0,0 +1,5 @@
+; This is a zone-signing key, keyid 63613, for example.com.
+; Created: 20210423012810 (Fri Apr 23 11:28:10 2021)
+; Publish: 20210423012810 (Fri Apr 23 11:28:10 2021)
+; Activate: 20210423012810 (Fri Apr 23 11:28:10 2021)
+example.com. IN DNSKEY 256 3 8 AwEAAZzun7bYfjmGDwUEn4pyJG34vsiawRMW6pEdoNMH87ozxriOzgG6 /4zTjEv8JyYjGQz2k2vcoWWcD+86xD5IUqfa1pdXXUU8bdhG9DBtW/K1 mc4P6g8heU+0f++mq/L4TPlWVZUG8lVH4H8mD6r8PsVK7v/QR7wMeg9b JpCYyxon2A9rZ4zS0J9kX9bfciQVh6ODGVENctwEK5FNp5u0VonPEIx3 5Kj+IVn/mHpfbz4LaC02s7C6Kgvn3ToFFSJczwbOaexl/d+/ai8FLJi7 8UgiAq5/178bcVLItMeY6aD5eQGkRtr2c3JZ/JR4Nf+TQAWFBnl9NSDa RH4Qa55ZNqs=
diff --git a/bin/tests/system/dnssec/signer/general/Kexample.com.+008+63613.private b/bin/tests/system/dnssec/signer/general/Kexample.com.+008+63613.private
new file mode 100644
index 0000000..1765d3f
--- /dev/null
+++ b/bin/tests/system/dnssec/signer/general/Kexample.com.+008+63613.private
@@ -0,0 +1,13 @@
+Private-key-format: v1.3
+Algorithm: 8 (RSASHA256)
+Modulus: nO6ftth+OYYPBQSfinIkbfi+yJrBExbqkR2g0wfzujPGuI7OAbr/jNOMS/wnJiMZDPaTa9yhZZwP7zrEPkhSp9rWl1ddRTxt2Eb0MG1b8rWZzg/qDyF5T7R/76ar8vhM+VZVlQbyVUfgfyYPqvw+xUru/9BHvAx6D1smkJjLGifYD2tnjNLQn2Rf1t9yJBWHo4MZUQ1y3AQrkU2nm7RWic8QjHfkqP4hWf+Yel9vPgtoLTazsLoqC+fdOgUVIlzPBs5p7GX9379qLwUsmLvxSCICrn/XvxtxUsi0x5jpoPl5AaRG2vZzcln8lHg1/5NABYUGeX01INpEfhBrnlk2qw==
+PublicExponent: AQAB
+PrivateExponent: N4egcDzO/V/YdLgcFAsrpNY9/BH2e+DCA7NuMv4/WgX0LV4quyYGQzigDksdNzt4I8Qkiig53BCK+uXahwdkaAzhng/F6zfkzoDc6z3nKUzlLasn8U6w9Gk0VAKwGXuPETNheShKG68hWxyGssQrGfjX9SEoIPxxPHnOfZ/zTj95KAnVV5qPz90xVAb0+FUrLXAt72KuRwepOTlsETsMFDKe17uUCqCCdX98Ko0u14wrO6zGRQtNhUsfvNB/pY8fvbHD1GcCTbFSx4FxsUsZMrNtMsvMe3HN9ggC0Y9htbH9HV0hS0w9SKCUyoeOVwf/JZL4hlfoe8+jglsyJpAgoQ==
+Prime1: zeXvO3PT4iXv9GlGeebl39pF1sXs8tXY4B9VHUJGGSYlyOlyCEy4URQJIPfuL6VjFKCErSxUJSrGz0HyQuKr8l9qP/0MGxGRH7wxvUR7YTmai84yyQ4fFENRmn8bzxGwj0MVHIW7cKC59j7nWT24gseT21/NP5m8EnPsjz/K40M=
+Prime2: wx5vVFSydUfr8HtOHNS1kRrTjhnQOfjmj8SxGi72Hk+mgi9fBCTC5fRLifd80wGbgyFk1vZOXeStOC8L3IlnBGLX0O9MNip+vVX3hRzIRhLwHhL1ygN3xEd04qwVH0XJ8+4A0XCzh/FJgW59F62geN6gwedo7GmZAOSZUBAyRHk=
+Exponent1: IlkqeLuQ7Fgx2I87b5iiXp62Keco6TXdkT4I3/GvagCgKw0utc2+rd/uye4ycQZhKg7BM3aCrxScx/STaq8PykY6nmQjgdyDXkzx60YiYwzOCGakuD+/1YyJb4Gm7PthffTN780rgNV/UGIcDBoszrxmoSExR1vpMRbfruIQgas=
+Exponent2: or0Os/KUibc79W6Snv9WlLkgPAQRpViQzNaLtD/47R0Xzrs975HNsMgJ/P+bb86Ga1994MC8ahmh1BuBNCax8nmScWQ1V3QoEzjRYoe4DqIa/aposF4mFWJX/fry/wtRPo+CxSzPwJGh8j86PHaHQmjFAhVFcPE+OP1xVdK8alk=
+Coefficient: r5wPmPXUF5pVC0Y7La3jVkL4w/3wvq9LBz91tH9gA8OUNLpDDBuFZISiJdhOZ4JVw+qSSoHcEa+3Phd+BqxmXzwZDU1Fqta9mLDDGCqCWjVQOopeeJgrvkv9P0TIzEuoGmW50cQhyqHYCtuUxjOnHfiQSc53p7rfD4Vom1VQ3Ok=
+Created: 20210423012810
+Publish: 20210423012810
+Activate: 20210423012810
diff --git a/bin/tests/system/dnssec/signer/general/Kexample.com.+010+18240.key b/bin/tests/system/dnssec/signer/general/Kexample.com.+010+18240.key
new file mode 100644
index 0000000..47003a4
--- /dev/null
+++ b/bin/tests/system/dnssec/signer/general/Kexample.com.+010+18240.key
@@ -0,0 +1,5 @@
+; This is a zone-signing key, keyid 18240, for example.com.
+; Created: 20211221062121 (Tue Dec 21 17:21:21 2021)
+; Publish: 20211221062121 (Tue Dec 21 17:21:21 2021)
+; Activate: 20211221062121 (Tue Dec 21 17:21:21 2021)
+example.com. IN DNSKEY 256 3 10 AwEAAe5GunnuJFyzmKiGUknSQY3aPtR5UR8vNLLyMCJswffRzoYwY14/ 60ZTsqzh7N+lJV3KAOraocFSsTnmWIM7D7DPpqtaJMQw90ypBG0cnUP1 wKX9L/gdOH/ITlluBiZpCv9Aux3FRECHBO4Gx8Rse8ST2Vag3UuOPW+q HkLsWQt22K/hYuDhEtUWWx2dTIaXUVXNSNbk2zPL+lhC9PaRV+//1Fjo UX4qXCUuUN4TiqlkK2v4UkcIyld1n2R7qTQAkoN9amGFtPu8z5Zw7CxC San03yUSNuKub3fGys11gQRFuEHRX7FxKxvJjmcngG9qCh8AyfHZ8zYb VstTy1unFoM=
diff --git a/bin/tests/system/dnssec/signer/general/Kexample.com.+010+18240.private b/bin/tests/system/dnssec/signer/general/Kexample.com.+010+18240.private
new file mode 100644
index 0000000..f16b627
--- /dev/null
+++ b/bin/tests/system/dnssec/signer/general/Kexample.com.+010+18240.private
@@ -0,0 +1,13 @@
+Private-key-format: v1.3
+Algorithm: 10 (RSASHA512)
+Modulus: 7ka6ee4kXLOYqIZSSdJBjdo+1HlRHy80svIwImzB99HOhjBjXj/rRlOyrOHs36UlXcoA6tqhwVKxOeZYgzsPsM+mq1okxDD3TKkEbRydQ/XApf0v+B04f8hOWW4GJmkK/0C7HcVEQIcE7gbHxGx7xJPZVqDdS449b6oeQuxZC3bYr+Fi4OES1RZbHZ1MhpdRVc1I1uTbM8v6WEL09pFX7//UWOhRfipcJS5Q3hOKqWQra/hSRwjKV3WfZHupNACSg31qYYW0+7zPlnDsLEJJqfTfJRI24q5vd8bKzXWBBEW4QdFfsXErG8mOZyeAb2oKHwDJ8dnzNhtWy1PLW6cWgw==
+PublicExponent: AQAB
+PrivateExponent: U/ipDv9V4TWJvxpXNZzbbVpUehym8g54y/d97yPU17kgxzmWS0jLaWVluneEOuzAVmUyHZIfHzo9KuJ6nwTZar5DRm/mNR3siR+nZ6yF38VjtxubJB1oI+A7fFjB4hdywLHXP46dlv/+RMQu8pIorAZOubDHTDE8hXW2ZG9WkisJ5P7KoaL4KFHHHXi5vsXAMph4Zphd/zPxVL2tHD3l5c3QXRpQWfTNZNQcZ1f/4yVCuMRibg5LCvpia0ZwRrlygfZdAHUUd0VJDfRO45J5nlIJSAHQtjYtVTL+xNISWOHXovVlInkVyluACqfX94I7qPXTu41yg3SxrrtHE6RTwQ==
+Prime1: +/YsRxmUxgvHKUh4SxdjzqNDDEi8b2BtM5IpctjVG3oYsL6J9xJB3U5/lbrGEPgl/1ndBUSXMQ6zQ5WcDE1qBAdW8t0eyniyuiexcgQ9f04Ds7p7oUiSHGLRn8YqQOzmiASXoZmkzfJZ+42pGhT3RZ+aYKtWQGMHqXabwV3zZl0=
+Prime2: 8hhnKzPzExy6wv/MV0aYKo1g4azrRjug6743/ctTC7zjnMmDW7RMFTXmq5Tu3pFaIL4N4C4m1b7P3abfTrjm+DwHnrlRIvLWS3zJnvUEM22i4BwqqTLRiJpoT5Bfp4pVsdOPT7Iyx1q5UsJZ7Q4qMpg2TFpGiQyieRB5Xwpu4l8=
+Exponent1: ZFPx7Z3SD8pA0793pu75Xx7DY/DSl8bdtNtOhdyxfu9vRXGZnjg24diQFR76H2ewOa2exKo7Sd2ApDi+mmd4/4Gsrag+yoClKlsD3VKy6i42ayqmb+Jly8fNkMFnsdKjOSYa+s4jQZ5vFiuiWjBfBeo3nqabAahtNJ12B9lRQkE=
+Exponent2: tNz4TnVsFo4zFLVHsrghvECM7WxjBMBNc3FToT6CV1WRcjO1+A/Ve08eenc0kYBjpex2r1GrX6pC3uPpFoXav/8Q7kqiTArBf/nFIwUHU2iH8wf38xntIjHA1hgU7jTR2p0kBrUpbHfh1esuhYQ8kDnY7ufOpFqVEv70vcUsm98=
+Coefficient: 3acDCJ9jCnHAP1km7jRO388mOpiI8U6SMv0PBD8l2UoB4CYwujrFxy6PhgUa486bbm5xZEaOwhYZcbw/g1qyC6Qt5kYOb2fVWOob/lEQmyqbDvHMQWTJoIbqaDTKQN/szI4xVdb/xZ6QR4Bq7JgbJpUACgweS540Y7Lf8Dry8C0=
+Created: 20211221062121
+Publish: 20211221062121
+Activate: 20211221062121
diff --git a/bin/tests/system/dnssec/signer/general/Kexample.com.+010+28633.key b/bin/tests/system/dnssec/signer/general/Kexample.com.+010+28633.key
new file mode 100644
index 0000000..37bd259
--- /dev/null
+++ b/bin/tests/system/dnssec/signer/general/Kexample.com.+010+28633.key
@@ -0,0 +1,5 @@
+; This is a key-signing key, keyid 28633, for example.com.
+; Created: 20211221062130 (Tue Dec 21 17:21:30 2021)
+; Publish: 20211221062130 (Tue Dec 21 17:21:30 2021)
+; Activate: 20211221062130 (Tue Dec 21 17:21:30 2021)
+example.com. IN DNSKEY 257 3 10 AwEAAc4lt8fDsdCzMCLHxXm8Ok/dw6XDiqx06Rf47LTeLmo6b64xm1Fs 0zloNMrcZDgwS5IxjQ3Breqc5aEc+jehueqCXa/fJXMdIt1VpUG0H7GP 4B+1IVmEiziHfmOozktdkuAyLqcsNhsf+J1+bCoHJSffgz6KbjBks/jR 12uyUnZCDrKGE/KfiR0gpT3watqGqqChO0KXq2N2PsnYfyRDea5FMUjM oPgOOyAT8LIMsM8x4f+EbU6m9Zc3Esafek9iLCS9R1333Pm1EEh5ghQT BsZ7omc5aSvrKUaIneojU3RdofceZouCliIDXmqscfY0y6bivGcmCQI/ LM4XUh7GWlM=
diff --git a/bin/tests/system/dnssec/signer/general/Kexample.com.+010+28633.private b/bin/tests/system/dnssec/signer/general/Kexample.com.+010+28633.private
new file mode 100644
index 0000000..6d7f72e
--- /dev/null
+++ b/bin/tests/system/dnssec/signer/general/Kexample.com.+010+28633.private
@@ -0,0 +1,13 @@
+Private-key-format: v1.3
+Algorithm: 10 (RSASHA512)
+Modulus: ziW3x8Ox0LMwIsfFebw6T93DpcOKrHTpF/jstN4uajpvrjGbUWzTOWg0ytxkODBLkjGNDcGt6pzloRz6N6G56oJdr98lcx0i3VWlQbQfsY/gH7UhWYSLOId+Y6jOS12S4DIupyw2Gx/4nX5sKgclJ9+DPopuMGSz+NHXa7JSdkIOsoYT8p+JHSClPfBq2oaqoKE7QperY3Y+ydh/JEN5rkUxSMyg+A47IBPwsgywzzHh/4RtTqb1lzcSxp96T2IsJL1HXffc+bUQSHmCFBMGxnuiZzlpK+spRoid6iNTdF2h9x5mi4KWIgNeaqxx9jTLpuK8ZyYJAj8szhdSHsZaUw==
+PublicExponent: AQAB
+PrivateExponent: Wr3fl99cdjFqDuVA18UzJdTIOj9I24Da2eKIz1S9uaTfZB4R8FWm5K4qDuHUe6dGnKOTI2sN0ygdLD5FJhfabo/UDYZ8RZ+dqS/5/mH7UX2zekGQ3Iargcaiq9uycxpNfMKaJpwfdPEtzqXHlvhuMo8AhpcIyeSKFAzKdm2YPtUqIrum4RARHyfRLfLyWlkIotPdyiaKCVGQxiRbFsTcmIB2Bizmt7zRjlB+Hxf8MooXmaKUFRQtMCLnFGK0ecFI1CWAxmLSanvYVKQ0HxcFkFKzRiZAz1au7ZfMgYDZj0jF72WAGU3Edcmdc0QIQRTWjb/3wcBfwlr9s6lKoF3ngQ==
+Prime1: 1EIziKhz7dF41rb/hckdr2qeY8eM7tLrT5jIMPLISHCCuKm5IK2u7PY6m6NjMdhx1ilm7K2RGTt+TTFZaqDIEd8qpzRCxAGcfTVOmB9iHwmi9i9RoPSlY6o+iShft68ZnvPiGJWUF2huRYVK2F0cIWErwSqaBGsFd79mXmlkn98=
+Prime2: +KEdNtZj9JyCCR2xbLAw3tnAYxHvJ3skVMjxV3cyUupMWi12NWxGhHH1nnetXxDR2LBBuqIl4pE/4MeXe3sClMHTL3Z9XG+pzQAsHS7yvsfZERdyuWZYYy0ya/7XY2auvRVO6LxN7d47VWjYxAGfoCsbCEivgDxmt1dTZhAtRA0=
+Exponent1: d5TcZ69PsLoEtCLhDkRh/wO4PEqeMaaOf4d5sWn2QCly3Apyi+CN3l5SYoDIT7q7V4Z3v/uA9ZA49dBJqfLvBHKQGycsPjUSLtAreTSlGQtazguWl3F9BAtTs/4U/u0dKBoKVQNgLVfeWDhiFEdQo9WUyvzvTHHm4LHqQGJsGE0=
+Exponent2: EU2dK+DVygNOZXYEkAzfCdNbuUlZPIUsbR4i9bRc8zpNIAWD8YncioEn1+R6U2BnSk5R9LwuKMt1B568YyKXdmTa3rW/WbyHs7WsXEeVK0PbTn40RMTjp9tQZAWzVb6isJQYDsh0H/bUaEhItbNrOYlmczgjxqftehsAudysWc0=
+Coefficient: sl2u/8vttxpiTbspGV4SsaDmKUNdzQH7BgJ5rl3mXPp/aUpLw0Sr7FuARy8W8tq3yVNi9qCOnvGwVl6aQzZP7b8N04KiH8gewlAVdSfxG24yFKJIQNbWGKFZYZFYyjtLVlpK6NYF0f0I1KpAjn58XR0qIBvRFZYWBAkggU9C7ro=
+Created: 20211221062130
+Publish: 20211221062130
+Activate: 20211221062130
diff --git a/bin/tests/system/dnssec/signer/general/bogus-ksk.key b/bin/tests/system/dnssec/signer/general/bogus-ksk.key
new file mode 100644
index 0000000..e468574
--- /dev/null
+++ b/bin/tests/system/dnssec/signer/general/bogus-ksk.key
@@ -0,0 +1,6 @@
+;
+; This is a bogus key. It will not have a .private file.
+;
+; This will be key id 23221
+;
+example.com. IN DNSKEY 257 3 10 AwEAAbcyptpM++pVjhpYQW2fVtyOw04IBSw4X0SYi/Ke4wVkmDNW2vBm AFkgiVVKmmNbb0IHDYQiIY7seXk0fjEwjzeY2bmeOAZxDdv2KT9VQpoY Matk2y4NTi6F/V04x0lL/CBvyifTeNbZKvY+S1eKFuWHeS5Ss8tiagz9 zdYWUe/msvmin+Hbs2tlLwXVl4hOmABCL9uK9H8R6GPL5VdEXYyFOh/v 71CNhRU5ufrARti69YYkfzH6NpWhlJWyJvDjqAdt2L3H8V71C2vcXbBu S5NscEYl+8JQfwUvOTN553I5IQrG+NQEusW36UM/Rkad8mMnUVM9Vzqk GH86GHKtLMc=
diff --git a/bin/tests/system/dnssec/signer/general/bogus-zsk.key b/bin/tests/system/dnssec/signer/general/bogus-zsk.key
new file mode 100644
index 0000000..aa45938
--- /dev/null
+++ b/bin/tests/system/dnssec/signer/general/bogus-zsk.key
@@ -0,0 +1,6 @@
+;
+; This is a bogus key. It will not have a .private file.
+;
+; This will be key id 48930
+;
+example.com. IN DNSKEY 256 3 10 AwEAAa/0IcnbGutPVkrz04tw5ZIYx6rU+FprB2rlKS8cTK/wiBOqbOC6 QIDdegDpZG1fOdj04ZQGa3pIizqC2CnlIWfxpfR6W+qSLRBuQ8gmwTmS c/Jy/0vAGB3fv3oVIqKslLNqIXZb3CKNiA2kGcut3aUgfeOW970Jga6z PAGKqPpPZTelW1Qy9N5BO4cRTuYo4uvbZveJv1W/2n5RN+UaeqU0f+AE DP0+wqSWNUfZsi6HygLwk08x3eO8PzTBlqBlAMfvNAygrmXqccMREyyH KEc5dVJ1qOXfj8BAdJUPmunyJhIwC9PxzOW7mn1lW7mZO2D5U/Jaxw2k eX2KblmVk8s=
diff --git a/bin/tests/system/dnssec/signer/general/test1.zone b/bin/tests/system/dnssec/signer/general/test1.zone
new file mode 100644
index 0000000..98c9f02
--- /dev/null
+++ b/bin/tests/system/dnssec/signer/general/test1.zone
@@ -0,0 +1,19 @@
+; Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+;
+; SPDX-License-Identifier: MPL-2.0
+;
+; This Source Code Form is subject to the terms of the Mozilla Public
+; License, v. 2.0. If a copy of the MPL was not distributed with this
+; file, you can obtain one at https://mozilla.org/MPL/2.0/.
+;
+; See the COPYRIGHT file distributed with this work for additional
+; information regarding copyright ownership.
+
+; This is a zone which has two DNSKEY records, both of which have
+; existing private key files available. They should be loaded automatically
+; and the zone correctly signed.
+;
+$TTL 3600
+example.com. IN SOA ns hostmaster 00090000 1200 3600 604800 300
+$include Kexample.com.+010+18240.key
+$include Kexample.com.+010+28633.key
diff --git a/bin/tests/system/dnssec/signer/general/test2.zone b/bin/tests/system/dnssec/signer/general/test2.zone
new file mode 100644
index 0000000..97c0d3d
--- /dev/null
+++ b/bin/tests/system/dnssec/signer/general/test2.zone
@@ -0,0 +1,18 @@
+; Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+;
+; SPDX-License-Identifier: MPL-2.0
+;
+; This Source Code Form is subject to the terms of the Mozilla Public
+; License, v. 2.0. If a copy of the MPL was not distributed with this
+; file, you can obtain one at https://mozilla.org/MPL/2.0/.
+;
+; See the COPYRIGHT file distributed with this work for additional
+; information regarding copyright ownership.
+
+; This is a zone which has one non-KSK DNSKEY record for which the
+; private key file exists. It should be loaded automatically and the zone
+; correctly signed.
+;
+$TTL 3600
+example.com. IN SOA ns hostmaster 00090000 1200 3600 604800 300
+$include Kexample.com.+010+18240.key
diff --git a/bin/tests/system/dnssec/signer/general/test3.zone b/bin/tests/system/dnssec/signer/general/test3.zone
new file mode 100644
index 0000000..bf9bc66
--- /dev/null
+++ b/bin/tests/system/dnssec/signer/general/test3.zone
@@ -0,0 +1,18 @@
+; Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+;
+; SPDX-License-Identifier: MPL-2.0
+;
+; This Source Code Form is subject to the terms of the Mozilla Public
+; License, v. 2.0. If a copy of the MPL was not distributed with this
+; file, you can obtain one at https://mozilla.org/MPL/2.0/.
+;
+; See the COPYRIGHT file distributed with this work for additional
+; information regarding copyright ownership.
+
+; This is a zone which has one KSK DNSKEY record for which the
+; private key file exists. It should be loaded automatically. As there
+; is no non-KSK DNSKEY the resulting zone should be rejected.
+;
+$TTL 3600
+example.com. IN SOA ns hostmaster 00090000 1200 3600 604800 300
+$include Kexample.com.+010+28633.key
diff --git a/bin/tests/system/dnssec/signer/general/test4.zone b/bin/tests/system/dnssec/signer/general/test4.zone
new file mode 100644
index 0000000..9f05de5
--- /dev/null
+++ b/bin/tests/system/dnssec/signer/general/test4.zone
@@ -0,0 +1,20 @@
+; Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+;
+; SPDX-License-Identifier: MPL-2.0
+;
+; This Source Code Form is subject to the terms of the Mozilla Public
+; License, v. 2.0. If a copy of the MPL was not distributed with this
+; file, you can obtain one at https://mozilla.org/MPL/2.0/.
+;
+; See the COPYRIGHT file distributed with this work for additional
+; information regarding copyright ownership.
+
+; This is a zone which has three DNSKEY records, two (KSK + ZSK) of
+; which have existing private key files available. The third is a
+; pre-published ZSK.
+;
+$TTL 3600
+example.com. IN SOA ns hostmaster 00090000 1200 3600 604800 300
+$include Kexample.com.+010+18240.key
+$include Kexample.com.+010+28633.key
+$include bogus-zsk.key
diff --git a/bin/tests/system/dnssec/signer/general/test5.zone b/bin/tests/system/dnssec/signer/general/test5.zone
new file mode 100644
index 0000000..d61504f
--- /dev/null
+++ b/bin/tests/system/dnssec/signer/general/test5.zone
@@ -0,0 +1,19 @@
+; Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+;
+; SPDX-License-Identifier: MPL-2.0
+;
+; This Source Code Form is subject to the terms of the Mozilla Public
+; License, v. 2.0. If a copy of the MPL was not distributed with this
+; file, you can obtain one at https://mozilla.org/MPL/2.0/.
+;
+; See the COPYRIGHT file distributed with this work for additional
+; information regarding copyright ownership.
+
+; This is a zone which has three DNSKEY records, two (KSK +ZSK) of which
+; have existing private key files available. The third is a KSK.
+;
+$TTL 3600
+example.com. IN SOA ns hostmaster 00090000 1200 3600 604800 300
+$include Kexample.com.+010+18240.key
+$include Kexample.com.+010+28633.key
+$include bogus-ksk.key
diff --git a/bin/tests/system/dnssec/signer/general/test6.zone b/bin/tests/system/dnssec/signer/general/test6.zone
new file mode 100644
index 0000000..fcfb1ec
--- /dev/null
+++ b/bin/tests/system/dnssec/signer/general/test6.zone
@@ -0,0 +1,21 @@
+; Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+;
+; SPDX-License-Identifier: MPL-2.0
+;
+; This Source Code Form is subject to the terms of the Mozilla Public
+; License, v. 2.0. If a copy of the MPL was not distributed with this
+; file, you can obtain one at https://mozilla.org/MPL/2.0/.
+;
+; See the COPYRIGHT file distributed with this work for additional
+; information regarding copyright ownership.
+
+; This is a zone which has four DNSKEY records, two (KK + ZSK) of which
+; have existing private key files available. There are also a KSK and ZSK
+; for which there will be no signatures.
+;
+$TTL 3600
+example.com. IN SOA ns hostmaster 00090000 1200 3600 604800 300
+$include Kexample.com.+010+18240.key
+$include Kexample.com.+010+28633.key
+$include bogus-ksk.key
+$include bogus-zsk.key
diff --git a/bin/tests/system/dnssec/signer/general/test7.zone b/bin/tests/system/dnssec/signer/general/test7.zone
new file mode 100644
index 0000000..e52c535
--- /dev/null
+++ b/bin/tests/system/dnssec/signer/general/test7.zone
@@ -0,0 +1,19 @@
+; Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+;
+; SPDX-License-Identifier: MPL-2.0
+;
+; This Source Code Form is subject to the terms of the Mozilla Public
+; License, v. 2.0. If a copy of the MPL was not distributed with this
+; file, you can obtain one at https://mozilla.org/MPL/2.0/.
+;
+; See the COPYRIGHT file distributed with this work for additional
+; information regarding copyright ownership.
+
+; This is a zone which has two DNSKEY records, none of which have
+; existing private key files available. The resulting zone should fail
+; the consistency tests.
+;
+$TTL 3600
+example.com. IN SOA ns hostmaster 00090000 1200 3600 604800 300
+$include bogus-ksk.key
+$include bogus-zsk.key
diff --git a/bin/tests/system/dnssec/signer/general/test8.zone b/bin/tests/system/dnssec/signer/general/test8.zone
new file mode 100644
index 0000000..893d32d
--- /dev/null
+++ b/bin/tests/system/dnssec/signer/general/test8.zone
@@ -0,0 +1,19 @@
+; Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+;
+; SPDX-License-Identifier: MPL-2.0
+;
+; This Source Code Form is subject to the terms of the Mozilla Public
+; License, v. 2.0. If a copy of the MPL was not distributed with this
+; file, you can obtain one at https://mozilla.org/MPL/2.0/.
+;
+; See the COPYRIGHT file distributed with this work for additional
+; information regarding copyright ownership.
+
+; This is a zone which has two DNSKEY records, one of which,
+; the KSK, has a private key. The resulting zone should be rejected as
+; it has no ZSK signatures.
+;
+$TTL 3600
+example.com. IN SOA ns hostmaster 00090000 1200 3600 604800 300
+$include Kexample.com.+010+28633.key
+$include bogus-zsk.key
diff --git a/bin/tests/system/dnssec/signer/general/test9.zone b/bin/tests/system/dnssec/signer/general/test9.zone
new file mode 100644
index 0000000..14c47d0
--- /dev/null
+++ b/bin/tests/system/dnssec/signer/general/test9.zone
@@ -0,0 +1,19 @@
+; Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+;
+; SPDX-License-Identifier: MPL-2.0
+;
+; This Source Code Form is subject to the terms of the Mozilla Public
+; License, v. 2.0. If a copy of the MPL was not distributed with this
+; file, you can obtain one at https://mozilla.org/MPL/2.0/.
+;
+; See the COPYRIGHT file distributed with this work for additional
+; information regarding copyright ownership.
+
+; This is a zone which has two DNSKEY records, both of which have
+; existing private key files available. They should be loaded automatically
+; and the zone correctly signed.
+;
+$TTL 3600
+example.com. IN SOA ns hostmaster 00090000 1200 3600 604800 300
+$include Kexample.com.+008+63613.key
+$include Kexample.com.+008+15002.key
diff --git a/bin/tests/system/dnssec/signer/prepub.db.in b/bin/tests/system/dnssec/signer/prepub.db.in
new file mode 100644
index 0000000..946aac1
--- /dev/null
+++ b/bin/tests/system/dnssec/signer/prepub.db.in
@@ -0,0 +1,17 @@
+; Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+;
+; SPDX-License-Identifier: MPL-2.0
+;
+; This Source Code Form is subject to the terms of the Mozilla Public
+; License, v. 2.0. If a copy of the MPL was not distributed with this
+; file, you can obtain one at https://mozilla.org/MPL/2.0/.
+;
+; See the COPYRIGHT file distributed with this work for additional
+; information regarding copyright ownership.
+
+$TTL 60
+prepub. 60 IN SOA prepub. . 0 0 0 0 0
+prepub. 60 IN NS prepub.
+prepub. 60 IN A 1.2.3.4
+; out of zone record
+out-of-zone. 60 IN A 1.2.3.4
diff --git a/bin/tests/system/dnssec/signer/remove.db.in b/bin/tests/system/dnssec/signer/remove.db.in
new file mode 100644
index 0000000..5629a42
--- /dev/null
+++ b/bin/tests/system/dnssec/signer/remove.db.in
@@ -0,0 +1,18 @@
+; Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+;
+; SPDX-License-Identifier: MPL-2.0
+;
+; This Source Code Form is subject to the terms of the Mozilla Public
+; License, v. 2.0. If a copy of the MPL was not distributed with this
+; file, you can obtain one at https://mozilla.org/MPL/2.0/.
+;
+; See the COPYRIGHT file distributed with this work for additional
+; information regarding copyright ownership.
+
+$TTL 60
+remove. 60 IN SOA remove. . 0 0 0 0 0
+remove. 60 IN NS remove.
+remove. 60 IN A 1.2.3.4
+remove. 60 IN AAAA ::ffff:1.2.3.4
+remove. 60 IN MX 0 remove.
+$INCLUDE remove.db.signed
diff --git a/bin/tests/system/dnssec/signer/remove2.db.in b/bin/tests/system/dnssec/signer/remove2.db.in
new file mode 100644
index 0000000..b2962b9
--- /dev/null
+++ b/bin/tests/system/dnssec/signer/remove2.db.in
@@ -0,0 +1,16 @@
+; Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+;
+; SPDX-License-Identifier: MPL-2.0
+;
+; This Source Code Form is subject to the terms of the Mozilla Public
+; License, v. 2.0. If a copy of the MPL was not distributed with this
+; file, you can obtain one at https://mozilla.org/MPL/2.0/.
+;
+; See the COPYRIGHT file distributed with this work for additional
+; information regarding copyright ownership.
+
+$TTL 60
+remove. 60 IN SOA remove. . 0 0 0 0 0
+remove. 60 IN NS remove.
+remove. 60 IN A 1.2.3.4
+$INCLUDE remove.db.signed
diff --git a/bin/tests/system/dnssec/tests.sh b/bin/tests/system/dnssec/tests.sh
new file mode 100644
index 0000000..97bffb5
--- /dev/null
+++ b/bin/tests/system/dnssec/tests.sh
@@ -0,0 +1,4446 @@
+#!/bin/sh
+
+# Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+#
+# SPDX-License-Identifier: MPL-2.0
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, you can obtain one at https://mozilla.org/MPL/2.0/.
+#
+# See the COPYRIGHT file distributed with this work for additional
+# information regarding copyright ownership.
+
+set -e
+
+# shellcheck source=conf.sh
+. ../conf.sh
+
+status=0
+n=1
+
+rm -f dig.out.*
+
+dig_with_opts() {
+ "$DIG" +tcp +noadd +nosea +nostat +nocmd +dnssec -p "$PORT" "$@"
+}
+
+dig_with_additionalopts() {
+ "$DIG" +noall +additional +dnssec -p "$PORT" "$@"
+}
+
+dig_with_answeropts() {
+ "$DIG" +noall +answer +dnssec -p "$PORT" "$@"
+}
+
+delv_with_opts() {
+ "$DELV" -a ns1/trusted.conf -p "$PORT" "$@"
+}
+
+rndccmd() {
+ "$RNDC" -c ../common/rndc.conf -p "$CONTROLPORT" -s "$@"
+}
+
+# TODO: Move loadkeys_on to conf.sh.common
+dnssec_loadkeys_on() {
+ nsidx=$1
+ zone=$2
+ nextpart ns${nsidx}/named.run > /dev/null
+ rndccmd 10.53.0.${nsidx} loadkeys ${zone} | sed "s/^/ns${nsidx} /" | cat_i
+ wait_for_log 20 "next key event" ns${nsidx}/named.run || return 1
+}
+
+# convert private-type records to readable form
+showprivate () {
+ echo "-- $* --"
+ dig_with_opts +nodnssec +short "@$2" -t type65534 "$1" | cut -f3 -d' ' |
+ while read -r record; do
+ # shellcheck disable=SC2016
+ $PERL -e 'my $rdata = pack("H*", @ARGV[0]);
+ die "invalid record" unless length($rdata) == 5;
+ my ($alg, $key, $remove, $complete) = unpack("CnCC", $rdata);
+ my $action = "signing";
+ $action = "removing" if $remove;
+ my $state = " (incomplete)";
+ $state = " (complete)" if $complete;
+ print ("$action: alg: $alg, key: $key$state\n");' "$record"
+ done
+}
+
+# check that signing records are marked as complete
+checkprivate () {
+ for i in 1 2 3 4 5 6 7 8 9 10; do
+ showprivate "$@" | grep -q incomplete || return 0
+ sleep 1
+ done
+ echo_d "$1 signing incomplete"
+ return 1
+}
+
+# check that a zone file is raw format, version 0
+israw0 () {
+ # shellcheck disable=SC2016
+ < "$1" $PERL -e 'binmode STDIN;
+ read(STDIN, $input, 8);
+ ($style, $version) = unpack("NN", $input);
+ exit 1 if ($style != 2 || $version != 0);' || return $?
+}
+
+# check that a zone file is raw format, version 1
+israw1 () {
+ # shellcheck disable=SC2016
+ < "$1" $PERL -e 'binmode STDIN;
+ read(STDIN, $input, 8);
+ ($style, $version) = unpack("NN", $input);
+ exit 1 if ($style != 2 || $version != 1);' || return $?
+}
+
+# strip NS and RRSIG NS from input
+stripns () {
+ awk '($4 == "NS") || ($4 == "RRSIG" && $5 == "NS") { next} { print }' "$1"
+}
+
+#
+# Ensure there is not multiple consecutive blank lines.
+# Ensure there is a blank line before "Start view" and
+# "Negative trust anchors:".
+# Ensure there is not a blank line before "Secure roots:".
+#
+check_secroots_layout () {
+ awk '$0 == "" { if (empty) exit(1); empty=1; next }
+ /Start view/ { if (!empty) exit(1) }
+ /Secure roots:/ { if (empty) exit(1) }
+ /Negative trust anchors:/ { if (!empty) exit(1) }
+ { empty=0 }' $1 || return $?
+}
+
+# Check that for a query against a validating resolver where the
+# authoritative zone is unsigned (insecure delegation), glue is returned
+# in the additional section
+echo_i "checking that additional glue is returned for unsigned delegation ($n)"
+ret=0
+$DIG +tcp +dnssec -p "$PORT" a.insecure.example. @10.53.0.4 a > dig.out.ns4.test$n || ret=1
+grep "ANSWER: 1, AUTHORITY: 1, ADDITIONAL: 2" dig.out.ns4.test$n > /dev/null || ret=1
+grep "ns\\.insecure\\.example\\..*A.10\\.53\\.0\\.3" dig.out.ns4.test$n > /dev/null || ret=1
+n=$((n+1))
+if [ "$ret" -ne 0 ]; then echo_i "failed"; fi
+status=$((status+ret))
+
+# Check the example. domain
+
+echo_i "checking that zone transfer worked ($n)"
+for i in 1 2 3 4 5 6 7 8 9
+do
+ ret=0
+ dig_with_opts a.example. @10.53.0.2 a > dig.out.ns2.test$n || ret=1
+ dig_with_opts a.example. @10.53.0.3 a > dig.out.ns3.test$n || ret=1
+ $PERL ../digcomp.pl dig.out.ns2.test$n dig.out.ns3.test$n > /dev/null || ret=1
+ [ "$ret" -eq 0 ] && break
+ sleep 1
+done
+digcomp dig.out.ns2.test$n dig.out.ns3.test$n > /dev/null || ret=1
+n=$((n+1))
+test "$ret" -eq 0 || echo_i "failed"
+status=$((status+ret))
+
+# test AD bit:
+# - dig +adflag asks for authentication (ad in response)
+echo_i "checking AD bit asking for validation ($n)"
+ret=0
+dig_with_opts +noauth +noadd +nodnssec +adflag a.example. @10.53.0.2 a > dig.out.ns2.test$n || ret=1
+dig_with_opts +noauth +noadd +nodnssec +adflag a.example. @10.53.0.4 a > dig.out.ns4.test$n || ret=1
+digcomp dig.out.ns2.test$n dig.out.ns4.test$n || ret=1
+grep "flags:.*ad.*QUERY" dig.out.ns4.test$n > /dev/null || ret=1
+n=$((n+1))
+test "$ret" -eq 0 || echo_i "failed"
+status=$((status+ret))
+
+# test AD bit:
+# - dig +noadflag
+echo_i "checking that AD is not set without +adflag or +dnssec ($n)"
+ret=0
+dig_with_opts +noauth +noadd +nodnssec +noadflag a.example. @10.53.0.2 a > dig.out.ns2.test$n || ret=1
+dig_with_opts +noauth +noadd +nodnssec +noadflag a.example. @10.53.0.4 a > dig.out.ns4.test$n || ret=1
+digcomp dig.out.ns2.test$n dig.out.ns4.test$n || ret=1
+grep "flags:.*ad.*QUERY" dig.out.ns4.test$n > /dev/null && ret=1
+n=$((n+1))
+test "$ret" -eq 0 || echo_i "failed"
+status=$((status+ret))
+
+echo_i "checking for AD in authoritative answer ($n)"
+ret=0
+dig_with_opts a.example. @10.53.0.2 a > dig.out.ns2.test$n || ret=1
+grep "flags:.*ad.*QUERY" dig.out.ns2.test$n > /dev/null && ret=1
+n=$((n+1))
+test "$ret" -eq 0 || echo_i "failed"
+status=$((status+ret))
+
+echo_i "checking positive validation NSEC ($n)"
+ret=0
+dig_with_opts +noauth a.example. @10.53.0.2 a > dig.out.ns2.test$n || ret=1
+dig_with_opts +noauth a.example. @10.53.0.4 a > dig.out.ns4.test$n || ret=1
+digcomp dig.out.ns2.test$n dig.out.ns4.test$n || ret=1
+grep "flags:.*ad.*QUERY" dig.out.ns4.test$n > /dev/null || ret=1
+n=$((n+1))
+test "$ret" -eq 0 || echo_i "failed"
+status=$((status+ret))
+
+echo_i "checking that 'example/DS' from the referral was used in previous validation ($n)"
+ret=0
+grep "query 'example/DS/IN' approved" ns1/named.run > /dev/null && ret=1
+grep "fetch: example/DS" ns4/named.run > /dev/null && ret=1
+grep "validating example/DS: starting" ns4/named.run > /dev/null || ret=1
+n=$((n+1))
+test "$ret" -eq 0 || echo_i "failed"
+status=$((status+ret))
+
+if [ -x "${DELV}" ] ; then
+ ret=0
+ echo_i "checking positive validation NSEC using dns_client ($n)"
+ delv_with_opts @10.53.0.4 a a.example > delv.out$n || ret=1
+ grep "a.example..*10.0.0.1" delv.out$n > /dev/null || ret=1
+ grep "a.example..*.RRSIG.A [0-9][0-9]* 2 300 .*" delv.out$n > /dev/null || ret=1
+ n=$((n+1))
+ test "$ret" -eq 0 || echo_i "failed"
+ status=$((status+ret))
+
+ ret=0
+ echo_i "checking positive validation NSEC using dns_client (trusted-keys) ($n)"
+ "$DELV" -a ns1/trusted.keys -p "$PORT" @10.53.0.4 a a.example > delv.out$n || ret=1
+ grep "a.example..*10.0.0.1" delv.out$n > /dev/null || ret=1
+ grep "a.example..*.RRSIG.A [0-9][0-9]* 2 300 .*" delv.out$n > /dev/null || ret=1
+ n=$((n+1))
+ test "$ret" -eq 0 || echo_i "failed"
+ status=$((status+ret))
+fi
+
+echo_i "checking positive validation NSEC3 ($n)"
+ret=0
+dig_with_opts +noauth a.nsec3.example. \
+ @10.53.0.3 a > dig.out.ns3.test$n || ret=1
+dig_with_opts +noauth a.nsec3.example. \
+ @10.53.0.4 a > dig.out.ns4.test$n || ret=1
+digcomp dig.out.ns3.test$n dig.out.ns4.test$n || ret=1
+grep "flags:.*ad.*QUERY" dig.out.ns4.test$n > /dev/null || ret=1
+n=$((n+1))
+test "$ret" -eq 0 || echo_i "failed"
+status=$((status+ret))
+
+if [ -x "${DELV}" ] ; then
+ ret=0
+ echo_i "checking positive validation NSEC3 using dns_client ($n)"
+ delv_with_opts @10.53.0.4 a a.nsec3.example > delv.out$n || ret=1
+ grep "a.nsec3.example..*10.0.0.1" delv.out$n > /dev/null || ret=1
+ grep "a.nsec3.example..*RRSIG.A [0-9][0-9]* 3 300.*" delv.out$n > /dev/null || ret=1
+ n=$((n+1))
+ test "$ret" -eq 0 || echo_i "failed"
+ status=$((status+ret))
+fi
+
+echo_i "checking positive validation OPTOUT ($n)"
+ret=0
+dig_with_opts +noauth a.optout.example. \
+ @10.53.0.3 a > dig.out.ns3.test$n || ret=1
+dig_with_opts +noauth a.optout.example. \
+ @10.53.0.4 a > dig.out.ns4.test$n || ret=1
+digcomp dig.out.ns3.test$n dig.out.ns4.test$n || ret=1
+grep "flags:.*ad.*QUERY" dig.out.ns4.test$n > /dev/null || ret=1
+n=$((n+1))
+test "$ret" -eq 0 || echo_i "failed"
+status=$((status+ret))
+
+SP="[[:space:]]+"
+
+if [ -x "${DELV}" ] ; then
+ ret=0
+ echo_i "checking positive validation OPTOUT using dns_client ($n)"
+ delv_with_opts @10.53.0.4 a a.optout.example > delv.out$n || ret=1
+ grep -Eq "^a\\.optout\\.example\\.""$SP""[0-9]+""$SP""IN""$SP""A""$SP""10.0.0.1" delv.out$n || ret=1
+ grep -Eq "^a\\.optout\\.example\\.""$SP""[0-9]+""$SP""IN""$SP""RRSIG""$SP""A""$SP""$DEFAULT_ALGORITHM_NUMBER""$SP""3""$SP""300" delv.out$n || ret=1
+ n=$((n+1))
+ test "$ret" -eq 0 || echo_i "failed"
+ status=$((status+ret))
+fi
+
+echo_i "checking positive wildcard validation NSEC ($n)"
+ret=0
+dig_with_opts a.wild.example. @10.53.0.3 a > dig.out.ns3.test$n || ret=1
+dig_with_opts a.wild.example. @10.53.0.4 a > dig.out.ns4.test$n || ret=1
+stripns dig.out.ns3.test$n > dig.out.ns3.stripped.test$n
+stripns dig.out.ns4.test$n > dig.out.ns4.stripped.test$n
+digcomp dig.out.ns3.stripped.test$n dig.out.ns4.stripped.test$n || ret=1
+grep "\\*\\.wild\\.example\\..*RRSIG NSEC" dig.out.ns4.test$n > /dev/null || ret=1
+grep "\\*\\.wild\\.example\\..*NSEC z\\.example" dig.out.ns4.test$n > /dev/null || ret=1
+grep "flags:.*ad.*QUERY" dig.out.ns4.test$n > /dev/null || ret=1
+grep "status: NOERROR" dig.out.ns4.test$n > /dev/null || ret=1
+n=$((n+1))
+test "$ret" -eq 0 || echo_i "failed"
+status=$((status+ret))
+
+if [ -x "${DELV}" ] ; then
+ ret=0
+ echo_i "checking positive wildcard validation NSEC using dns_client ($n)"
+ delv_with_opts @10.53.0.4 a a.wild.example > delv.out$n || ret=1
+ grep "a.wild.example..*10.0.0.27" delv.out$n > /dev/null || ret=1
+ grep -E "a.wild.example..*RRSIG.A [0-9]+ 2 300.*" delv.out$n > /dev/null || ret=1
+ n=$((n+1))
+ test "$ret" -eq 0 || echo_i "failed"
+ status=$((status+ret))
+fi
+
+echo_i "checking positive wildcard answer NSEC3 ($n)"
+ret=0
+dig_with_opts a.wild.nsec3.example. @10.53.0.3 a > dig.out.ns3.test$n || ret=1
+grep "AUTHORITY: 4," dig.out.ns3.test$n > /dev/null || ret=1
+grep "status: NOERROR" dig.out.ns3.test$n > /dev/null || ret=1
+n=$((n+1))
+test "$ret" -eq 0 || echo_i "failed"
+status=$((status+ret))
+
+echo_i "checking positive wildcard answer NSEC3 ($n)"
+ret=0
+dig_with_opts a.wild.nsec3.example. @10.53.0.4 a > dig.out.ns4.test$n || ret=1
+grep "AUTHORITY: 4," dig.out.ns4.test$n > /dev/null || ret=1
+grep "status: NOERROR" dig.out.ns4.test$n > /dev/null || ret=1
+n=$((n+1))
+test "$ret" -eq 0 || echo_i "failed"
+status=$((status+ret))
+
+echo_i "checking positive wildcard validation NSEC3 ($n)"
+ret=0
+dig_with_opts a.wild.nsec3.example. @10.53.0.3 a > dig.out.ns3.test$n || ret=1
+dig_with_opts a.wild.nsec3.example. @10.53.0.4 a > dig.out.ns4.test$n || ret=1
+stripns dig.out.ns3.test$n > dig.out.ns3.stripped.test$n
+stripns dig.out.ns4.test$n > dig.out.ns4.stripped.test$n
+digcomp dig.out.ns3.stripped.test$n dig.out.ns4.stripped.test$n || ret=1
+grep "flags:.*ad.*QUERY" dig.out.ns4.test$n > /dev/null || ret=1
+grep "status: NOERROR" dig.out.ns4.test$n > /dev/null || ret=1
+n=$((n+1))
+test "$ret" -eq 0 || echo_i "failed"
+status=$((status+ret))
+
+if [ -x "${DELV}" ] ; then
+ ret=0
+ echo_i "checking positive wildcard validation NSEC3 using dns_client ($n)"
+ delv_with_opts @10.53.0.4 a a.wild.nsec3.example > delv.out$n || ret=1
+ grep -E "a.wild.nsec3.example..*10.0.0.6" delv.out$n > /dev/null || ret=1
+ grep -E "a.wild.nsec3.example..*RRSIG.A [0-9][0-9]* 3 300.*" delv.out$n > /dev/null || ret=1
+ n=$((n+1))
+ test "$ret" -eq 0 || echo_i "failed"
+ status=$((status+ret))
+fi
+
+echo_i "checking positive wildcard validation OPTOUT ($n)"
+ret=0
+dig_with_opts a.wild.optout.example. \
+ @10.53.0.3 a > dig.out.ns3.test$n || ret=1
+dig_with_opts a.wild.optout.example. \
+ @10.53.0.4 a > dig.out.ns4.test$n || ret=1
+stripns dig.out.ns3.test$n > dig.out.ns3.stripped.test$n
+stripns dig.out.ns4.test$n > dig.out.ns4.stripped.test$n
+digcomp dig.out.ns3.stripped.test$n dig.out.ns4.stripped.test$n || ret=1
+grep "flags:.*ad.*QUERY" dig.out.ns4.test$n > /dev/null && ret=1
+grep "status: NOERROR" dig.out.ns4.test$n > /dev/null || ret=1
+n=$((n+1))
+test "$ret" -eq 0 || echo_i "failed"
+status=$((status+ret))
+
+if [ -x "${DELV}" ] ; then
+ ret=0
+ echo_i "checking positive wildcard validation OPTOUT using dns_client ($n)"
+ delv_with_opts @10.53.0.4 a a.wild.optout.example > delv.out$n || ret=1
+ grep "a.wild.optout.example..*10.0.0.6" delv.out$n > /dev/null || ret=1
+ grep "a.wild.optout.example..*RRSIG.A [0-9][0-9]* 3 300.*" delv.out$n > /dev/null || ret=1
+ n=$((n+1))
+ test "$ret" -eq 0 || echo_i "failed"
+ status=$((status+ret))
+fi
+
+echo_i "checking negative validation NXDOMAIN NSEC ($n)"
+ret=0
+dig_with_opts +noauth q.example. @10.53.0.2 a > dig.out.ns2.test$n || ret=1
+dig_with_opts +noauth q.example. @10.53.0.4 a > dig.out.ns4.test$n || ret=1
+digcomp dig.out.ns2.test$n dig.out.ns4.test$n || ret=1
+grep "flags:.*ad.*QUERY" dig.out.ns4.test$n > /dev/null || ret=1
+grep "status: NXDOMAIN" dig.out.ns4.test$n > /dev/null || ret=1
+n=$((n+1))
+test "$ret" -eq 0 || echo_i "failed"
+status=$((status+ret))
+
+if [ -x "${DELV}" ] ; then
+ ret=0
+ echo_i "checking negative validation NXDOMAIN NSEC using dns_client ($n)"
+ delv_with_opts @10.53.0.4 a q.example > delv.out$n 2>&1 || ret=1
+ grep "resolution failed: ncache nxdomain" delv.out$n > /dev/null || ret=1
+ n=$((n+1))
+ test "$ret" -eq 0 || echo_i "failed"
+ status=$((status+ret))
+fi
+
+echo_i "checking negative validation NXDOMAIN NSEC3 ($n)"
+ret=0
+dig_with_opts +noauth q.nsec3.example. \
+ @10.53.0.3 a > dig.out.ns3.test$n || ret=1
+dig_with_opts +noauth q.nsec3.example. \
+ @10.53.0.4 a > dig.out.ns4.test$n || ret=1
+digcomp dig.out.ns3.test$n dig.out.ns4.test$n || ret=1
+grep "flags:.*ad.*QUERY" dig.out.ns4.test$n > /dev/null || ret=1
+grep "status: NXDOMAIN" dig.out.ns4.test$n > /dev/null || ret=1
+n=$((n+1))
+test "$ret" -eq 0 || echo_i "failed"
+status=$((status+ret))
+
+if [ -x "${DELV}" ] ; then
+ ret=0
+ echo_i "checking negative validation NXDOMAIN NSEC3 using dns_client ($n)"
+ delv_with_opts @10.53.0.4 a q.nsec3.example > delv.out$n 2>&1 || ret=1
+ grep "resolution failed: ncache nxdomain" delv.out$n > /dev/null || ret=1
+ n=$((n+1))
+ test "$ret" -eq 0 || echo_i "failed"
+ status=$((status+ret))
+fi
+
+echo_i "checking negative validation NXDOMAIN OPTOUT ($n)"
+ret=0
+dig_with_opts +noauth q.optout.example. \
+ @10.53.0.3 a > dig.out.ns3.test$n || ret=1
+dig_with_opts +noauth q.optout.example. \
+ @10.53.0.4 a > dig.out.ns4.test$n || ret=1
+digcomp dig.out.ns3.test$n dig.out.ns4.test$n || ret=1
+grep "status: NXDOMAIN" dig.out.ns4.test$n > /dev/null || ret=1
+# Note - this is looking for failure, hence the &&
+grep "flags:.*ad.*QUERY" dig.out.ns4.test$n > /dev/null && ret=1
+n=$((n+1))
+test "$ret" -eq 0 || echo_i "failed"
+status=$((status+ret))
+
+if [ -x "${DELV}" ] ; then
+ ret=0
+ echo_i "checking negative validation NXDOMAIN OPTOUT using dns_client ($n)"
+ delv_with_opts @10.53.0.4 a q.optout.example > delv.out$n 2>&1 || ret=1
+ grep "resolution failed: ncache nxdomain" delv.out$n > /dev/null || ret=1
+ n=$((n+1))
+ test "$ret" -eq 0 || echo_i "failed"
+ status=$((status+ret))
+fi
+
+echo_i "checking negative validation NODATA NSEC ($n)"
+ret=0
+dig_with_opts +noauth a.example. @10.53.0.2 txt > dig.out.ns2.test$n || ret=1
+dig_with_opts +noauth a.example. @10.53.0.4 txt > dig.out.ns4.test$n || ret=1
+digcomp dig.out.ns2.test$n dig.out.ns4.test$n || ret=1
+grep "flags:.*ad.*QUERY" dig.out.ns4.test$n > /dev/null || ret=1
+grep "status: NOERROR" dig.out.ns4.test$n > /dev/null || ret=1
+grep "ANSWER: 0" dig.out.ns4.test$n > /dev/null || ret=1
+n=$((n+1))
+test "$ret" -eq 0 || echo_i "failed"
+status=$((status+ret))
+
+if [ -x "${DELV}" ] ; then
+ ret=0
+ echo_i "checking negative validation NODATA OPTOUT using dns_client ($n)"
+ delv_with_opts @10.53.0.4 txt a.example > delv.out$n 2>&1 || ret=1
+ grep "resolution failed: ncache nxrrset" delv.out$n > /dev/null || ret=1
+ n=$((n+1))
+ test "$ret" -eq 0 || echo_i "failed"
+ status=$((status+ret))
+fi
+
+echo_i "checking negative validation NODATA NSEC3 ($n)"
+ret=0
+dig_with_opts +noauth a.nsec3.example. \
+ @10.53.0.3 txt > dig.out.ns3.test$n || ret=1
+dig_with_opts +noauth a.nsec3.example. \
+ @10.53.0.4 txt > dig.out.ns4.test$n || ret=1
+digcomp dig.out.ns3.test$n dig.out.ns4.test$n || ret=1
+grep "flags:.*ad.*QUERY" dig.out.ns4.test$n > /dev/null || ret=1
+grep "status: NOERROR" dig.out.ns4.test$n > /dev/null || ret=1
+grep "ANSWER: 0" dig.out.ns4.test$n > /dev/null || ret=1
+n=$((n+1))
+test "$ret" -eq 0 || echo_i "failed"
+status=$((status+ret))
+
+if [ -x "${DELV}" ] ; then
+ ret=0
+ echo_i "checking negative validation NODATA NSEC3 using dns_client ($n)"
+ delv_with_opts @10.53.0.4 txt a.nsec3.example > delv.out$n 2>&1 || ret=1
+ grep "resolution failed: ncache nxrrset" delv.out$n > /dev/null || ret=1
+ n=$((n+1))
+ test "$ret" -eq 0 || echo_i "failed"
+ status=$((status+ret))
+fi
+
+echo_i "checking negative validation NODATA OPTOUT ($n)"
+ret=0
+dig_with_opts +noauth a.optout.example. \
+ @10.53.0.3 txt > dig.out.ns3.test$n || ret=1
+dig_with_opts +noauth a.optout.example. \
+ @10.53.0.4 txt > dig.out.ns4.test$n || ret=1
+digcomp dig.out.ns3.test$n dig.out.ns4.test$n || ret=1
+grep "flags:.*ad.*QUERY" dig.out.ns4.test$n > /dev/null || ret=1
+grep "status: NOERROR" dig.out.ns4.test$n > /dev/null || ret=1
+grep "ANSWER: 0" dig.out.ns4.test$n > /dev/null || ret=1
+n=$((n+1))
+test "$ret" -eq 0 || echo_i "failed"
+status=$((status+ret))
+
+if [ -x "${DELV}" ] ; then
+ ret=0
+ echo_i "checking negative validation NODATA OPTOUT using dns_client ($n)"
+ delv_with_opts @10.53.0.4 txt a.optout.example > delv.out$n 2>&1 || ret=1
+ grep "resolution failed: ncache nxrrset" delv.out$n > /dev/null || ret=1
+ n=$((n+1))
+ test "$ret" -eq 0 || echo_i "failed"
+ status=$((status+ret))
+fi
+
+echo_i "checking negative wildcard validation NSEC ($n)"
+ret=0
+dig_with_opts b.wild.example. @10.53.0.2 txt > dig.out.ns2.test$n || ret=1
+dig_with_opts b.wild.example. @10.53.0.4 txt > dig.out.ns4.test$n || ret=1
+digcomp dig.out.ns2.test$n dig.out.ns4.test$n || ret=1
+grep "flags:.*ad.*QUERY" dig.out.ns4.test$n > /dev/null || ret=1
+grep "status: NOERROR" dig.out.ns4.test$n > /dev/null || ret=1
+n=$((n+1))
+test "$ret" -eq 0 || echo_i "failed"
+status=$((status+ret))
+
+if [ -x "${DELV}" ] ; then
+ ret=0
+ echo_i "checking negative wildcard validation NSEC using dns_client ($n)"
+ delv_with_opts @10.53.0.4 txt b.wild.example > delv.out$n 2>&1 || ret=1
+ grep "resolution failed: ncache nxrrset" delv.out$n > /dev/null || ret=1
+ n=$((n+1))
+ test "$ret" -eq 0 || echo_i "failed"
+ status=$((status+ret))
+fi
+
+echo_i "checking negative wildcard validation NSEC3 ($n)"
+ret=0
+dig_with_opts b.wild.nsec3.example. @10.53.0.3 txt > dig.out.ns3.test$n || ret=1
+dig_with_opts b.wild.nsec3.example. @10.53.0.4 txt > dig.out.ns4.test$n || ret=1
+digcomp dig.out.ns3.test$n dig.out.ns4.test$n || ret=1
+grep "flags:.*ad.*QUERY" dig.out.ns4.test$n > /dev/null || ret=1
+n=$((n+1))
+test "$ret" -eq 0 || echo_i "failed"
+status=$((status+ret))
+
+if [ -x "${DELV}" ] ; then
+ ret=0
+ echo_i "checking negative wildcard validation NSEC3 using dns_client ($n)"
+ delv_with_opts @10.53.0.4 txt b.wild.nsec3.example > delv.out$n 2>&1 || ret=1
+ grep "resolution failed: ncache nxrrset" delv.out$n > /dev/null || ret=1
+ n=$((n+1))
+ test "$ret" -eq 0 || echo_i "failed"
+ status=$((status+ret))
+fi
+
+echo_i "checking negative wildcard validation OPTOUT ($n)"
+ret=0
+dig_with_opts b.wild.optout.example. \
+ @10.53.0.3 txt > dig.out.ns3.test$n || ret=1
+dig_with_opts b.wild.optout.example. \
+ @10.53.0.4 txt > dig.out.ns4.test$n || ret=1
+digcomp dig.out.ns3.test$n dig.out.ns4.test$n || ret=1
+grep "status: NOERROR" dig.out.ns4.test$n > /dev/null || ret=1
+# Note - this is looking for failure, hence the &&
+grep "flags:.*ad.*QUERY" dig.out.ns4.test$n > /dev/null && ret=1
+n=$((n+1))
+test "$ret" -eq 0 || echo_i "failed"
+status=$((status+ret))
+
+if [ -x "${DELV}" ] ; then
+ ret=0
+ echo_i "checking negative wildcard validation OPTOUT using dns_client ($n)"
+ delv_with_opts @10.53.0.4 txt b.optout.nsec3.example > delv.out$n 2>&1 || ret=1
+ grep "resolution failed: ncache nxrrset" delv.out$n > /dev/null || ret=1
+ n=$((n+1))
+ test "$ret" -eq 0 || echo_i "failed"
+ status=$((status+ret))
+fi
+
+# Check the insecure.example domain
+
+echo_i "checking 1-server insecurity proof NSEC ($n)"
+ret=0
+dig_with_opts +noauth a.insecure.example. @10.53.0.3 a > dig.out.ns3.test$n || ret=1
+dig_with_opts +noauth a.insecure.example. @10.53.0.4 a > dig.out.ns4.test$n || ret=1
+digcomp dig.out.ns3.test$n dig.out.ns4.test$n || ret=1
+grep "status: NOERROR" dig.out.ns4.test$n > /dev/null || ret=1
+# Note - this is looking for failure, hence the &&
+grep "flags:.*ad.*QUERY" dig.out.ns4.test$n > /dev/null && ret=1
+n=$((n+1))
+test "$ret" -eq 0 || echo_i "failed"
+status=$((status+ret))
+
+if [ -x "${DELV}" ] ; then
+ ret=0
+ echo_i "checking 1-server insecurity proof NSEC using dns_client ($n)"
+ delv_with_opts @10.53.0.4 a a.insecure.example > delv.out$n || ret=1
+ grep "a.insecure.example..*10.0.0.1" delv.out$n > /dev/null || ret=1
+ n=$((n+1))
+ test "$ret" -eq 0 || echo_i "failed"
+ status=$((status+ret))
+fi
+
+echo_i "checking 1-server insecurity proof NSEC3 ($n)"
+ret=0
+dig_with_opts +noauth a.insecure.nsec3.example. @10.53.0.3 a > dig.out.ns3.test$n || ret=1
+dig_with_opts +noauth a.insecure.nsec3.example. @10.53.0.4 a > dig.out.ns4.test$n || ret=1
+digcomp dig.out.ns3.test$n dig.out.ns4.test$n || ret=1
+grep "status: NOERROR" dig.out.ns4.test$n > /dev/null || ret=1
+# Note - this is looking for failure, hence the &&
+grep "flags:.*ad.*QUERY" dig.out.ns4.test$n > /dev/null && ret=1
+n=$((n+1))
+test "$ret" -eq 0 || echo_i "failed"
+status=$((status+ret))
+
+if [ -x "${DELV}" ] ; then
+ ret=0
+ echo_i "checking 1-server insecurity proof NSEC3 using dns_client ($n)"
+ delv_with_opts @10.53.0.4 a a.insecure.nsec3.example > delv.out$n || ret=1
+ grep "a.insecure.nsec3.example..*10.0.0.1" delv.out$n > /dev/null || ret=1
+ n=$((n+1))
+ test "$ret" -eq 0 || echo_i "failed"
+ status=$((status+ret))
+fi
+
+echo_i "checking 1-server insecurity proof OPTOUT ($n)"
+ret=0
+dig_with_opts +noauth a.insecure.optout.example. @10.53.0.3 a > dig.out.ns3.test$n || ret=1
+dig_with_opts +noauth a.insecure.optout.example. @10.53.0.4 a > dig.out.ns4.test$n || ret=1
+digcomp dig.out.ns3.test$n dig.out.ns4.test$n || ret=1
+grep "status: NOERROR" dig.out.ns4.test$n > /dev/null || ret=1
+# Note - this is looking for failure, hence the &&
+grep "flags:.*ad.*QUERY" dig.out.ns4.test$n > /dev/null && ret=1
+n=$((n+1))
+test "$ret" -eq 0 || echo_i "failed"
+status=$((status+ret))
+
+if [ -x "${DELV}" ] ; then
+ ret=0
+ echo_i "checking 1-server insecurity proof OPTOUT using dns_client ($n)"
+ delv_with_opts @10.53.0.4 a a.insecure.optout.example > delv.out$n || ret=1
+ grep "a.insecure.optout.example..*10.0.0.1" delv.out$n > /dev/null || ret=1
+ n=$((n+1))
+ test "$ret" -eq 0 || echo_i "failed"
+ status=$((status+ret))
+fi
+
+echo_i "checking 1-server negative insecurity proof NSEC ($n)"
+ret=0
+dig_with_opts q.insecure.example. a @10.53.0.3 \
+ > dig.out.ns3.test$n || ret=1
+dig_with_opts q.insecure.example. a @10.53.0.4 \
+ > dig.out.ns4.test$n || ret=1
+digcomp dig.out.ns3.test$n dig.out.ns4.test$n || ret=1
+grep "status: NXDOMAIN" dig.out.ns4.test$n > /dev/null || ret=1
+# Note - this is looking for failure, hence the &&
+grep "flags:.*ad.*QUERY" dig.out.ns4.test$n > /dev/null && ret=1
+n=$((n+1))
+test "$ret" -eq 0 || echo_i "failed"
+status=$((status+ret))
+
+if [ -x "${DELV}" ] ; then
+ ret=0
+ echo_i "checking 1-server negative insecurity proof NSEC using dns_client ($n)"
+ delv_with_opts @10.53.0.4 a q.insecure.example > delv.out$n 2>&1 || ret=1
+ grep "resolution failed: ncache nxdomain" delv.out$n > /dev/null || ret=1
+ n=$((n+1))
+ test "$ret" -eq 0 || echo_i "failed"
+ status=$((status+ret))
+fi
+
+echo_i "checking 1-server negative insecurity proof NSEC3 ($n)"
+ret=0
+dig_with_opts q.insecure.nsec3.example. a @10.53.0.3 \
+ > dig.out.ns3.test$n || ret=1
+dig_with_opts q.insecure.nsec3.example. a @10.53.0.4 \
+ > dig.out.ns4.test$n || ret=1
+digcomp dig.out.ns3.test$n dig.out.ns4.test$n || ret=1
+grep "status: NXDOMAIN" dig.out.ns4.test$n > /dev/null || ret=1
+# Note - this is looking for failure, hence the &&
+grep "flags:.*ad.*QUERY" dig.out.ns4.test$n > /dev/null && ret=1
+n=$((n+1))
+test "$ret" -eq 0 || echo_i "failed"
+status=$((status+ret))
+
+if [ -x "${DELV}" ] ; then
+ ret=0
+ echo_i "checking 1-server negative insecurity proof NSEC3 using dns_client ($n)"
+ delv_with_opts @10.53.0.4 a q.insecure.nsec3.example > delv.out$n 2>&1 || ret=1
+ grep "resolution failed: ncache nxdomain" delv.out$n > /dev/null || ret=1
+ n=$((n+1))
+ test "$ret" -eq 0 || echo_i "failed"
+ status=$((status+ret))
+fi
+
+echo_i "checking 1-server negative insecurity proof OPTOUT ($n)"
+ret=0
+dig_with_opts q.insecure.optout.example. a @10.53.0.3 \
+ > dig.out.ns3.test$n || ret=1
+dig_with_opts q.insecure.optout.example. a @10.53.0.4 \
+ > dig.out.ns4.test$n || ret=1
+digcomp dig.out.ns3.test$n dig.out.ns4.test$n || ret=1
+grep "status: NXDOMAIN" dig.out.ns4.test$n > /dev/null || ret=1
+# Note - this is looking for failure, hence the &&
+grep "flags:.*ad.*QUERY" dig.out.ns4.test$n > /dev/null && ret=1
+n=$((n+1))
+test "$ret" -eq 0 || echo_i "failed"
+status=$((status+ret))
+
+if [ -x "${DELV}" ] ; then
+ ret=0
+ echo_i "checking 1-server negative insecurity proof OPTOUT using dns_client ($n)"
+ delv_with_opts @10.53.0.4 a q.insecure.optout.example > delv.out$n 2>&1 || ret=1
+ grep "resolution failed: ncache nxdomain" delv.out$n > /dev/null || ret=1
+ n=$((n+1))
+ test "$ret" -eq 0 || echo_i "failed"
+ status=$((status+ret))
+fi
+
+echo_i "checking 1-server negative insecurity proof with SOA hack NSEC ($n)"
+ret=0
+dig_with_opts r.insecure.example. soa @10.53.0.3 \
+ > dig.out.ns3.test$n || ret=1
+dig_with_opts r.insecure.example. soa @10.53.0.4 \
+ > dig.out.ns4.test$n || ret=1
+digcomp dig.out.ns3.test$n dig.out.ns4.test$n || ret=1
+grep "status: NXDOMAIN" dig.out.ns4.test$n > /dev/null || ret=1
+grep "0 IN SOA" dig.out.ns4.test$n > /dev/null || ret=1
+# Note - this is looking for failure, hence the &&
+grep "flags:.*ad.*QUERY" dig.out.ns4.test$n > /dev/null && ret=1
+n=$((n+1))
+test "$ret" -eq 0 || echo_i "failed"
+status=$((status+ret))
+
+echo_i "checking 1-server negative insecurity proof with SOA hack NSEC3 ($n)"
+ret=0
+dig_with_opts r.insecure.nsec3.example. soa @10.53.0.3 \
+ > dig.out.ns3.test$n || ret=1
+dig_with_opts r.insecure.nsec3.example. soa @10.53.0.4 \
+ > dig.out.ns4.test$n || ret=1
+digcomp dig.out.ns3.test$n dig.out.ns4.test$n || ret=1
+grep "status: NXDOMAIN" dig.out.ns4.test$n > /dev/null || ret=1
+grep "0 IN SOA" dig.out.ns4.test$n > /dev/null || ret=1
+# Note - this is looking for failure, hence the &&
+grep "flags:.*ad.*QUERY" dig.out.ns4.test$n > /dev/null && ret=1
+n=$((n+1))
+test "$ret" -eq 0 || echo_i "failed"
+status=$((status+ret))
+
+echo_i "checking 1-server negative insecurity proof with SOA hack OPTOUT ($n)"
+ret=0
+dig_with_opts r.insecure.optout.example. soa @10.53.0.3 \
+ > dig.out.ns3.test$n || ret=1
+dig_with_opts r.insecure.optout.example. soa @10.53.0.4 \
+ > dig.out.ns4.test$n || ret=1
+digcomp dig.out.ns3.test$n dig.out.ns4.test$n || ret=1
+grep "status: NXDOMAIN" dig.out.ns4.test$n > /dev/null || ret=1
+grep "0 IN SOA" dig.out.ns4.test$n > /dev/null || ret=1
+# Note - this is looking for failure, hence the &&
+grep "flags:.*ad.*QUERY" dig.out.ns4.test$n > /dev/null && ret=1
+n=$((n+1))
+test "$ret" -eq 0 || echo_i "failed"
+status=$((status+ret))
+
+# Check the secure.example domain
+
+echo_i "checking multi-stage positive validation NSEC/NSEC ($n)"
+ret=0
+dig_with_opts +noauth a.secure.example. \
+ @10.53.0.3 a > dig.out.ns3.test$n || ret=1
+dig_with_opts +noauth a.secure.example. \
+ @10.53.0.4 a > dig.out.ns4.test$n || ret=1
+digcomp dig.out.ns3.test$n dig.out.ns4.test$n || ret=1
+grep "status: NOERROR" dig.out.ns4.test$n > /dev/null || ret=1
+grep "flags:.*ad.*QUERY" dig.out.ns4.test$n > /dev/null || ret=1
+n=$((n+1))
+test "$ret" -eq 0 || echo_i "failed"
+status=$((status+ret))
+
+echo_i "checking multi-stage positive validation NSEC/NSEC3 ($n)"
+ret=0
+dig_with_opts +noauth a.nsec3.example. \
+ @10.53.0.3 a > dig.out.ns3.test$n || ret=1
+dig_with_opts +noauth a.nsec3.example. \
+ @10.53.0.4 a > dig.out.ns4.test$n || ret=1
+digcomp dig.out.ns3.test$n dig.out.ns4.test$n || ret=1
+grep "status: NOERROR" dig.out.ns4.test$n > /dev/null || ret=1
+grep "flags:.*ad.*QUERY" dig.out.ns4.test$n > /dev/null || ret=1
+n=$((n+1))
+test "$ret" -eq 0 || echo_i "failed"
+status=$((status+ret))
+
+echo_i "checking multi-stage positive validation NSEC/OPTOUT ($n)"
+ret=0
+dig_with_opts +noauth a.optout.example. \
+ @10.53.0.3 a > dig.out.ns3.test$n || ret=1
+dig_with_opts +noauth a.optout.example. \
+ @10.53.0.4 a > dig.out.ns4.test$n || ret=1
+digcomp dig.out.ns3.test$n dig.out.ns4.test$n || ret=1
+grep "status: NOERROR" dig.out.ns4.test$n > /dev/null || ret=1
+grep "flags:.*ad.*QUERY" dig.out.ns4.test$n > /dev/null || ret=1
+n=$((n+1))
+test "$ret" -eq 0 || echo_i "failed"
+status=$((status+ret))
+
+echo_i "checking multi-stage positive validation NSEC3/NSEC ($n)"
+ret=0
+dig_with_opts +noauth a.secure.nsec3.example. \
+ @10.53.0.3 a > dig.out.ns3.test$n || ret=1
+dig_with_opts +noauth a.secure.nsec3.example. \
+ @10.53.0.4 a > dig.out.ns4.test$n || ret=1
+digcomp dig.out.ns3.test$n dig.out.ns4.test$n || ret=1
+grep "status: NOERROR" dig.out.ns4.test$n > /dev/null || ret=1
+grep "flags:.*ad.*QUERY" dig.out.ns4.test$n > /dev/null || ret=1
+n=$((n+1))
+test "$ret" -eq 0 || echo_i "failed"
+status=$((status+ret))
+
+echo_i "checking multi-stage positive validation NSEC3/NSEC3 ($n)"
+ret=0
+dig_with_opts +noauth a.nsec3.nsec3.example. \
+ @10.53.0.3 a > dig.out.ns3.test$n || ret=1
+dig_with_opts +noauth a.nsec3.nsec3.example. \
+ @10.53.0.4 a > dig.out.ns4.test$n || ret=1
+digcomp dig.out.ns3.test$n dig.out.ns4.test$n || ret=1
+grep "status: NOERROR" dig.out.ns4.test$n > /dev/null || ret=1
+grep "flags:.*ad.*QUERY" dig.out.ns4.test$n > /dev/null || ret=1
+n=$((n+1))
+test "$ret" -eq 0 || echo_i "failed"
+status=$((status+ret))
+
+echo_i "checking multi-stage positive validation NSEC3/OPTOUT ($n)"
+ret=0
+dig_with_opts +noauth a.optout.nsec3.example. \
+ @10.53.0.3 a > dig.out.ns3.test$n || ret=1
+dig_with_opts +noauth a.optout.nsec3.example. \
+ @10.53.0.4 a > dig.out.ns4.test$n || ret=1
+digcomp dig.out.ns3.test$n dig.out.ns4.test$n || ret=1
+grep "status: NOERROR" dig.out.ns4.test$n > /dev/null || ret=1
+grep "flags:.*ad.*QUERY" dig.out.ns4.test$n > /dev/null || ret=1
+n=$((n+1))
+test "$ret" -eq 0 || echo_i "failed"
+status=$((status+ret))
+
+echo_i "checking multi-stage positive validation OPTOUT/NSEC ($n)"
+ret=0
+dig_with_opts +noauth a.secure.optout.example. \
+ @10.53.0.3 a > dig.out.ns3.test$n || ret=1
+dig_with_opts +noauth a.secure.optout.example. \
+ @10.53.0.4 a > dig.out.ns4.test$n || ret=1
+digcomp dig.out.ns3.test$n dig.out.ns4.test$n || ret=1
+grep "status: NOERROR" dig.out.ns4.test$n > /dev/null || ret=1
+grep "flags:.*ad.*QUERY" dig.out.ns4.test$n > /dev/null || ret=1
+n=$((n+1))
+test "$ret" -eq 0 || echo_i "failed"
+status=$((status+ret))
+
+echo_i "checking multi-stage positive validation OPTOUT/NSEC3 ($n)"
+ret=0
+dig_with_opts +noauth a.nsec3.optout.example. \
+ @10.53.0.3 a > dig.out.ns3.test$n || ret=1
+dig_with_opts +noauth a.nsec3.optout.example. \
+ @10.53.0.4 a > dig.out.ns4.test$n || ret=1
+digcomp dig.out.ns3.test$n dig.out.ns4.test$n || ret=1
+grep "status: NOERROR" dig.out.ns4.test$n > /dev/null || ret=1
+grep "flags:.*ad.*QUERY" dig.out.ns4.test$n > /dev/null || ret=1
+n=$((n+1))
+test "$ret" -eq 0 || echo_i "failed"
+status=$((status+ret))
+
+echo_i "checking multi-stage positive validation OPTOUT/OPTOUT ($n)"
+ret=0
+dig_with_opts +noauth a.optout.optout.example. \
+ @10.53.0.3 a > dig.out.ns3.test$n || ret=1
+dig_with_opts +noauth a.optout.optout.example. \
+ @10.53.0.4 a > dig.out.ns4.test$n || ret=1
+digcomp dig.out.ns3.test$n dig.out.ns4.test$n || ret=1
+grep "status: NOERROR" dig.out.ns4.test$n > /dev/null || ret=1
+grep "flags:.*ad.*QUERY" dig.out.ns4.test$n > /dev/null || ret=1
+n=$((n+1))
+test "$ret" -eq 0 || echo_i "failed"
+status=$((status+ret))
+
+echo_i "checking empty NODATA OPTOUT ($n)"
+ret=0
+dig_with_opts +noauth empty.optout.example. \
+ @10.53.0.3 a > dig.out.ns3.test$n || ret=1
+dig_with_opts +noauth empty.optout.example. \
+ @10.53.0.4 a > dig.out.ns4.test$n || ret=1
+digcomp dig.out.ns3.test$n dig.out.ns4.test$n || ret=1
+grep "status: NOERROR" dig.out.ns4.test$n > /dev/null || ret=1
+#grep "flags:.*ad.*QUERY" dig.out.ns4.test$n > /dev/null || ret=1
+n=$((n+1))
+test "$ret" -eq 0 || echo_i "failed"
+status=$((status+ret))
+
+# Check the bogus domain
+
+echo_i "checking failed validation ($n)"
+ret=0
+dig_with_opts a.bogus.example. @10.53.0.4 a > dig.out.ns4.test$n || ret=1
+grep "SERVFAIL" dig.out.ns4.test$n > /dev/null || ret=1
+n=$((n+1))
+test "$ret" -eq 0 || echo_i "failed"
+status=$((status+ret))
+
+if [ -x "${DELV}" ] ; then
+ ret=0
+ echo_i "checking failed validation using dns_client ($n)"
+ delv_with_opts +cd @10.53.0.4 a a.bogus.example > delv.out$n 2>&1 || ret=1
+ grep "resolution failed: RRSIG failed to verify" delv.out$n > /dev/null || ret=1
+ n=$((n+1))
+ test "$ret" -eq 0 || echo_i "failed"
+ status=$((status+ret))
+fi
+
+# Try validating with a bad trusted key.
+# This should fail.
+
+echo_i "checking that validation fails with a misconfigured trusted key ($n)"
+ret=0
+dig_with_opts example. soa @10.53.0.5 > dig.out.ns5.test$n || ret=1
+grep "SERVFAIL" dig.out.ns5.test$n > /dev/null || ret=1
+n=$((n+1))
+test "$ret" -eq 0 || echo_i "failed"
+status=$((status+ret))
+
+echo_i "checking that negative validation fails with a misconfigured trusted key ($n)"
+ret=0
+dig_with_opts example. ptr @10.53.0.5 > dig.out.ns5.test$n || ret=1
+grep "SERVFAIL" dig.out.ns5.test$n > /dev/null || ret=1
+n=$((n+1))
+test "$ret" -eq 0 || echo_i "failed"
+status=$((status+ret))
+
+echo_i "checking that insecurity proofs fail with a misconfigured trusted key ($n)"
+ret=0
+dig_with_opts a.insecure.example. a @10.53.0.5 > dig.out.ns5.test$n || ret=1
+grep "SERVFAIL" dig.out.ns5.test$n > /dev/null || ret=1
+n=$((n+1))
+test "$ret" -eq 0 || echo_i "failed"
+status=$((status+ret))
+
+echo_i "checking that validation fails when key record is missing ($n)"
+ret=0
+dig_with_opts a.b.keyless.example. a @10.53.0.4 > dig.out.ns4.test$n || ret=1
+grep "SERVFAIL" dig.out.ns4.test$n > /dev/null || ret=1
+n=$((n+1))
+test "$ret" -eq 0 || echo_i "failed"
+status=$((status+ret))
+
+if [ -x "${DELV}" ] ; then
+ ret=0
+ echo_i "checking that validation fails when key record is missing using dns_client ($n)"
+ delv_with_opts +cd @10.53.0.4 a a.b.keyless.example > delv.out$n 2>&1 || ret=1
+ grep "resolution failed: insecurity proof failed" delv.out$n > /dev/null || ret=1
+ n=$((n+1))
+ test "$ret" -eq 0 || echo_i "failed"
+ status=$((status+ret))
+fi
+
+echo_i "checking that validation succeeds when a revoked key is encountered ($n)"
+ret=0
+dig_with_opts revkey.example soa @10.53.0.4 > dig.out.ns4.test$n || ret=1
+grep "NOERROR" dig.out.ns4.test$n > /dev/null || ret=1
+grep "flags: .* ad" dig.out.ns4.test$n > /dev/null || ret=1
+n=$((n+1))
+test "$ret" -eq 0 || echo_i "failed"
+status=$((status+ret))
+
+if [ -x "${DELV}" ] ; then
+ ret=0
+ echo_i "checking that validation succeeds when a revoked key is encountered using dns_client ($n)"
+ delv_with_opts +cd @10.53.0.4 soa revkey.example > delv.out$n 2>&1 || ret=1
+ grep "fully validated" delv.out$n > /dev/null || ret=1
+ n=$((n+1))
+ test "$ret" -eq 0 || echo_i "failed"
+ status=$((status+ret))
+fi
+
+echo_i "Checking that a bad CNAME signature is caught after a +CD query ($n)"
+ret=0
+#prime
+dig_with_opts +cd bad-cname.example. @10.53.0.4 > dig.out.ns4.prime$n || ret=1
+#check: requery with +CD. pending data should be returned even if it's bogus
+expect="a.example.
+10.0.0.1"
+ans=$(dig_with_opts +cd +nodnssec +short bad-cname.example. @10.53.0.4) || ret=1
+test "$ans" = "$expect" || ret=1
+test "$ret" -eq 0 || echo_i "failed, got '$ans', expected '$expect'"
+#check: requery without +CD. bogus cached data should be rejected.
+dig_with_opts +nodnssec bad-cname.example. @10.53.0.4 > dig.out.ns4.test$n || ret=1
+grep "SERVFAIL" dig.out.ns4.test$n > /dev/null || ret=1
+n=$((n+1))
+test "$ret" -eq 0 || echo_i "failed"
+status=$((status+ret))
+
+echo_i "Checking that a bad DNAME signature is caught after a +CD query ($n)"
+ret=0
+#prime
+dig_with_opts +cd a.bad-dname.example. @10.53.0.4 > dig.out.ns4.prime$n || ret=1
+#check: requery with +CD. pending data should be returned even if it's bogus
+expect="example.
+a.example.
+10.0.0.1"
+ans=$(dig_with_opts +cd +nodnssec +short a.bad-dname.example. @10.53.0.4) || ret=1
+test "$ans" = "$expect" || ret=1
+test "$ret" -eq 0 || echo_i "failed, got '$ans', expected '$expect'"
+#check: requery without +CD. bogus cached data should be rejected.
+dig_with_opts +nodnssec a.bad-dname.example. @10.53.0.4 > dig.out.ns4.test$n || ret=1
+grep "SERVFAIL" dig.out.ns4.test$n > /dev/null || ret=1
+n=$((n+1))
+test "$ret" -eq 0 || echo_i "failed"
+status=$((status+ret))
+
+# Check the insecure.secure.example domain (insecurity proof)
+
+echo_i "checking 2-server insecurity proof ($n)"
+ret=0
+dig_with_opts +noauth a.insecure.secure.example. @10.53.0.2 a \
+ > dig.out.ns2.test$n || ret=1
+dig_with_opts +noauth a.insecure.secure.example. @10.53.0.4 a \
+ > dig.out.ns4.test$n || ret=1
+digcomp dig.out.ns2.test$n dig.out.ns4.test$n || ret=1
+grep "status: NOERROR" dig.out.ns4.test$n > /dev/null || ret=1
+# Note - this is looking for failure, hence the &&
+grep "flags:.*ad.*QUERY" dig.out.ns4.test$n > /dev/null && ret=1
+n=$((n+1))
+test "$ret" -eq 0 || echo_i "failed"
+status=$((status+ret))
+
+# Check a negative response in insecure.secure.example
+
+echo_i "checking 2-server insecurity proof with a negative answer ($n)"
+ret=0
+dig_with_opts q.insecure.secure.example. @10.53.0.2 a > dig.out.ns2.test$n \
+ || ret=1
+dig_with_opts q.insecure.secure.example. @10.53.0.4 a > dig.out.ns4.test$n \
+ || ret=1
+digcomp dig.out.ns2.test$n dig.out.ns4.test$n || ret=1
+grep "status: NXDOMAIN" dig.out.ns4.test$n > /dev/null || ret=1
+# Note - this is looking for failure, hence the &&
+grep "flags:.*ad.*QUERY" dig.out.ns4.test$n > /dev/null && ret=1
+n=$((n+1))
+test "$ret" -eq 0 || echo_i "failed"
+status=$((status+ret))
+
+echo_i "checking 2-server insecurity proof with a negative answer and SOA hack ($n)"
+ret=0
+dig_with_opts r.insecure.secure.example. @10.53.0.2 soa > dig.out.ns2.test$n \
+ || ret=1
+dig_with_opts r.insecure.secure.example. @10.53.0.4 soa > dig.out.ns4.test$n \
+ || ret=1
+digcomp dig.out.ns2.test$n dig.out.ns4.test$n || ret=1
+grep "status: NXDOMAIN" dig.out.ns4.test$n > /dev/null || ret=1
+# Note - this is looking for failure, hence the &&
+grep "flags:.*ad.*QUERY" dig.out.ns4.test$n > /dev/null && ret=1
+n=$((n+1))
+test "$ret" -eq 0 || echo_i "failed"
+status=$((status+ret))
+
+# Check that the query for a security root is successful and has ad set
+
+echo_i "checking security root query ($n)"
+ret=0
+dig_with_opts . @10.53.0.4 key > dig.out.ns4.test$n || ret=1
+grep "NOERROR" dig.out.ns4.test$n > /dev/null || ret=1
+grep "flags:.*ad.*QUERY" dig.out.ns4.test$n > /dev/null || ret=1
+n=$((n+1))
+test "$ret" -eq 0 || echo_i "failed"
+status=$((status+ret))
+
+# Check that the setting the cd bit works
+
+echo_i "checking cd bit on a positive answer ($n)"
+ret=0
+dig_with_opts +noauth example. soa @10.53.0.4 \
+ > dig.out.ns4.test$n || ret=1
+dig_with_opts +noauth +cdflag example. soa @10.53.0.5 \
+ > dig.out.ns5.test$n || ret=1
+digcomp dig.out.ns4.test$n dig.out.ns5.test$n || ret=1
+grep "flags:.*ad.*QUERY" dig.out.ns4.test$n > /dev/null || ret=1
+# Note - this is looking for failure, hence the &&
+grep "flags:.*ad.*QUERY" dig.out.ns5.test$n > /dev/null && ret=1
+n=$((n+1))
+test "$ret" -eq 0 || echo_i "failed"
+status=$((status+ret))
+
+echo_i "checking cd bit on a negative answer ($n)"
+ret=0
+dig_with_opts q.example. soa @10.53.0.4 > dig.out.ns4.test$n || ret=1
+dig_with_opts +cdflag q.example. soa @10.53.0.5 > dig.out.ns5.test$n || ret=1
+digcomp dig.out.ns4.test$n dig.out.ns5.test$n || ret=1
+grep "flags:.*ad.*QUERY" dig.out.ns4.test$n > /dev/null || ret=1
+# Note - this is looking for failure, hence the &&
+grep "flags:.*ad.*QUERY" dig.out.ns5.test$n > /dev/null && ret=1
+n=$((n+1))
+test "$ret" -eq 0 || echo_i "failed"
+status=$((status+ret))
+
+echo_i "checking insecurity proof works using negative cache ($n)"
+ret=0
+rndccmd 10.53.0.4 flush 2>&1 | sed 's/^/ns4 /' | cat_i
+dig_with_opts +cd @10.53.0.4 insecure.example. ds > dig.out.ns4.test$n.1 || ret=1
+for i in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
+do
+ dig_with_opts @10.53.0.4 nonexistent.insecure.example. > dig.out.ns4.test$n.2 || ret=1
+ if grep "status: NXDOMAIN" dig.out.ns4.test$n.2 >/dev/null; then
+ break
+ fi
+ sleep 1
+done
+grep "status: NXDOMAIN" dig.out.ns4.test$n.2 >/dev/null || ret=1
+n=$((n+1))
+test "$ret" -eq 0 || echo_i "failed"
+status=$((status+ret))
+
+echo_i "checking positive validation RSASHA256 NSEC ($n)"
+ret=0
+dig_with_opts +noauth a.rsasha256.example. @10.53.0.3 a > dig.out.ns3.test$n || ret=1
+dig_with_opts +noauth a.rsasha256.example. @10.53.0.4 a > dig.out.ns4.test$n || ret=1
+digcomp dig.out.ns3.test$n dig.out.ns4.test$n || ret=1
+grep "flags:.*ad.*QUERY" dig.out.ns4.test$n > /dev/null || ret=1
+n=$((n+1))
+test "$ret" -eq 0 || echo_i "failed"
+status=$((status+ret))
+
+echo_i "checking positive validation RSASHA512 NSEC ($n)"
+ret=0
+dig_with_opts +noauth a.rsasha512.example. @10.53.0.3 a > dig.out.ns3.test$n || ret=1
+dig_with_opts +noauth a.rsasha512.example. @10.53.0.4 a > dig.out.ns4.test$n || ret=1
+digcomp dig.out.ns3.test$n dig.out.ns4.test$n || ret=1
+grep "flags:.*ad.*QUERY" dig.out.ns4.test$n > /dev/null || ret=1
+n=$((n+1))
+test "$ret" -eq 0 || echo_i "failed"
+status=$((status+ret))
+
+echo_i "checking positive validation with KSK-only DNSKEY signature ($n)"
+ret=0
+dig_with_opts +noauth a.kskonly.example. @10.53.0.3 a > dig.out.ns3.test$n || ret=1
+dig_with_opts +noauth a.kskonly.example. @10.53.0.4 a > dig.out.ns4.test$n || ret=1
+digcomp dig.out.ns3.test$n dig.out.ns4.test$n || ret=1
+grep "flags:.*ad.*QUERY" dig.out.ns4.test$n > /dev/null || ret=1
+n=$((n+1))
+test "$ret" -eq 0 || echo_i "failed"
+status=$((status+ret))
+
+echo_i "checking cd bit on a query that should fail ($n)"
+ret=0
+dig_with_opts a.bogus.example. soa @10.53.0.4 \
+ > dig.out.ns4.test$n || ret=1
+dig_with_opts +cdflag a.bogus.example. soa @10.53.0.5 \
+ > dig.out.ns5.test$n || ret=1
+digcomp dig.out.ns4.test$n dig.out.ns5.test$n || ret=1
+grep "flags:.*ad.*QUERY" dig.out.ns4.test$n > /dev/null || ret=1
+# Note - this is looking for failure, hence the &&
+grep "flags:.*ad.*QUERY" dig.out.ns5.test$n > /dev/null && ret=1
+n=$((n+1))
+test "$ret" -eq 0 || echo_i "failed"
+status=$((status+ret))
+
+echo_i "checking cd bit on an insecurity proof ($n)"
+ret=0
+dig_with_opts +noauth a.insecure.example. soa @10.53.0.4 \
+ > dig.out.ns4.test$n || ret=1
+dig_with_opts +noauth +cdflag a.insecure.example. soa @10.53.0.5 \
+ > dig.out.ns5.test$n || ret=1
+digcomp dig.out.ns4.test$n dig.out.ns5.test$n || ret=1
+grep "status: NOERROR" dig.out.ns4.test$n > /dev/null || ret=1
+# Note - these are looking for failure, hence the &&
+grep "flags:.*ad.*QUERY" dig.out.ns4.test$n > /dev/null && ret=1
+grep "flags:.*ad.*QUERY" dig.out.ns5.test$n > /dev/null && ret=1
+n=$((n+1))
+test "$ret" -eq 0 || echo_i "failed"
+status=$((status+ret))
+
+echo_i "checking cd bit on a negative insecurity proof ($n)"
+ret=0
+dig_with_opts q.insecure.example. a @10.53.0.4 \
+ > dig.out.ns4.test$n || ret=1
+dig_with_opts +cdflag q.insecure.example. a @10.53.0.5 \
+ > dig.out.ns5.test$n || ret=1
+digcomp dig.out.ns4.test$n dig.out.ns5.test$n || ret=1
+grep "status: NXDOMAIN" dig.out.ns4.test$n > /dev/null || ret=1
+# Note - these are looking for failure, hence the &&
+grep "flags:.*ad.*QUERY" dig.out.ns4.test$n > /dev/null && ret=1
+grep "flags:.*ad.*QUERY" dig.out.ns5.test$n > /dev/null && ret=1
+n=$((n+1))
+test "$ret" -eq 0 || echo_i "failed"
+status=$((status+ret))
+
+echo_i "checking that validation of an ANY query works ($n)"
+ret=0
+dig_with_opts +noauth foo.example. any @10.53.0.2 > dig.out.ns2.test$n || ret=1
+dig_with_opts +noauth foo.example. any @10.53.0.4 > dig.out.ns4.test$n || ret=1
+digcomp dig.out.ns2.test$n dig.out.ns4.test$n || ret=1
+grep "NOERROR" dig.out.ns4.test$n > /dev/null || ret=1
+# 2 records in the zone, 1 NXT, 3 SIGs
+grep "ANSWER: 6" dig.out.ns4.test$n > /dev/null || ret=1
+n=$((n+1))
+test "$ret" -eq 0 || echo_i "failed"
+status=$((status+ret))
+
+echo_i "checking that validation of a query returning a CNAME works ($n)"
+ret=0
+dig_with_opts +noauth cname1.example. txt @10.53.0.2 \
+ > dig.out.ns2.test$n || ret=1
+dig_with_opts +noauth cname1.example. txt @10.53.0.4 \
+ > dig.out.ns4.test$n || ret=1
+digcomp dig.out.ns2.test$n dig.out.ns4.test$n || ret=1
+grep "NOERROR" dig.out.ns4.test$n > /dev/null || ret=1
+# the CNAME & its sig, the TXT and its SIG
+grep "ANSWER: 4" dig.out.ns4.test$n > /dev/null || ret=1
+n=$((n+1))
+test "$ret" -eq 0 || echo_i "failed"
+status=$((status+ret))
+
+echo_i "checking that validation of a query returning a DNAME works ($n)"
+ret=0
+dig_with_opts +noauth foo.dname1.example. txt @10.53.0.2 \
+ > dig.out.ns2.test$n || ret=1
+dig_with_opts +noauth foo.dname1.example. txt @10.53.0.4 \
+ > dig.out.ns4.test$n || ret=1
+digcomp dig.out.ns2.test$n dig.out.ns4.test$n || ret=1
+grep "NOERROR" dig.out.ns4.test$n > /dev/null || ret=1
+# The DNAME & its sig, the TXT and its SIG, and the synthesized CNAME.
+# It would be nice to test that the CNAME is being synthesized by the
+# recursive server and not cached, but I don't know how.
+grep "ANSWER: 5" dig.out.ns4.test$n > /dev/null || ret=1
+n=$((n+1))
+test "$ret" -eq 0 || echo_i "failed"
+status=$((status+ret))
+
+echo_i "checking that validation of an ANY query returning a CNAME works ($n)"
+ret=0
+dig_with_opts +noauth cname2.example. any @10.53.0.2 \
+ > dig.out.ns2.test$n || ret=1
+dig_with_opts +noauth cname2.example. any @10.53.0.4 \
+ > dig.out.ns4.test$n || ret=1
+digcomp dig.out.ns2.test$n dig.out.ns4.test$n || ret=1
+grep "NOERROR" dig.out.ns4.test$n > /dev/null || ret=1
+# The CNAME, NXT, and their SIGs
+grep "ANSWER: 4" dig.out.ns4.test$n > /dev/null || ret=1
+n=$((n+1))
+test "$ret" -eq 0 || echo_i "failed"
+status=$((status+ret))
+
+echo_i "checking that validation of an ANY query returning a DNAME works ($n)"
+ret=0
+dig_with_opts +noauth foo.dname2.example. any @10.53.0.2 \
+ > dig.out.ns2.test$n || ret=1
+dig_with_opts +noauth foo.dname2.example. any @10.53.0.4 \
+ > dig.out.ns4.test$n || ret=1
+digcomp dig.out.ns2.test$n dig.out.ns4.test$n || ret=1
+grep "NOERROR" dig.out.ns4.test$n > /dev/null || ret=1
+n=$((n+1))
+test "$ret" -eq 0 || echo_i "failed"
+status=$((status+ret))
+
+echo_i "checking that lookups succeed after disabling an algorithm ($n)"
+ret=0
+dig_with_opts +noauth example. SOA @10.53.0.2 \
+ > dig.out.ns2.test$n || ret=1
+dig_with_opts +noauth example. SOA @10.53.0.6 \
+ > dig.out.ns6.test$n || ret=1
+digcomp dig.out.ns2.test$n dig.out.ns6.test$n || ret=1
+# Note - this is looking for failure, hence the &&
+grep "flags:.*ad.*QUERY" dig.out.ns6.test$n > /dev/null && ret=1
+n=$((n+1))
+test "$ret" -eq 0 || echo_i "failed"
+status=$((status+ret))
+
+echo_i "checking a non-cachable NODATA works ($n)"
+ret=0
+dig_with_opts +noauth a.nosoa.secure.example. txt @10.53.0.7 \
+ > dig.out.ns7.test$n || ret=1
+grep "AUTHORITY: 0" dig.out.ns7.test$n > /dev/null || ret=1
+dig_with_opts +noauth a.nosoa.secure.example. txt @10.53.0.4 \
+ > dig.out.ns4.test$n || ret=1
+grep "status: NOERROR" dig.out.ns4.test$n > /dev/null || ret=1
+n=$((n+1))
+test "$ret" -eq 0 || echo_i "failed"
+status=$((status+ret))
+
+echo_i "checking a non-cachable NXDOMAIN works ($n)"
+ret=0
+dig_with_opts +noauth b.nosoa.secure.example. txt @10.53.0.7 \
+ > dig.out.ns7.test$n || ret=1
+grep "AUTHORITY: 0" dig.out.ns7.test$n > /dev/null || ret=1
+dig_with_opts +noauth b.nosoa.secure.example. txt @10.53.0.4 \
+ > dig.out.ns4.test$n || ret=1
+grep "status: NXDOMAIN" dig.out.ns4.test$n > /dev/null || ret=1
+n=$((n+1))
+test "$ret" -eq 0 || echo_i "failed"
+status=$((status+ret))
+
+echo_i "checking that we can load a rfc2535 signed zone ($n)"
+ret=0
+dig_with_opts rfc2535.example. SOA @10.53.0.2 \
+ > dig.out.ns2.test$n || ret=1
+grep "status: NOERROR" dig.out.ns2.test$n > /dev/null || ret=1
+n=$((n+1))
+test "$ret" -eq 0 || echo_i "failed"
+status=$((status+ret))
+
+echo_i "checking that we can transfer a rfc2535 signed zone ($n)"
+ret=0
+dig_with_opts rfc2535.example. SOA @10.53.0.3 \
+ > dig.out.ns3.test$n || ret=1
+grep "status: NOERROR" dig.out.ns3.test$n > /dev/null || ret=1
+n=$((n+1))
+test "$ret" -eq 0 || echo_i "failed"
+status=$((status+ret))
+
+echo_i "basic dnssec-signzone checks:"
+echo_ic "two DNSKEYs ($n)"
+ret=0
+(
+cd signer/general || exit 1
+rm -f signed.zone
+$SIGNER -f signed.zone -o example.com. test1.zone > signer.out.$n
+test -f signed.zone
+) || ret=1
+n=$((n+1))
+test "$ret" -eq 0 || echo_i "failed"
+status=$((status+ret))
+
+echo_ic "one non-KSK DNSKEY ($n)"
+ret=0
+(
+cd signer/general || exit 0
+rm -f signed.zone
+$SIGNER -f signed.zone -o example.com. test2.zone > signer.out.$n
+test -f signed.zone
+) && ret=1
+n=$((n+1))
+test "$ret" -eq 0 || echo_i "failed"
+status=$((status+ret))
+
+echo_ic "one KSK DNSKEY ($n)"
+ret=0
+(
+cd signer/general || exit 0
+rm -f signed.zone
+$SIGNER -f signed.zone -o example.com. test3.zone > signer.out.$n
+test -f signed.zone
+) && ret=1
+n=$((n+1))
+test "$ret" -eq 0 || echo_i "failed"
+status=$((status+ret))
+
+echo_ic "three DNSKEY ($n)"
+ret=0
+(
+cd signer/general || exit 1
+rm -f signed.zone
+$SIGNER -f signed.zone -o example.com. test4.zone > signer.out.$n
+test -f signed.zone
+) || ret=1
+n=$((n+1))
+test "$ret" -eq 0 || echo_i "failed"
+status=$((status+ret))
+
+echo_ic "three DNSKEY, one private key missing ($n)"
+ret=0
+(
+cd signer/general || exit 1
+rm -f signed.zone
+$SIGNER -f signed.zone -o example.com. test5.zone > signer.out.$n
+test -f signed.zone
+) || ret=1
+n=$((n+1))
+test "$ret" -eq 0 || echo_i "failed"
+status=$((status+ret))
+
+echo_ic "four DNSKEY ($n)"
+ret=0
+(
+cd signer/general || exit 1
+rm -f signed.zone
+$SIGNER -f signed.zone -o example.com. test6.zone > signer.out.$n
+test -f signed.zone
+) || ret=1
+n=$((n+1))
+test "$ret" -eq 0 || echo_i "failed"
+status=$((status+ret))
+
+echo_ic "two DNSKEY, both private keys missing ($n)"
+ret=0
+(
+cd signer/general || exit 0
+rm -f signed.zone
+$SIGNER -f signed.zone -o example.com. test7.zone > signer.out.$n
+test -f signed.zone
+) && ret=1
+n=$((n+1))
+test "$ret" -eq 0 || echo_i "failed"
+status=$((status+ret))
+
+echo_ic "two DNSKEY, one private key missing ($n)"
+ret=0
+(
+cd signer/general || exit 0
+rm -f signed.zone
+$SIGNER -f signed.zone -o example.com. test8.zone > signer.out.$n
+test -f signed.zone
+) && ret=1
+n=$((n+1))
+test "$ret" -eq 0 || echo_i "failed"
+status=$((status+ret))
+
+echo_ic "check that dnssec-signzone rejects excessive NSEC3 iterations ($n)"
+ret=0
+(
+cd signer/general || exit 0
+rm -f signed.zone
+$SIGNER -f signed.zone -3 - -H 151 -o example.com. test9.zone > signer.out.$n
+test -f signed.zone
+) && ret=1
+n=$((n+1))
+test "$ret" -eq 0 || echo_i "failed"
+status=$((status+ret))
+
+echo_ic "check that dnssec-signzone accepts maximum NSEC3 iterations ($n)"
+ret=0
+(
+cd signer/general || exit 1
+rm -f signed.zone
+$SIGNER -f signed.zone -3 - -H 150 -o example.com. test9.zone > signer.out.$n
+test -f signed.zone
+) || ret=1
+n=$((n+1))
+test "$ret" -eq 0 || echo_i "failed"
+status=$((status+ret))
+
+get_default_algorithm_key_ids_from_sigs() {
+ zone=$1
+
+ awk -v alg=$DEFAULT_ALGORITHM_NUMBER '
+ NF < 8 { next }
+ $(NF-5) != "RRSIG" { next }
+ $(NF-3) != alg { next }
+ $NF != "(" { next }
+ {
+ getline;
+ print $3;
+ }
+ ' signer/$zone.db.signed | sort -u
+}
+
+# Test dnssec-signzone ZSK prepublish smooth rollover.
+echo_i "check dnssec-signzone doesn't sign with prepublished zsk ($n)"
+ret=0
+zone=prepub
+# Generate keys.
+ksk=$("$KEYGEN" -K signer -f KSK -q -a $DEFAULT_ALGORITHM -n zone "$zone")
+zsk1=$("$KEYGEN" -K signer -q -a $DEFAULT_ALGORITHM -n zone "$zone")
+zsk2=$("$KEYGEN" -K signer -q -a $DEFAULT_ALGORITHM -n zone "$zone")
+zskid1=$(keyfile_to_key_id "$zsk1")
+zskid2=$(keyfile_to_key_id "$zsk2")
+(
+cd signer || exit 1
+# Set times such that the current set of keys are introduced 60 days ago and
+# start signing now. The successor key is prepublished now and will be active
+# next day.
+$SETTIME -P now-60d -A now $ksk > /dev/null
+$SETTIME -P now-60d -A now -I now+1d -D now+60d $zsk1 > /dev/null
+$SETTIME -S $zsk1 -i 1h $zsk2.key > /dev/null
+$SETTIME -P now -A now+1d $zsk2.key > /dev/null
+# Sign the zone with initial keys and prepublish successor. The zone signatures
+# are valid for 30 days and the DNSKEY signature is valid for 60 days.
+cp -f $zone.db.in $zone.db
+$SIGNER -SDx -e +2592000 -X +5184000 -o $zone $zone.db > /dev/null
+echo "\$INCLUDE \"$zone.db.signed\"" >> $zone.db
+)
+get_default_algorithm_key_ids_from_sigs $zone | grep "^$zskid1$" > /dev/null || ret=1
+get_default_algorithm_key_ids_from_sigs $zone | grep "^$zskid2$" > /dev/null && ret=1
+n=$((n+1))
+test "$ret" -eq 0 || echo_i "failed: missing signatures from key $zskid1"
+status=$((status+ret))
+
+echo_i "check dnssec-signzone retains signatures of predecessor zsk ($n)"
+ret=0
+zone=prepub
+(
+cd signer || exit 1
+# Roll the ZSK. The predecessor is inactive from now on and the successor is
+# activated. The zone signatures are valid for 30 days and the DNSKEY
+# signature is valid for 60 days. Because of the predecessor/successor
+# relationship, the signatures of the predecessor are retained and no new
+# signatures with the successor should be generated.
+$SETTIME -A now-30d -I now -D now+30d $zsk1 > /dev/null
+$SETTIME -A now $zsk2 > /dev/null
+$SIGNER -SDx -e +2592000 -X +5184000 -o $zone $zone.db > /dev/null
+)
+get_default_algorithm_key_ids_from_sigs $zone | grep "^$zskid1$" > /dev/null || ret=1
+get_default_algorithm_key_ids_from_sigs $zone | grep "^$zskid2$" > /dev/null && ret=1
+n=$((n+1))
+test "$ret" -eq 0 || echo_i "failed"
+status=$((status+ret))
+
+echo_i "check dnssec-signzone swaps zone signatures after interval ($n)"
+ret=0
+zone=prepub
+(
+cd signer || exit 1
+# After some time the signatures should be replaced. When signing, set the
+# interval to 30 days plus one second, meaning all predecessor signatures
+# are within the refresh interval and should be replaced with successor
+# signatures.
+$SETTIME -A now-50d -I now-20d -D now+10d $zsk1 > /dev/null
+$SETTIME -A now-20d $zsk2 > /dev/null
+$SIGNER -SDx -e +2592000 -X +5184000 -i 2592001 -o $zone $zone.db > /dev/null
+)
+get_default_algorithm_key_ids_from_sigs $zone | grep "^$zskid1$" > /dev/null && ret=1
+get_default_algorithm_key_ids_from_sigs $zone | grep "^$zskid2$" > /dev/null || ret=1
+n=$((n+1))
+test "$ret" -eq 0 || echo_i "failed"
+status=$((status+ret))
+
+echo_i "checking that a key using an unsupported algorithm cannot be generated ($n)"
+ret=0
+zone=example
+# If dnssec-keygen fails, the test script will exit immediately. Prevent that
+# from happening, and also trigger a test failure if dnssec-keygen unexpectedly
+# succeeds, by using "&& ret=1".
+$KEYGEN -a 255 $zone > dnssectools.out.test$n 2>&1 && ret=1
+grep -q "unsupported algorithm: 255" dnssectools.out.test$n || ret=1
+n=$((n+1))
+test "$ret" -eq 0 || echo_i "failed"
+status=$((status+ret))
+
+echo_i "checking that a DS record cannot be generated for a key using an unsupported algorithm ($n)"
+ret=0
+zone=example
+# Fake an unsupported algorithm key
+unsupportedkey=$("$KEYGEN" -q -a "$DEFAULT_ALGORITHM" -b "$DEFAULT_BITS" -n zone "$zone")
+awk '$3 == "DNSKEY" { $6 = 255 } { print }' ${unsupportedkey}.key > ${unsupportedkey}.tmp
+mv ${unsupportedkey}.tmp ${unsupportedkey}.key
+# If dnssec-dsfromkey fails, the test script will exit immediately. Prevent
+# that from happening, and also trigger a test failure if dnssec-dsfromkey
+# unexpectedly succeeds, by using "&& ret=1".
+$DSFROMKEY ${unsupportedkey} > dnssectools.out.test$n 2>&1 && ret=1
+grep -q "algorithm is unsupported" dnssectools.out.test$n || ret=1
+n=$((n+1))
+test "$ret" -eq 0 || echo_i "failed"
+status=$((status+ret))
+
+echo_i "checking that a zone cannot be signed with a key using an unsupported algorithm ($n)"
+ret=0
+ret=0
+cat signer/example.db.in "${unsupportedkey}.key" > signer/example.db
+# If dnssec-signzone fails, the test script will exit immediately. Prevent that
+# from happening, and also trigger a test failure if dnssec-signzone
+# unexpectedly succeeds, by using "&& ret=1".
+$SIGNER -o example signer/example.db ${unsupportedkey} > dnssectools.out.test$n 2>&1 && ret=1
+grep -q "algorithm is unsupported" dnssectools.out.test$n || ret=1
+n=$((n+1))
+test "$ret" -eq 0 || echo_i "failed"
+status=$((status+ret))
+
+echo_i "checking that we can sign a zone with out-of-zone records ($n)"
+ret=0
+zone=example
+key1=$($KEYGEN -K signer -q -a $DEFAULT_ALGORITHM -n zone $zone)
+key2=$($KEYGEN -K signer -q -f KSK -a $DEFAULT_ALGORITHM -n zone $zone)
+(
+cd signer || exit 1
+cat example.db.in "$key1.key" "$key2.key" > example.db
+$SIGNER -o example -f example.db example.db > /dev/null
+) || ret=1
+n=$((n+1))
+test "$ret" -eq 0 || echo_i "failed"
+status=$((status+ret))
+
+echo_i "checking that we can sign a zone (NSEC3) with out-of-zone records ($n)"
+ret=0
+zone=example
+key1=$($KEYGEN -K signer -q -a $DEFAULT_ALGORITHM -n zone $zone)
+key2=$($KEYGEN -K signer -q -f KSK -a $DEFAULT_ALGORITHM -n zone $zone)
+(
+cd signer || exit 1
+cat example.db.in "$key1.key" "$key2.key" > example.db
+$SIGNER -3 - -H 10 -o example -f example.db example.db > /dev/null
+awk '/^IQF9LQTLK/ {
+ printf("%s", $0);
+ while (!index($0, ")")) {
+ if (getline <= 0)
+ break;
+ printf (" %s", $0);
+ }
+ printf("\n");
+ }' example.db | sed 's/[ ][ ]*/ /g' > nsec3param.out
+
+grep "IQF9LQTLKKNFK0KVIFELRAK4IC4QLTMG.example. 0 IN NSEC3 1 0 10 - ( IQF9LQTLKKNFK0KVIFELRAK4IC4QLTMG A NS SOA RRSIG DNSKEY NSEC3PARAM )" nsec3param.out > /dev/null
+) || ret=1
+n=$((n+1))
+test "$ret" -eq 0 || echo_i "failed"
+status=$((status+ret))
+
+echo_i "checking NSEC3 signing with empty nonterminals above a delegation ($n)"
+ret=0
+zone=example
+key1=$($KEYGEN -K signer -q -a $DEFAULT_ALGORITHM -n zone $zone)
+key2=$($KEYGEN -K signer -q -f KSK -a $DEFAULT_ALGORITHM -n zone $zone)
+(
+cd signer || exit 1
+cat example.db.in "$key1.key" "$key2.key" > example3.db
+echo "some.empty.nonterminal.nodes.example 60 IN NS ns.example.tld" >> example3.db
+$SIGNER -3 - -A -H 10 -o example -f example3.db example3.db > /dev/null
+awk '/^IQF9LQTLK/ {
+ printf("%s", $0);
+ while (!index($0, ")")) {
+ if (getline <= 0)
+ break;
+ printf (" %s", $0);
+ }
+ printf("\n");
+ }' example.db | sed 's/[ ][ ]*/ /g' > nsec3param.out
+
+grep "IQF9LQTLKKNFK0KVIFELRAK4IC4QLTMG.example. 0 IN NSEC3 1 0 10 - ( IQF9LQTLKKNFK0KVIFELRAK4IC4QLTMG A NS SOA RRSIG DNSKEY NSEC3PARAM )" nsec3param.out > /dev/null
+) || ret=1
+n=$((n+1))
+test "$ret" -eq 0 || echo_i "failed"
+status=$((status+ret))
+
+echo_i "checking that dnssec-signzone updates originalttl on ttl changes ($n)"
+ret=0
+zone=example
+key1=$($KEYGEN -K signer -q -a $DEFAULT_ALGORITHM -n zone $zone)
+key2=$($KEYGEN -K signer -q -f KSK -a $DEFAULT_ALGORITHM -n zone $zone)
+(
+cd signer || exit 1
+cat example.db.in "$key1.key" "$key2.key" > example.db
+$SIGNER -o example -f example.db.before example.db > /dev/null
+sed 's/60.IN.SOA./50 IN SOA /' example.db.before > example.db.changed
+$SIGNER -o example -f example.db.after example.db.changed > /dev/null
+)
+grep "SOA $DEFAULT_ALGORITHM_NUMBER 1 50" signer/example.db.after > /dev/null || ret=1
+n=$((n+1))
+test "$ret" -eq 0 || echo_i "failed"
+status=$((status+ret))
+
+echo_i "checking dnssec-signzone keeps valid signatures from removed keys ($n)"
+ret=0
+zone=example
+key1=$($KEYGEN -K signer -q -f KSK -a $DEFAULT_ALGORITHM -n zone $zone)
+key2=$($KEYGEN -K signer -q -a $DEFAULT_ALGORITHM -n zone $zone)
+keyid2=$(keyfile_to_key_id "$key2")
+key3=$($KEYGEN -K signer -q -a $DEFAULT_ALGORITHM -n zone $zone)
+keyid3=$(keyfile_to_key_id "$key3")
+(
+cd signer || exit 1
+cat example.db.in "$key1.key" "$key2.key" > example.db
+$SIGNER -D -o example example.db > /dev/null
+
+# now switch out key2 for key3 and resign the zone
+cat example.db.in "$key1.key" "$key3.key" > example.db
+echo "\$INCLUDE \"example.db.signed\"" >> example.db
+$SIGNER -D -o example example.db > /dev/null
+) || ret=1
+get_default_algorithm_key_ids_from_sigs $zone | grep "^$keyid2$" > /dev/null || ret=1
+get_default_algorithm_key_ids_from_sigs $zone | grep "^$keyid3$" > /dev/null || ret=1
+n=$((n+1))
+test "$ret" -eq 0 || echo_i "failed"
+status=$((status+ret))
+
+echo_i "checking dnssec-signzone -R purges signatures from removed keys ($n)"
+ret=0
+(
+cd signer || exit 1
+$SIGNER -RD -o example example.db > /dev/null
+) || ret=1
+get_default_algorithm_key_ids_from_sigs $zone | grep "^$keyid2$" > /dev/null && ret=1
+get_default_algorithm_key_ids_from_sigs $zone | grep "^$keyid3$" > /dev/null || ret=1
+n=$((n+1))
+test "$ret" -eq 0 || echo_i "failed"
+status=$((status+ret))
+
+echo_i "checking dnssec-signzone keeps valid signatures from inactive keys ($n)"
+ret=0
+zone=example
+(
+cd signer || exit 1
+cp -f example.db.in example.db
+$SIGNER -SD -o example example.db > /dev/null
+echo "\$INCLUDE \"example.db.signed\"" >> example.db
+# now retire key2 and resign the zone
+$SETTIME -I now "$key2" > /dev/null 2>&1
+$SIGNER -SD -o example example.db > /dev/null
+) || ret=1
+get_default_algorithm_key_ids_from_sigs $zone | grep "^$keyid2$" > /dev/null || ret=1
+get_default_algorithm_key_ids_from_sigs $zone | grep "^$keyid3$" > /dev/null || ret=1
+n=$((n+1))
+test "$ret" -eq 0 || echo_i "failed"
+status=$((status+ret))
+
+echo_i "checking dnssec-signzone -Q purges signatures from inactive keys ($n)"
+ret=0
+(
+cd signer || exit 1
+$SIGNER -SDQ -o example example.db > /dev/null
+) || ret=1
+get_default_algorithm_key_ids_from_sigs $zone | grep "^$keyid2$" > /dev/null && ret=1
+get_default_algorithm_key_ids_from_sigs $zone | grep "^$keyid3$" > /dev/null || ret=1
+n=$((n+1))
+test "$ret" -eq 0 || echo_i "failed"
+status=$((status+ret))
+
+echo_i "checking dnssec-signzone retains unexpired signatures ($n)"
+ret=0
+(
+cd signer || exit 1
+$SIGNER -Sxt -o example example.db > signer.out.1
+$SIGNER -Sxt -o example -f example.db.signed example.db.signed > signer.out.2
+) || ret=1
+gen1=$(awk '/generated/ {print $3}' signer/signer.out.1)
+retain1=$(awk '/retained/ {print $3}' signer/signer.out.1)
+gen2=$(awk '/generated/ {print $3}' signer/signer.out.2)
+retain2=$(awk '/retained/ {print $3}' signer/signer.out.2)
+drop2=$(awk '/dropped/ {print $3}' signer/signer.out.2)
+[ "$retain2" -eq $((gen1+retain1)) ] || ret=1
+[ "$gen2" -eq 0 ] || ret=1
+[ "$drop2" -eq 0 ] || ret=1
+n=$((n+1))
+test "$ret" -eq 0 || echo_i "failed"
+status=$((status+ret))
+
+echo_i "checking dnssec-signzone purges RRSIGs from formerly-owned glue (nsec) ($n)"
+ret=0
+(
+cd signer || exit 1
+# remove NSEC-only keys
+rm -f Kexample.+005*
+cp -f example.db.in example2.db
+cat << EOF >> example2.db
+sub1.example. IN A 10.53.0.1
+ns.sub2.example. IN A 10.53.0.2
+EOF
+echo "\$INCLUDE \"example2.db.signed\"" >> example2.db
+touch example2.db.signed
+$SIGNER -DS -O full -f example2.db.signed -o example example2.db > /dev/null
+) || ret=1
+grep "^sub1\\.example\\..*RRSIG[ ]A[ ]" signer/example2.db.signed > /dev/null 2>&1 || ret=1
+grep "^ns\\.sub2\\.example\\..*RRSIG[ ]A[ ]" signer/example2.db.signed > /dev/null 2>&1 || ret=1
+(
+cd signer || exit 1
+cp -f example.db.in example2.db
+cat << EOF >> example2.db
+sub1.example. IN NS sub1.example.
+sub1.example. IN A 10.53.0.1
+sub2.example. IN NS ns.sub2.example.
+ns.sub2.example. IN A 10.53.0.2
+EOF
+echo "\$INCLUDE \"example2.db.signed\"" >> example2.db
+$SIGNER -DS -O full -f example2.db.signed -o example example2.db > /dev/null
+) || ret=1
+grep "^sub1\\.example\\..*RRSIG[ ]A[ ]" signer/example2.db.signed > /dev/null 2>&1 && ret=1
+grep "^ns\\.sub2\\.example\\..*RRSIG[ ]A[ ]" signer/example2.db.signed > /dev/null 2>&1 && ret=1
+n=$((n+1))
+test "$ret" -eq 0 || echo_i "failed"
+status=$((status+ret))
+
+echo_i "checking dnssec-signzone purges RRSIGs from formerly-owned glue (nsec3) ($n)"
+ret=0
+(
+cd signer || exit 1
+rm -f example2.db.signed
+cp -f example.db.in example2.db
+cat << EOF >> example2.db
+sub1.example. IN A 10.53.0.1
+ns.sub2.example. IN A 10.53.0.2
+EOF
+echo "\$INCLUDE \"example2.db.signed\"" >> example2.db
+touch example2.db.signed
+$SIGNER -DS -3 feedabee -O full -f example2.db.signed -o example example2.db > /dev/null
+) || ret=1
+grep "^sub1\\.example\\..*RRSIG[ ]A[ ]" signer/example2.db.signed > /dev/null 2>&1 || ret=1
+grep "^ns\\.sub2\\.example\\..*RRSIG[ ]A[ ]" signer/example2.db.signed > /dev/null 2>&1 || ret=1
+(
+cd signer || exit 1
+cp -f example.db.in example2.db
+cat << EOF >> example2.db
+sub1.example. IN NS sub1.example.
+sub1.example. IN A 10.53.0.1
+sub2.example. IN NS ns.sub2.example.
+ns.sub2.example. IN A 10.53.0.2
+EOF
+echo "\$INCLUDE \"example2.db.signed\"" >> example2.db
+$SIGNER -DS -3 feedabee -O full -f example2.db.signed -o example example2.db > /dev/null
+) || ret=1
+grep "^sub1\\.example\\..*RRSIG[ ]A[ ]" signer/example2.db.signed > /dev/null 2>&1 && ret=1
+grep "^ns\\.sub2\\.example\\..*RRSIG[ ]A[ ]" signer/example2.db.signed > /dev/null 2>&1 && ret=1
+n=$((n+1))
+test "$ret" -eq 0 || echo_i "failed"
+status=$((status+ret))
+
+echo_i "checking dnssec-signzone output format ($n)"
+ret=0
+(
+cd signer || exit 1
+$SIGNER -O full -f - -Sxt -o example example.db > signer.out.3 2> /dev/null
+$SIGNER -O text -f - -Sxt -o example example.db > signer.out.4 2> /dev/null
+$SIGNER -O raw -f signer.out.5 -Sxt -o example example.db > /dev/null
+$SIGNER -O raw=0 -f signer.out.6 -Sxt -o example example.db > /dev/null
+$SIGNER -O raw -f - -Sxt -o example example.db > signer.out.7 2> /dev/null
+) || ret=1
+awk 'BEGIN { found = 0; }
+ $1 == "example." && $3 == "IN" && $4 == "SOA" { found = 1; if (NF != 11) exit(1); }
+ END { if (!found) exit(1); }' signer/signer.out.3 || ret=1
+awk 'BEGIN { found = 0; }
+ $1 == "example." && $3 == "IN" && $4 == "SOA" { found = 1; if (NF != 7) exit(1); }
+ END { if (!found) exit(1); }' signer/signer.out.4 || ret=1
+israw1 signer/signer.out.5 || ret=1
+israw0 signer/signer.out.6 || ret=1
+israw1 signer/signer.out.7 || ret=1
+n=$((n+1))
+test "$ret" -eq 0 || echo_i "failed"
+status=$((status+ret))
+
+echo_i "checking TTLs are capped by dnssec-signzone -M ($n)"
+ret=0
+(
+cd signer || exit 1
+$SIGNER -O full -f signer.out.8 -S -M 30 -o example example.db > /dev/null
+) || ret=1
+awk '/^;/ { next; } $2 > 30 { exit 1; }' signer/signer.out.8 || ret=1
+n=$((n+1))
+test "$ret" -eq 0 || echo_i "failed"
+status=$((status+ret))
+
+echo_i "checking dnssec-signzone -N date ($n)"
+ret=0
+(
+cd signer || exit 1
+TZ=UTC $SIGNER -O full -f signer.out.9 -S -N date -o example example2.db > /dev/null
+) || ret=1
+# shellcheck disable=SC2016
+now=$(TZ=UTC $PERL -e '@lt=localtime(); printf "%.4d%0.2d%0.2d00\n",$lt[5]+1900,$lt[4]+1,$lt[3];')
+serial=$(awk '/^;/ { next; } $4 == "SOA" { print $7 }' signer/signer.out.9)
+[ "$now" -eq "$serial" ] || ret=1
+n=$((n+1))
+test "$ret" -eq 0 || echo_i "failed"
+status=$((status+ret))
+
+echo_i "checking validated data are not cached longer than originalttl ($n)"
+ret=0
+dig_with_opts +ttl +noauth a.ttlpatch.example. @10.53.0.3 a > dig.out.ns3.test$n || ret=1
+dig_with_opts +ttl +noauth a.ttlpatch.example. @10.53.0.4 a > dig.out.ns4.test$n || ret=1
+grep "3600.IN" dig.out.ns3.test$n > /dev/null || ret=1
+grep "300.IN" dig.out.ns3.test$n > /dev/null && ret=1
+grep "300.IN" dig.out.ns4.test$n > /dev/null || ret=1
+grep "3600.IN" dig.out.ns4.test$n > /dev/null && ret=1
+n=$((n+1))
+test "$ret" -eq 0 || echo_i "failed"
+status=$((status+ret))
+
+# Test that "rndc secroots" is able to dump trusted keys
+echo_i "checking rndc secroots ($n)"
+ret=0
+keyid=$(cat ns1/managed.key.id)
+rndccmd 10.53.0.4 secroots 2>&1 | sed 's/^/ns4 /' | cat_i
+cp ns4/named.secroots named.secroots.test$n
+check_secroots_layout named.secroots.test$n || ret=1
+linecount=$(grep -c "./$DEFAULT_ALGORITHM/$keyid ; static" named.secroots.test$n || true)
+[ "$linecount" -eq 1 ] || ret=1
+linecount=$(< named.secroots.test$n wc -l)
+[ "$linecount" -eq 10 ] || ret=1
+n=$((n+1))
+test "$ret" -eq 0 || echo_i "failed"
+status=$((status+ret))
+
+# Check direct query for RRSIG. If we first ask for normal (non RRSIG)
+# record, the corresponding RRSIG should be cached and subsequent query
+# for RRSIG will be returned with the cached record.
+echo_i "checking RRSIG query from cache ($n)"
+ret=0
+dig_with_opts normalthenrrsig.secure.example. @10.53.0.4 a > /dev/null || ret=1
+ans=$(dig_with_opts +short normalthenrrsig.secure.example. @10.53.0.4 rrsig) || ret=1
+expect=$(dig_with_opts +short normalthenrrsig.secure.example. @10.53.0.3 rrsig | grep '^A' ) || ret=1
+test "$ans" = "$expect" || ret=1
+# also check that RA is set
+dig_with_opts normalthenrrsig.secure.example. @10.53.0.4 rrsig > dig.out.ns4.test$n || ret=1
+grep "flags:.*ra.*QUERY" dig.out.ns4.test$n > /dev/null || ret=1
+n=$((n+1))
+test "$ret" -eq 0 || echo_i "failed"
+status=$((status+ret))
+
+# Check direct query for RRSIG: If it's not cached with other records,
+# it should result in an empty response.
+echo_i "checking RRSIG query not in cache ($n)"
+ret=0
+ans=$(dig_with_opts +short rrsigonly.secure.example. @10.53.0.4 rrsig) || ret=1
+test -z "$ans" || ret=1
+# also check that RA is cleared
+dig_with_opts rrsigonly.secure.example. @10.53.0.4 rrsig > dig.out.ns4.test$n || ret=1
+grep "flags:.*ra.*QUERY" dig.out.ns4.test$n > /dev/null && ret=1
+n=$((n+1))
+test "$ret" -eq 0 || echo_i "failed"
+status=$((status+ret))
+
+#
+# RT21868 regression test.
+#
+echo_i "checking NSEC3 zone with mismatched NSEC3PARAM / NSEC parameters ($n)"
+ret=0
+dig_with_opts non-exist.badparam. @10.53.0.2 a > dig.out.ns2.test$n || ret=1
+grep "status: NXDOMAIN" dig.out.ns2.test$n > /dev/null || ret=1
+n=$((n+1))
+test "$ret" -eq 0 || echo_i "failed"
+status=$((status+ret))
+
+#
+# RT22007 regression test.
+#
+echo_i "checking optout NSEC3 referral with only insecure delegations ($n)"
+ret=0
+dig_with_opts +norec delegation.single-nsec3. @10.53.0.2 a > dig.out.ns2.test$n || ret=1
+grep "status: NOERROR" dig.out.ns2.test$n > /dev/null || ret=1
+grep "3KL3NK1HKQ4IUEEHBEF12VGFKUETNBAN.*NSEC3 1 1 1 - 3KL3NK1HKQ4IUEEHBEF12VGFKUETNBAN" dig.out.ns2.test$n > /dev/null || ret=1
+n=$((n+1))
+test "$ret" -eq 0 || echo_i "failed"
+status=$((status+ret))
+
+echo_i "checking optout NSEC3 NXDOMAIN with only insecure delegations ($n)"
+ret=0
+dig_with_opts +norec nonexist.single-nsec3. @10.53.0.2 a > dig.out.ns2.test$n || ret=1
+grep "status: NXDOMAIN" dig.out.ns2.test$n > /dev/null || ret=1
+grep "3KL3NK1HKQ4IUEEHBEF12VGFKUETNBAN.*NSEC3 1 1 1 - 3KL3NK1HKQ4IUEEHBEF12VGFKUETNBAN" dig.out.ns2.test$n > /dev/null || ret=1
+n=$((n+1))
+test "$ret" -eq 0 || echo_i "failed"
+
+status=$((status+ret))
+echo_i "checking optout NSEC3 nodata with only insecure delegations ($n)"
+ret=0
+dig_with_opts +norec single-nsec3. @10.53.0.2 a > dig.out.ns2.test$n || ret=1
+grep "status: NOERROR" dig.out.ns2.test$n > /dev/null || ret=1
+grep "3KL3NK1HKQ4IUEEHBEF12VGFKUETNBAN.*NSEC3 1 1 1 - 3KL3NK1HKQ4IUEEHBEF12VGFKUETNBAN" dig.out.ns2.test$n > /dev/null || ret=1
+n=$((n+1))
+test "$ret" -eq 0 || echo_i "failed"
+status=$((status+ret))
+
+echo_i "checking that a zone finishing the transition from $ALTERNATIVE_ALGORITHM to $DEFAULT_ALGORITHM validates secure ($n)"
+ret=0
+dig_with_opts ns algroll. @10.53.0.4 > dig.out.ns4.test$n || ret=1
+grep "NOERROR" dig.out.ns4.test$n > /dev/null || ret=1
+grep "flags:[^;]* ad[^;]*;" dig.out.ns4.test$n > /dev/null || ret=1
+n=$((n+1))
+test "$ret" -eq 0 || echo_i "failed"
+status=$((status+ret))
+
+echo_i "checking validate-except in an insecure local domain ($n)"
+ret=0
+dig_with_opts ns www.corp @10.53.0.4 > dig.out.ns4.test$n || ret=1
+grep "NOERROR" dig.out.ns4.test$n > /dev/null || ret=1
+grep "flags:[^;]* ad[^;]*;" dig.out.ns4.test$n > /dev/null && ret=1
+n=$((n+1))
+test "$ret" -eq 0 || echo_i "failed"
+status=$((status+ret))
+
+echo_i "checking positive and negative validation with negative trust anchors ($n)"
+ret=0
+
+#
+# check correct initial behavior
+#
+dig_with_opts a.bogus.example. a @10.53.0.4 > dig.out.ns4.test$n.1 || ret=1
+grep "status: SERVFAIL" dig.out.ns4.test$n.1 > /dev/null || ret=1
+dig_with_opts badds.example. soa @10.53.0.4 > dig.out.ns4.test$n.2 || ret=1
+grep "status: SERVFAIL" dig.out.ns4.test$n.2 > /dev/null || ret=1
+dig_with_opts a.secure.example. a @10.53.0.4 > dig.out.ns4.test$n.3 || ret=1
+grep "status: SERVFAIL" dig.out.ns4.test$n.3 > /dev/null && ret=1
+grep "flags:[^;]* ad[^;]*;" dig.out.ns4.test$n.3 > /dev/null || ret=1
+
+if [ "$ret" -ne 0 ]; then echo_i "failed - checking initial state"; fi
+status=$((status+ret))
+ret=0
+
+#
+# add negative trust anchors
+#
+rndccmd 10.53.0.4 nta -f -l 20s bogus.example 2>&1 | sed 's/^/ns4 /' | cat_i
+rndccmd 10.53.0.4 nta badds.example 2>&1 | sed 's/^/ns4 /' | cat_i
+# reconfig should maintain NTAs
+rndccmd 10.53.0.4 reconfig 2>&1 | sed 's/^/ns4 /' | cat_i
+rndccmd 10.53.0.4 nta -d > rndc.out.ns4.test$n.1
+lines=$(wc -l < rndc.out.ns4.test$n.1)
+[ "$lines" -eq 3 ] || ret=1
+rndccmd 10.53.0.4 nta secure.example 2>&1 | sed 's/^/ns4 /' | cat_i
+rndccmd 10.53.0.4 nta fakenode.secure.example 2>&1 | sed 's/^/ns4 /' | cat_i
+# reload should maintain NTAs
+rndc_reload ns4 10.53.0.4
+rndccmd 10.53.0.4 nta -d > rndc.out.ns4.test$n.2
+lines=$(wc -l < rndc.out.ns4.test$n.2)
+[ "$lines" -eq 5 ] || ret=1
+# shellcheck disable=SC2016
+start=$($PERL -e 'print time()."\n";')
+
+if [ "$ret" -ne 0 ]; then echo_i "failed - adding NTA's failed"; fi
+status=$((status+ret))
+ret=0
+
+#
+# check behavior with NTA's in place
+#
+dig_with_opts a.bogus.example. a @10.53.0.4 > dig.out.ns4.test$n.4 || ret=1
+grep "status: SERVFAIL" dig.out.ns4.test$n.4 > /dev/null && ret=1
+grep "flags:[^;]* ad[^;]*;" dig.out.ns4.test$n.4 > /dev/null && ret=1
+dig_with_opts badds.example. soa @10.53.0.4 > dig.out.ns4.test$n.5 || ret=1
+grep "status: SERVFAIL" dig.out.ns4.test$n.5 > /dev/null && ret=1
+grep "flags:[^;]* ad[^;]*;" dig.out.ns4.test$n.5 > /dev/null && ret=1
+dig_with_opts a.secure.example. a @10.53.0.4 > dig.out.ns4.test$n.6 || ret=1
+grep "status: SERVFAIL" dig.out.ns4.test$n.6 > /dev/null && ret=1
+grep "flags:[^;]* ad[^;]*;" dig.out.ns4.test$n.6 > /dev/null && ret=1
+dig_with_opts a.fakenode.secure.example. a @10.53.0.4 > dig.out.ns4.test$n.7 || ret=1
+grep "flags:[^;]* ad[^;]*;" dig.out.ns4.test$n.7 > /dev/null && ret=1
+echo_i "dumping secroots"
+rndccmd 10.53.0.4 secroots | sed 's/^/ns4 /' | cat_i
+cp ns4/named.secroots named.secroots.test$n
+check_secroots_layout named.secroots.test$n || ret=1
+grep "bogus.example: expiry" named.secroots.test$n > /dev/null || ret=1
+grep "badds.example: expiry" named.secroots.test$n > /dev/null || ret=1
+grep "secure.example: expiry" named.secroots.test$n > /dev/null || ret=1
+grep "fakenode.secure.example: expiry" named.secroots.test$n > /dev/null || ret=1
+
+if [ "$ret" -ne 0 ]; then echo_i "failed - with NTA's in place failed"; fi
+status=$((status+ret))
+ret=0
+
+echo_i "waiting for NTA rechecks/expirations"
+
+#
+# secure.example and badds.example used default nta-duration
+# (configured as 12s in ns4/named1.conf), but nta recheck interval
+# is configured to 9s, so at t=10 the NTAs for secure.example and
+# fakenode.secure.example should both be lifted, but badds.example
+# should still be going.
+#
+# shellcheck disable=SC2016
+$PERL -e 'my $delay = '"$start"' + 10 - time(); select(undef, undef, undef, $delay) if ($delay > 0);'
+dig_with_opts b.secure.example. a @10.53.0.4 > dig.out.ns4.test$n.8 || ret=1
+grep "status: SERVFAIL" dig.out.ns4.test$n.8 > /dev/null && ret=1
+grep "flags:[^;]* ad[^;]*;" dig.out.ns4.test$n.8 > /dev/null || ret=1
+dig_with_opts b.fakenode.secure.example. a @10.53.0.4 > dig.out.ns4.test$n.9 || ret=1
+grep "flags:[^;]* ad[^;]*;" dig.out.ns4.test$n.9 > /dev/null || ret=1
+grep "status: NXDOMAIN" dig.out.ns4.test$n.9 > /dev/null || ret=1
+dig_with_opts badds.example. soa @10.53.0.4 > dig.out.ns4.test$n.10 || ret=1
+grep "status: SERVFAIL" dig.out.ns4.test$n.10 > /dev/null && ret=1
+grep "flags:[^;]* ad[^;]*;" dig.out.ns4.test$n.10 > /dev/null && ret=1
+
+if [ "$ret" -ne 0 ]; then echo_i "failed - checking that default nta's were lifted due to recheck"; fi
+status=$((status+ret))
+ret=0
+
+#
+# bogus.example was set to expire in 20s, so at t=13
+# it should still be NTA'd, but badds.example used the default
+# lifetime of 12s, so it should revert to SERVFAIL now.
+#
+# shellcheck disable=SC2016
+$PERL -e 'my $delay = '"$start"' + 13 - time(); select(undef, undef, undef, $delay) if ($delay > 0);'
+# check nta table
+rndccmd 10.53.0.4 nta -d > rndc.out.ns4.test$n._11
+lines=$(grep -c " expiry " rndc.out.ns4.test$n._11 || true)
+[ "$lines" -le 2 ] || ret=1
+grep "bogus.example/_default: expiry" rndc.out.ns4.test$n._11 > /dev/null || ret=1
+grep "badds.example/_default: expiry" rndc.out.ns4.test$n._11 > /dev/null && ret=1
+dig_with_opts b.bogus.example. a @10.53.0.4 > dig.out.ns4.test$n.11 || ret=1
+grep "status: SERVFAIL" dig.out.ns4.test$n.11 > /dev/null && ret=1
+dig_with_opts a.badds.example. a @10.53.0.4 > dig.out.ns4.test$n.12 || ret=1
+grep "status: SERVFAIL" dig.out.ns4.test$n.12 > /dev/null || ret=1
+grep "flags:[^;]* ad[^;]*;" dig.out.ns4.test$n.12 > /dev/null && ret=1
+dig_with_opts c.secure.example. a @10.53.0.4 > dig.out.ns4.test$n.13 || ret=1
+grep "status: SERVFAIL" dig.out.ns4.test$n.13 > /dev/null && ret=1
+grep "flags:[^;]* ad[^;]*;" dig.out.ns4.test$n.13 > /dev/null || ret=1
+
+if [ "$ret" -ne 0 ]; then echo_i "failed - checking that default nta's were lifted due to lifetime"; fi
+status=$((status+ret))
+ret=0
+
+#
+# at t=21, all the NTAs should have expired.
+#
+# shellcheck disable=SC2016
+$PERL -e 'my $delay = '"$start"' + 21 - time(); select(undef, undef, undef, $delay) if ($delay > 0);'
+# check correct behavior after bogus.example expiry
+dig_with_opts d.secure.example. a @10.53.0.4 > dig.out.ns4.test$n.14 || ret=1
+grep "status: SERVFAIL" dig.out.ns4.test$n.14 > /dev/null && ret=1
+grep "flags:[^;]* ad[^;]*;" dig.out.ns4.test$n.14 > /dev/null || ret=1
+dig_with_opts c.bogus.example. a @10.53.0.4 > dig.out.ns4.test$n.15 || ret=1
+grep "status: SERVFAIL" dig.out.ns4.test$n.15 > /dev/null || ret=1
+# check nta table has been cleaned up now
+rndccmd 10.53.0.4 nta -d > rndc.out.ns4.test$n.3
+lines=$(grep -c " expiry " rndc.out.ns4.test$n.3 || true)
+[ "$lines" -eq 0 ] || ret=1
+n=$((n+1))
+if [ "$ret" -ne 0 ]; then echo_i "failed - checking that all nta's have been lifted"; fi
+status=$((status+ret))
+ret=0
+
+echo_i "testing NTA removals ($n)"
+rndccmd 10.53.0.4 nta badds.example 2>&1 | sed 's/^/ns4 /' | cat_i
+rndccmd 10.53.0.4 nta -d > rndc.out.ns4.test$n.1
+grep "badds.example/_default: expiry" rndc.out.ns4.test$n.1 > /dev/null || ret=1
+dig_with_opts a.badds.example. a @10.53.0.4 > dig.out.ns4.test$n.1 || ret=1
+grep "status: SERVFAIL" dig.out.ns4.test$n.1 > /dev/null && ret=1
+grep "^a.badds.example." dig.out.ns4.test$n.1 > /dev/null || ret=1
+rndccmd 10.53.0.4 nta -remove badds.example > rndc.out.ns4.test$n.2
+grep "Negative trust anchor removed: badds.example/_default" rndc.out.ns4.test$n.2 > /dev/null || ret=1
+rndccmd 10.53.0.4 nta -d > rndc.out.ns4.test$n.3
+grep "badds.example/_default: expiry" rndc.out.ns4.test$n.3 > /dev/null && ret=1
+dig_with_opts a.badds.example. a @10.53.0.4 > dig.out.ns4.test$n.2 || ret=1
+grep "status: SERVFAIL" dig.out.ns4.test$n.2 > /dev/null || ret=1
+test "$ret" -eq 0 || echo_i "failed"
+status=$((status+ret))
+ret=0
+
+echo_i "remove non-existent NTA three times"
+rndccmd 10.53.0.4 nta -r foo > rndc.out.ns4.test$n.4 2>&1
+rndccmd 10.53.0.4 nta -remove foo > rndc.out.ns4.test$n.5 2>&1
+rndccmd 10.53.0.4 nta -r foo > rndc.out.ns4.test$n.6 2>&1
+grep "not found" rndc.out.ns4.test$n.6 > /dev/null || ret=1
+test "$ret" -eq 0 || echo_i "failed"
+status=$((status+ret))
+ret=0
+
+n=$((n+1))
+echo_i "testing NTA with bogus lifetimes ($n)"
+echo_i "check with no nta lifetime specified"
+rndccmd 10.53.0.4 nta -l "" foo > rndc.out.ns4.test$n.1 2>&1 || true
+grep "'nta' failed: bad ttl" rndc.out.ns4.test$n.1 > /dev/null || ret=1
+test "$ret" -eq 0 || echo_i "failed"
+status=$((status+ret))
+ret=0
+
+echo_i "check with bad nta lifetime"
+rndccmd 10.53.0.4 nta -l garbage foo > rndc.out.ns4.test$n.2 2>&1 || true
+grep "'nta' failed: bad ttl" rndc.out.ns4.test$n.2 > /dev/null || ret=1
+test "$ret" -eq 0 || echo_i "failed"
+status=$((status+ret))
+ret=0
+
+echo_i "check with too long nta lifetime"
+rndccmd 10.53.0.4 nta -l 7d1h foo > rndc.out.ns4.test$n.3 2>&1 || true
+grep "'nta' failed: out of range" rndc.out.ns4.test$n.3 > /dev/null || ret=1
+test "$ret" -eq 0 || echo_i "failed"
+status=$((status+ret))
+ret=0
+
+#
+# check NTA persistence across restarts
+#
+n=$((n+1))
+echo_i "testing NTA persistence across restarts ($n)"
+rndccmd 10.53.0.4 nta -d > rndc.out.ns4.test$n.1
+lines=$(grep -c " expiry " rndc.out.ns4.test$n.1 || true)
+[ "$lines" -eq 0 ] || ret=1
+rndccmd 10.53.0.4 nta -f -l 30s bogus.example 2>&1 | sed 's/^/ns4 /' | cat_i
+rndccmd 10.53.0.4 nta -f -l 10s badds.example 2>&1 | sed 's/^/ns4 /' | cat_i
+rndccmd 10.53.0.4 nta -d > rndc.out.ns4.test$n.2
+lines=$(grep -c " expiry " rndc.out.ns4.test$n.2 || true)
+[ "$lines" -eq 2 ] || ret=1
+# shellcheck disable=SC2016
+start=$($PERL -e 'print time()."\n";')
+
+if [ "$ret" -ne 0 ]; then echo_i "failed - NTA persistence: adding NTA's failed"; fi
+status=$((status+ret))
+ret=0
+
+echo_i "killing ns4 with SIGTERM"
+kill -TERM "$(cat ns4/named.pid)"
+rm -f ns4/named.pid
+
+#
+# ns4 has now shutdown. wait until t=14 when badds.example's NTA
+# (lifetime=10s) would have expired, and then restart ns4.
+#
+echo_i "waiting till 14s have passed since NTAs were added before restarting ns4"
+# shellcheck disable=SC2016
+$PERL -e 'my $delay = '"$start"' + 14 - time(); select(undef, undef, undef, $delay) if ($delay > 0);'
+
+if
+ start_server --noclean --restart --port "$PORT" ns4
+then
+ echo_i "restarted server ns4"
+else
+ echo_i "could not restart server ns4"
+ exit 1
+fi
+
+echo_i "sleeping for an additional 4 seconds for ns4 to fully startup"
+sleep 4
+
+#
+# ns4 should be back up now. The NTA for bogus.example should still be
+# valid, whereas badds.example should not have been added during named
+# startup (as it had already expired), the fact that it's ignored should
+# be logged.
+#
+rndccmd 10.53.0.4 nta -d > rndc.out.ns4.test$n.3
+lines=$(wc -l < rndc.out.ns4.test$n.3)
+[ "$lines" -eq 2 ] || ret=1
+grep "bogus.example/_default: expiry" rndc.out.ns4.test$n.3 > /dev/null || ret=1
+dig_with_opts b.bogus.example. a @10.53.0.4 > dig.out.ns4.test$n.4 || ret=1
+grep "status: SERVFAIL" dig.out.ns4.test$n.4 > /dev/null && ret=1
+grep "flags:[^;]* ad[^;]*;" dig.out.ns4.test$n.4 > /dev/null && ret=1
+dig_with_opts a.badds.example. a @10.53.0.4 > dig.out.ns4.test$n.5 || ret=1
+grep "status: SERVFAIL" dig.out.ns4.test$n.5 > /dev/null || ret=1
+grep "ignoring expired NTA at badds.example" ns4/named.run > /dev/null || ret=1
+
+# cleanup
+rndccmd 10.53.0.4 nta -remove bogus.example > rndc.out.ns4.test$n.6
+
+if [ "$ret" -ne 0 ]; then echo_i "failed - NTA persistence: restoring NTA failed"; fi
+status=$((status+ret))
+ret=0
+
+#
+# check "regular" attribute in NTA file works as expected at named
+# startup.
+#
+n=$((n+1))
+echo_i "testing loading regular attribute from NTA file ($n)"
+rndccmd 10.53.0.4 nta -d > rndc.out.ns4.test$n.1 2>/dev/null
+lines=$(wc -l < rndc.out.ns4.test$n.1)
+[ "$lines" -eq 1 ] || ret=1
+# initially, secure.example. validates with AD=1
+dig_with_opts a.secure.example. a @10.53.0.4 > dig.out.ns4.test$n.2 || ret=1
+grep "status: SERVFAIL" dig.out.ns4.test$n.2 > /dev/null && ret=1
+grep "flags:[^;]* ad[^;]*;" dig.out.ns4.test$n.2 > /dev/null || ret=1
+
+echo_i "killing ns4 with SIGTERM"
+kill -TERM "$(cat ns4/named.pid)"
+rm -f ns4/named.pid
+
+echo_i "sleeping for an additional 4 seconds for ns4 to fully shutdown"
+sleep 4
+
+#
+# ns4 has now shutdown. add NTA for secure.example. directly into the
+# _default.nta file with the regular attribute and some future timestamp.
+#
+future="$(($(date +%Y)+20))0101010000"
+echo "secure.example. regular $future" > ns4/_default.nta
+# shellcheck disable=SC2016
+start=$($PERL -e 'print time()."\n";')
+
+if
+ start_server --noclean --restart --port "$PORT" ns4
+then
+ echo_i "restarted server ns4"
+else
+ echo_i "could not restart server ns4"
+ exit 1
+fi
+
+# nta-recheck is configured as 9s, so at t=12 the NTAs for
+# secure.example. should be lifted as it is not a forced NTA.
+echo_i "waiting till 12s have passed after ns4 was restarted"
+# shellcheck disable=SC2016
+$PERL -e 'my $delay = '"$start"' + 12 - time(); select(undef, undef, undef, $delay) if ($delay > 0);'
+
+# secure.example. should now return an AD=1 answer (still validates) as
+# the NTA has been lifted.
+dig_with_opts a.secure.example. a @10.53.0.4 > dig.out.ns4.test$n.3 || ret=1
+grep "status: SERVFAIL" dig.out.ns4.test$n.3 > /dev/null && ret=1
+grep "flags:[^;]* ad[^;]*;" dig.out.ns4.test$n.3 > /dev/null || ret=1
+
+# cleanup
+rndccmd 10.53.0.4 nta -remove secure.example > rndc.out.ns4.test$n.4 2>/dev/null
+
+if [ "$ret" -ne 0 ]; then echo_i "failed - NTA persistence: loading regular NTAs failed"; fi
+status=$((status+ret))
+ret=0
+
+#
+# check "forced" attribute in NTA file works as expected at named
+# startup.
+#
+n=$((n+1))
+echo_i "testing loading forced attribute from NTA file ($n)"
+rndccmd 10.53.0.4 nta -d > rndc.out.ns4.test$n.1 2>/dev/null
+lines=$(wc -l < rndc.out.ns4.test$n.1)
+[ "$lines" -eq 1 ] || ret=1
+# initially, secure.example. validates with AD=1
+dig_with_opts a.secure.example. a @10.53.0.4 > dig.out.ns4.test$n.2 || ret=1
+grep "status: SERVFAIL" dig.out.ns4.test$n.2 > /dev/null && ret=1
+grep "flags:[^;]* ad[^;]*;" dig.out.ns4.test$n.2 > /dev/null || ret=1
+
+echo_i "killing ns4 with SIGTERM"
+kill -TERM "$(cat ns4/named.pid)"
+rm -f named.pid
+
+echo_i "sleeping for an additional 4 seconds for ns4 to fully shutdown"
+sleep 4
+
+#
+# ns4 has now shutdown. add NTA for secure.example. directly into the
+# _default.nta file with the forced attribute and some future timestamp.
+#
+echo "secure.example. forced $future" > ns4/_default.nta
+start=$($PERL -e 'print time()."\n";')
+
+if
+ start_server --noclean --restart --port "$PORT" ns4
+then
+ echo_i "restarted server ns4"
+else
+ echo_i "could not restart server ns4"
+ exit 1
+fi
+
+# nta-recheck is configured as 9s, but even at t=12 the NTAs for
+# secure.example. should not be lifted as it is a forced NTA.
+echo_i "waiting till 12s have passed after ns4 was restarted"
+# shellcheck disable=SC2016
+$PERL -e 'my $delay = '"$start"' + 12 - time(); select(undef, undef, undef, $delay) if ($delay > 0);'
+
+# secure.example. should now return an AD=0 answer (non-authenticated)
+# as the NTA is still there.
+dig_with_opts a.secure.example. a @10.53.0.4 > dig.out.ns4.test$n.3 || ret=1
+grep "status: SERVFAIL" dig.out.ns4.test$n.3 > /dev/null && ret=1
+grep "flags:[^;]* ad[^;]*;" dig.out.ns4.test$n.3 > /dev/null && ret=1
+
+# cleanup
+rndccmd 10.53.0.4 nta -remove secure.example > rndc.out.ns4.test$n.4 2>/dev/null
+
+if [ "$ret" -ne 0 ]; then echo_i "failed - NTA persistence: loading forced NTAs failed"; fi
+status=$((status+ret))
+ret=0
+
+#
+# check that NTA lifetime read from file is clamped to 1 week.
+#
+n=$((n+1))
+echo_i "testing loading out of bounds lifetime from NTA file ($n)"
+
+echo_i "killing ns4 with SIGTERM"
+kill -TERM "$(cat ns4/named.pid)"
+rm -f ns4/named.pid
+
+echo_i "sleeping for an additional 4 seconds for ns4 to fully shutdown"
+sleep 4
+
+#
+# ns4 has now shutdown. add NTA for secure.example. directly into the
+# _default.nta file with a lifetime well into the future.
+#
+echo "secure.example. forced $future" > ns4/_default.nta
+added=$($PERL -e 'print time()."\n";')
+
+if
+ start_server --noclean --restart --port "$PORT" ns4
+then
+ echo_i "restarted server ns4"
+else
+ echo_i "could not restart server ns4"
+ exit 1
+fi
+
+echo_i "sleeping for an additional 4 seconds for ns4 to fully startup"
+sleep 4
+
+# dump the NTA to a file (omit validate-except entries)
+echo_i "testing 'rndc nta -d' with NTA"
+rndccmd 10.53.0.4 nta -d | grep -v ": permanent" > rndc.out.ns4.test$n.1 2>/dev/null
+# "corp" is configured as a validate-except domain and thus should be
+# removed by the grep -v above. only "secure.example" should appear in
+# the dump.
+lines=$(wc -l < rndc.out.ns4.test$n.1)
+[ "$lines" -eq 1 ] || ret=1
+grep 'secure.example' rndc.out.ns4.test$n.1 > /dev/null || ret=1
+ts=$(awk '{print $3" "$4}' < rndc.out.ns4.test$n.1)
+# rndc nta outputs localtime, so append the timezone
+ts_with_zone="$ts $(date +%z)"
+echo "ts=$ts" > rndc.out.ns4.test$n.2
+echo "ts_with_zone=$ts_with_zone" >> rndc.out.ns4.test$n.2
+echo "added=$added" >> rndc.out.ns4.test$n.2
+if $PERL -e 'use Time::Piece; use Time::Seconds;' 2>/dev/null
+then
+ # ntadiff.pl computes $ts_with_zone - ($added + 1week)
+ d=$($PERL ./ntadiff.pl "$ts_with_zone" "$added")
+ echo "d=$d" >> rndc.out.ns4.test$n.2
+ # diff from $added(now) + 1week to the clamped NTA lifetime should be
+ # less than a few seconds (handle daylight saving changes by adding 3600).
+ [ "$d" -lt 3610 ] || ret=1
+else
+ echo_i "skipped ntadiff test; install PERL module Time::Piece"
+fi
+
+echo_i "testing 'rndc nta' lifetime clamping"
+rndccmd 10.53.0.4 nta -d | grep ": permanent" > rndc.out.ns4.test$n.1 2>/dev/null
+# "corp" is configured as a validate-except domain and thus should be
+# the only entry in the dump.
+lines=$(wc -l < rndc.out.ns4.test$n.1)
+[ "$lines" -eq 1 ] || ret=1
+grep 'corp/_default' rndc.out.ns4.test$n.1 > /dev/null || ret=1
+
+# cleanup
+rndccmd 10.53.0.4 nta -remove secure.example > rndc.out.ns4.test$n.3 2>/dev/null
+
+n=$((n+1))
+if [ "$ret" -ne 0 ]; then echo_i "failed"; fi
+status=$((status+ret))
+
+echo_i "testing 'rndc nta -d' displays validate-except entries"
+rndccmd 10.53.0.4 nta -d | grep ": permanent" > rndc.out.ns4.test$n.1 2>/dev/null
+lines=$(wc -l < rndc.out.ns4.test$n.1)
+[ "$lines" -eq 1 ] || ret=1
+grep 'corp/_default' rndc.out.ns4.test$n.1 > /dev/null || ret=1
+n=$((n+1))
+if [ "$ret" -ne 0 ]; then echo_i "failed"; fi
+status=$((status+ret))
+
+echo_i "checking that NTAs work with 'forward only;' to a validating resolver ($n)"
+ret=0
+# Sanity check behavior without an NTA in place.
+dig_with_opts @10.53.0.9 badds.example. SOA > dig.out.ns9.test$n.1 || ret=1
+grep "SERVFAIL" dig.out.ns9.test$n.1 > /dev/null || ret=1
+grep "ANSWER: 0" dig.out.ns9.test$n.1 > /dev/null || ret=1
+grep "flags:[^;]* ad[ ;].*QUERY" dig.out.ns9.test$n.1 > /dev/null && ret=1
+# Add an NTA, expecting that to cause resolution to succeed.
+rndccmd 10.53.0.9 nta badds.example > rndc.out.ns9.test$n.1 2>&1 || ret=1
+dig_with_opts @10.53.0.9 badds.example. SOA > dig.out.ns9.test$n.2 || ret=1
+grep "NOERROR" dig.out.ns9.test$n.2 > /dev/null || ret=1
+grep "ANSWER: 2" dig.out.ns9.test$n.2 > /dev/null || ret=1
+grep "flags:[^;]* ad[ ;].*QUERY" dig.out.ns9.test$n.2 > /dev/null && ret=1
+# Remove the NTA, expecting that to cause resolution to fail again.
+rndccmd 10.53.0.9 nta -remove badds.example > rndc.out.ns9.test$n.2 2>&1 || ret=1
+dig_with_opts @10.53.0.9 badds.example. SOA > dig.out.ns9.test$n.3 || ret=1
+grep "SERVFAIL" dig.out.ns9.test$n.3 > /dev/null || ret=1
+grep "ANSWER: 0" dig.out.ns9.test$n.3 > /dev/null || ret=1
+grep "flags:[^;]* ad[ ;].*QUERY" dig.out.ns9.test$n.3 > /dev/null && ret=1
+if [ "$ret" -ne 0 ]; then echo_i "failed"; fi
+status=$((status+ret))
+
+echo_i "completed NTA tests"
+
+# Run a minimal update test if possible. This is really just
+# a regression test for RT #2399; more tests should be added.
+
+if $PERL -e 'use Net::DNS;' 2>/dev/null
+then
+ echo_i "running DNSSEC update test"
+ ret=0
+ { output=$($PERL dnssec_update_test.pl -s 10.53.0.3 -p "$PORT" dynamic.example.); rc=$?; } || true
+ test "$rc" -eq 0 || ret=1
+ echo "$output" | cat_i
+ [ $ret -eq 1 ] && status=1
+else
+ echo_i "The DNSSEC update test requires the Net::DNS library." >&2
+fi
+
+n=$((n+1))
+echo_i "checking managed key maintenance has not started yet ($n)"
+ret=0
+[ -f "ns4/managed-keys.bind.jnl" ] && ret=1
+n=$((n+1))
+test "$ret" -eq 0 || echo_i "failed"
+status=$((status+ret))
+
+# Reconfigure caching server to use "dnssec-validation auto", and repeat
+# some of the DNSSEC validation tests to ensure that it works correctly.
+# Also setup a placeholder managed-keys zone to check if named can process it
+# correctly.
+echo_i "switching to automatic root key configuration"
+cp ns4/managed-keys.bind.in ns4/managed-keys.bind
+copy_setports ns4/named2.conf.in ns4/named.conf
+rndccmd 10.53.0.4 reconfig 2>&1 | sed 's/^/ns4 /' | cat_i
+sleep 5
+
+echo_i "checking managed key maintenance timer has now started ($n)"
+ret=0
+[ -f "ns4/managed-keys.bind.jnl" ] || ret=1
+n=$((n+1))
+test "$ret" -eq 0 || echo_i "failed"
+status=$((status+ret))
+
+echo_i "checking positive validation NSEC ($n)"
+ret=0
+dig_with_opts +noauth a.example. @10.53.0.2 a > dig.out.ns2.test$n || ret=1
+dig_with_opts +noauth a.example. @10.53.0.4 a > dig.out.ns4.test$n || ret=1
+digcomp dig.out.ns2.test$n dig.out.ns4.test$n || ret=1
+grep "flags:.*ad.*QUERY" dig.out.ns4.test$n > /dev/null || ret=1
+n=$((n+1))
+test "$ret" -eq 0 || echo_i "failed"
+status=$((status+ret))
+
+echo_i "checking positive validation NSEC3 ($n)"
+ret=0
+dig_with_opts +noauth a.nsec3.example. \
+ @10.53.0.3 a > dig.out.ns3.test$n || ret=1
+dig_with_opts +noauth a.nsec3.example. \
+ @10.53.0.4 a > dig.out.ns4.test$n || ret=1
+digcomp dig.out.ns3.test$n dig.out.ns4.test$n || ret=1
+grep "flags:.*ad.*QUERY" dig.out.ns4.test$n > /dev/null || ret=1
+n=$((n+1))
+test "$ret" -eq 0 || echo_i "failed"
+status=$((status+ret))
+
+echo_i "checking positive validation OPTOUT ($n)"
+ret=0
+dig_with_opts +noauth a.optout.example. \
+ @10.53.0.3 a > dig.out.ns3.test$n || ret=1
+dig_with_opts +noauth a.optout.example. \
+ @10.53.0.4 a > dig.out.ns4.test$n || ret=1
+digcomp dig.out.ns3.test$n dig.out.ns4.test$n || ret=1
+grep "flags:.*ad.*QUERY" dig.out.ns4.test$n > /dev/null || ret=1
+n=$((n+1))
+test "$ret" -eq 0 || echo_i "failed"
+status=$((status+ret))
+
+echo_i "checking negative validation ($n)"
+ret=0
+dig_with_opts +noauth q.example. @10.53.0.2 a > dig.out.ns2.test$n || ret=1
+dig_with_opts +noauth q.example. @10.53.0.4 a > dig.out.ns4.test$n || ret=1
+digcomp dig.out.ns2.test$n dig.out.ns4.test$n || ret=1
+grep "flags:.*ad.*QUERY" dig.out.ns4.test$n > /dev/null || ret=1
+grep "status: NXDOMAIN" dig.out.ns4.test$n > /dev/null || ret=1
+n=$((n+1))
+test "$ret" -eq 0 || echo_i "failed"
+status=$((status+ret))
+
+echo_i "checking that root DS queries validate ($n)"
+ret=0
+dig_with_opts +noauth . @10.53.0.1 ds > dig.out.ns1.test$n || ret=1
+dig_with_opts +noauth . @10.53.0.4 ds > dig.out.ns4.test$n || ret=1
+digcomp dig.out.ns1.test$n dig.out.ns4.test$n || ret=1
+grep "flags:.*ad.*QUERY" dig.out.ns4.test$n > /dev/null || ret=1
+grep "status: NOERROR" dig.out.ns4.test$n > /dev/null || ret=1
+n=$((n+1))
+test "$ret" -eq 0 || echo_i "failed"
+status=$((status+ret))
+
+echo_i "checking that DS at a RFC 1918 empty zone lookup succeeds ($n)"
+ret=0
+dig_with_opts +noauth 10.in-addr.arpa ds @10.53.0.2 >dig.out.ns2.test$n || ret=1
+dig_with_opts +noauth 10.in-addr.arpa ds @10.53.0.4 >dig.out.ns6.test$n || ret=1
+digcomp dig.out.ns2.test$n dig.out.ns6.test$n || ret=1
+grep "status: NOERROR" dig.out.ns6.test$n > /dev/null || ret=1
+n=$((n+1))
+test "$ret" -eq 0 || echo_i "failed"
+status=$((status+ret))
+
+echo_i "checking expired signatures remain with "'"allow-update { none; };"'" and no keys available ($n)"
+ret=0
+dig_with_opts +noauth expired.example. +dnssec @10.53.0.3 soa > dig.out.ns3.test$n || ret=1
+grep "RRSIG.SOA" dig.out.ns3.test$n > /dev/null || ret=1
+n=$((n+1))
+test "$ret" -eq 0 || echo_i "failed"
+
+status=$((status+ret))
+echo_i "checking expired signatures do not validate ($n)"
+ret=0
+dig_with_opts +noauth expired.example. +dnssec @10.53.0.4 soa > dig.out.ns4.test$n || ret=1
+grep "SERVFAIL" dig.out.ns4.test$n > /dev/null || ret=1
+grep "flags:.*ad.*QUERY" dig.out.ns4.test$n > /dev/null && ret=1
+grep "expired.example/.*: RRSIG has expired" ns4/named.run > /dev/null || ret=1
+n=$((n+1))
+test "$ret" -eq 0 || echo_i "failed"
+status=$((status+ret))
+
+echo_i "checking that the NSEC3 record for the apex is properly signed when a DNSKEY is added via UPDATE ($n)"
+ret=0
+(
+cd ns3 || exit 1
+kskname=$($KEYGEN -q -3 -a $DEFAULT_ALGORITHM -fk update-nsec3.example)
+(
+echo zone update-nsec3.example
+echo server 10.53.0.3 "$PORT"
+grep DNSKEY "${kskname}.key" | sed -e 's/^/update add /' -e 's/IN/300 IN/'
+echo send
+) | $NSUPDATE
+)
+dig_with_opts +dnssec a update-nsec3.example. @10.53.0.4 > dig.out.ns4.test$n || ret=1
+grep "NOERROR" dig.out.ns4.test$n > /dev/null || ret=1
+grep "flags:.* ad[ ;]" dig.out.ns4.test$n > /dev/null || ret=1
+grep "NSEC3 .* TYPE65534" dig.out.ns4.test$n > /dev/null || ret=1
+n=$((n+1))
+test "$ret" -eq 0 || echo_i "failed"
+status=$((status+ret))
+
+echo_i "checking that the NSEC record is properly generated when DNSKEY are added via auto-dnssec ($n)"
+ret=0
+dig_with_opts +dnssec a auto-nsec.example. @10.53.0.4 > dig.out.ns4.test$n || ret=1
+grep "NOERROR" dig.out.ns4.test$n > /dev/null || ret=1
+grep "flags:.* ad[ ;]" dig.out.ns4.test$n > /dev/null || ret=1
+grep "IN.NSEC[^3].* DNSKEY" dig.out.ns4.test$n > /dev/null || ret=1
+n=$((n+1))
+test "$ret" -eq 0 || echo_i "failed"
+status=$((status+ret))
+
+echo_i "checking that the NSEC3 record is properly generated when DNSKEY are added via auto-dnssec ($n)"
+ret=0
+dig_with_opts +dnssec a auto-nsec3.example. @10.53.0.4 > dig.out.ns4.test$n || ret=1
+grep "NOERROR" dig.out.ns4.test$n > /dev/null || ret=1
+grep "flags:.* ad[ ;]" dig.out.ns4.test$n > /dev/null || ret=1
+grep "IN.NSEC3 .* DNSKEY" dig.out.ns4.test$n > /dev/null || ret=1
+n=$((n+1))
+test "$ret" -eq 0 || echo_i "failed"
+status=$((status+ret))
+
+echo_i "checking that signing records have been marked as complete ($n)"
+ret=0
+checkprivate dynamic.example 10.53.0.3 || ret=1
+checkprivate update-nsec3.example 10.53.0.3 || ret=1
+checkprivate auto-nsec3.example 10.53.0.3 || ret=1
+checkprivate expiring.example 10.53.0.3 || ret=1
+checkprivate auto-nsec.example 10.53.0.3 || ret=1
+n=$((n+1))
+test "$ret" -eq 0 || echo_i "failed"
+status=$((status+ret))
+
+echo_i "check that 'rndc signing' without arguments is handled ($n)"
+ret=0
+rndccmd 10.53.0.3 signing > /dev/null 2>&1 && ret=1
+rndccmd 10.53.0.3 status > /dev/null || ret=1
+n=$((n+1))
+test "$ret" -eq 0 || echo_i "failed"
+status=$((status+ret))
+
+echo_i "check that 'rndc signing -list' without zone is handled ($n)"
+ret=0
+rndccmd 10.53.0.3 signing -list > /dev/null 2>&1 && ret=1
+rndccmd 10.53.0.3 status > /dev/null || ret=1
+n=$((n+1))
+test "$ret" -eq 0 || echo_i "failed"
+status=$((status+ret))
+
+echo_i "check that 'rndc signing -clear' without additional arguments is handled ($n)"
+ret=0
+rndccmd 10.53.0.3 signing -clear > /dev/null 2>&1 && ret=1
+rndccmd 10.53.0.3 status > /dev/null || ret=1
+n=$((n+1))
+test "$ret" -eq 0 || echo_i "failed"
+status=$((status+ret))
+
+echo_i "check that 'rndc signing -clear all' without zone is handled ($n)"
+ret=0
+rndccmd 10.53.0.3 signing -clear all > /dev/null 2>&1 && ret=1
+rndccmd 10.53.0.3 status > /dev/null || ret=1
+n=$((n+1))
+test "$ret" -eq 0 || echo_i "failed"
+status=$((status+ret))
+
+echo_i "check that 'rndc signing -nsec3param' without additional arguments is handled ($n)"
+ret=0
+rndccmd 10.53.0.3 signing -nsec3param > /dev/null 2>&1 && ret=1
+rndccmd 10.53.0.3 status > /dev/null || ret=1
+n=$((n+1))
+test "$ret" -eq 0 || echo_i "failed"
+status=$((status+ret))
+
+echo_i "check that 'rndc signing -nsec3param none' without zone is handled ($n)"
+ret=0
+rndccmd 10.53.0.3 signing -nsec3param none > /dev/null 2>&1 && ret=1
+rndccmd 10.53.0.3 status > /dev/null || ret=1
+n=$((n+1))
+test "$ret" -eq 0 || echo_i "failed"
+status=$((status+ret))
+
+echo_i "check that 'rndc signing -nsec3param 1' without additional arguments is handled ($n)"
+ret=0
+rndccmd 10.53.0.3 signing -nsec3param 1 > /dev/null 2>&1 && ret=1
+rndccmd 10.53.0.3 status > /dev/null || ret=1
+n=$((n+1))
+test "$ret" -eq 0 || echo_i "failed"
+status=$((status+ret))
+
+echo_i "check that 'rndc signing -nsec3param 1 0' without additional arguments is handled ($n)"
+ret=0
+rndccmd 10.53.0.3 signing -nsec3param 1 0 > /dev/null 2>&1 && ret=1
+rndccmd 10.53.0.3 status > /dev/null || ret=1
+n=$((n+1))
+test "$ret" -eq 0 || echo_i "failed"
+status=$((status+ret))
+
+echo_i "check that 'rndc signing -nsec3param 1 0 0' without additional arguments is handled ($n)"
+ret=0
+rndccmd 10.53.0.3 signing -nsec3param 1 0 0 > /dev/null 2>&1 && ret=1
+rndccmd 10.53.0.3 status > /dev/null || ret=1
+n=$((n+1))
+test "$ret" -eq 0 || echo_i "failed"
+status=$((status+ret))
+
+echo_i "check that 'rndc signing -nsec3param 1 0 0 -' without zone is handled ($n)"
+ret=0
+rndccmd 10.53.0.3 signing -nsec3param 1 0 0 - > /dev/null 2>&1 && ret=1
+rndccmd 10.53.0.3 status > /dev/null || ret=1
+n=$((n+1))
+test "$ret" -eq 0 || echo_i "failed"
+status=$((status+ret))
+
+echo_i "check that 'rndc signing -nsec3param' works with salt ($n)"
+ret=0
+rndccmd 10.53.0.3 signing -nsec3param 1 0 0 ffff inline.example > /dev/null 2>&1 || ret=1
+rndccmd 10.53.0.3 status > /dev/null || ret=1
+for i in 1 2 3 4 5 6 7 8 9 10 ; do
+ salt=$(dig_with_opts +nodnssec +short nsec3param inline.example. @10.53.0.3 | awk '{print $4}')
+ if [ "$salt" = "FFFF" ]; then
+ break;
+ fi
+ echo_i "sleeping ...."
+ sleep 1
+done;
+[ "$salt" = "FFFF" ] || ret=1
+n=$((n+1))
+test "$ret" -eq 0 || echo_i "failed"
+status=$((status+ret))
+
+echo_i "check that 'rndc signing -nsec3param' works without salt ($n)"
+ret=0
+rndccmd 10.53.0.3 signing -nsec3param 1 0 0 - inline.example > /dev/null 2>&1 || ret=1
+rndccmd 10.53.0.3 status > /dev/null || ret=1
+for i in 1 2 3 4 5 6 7 8 9 10 ; do
+ salt=$(dig_with_opts +nodnssec +short nsec3param inline.example. @10.53.0.3 | awk '{print $4}')
+ if [ "$salt" = "-" ]; then
+ break;
+ fi
+ echo_i "sleeping ...."
+ sleep 1
+done;
+[ "$salt" = "-" ] || ret=1
+n=$((n+1))
+test "$ret" -eq 0 || echo_i "failed"
+status=$((status+ret))
+
+echo_i "check that 'rndc signing -nsec3param' works with 'auto' as salt ($n)"
+ret=0
+rndccmd 10.53.0.3 signing -nsec3param 1 0 0 auto inline.example > /dev/null 2>&1 || ret=1
+rndccmd 10.53.0.3 status > /dev/null || ret=1
+for i in 1 2 3 4 5 6 7 8 9 10 ; do
+ salt=$(dig_with_opts +nodnssec +short nsec3param inline.example. @10.53.0.3 | awk '{print $4}')
+ [ -n "$salt" ] && [ "$salt" != "-" ] && break
+ echo_i "sleeping ...."
+ sleep 1
+done;
+[ "$salt" != "-" ] || ret=1
+[ "${#salt}" -eq 16 ] || ret=1
+n=$((n+1))
+test "$ret" -eq 0 || echo_i "failed"
+status=$((status+ret))
+
+echo_i "check that 'rndc signing -nsec3param' with 'auto' as salt again generates a different salt ($n)"
+ret=0
+oldsalt=$salt
+rndccmd 10.53.0.3 signing -nsec3param 1 0 0 auto inline.example > /dev/null 2>&1 || ret=1
+rndccmd 10.53.0.3 status > /dev/null || ret=1
+for i in 1 2 3 4 5 6 7 8 9 10 ; do
+ salt=$(dig_with_opts +nodnssec +short nsec3param inline.example. @10.53.0.3 | awk '{print $4}')
+ [ -n "$salt" ] && [ "$salt" != "$oldsalt" ] && break
+ echo_i "sleeping ...."
+ sleep 1
+done;
+[ "$salt" != "$oldsalt" ] || ret=1
+[ "${#salt}" -eq 16 ] || ret=1
+n=$((n+1))
+test "$ret" -eq 0 || echo_i "failed"
+status=$((status+ret))
+
+echo_i "check rndc signing -list output ($n)"
+ret=0
+{ rndccmd 10.53.0.3 signing -list dynamic.example > signing.out; } 2>&1
+grep -q "No signing records found" signing.out || {
+ ret=1
+ sed 's/^/ns3 /' signing.out | cat_i
+}
+{ rndccmd 10.53.0.3 signing -list update-nsec3.example > signing.out; } 2>&1
+grep -q "Done signing with key .*/$DEFAULT_ALGORITHM" signing.out || {
+ ret=1
+ sed 's/^/ns3 /' signing.out | cat_i
+}
+n=$((n+1))
+test "$ret" -eq 0 || echo_i "failed"
+status=$((status+ret))
+
+echo_i "clear signing records ($n)"
+{ rndccmd 10.53.0.3 signing -clear all update-nsec3.example > /dev/null; } 2>&1 || ret=1
+check_no_signing_record_found() {
+ { rndccmd 10.53.0.3 signing -list update-nsec3.example > signing.out; } 2>&1
+ grep -q "No signing records found" signing.out || {
+ sed 's/^/ns3 /' signing.out | cat_i
+ return 1
+ }
+ return 0
+}
+retry_quiet 5 check_no_signing_record_found || ret=1
+n=$((n+1))
+test "$ret" -eq 0 || echo_i "failed"
+status=$((status+ret))
+
+echo_i "checking that a insecure zone beneath a cname resolves ($n)"
+ret=0
+dig_with_opts soa insecure.below-cname.example. @10.53.0.4 > dig.out.ns4.test$n || ret=1
+grep "NOERROR" dig.out.ns4.test$n > /dev/null || ret=1
+grep "ANSWER: 1," dig.out.ns4.test$n > /dev/null || ret=1
+n=$((n+1))
+test "$ret" -eq 0 || echo_i "failed"
+status=$((status+ret))
+
+echo_i "checking that a secure zone beneath a cname resolves ($n)"
+ret=0
+dig_with_opts soa secure.below-cname.example. @10.53.0.4 > dig.out.ns4.test$n || ret=1
+grep "NOERROR" dig.out.ns4.test$n > /dev/null || ret=1
+grep "ANSWER: 2," dig.out.ns4.test$n > /dev/null || ret=1
+grep "flags:.* ad[ ;]" dig.out.ns4.test$n > /dev/null || ret=1
+n=$((n+1))
+test "$ret" -eq 0 || echo_i "failed"
+status=$((status+ret))
+
+my_dig() {
+ "$DIG" +noadd +nosea +nostat +noquest +nocomm +nocmd -p "$PORT" @10.53.0.4 "$@"
+}
+
+echo_i "checking DNSKEY query with no data still gets put in cache ($n)"
+ret=0
+firstVal=$(my_dig insecure.example. dnskey| awk '$1 != ";;" { print $2 }')
+sleep 1
+secondVal=$(my_dig insecure.example. dnskey| awk '$1 != ";;" { print $2 }')
+if [ "${firstVal:-0}" -eq "${secondVal:-0}" ]
+then
+ sleep 1
+ thirdVal=$(my_dig insecure.example. dnskey|awk '$1 != ";;" { print $2 }')
+ if [ "${firstVal:-0}" -eq "${thirdVal:-0}" ]
+ then
+ echo_i "cannot confirm query answer still in cache"
+ ret=1
+ fi
+fi
+n=$((n+1))
+test "$ret" -eq 0 || echo_i "failed"
+status=$((status+ret))
+
+echo_i "check that a split dnssec dnssec-signzone work ($n)"
+ret=0
+dig_with_opts soa split-dnssec.example. @10.53.0.4 > dig.out.ns4.test$n || ret=1
+grep "NOERROR" dig.out.ns4.test$n > /dev/null || ret=1
+grep "ANSWER: 2," dig.out.ns4.test$n > /dev/null || ret=1
+grep "flags:.* ad[ ;]" dig.out.ns4.test$n > /dev/null || ret=1
+n=$((n+1))
+test "$ret" -eq 0 || echo_i "failed"
+status=$((status+ret))
+
+echo_i "check that a smart split dnssec dnssec-signzone work ($n)"
+ret=0
+dig_with_opts soa split-smart.example. @10.53.0.4 > dig.out.ns4.test$n || ret=1
+grep "NOERROR" dig.out.ns4.test$n > /dev/null || ret=1
+grep "ANSWER: 2," dig.out.ns4.test$n > /dev/null || ret=1
+grep "flags:.* ad[ ;]" dig.out.ns4.test$n > /dev/null || ret=1
+n=$((n+1))
+test "$ret" -eq 0 || echo_i "failed"
+status=$((status+ret))
+
+echo_i "check that NOTIFY is sent at the end of NSEC3 chain generation ($n)"
+ret=0
+(
+echo zone nsec3chain-test
+echo server 10.53.0.2 "$PORT"
+echo update add nsec3chain-test. 0 nsec3param 1 0 1 123456
+echo send
+) | $NSUPDATE
+for i in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
+do
+ dig_with_opts nsec3param nsec3chain-test @10.53.0.2 > dig.out.ns2.test$n || ret=1
+ if grep "ANSWER: 3," dig.out.ns2.test$n >/dev/null
+ then
+ break;
+ fi
+ echo_i "sleeping ...."
+ sleep 3
+done
+grep "ANSWER: 3," dig.out.ns2.test$n > /dev/null || ret=1
+if [ "$ret" -ne 0 ]; then echo_i "nsec3 chain generation not complete"; fi
+dig_with_opts +noauth +nodnssec soa nsec3chain-test @10.53.0.2 > dig.out.ns2.test$n || ret=1
+s2=$(awk '$4 == "SOA" { print $7}' dig.out.ns2.test$n)
+for i in 1 2 3 4 5 6 7 8 9 10
+do
+ dig_with_opts +noauth +nodnssec soa nsec3chain-test @10.53.0.3 > dig.out.ns3.test$n || ret=1
+ s3=$(awk '$4 == "SOA" { print $7}' dig.out.ns3.test$n)
+ test "$s2" = "$s3" && break
+ sleep 1
+done
+digcomp dig.out.ns2.test$n dig.out.ns3.test$n || ret=1
+n=$((n+1))
+test "$ret" -eq 0 || echo_i "failed"
+status=$((status+ret))
+
+echo_i "check dnssec-dsfromkey from stdin ($n)"
+ret=0
+dig_with_opts dnskey algroll. @10.53.0.2 | \
+ $DSFROMKEY -f - algroll. > dig.out.ns2.test$n || ret=1
+NF=$(awk '{print NF}' dig.out.ns2.test$n | sort -u)
+[ "${NF}" = 7 ] || ret=1
+# make canonical
+awk '{
+ for (i=1;i<7;i++) printf("%s ", $i);
+ for (i=7;i<=NF;i++) printf("%s", $i);
+ printf("\n");
+}' < dig.out.ns2.test$n > canonical1.$n || ret=1
+awk '{
+ for (i=1;i<7;i++) printf("%s ", $i);
+ for (i=7;i<=NF;i++) printf("%s", $i);
+ printf("\n");
+}' < ns1/dsset-algroll. > canonical2.$n || ret=1
+diff -b canonical1.$n canonical2.$n > /dev/null 2>&1 || ret=1
+n=$((n+1))
+test "$ret" -eq 0 || echo_i "failed"
+status=$((status+ret))
+
+# Intentionally strip ".key" from keyfile name to ensure the error message
+# includes it anyway to avoid confusion (RT #21731)
+echo_i "check dnssec-dsfromkey error message when keyfile is not found ($n)"
+ret=0
+key=$($KEYGEN -a $DEFAULT_ALGORITHM -q example.) || ret=1
+mv "$key.key" "$key"
+$DSFROMKEY "$key" > dsfromkey.out.$n 2>&1 && ret=1
+grep "$key.key: file not found" dsfromkey.out.$n > /dev/null || ret=1
+n=$((n+1))
+test "$ret" -eq 0 || echo_i "failed"
+status=$((status+ret))
+
+echo_i "check dnssec-dsfromkey with revoked key ($n)"
+ret=0
+dig_with_opts revkey.example dnskey @10.53.0.4 > dig.out.ns4.test$n || ret=1
+grep "DNSKEY.256 3 13" dig.out.ns4.test$n > /dev/null || ret=1 # ZSK
+grep "DNSKEY.385 3 13" dig.out.ns4.test$n > /dev/null || ret=1 # revoked KSK
+grep "DNSKEY.257 3 13" dig.out.ns4.test$n > /dev/null || ret=1 # KSK
+test $(awk '$4 == "DNSKEY" { print }' dig.out.ns4.test$n | wc -l) -eq 3 || ret=1
+$DSFROMKEY -f dig.out.ns4.test$n revkey.example. > dsfromkey.out.test$n || ret=1
+test $(wc -l < dsfromkey.out.test$n) -eq 1 || ret=1
+n=$((n+1))
+test "$ret" -eq 0 || echo_i "failed"
+
+echo_i "testing soon-to-expire RRSIGs without a replacement private key ($n)"
+ret=0
+dig_with_answeropts +nottlid expiring.example ns @10.53.0.3 | grep RRSIG > dig.out.ns3.test$n 2>&1
+# there must be a signature here
+[ -s dig.out.ns3.test$n ] || ret=1
+n=$((n+1))
+test "$ret" -eq 0 || echo_i "failed"
+status=$((status+ret))
+
+echo_i "testing new records are signed with 'no-resign' ($n)"
+ret=0
+(
+echo zone nosign.example
+echo server 10.53.0.3 "$PORT"
+echo update add new.nosign.example 300 in txt "hi there"
+echo send
+) | $NSUPDATE
+sleep 1
+dig_with_answeropts +nottlid txt new.nosign.example @10.53.0.3 \
+ > dig.out.ns3.test$n 2>&1
+grep RRSIG dig.out.ns3.test$n > /dev/null 2>&1 || ret=1
+n=$((n+1))
+test "$ret" -eq 0 || echo_i "failed"
+status=$((status+ret))
+
+echo_i "testing expiring records aren't resigned with 'no-resign' ($n)"
+ret=0
+dig_with_answeropts +nottlid nosign.example ns @10.53.0.3 | \
+ grep RRSIG | sed 's/[ ][ ]*/ /g' > dig.out.ns3.test$n 2>&1
+# the NS RRSIG should not be changed
+diff nosign.before dig.out.ns3.test$n > /dev/null|| ret=1
+n=$((n+1))
+test "$ret" -eq 0 || echo_i "failed"
+status=$((status+ret))
+
+echo_i "testing updates fail with no private key ($n)"
+ret=0
+rm -f ns3/Knosign.example.*.private
+(
+echo zone nosign.example
+echo server 10.53.0.3 "$PORT"
+echo update add fail.nosign.example 300 in txt "reject me"
+echo send
+) | $NSUPDATE > /dev/null 2>&1 && ret=1
+dig_with_answeropts +nottlid fail.nosign.example txt @10.53.0.3 \
+ > dig.out.ns3.test$n 2>&1
+[ -s dig.out.ns3.test$n ] && ret=1
+n=$((n+1))
+test "$ret" -eq 0 || echo_i "failed"
+status=$((status+ret))
+
+echo_i "testing legacy upper case signer name validation ($n)"
+ret=0
+$DIG +tcp +noadd +noauth +dnssec -p "$PORT" soa upper.example @10.53.0.4 \
+ > dig.out.ns4.test$n 2>&1 || ret=1
+grep "flags:.* ad;" dig.out.ns4.test$n > /dev/null || ret=1
+grep "RRSIG.*SOA.* UPPER\\.EXAMPLE\\. " dig.out.ns4.test$n > /dev/null || ret=1
+n=$((n+1))
+test "$ret" -eq 0 || echo_i "failed"
+status=$((status+ret))
+
+echo_i "testing that we lower case signer name ($n)"
+ret=0
+$DIG +tcp +noadd +noauth +dnssec -p "$PORT" soa LOWER.EXAMPLE @10.53.0.4 \
+ > dig.out.ns4.test$n 2>&1 || ret=1
+grep "flags:.* ad;" dig.out.ns4.test$n > /dev/null || ret=1
+grep "RRSIG.*SOA.* lower\\.example\\. " dig.out.ns4.test$n > /dev/null || ret=1
+n=$((n+1))
+test "$ret" -eq 0 || echo_i "failed"
+status=$((status+ret))
+
+echo_i "testing TTL is capped at RRSIG expiry time ($n)"
+ret=0
+rndccmd 10.53.0.3 freeze expiring.example 2>&1 | sed 's/^/ns3 /' | cat_i
+(
+cd ns3 || exit 1
+for file in K*.moved; do
+ mv "$file" "$(basename "$file" .moved)"
+done
+$SIGNER -S -N increment -e now+1mi -o expiring.example expiring.example.db > /dev/null
+) || ret=1
+rndc_reload ns3 10.53.0.3 expiring.example
+
+rndccmd 10.53.0.4 flush 2>&1 | sed 's/^/ns4 /' | cat_i
+dig_with_answeropts +cd expiring.example soa @10.53.0.4 > dig.out.ns4.1.$n
+dig_with_answeropts expiring.example soa @10.53.0.4 > dig.out.ns4.2.$n
+ttls=$(awk '$1 != ";;" {print $2}' dig.out.ns4.1.$n)
+ttls2=$(awk '$1 != ";;" {print $2}' dig.out.ns4.2.$n)
+for ttl in ${ttls:-0}; do
+ [ "${ttl}" -eq 300 ] || ret=1
+done
+for ttl in ${ttls2:-0}; do
+ [ "${ttl}" -le 60 ] || ret=1
+done
+n=$((n+1))
+test "$ret" -eq 0 || echo_i "failed"
+status=$((status+ret))
+
+echo_i "testing TTL is capped at RRSIG expiry time for records in the additional section (NS) ($n)"
+ret=0
+rndccmd 10.53.0.4 flush 2>&1 | sed 's/^/ns4 /' | cat_i
+sleep 1
+dig_with_additionalopts +cd expiring.example ns @10.53.0.4 > dig.out.ns4.1.$n
+dig_with_additionalopts expiring.example ns @10.53.0.4 > dig.out.ns4.2.$n
+ttls=$(awk '$1 != ";;" {print $2}' dig.out.ns4.1.$n)
+ttls2=$(awk '$1 != ";;" {print $2}' dig.out.ns4.2.$n)
+for ttl in ${ttls:-300}; do
+ [ "$ttl" -le 300 ] && [ "$ttl" -gt 240 ] || ret=1
+done
+for ttl in ${ttls2:-0}; do
+ [ "$ttl" -le 60 ] || ret=1
+done
+n=$((n+1))
+test "$ret" -eq 0 || echo_i "failed"
+status=$((status+ret))
+
+echo_i "testing TTL is capped at RRSIG expiry time for records in the additional section (MX) ($n)"
+ret=0
+rndccmd 10.53.0.4 flush 2>&1 | sed 's/^/ns4 /' | cat_i
+sleep 1
+dig_with_additionalopts +cd expiring.example mx @10.53.0.4 > dig.out.ns4.1.$n
+dig_with_additionalopts expiring.example mx @10.53.0.4 > dig.out.ns4.2.$n
+ttls=$(awk '$1 != ";;" {print $2}' dig.out.ns4.1.$n)
+ttls2=$(awk '$1 != ";;" {print $2}' dig.out.ns4.2.$n)
+for ttl in ${ttls:-300}; do
+ [ "$ttl" -le 300 ] && [ "$ttl" -gt 240 ] || ret=1
+done
+for ttl in ${ttls2:-0}; do
+ [ "$ttl" -le 60 ] || ret=1
+done
+n=$((n+1))
+test "$ret" -eq 0 || echo_i "failed"
+status=$((status+ret))
+
+copy_setports ns4/named3.conf.in ns4/named.conf
+rndccmd 10.53.0.4 reconfig 2>&1 | sed 's/^/ns4 /' | cat_i
+sleep 3
+
+echo_i "testing TTL of about to expire RRsets with dnssec-accept-expired yes; ($n)"
+ret=0
+rndccmd 10.53.0.4 flush 2>&1 | sed 's/^/ns4 /' | cat_i
+dig_with_answeropts +cd expiring.example soa @10.53.0.4 > dig.out.ns4.1.$n
+dig_with_answeropts expiring.example soa @10.53.0.4 > dig.out.ns4.2.$n
+ttls=$(awk '$1 != ";;" {print $2}' dig.out.ns4.1.$n)
+ttls2=$(awk '$1 != ";;" {print $2}' dig.out.ns4.2.$n)
+for ttl in ${ttls:-0}; do
+ [ "$ttl" -eq 300 ] || ret=1
+done
+for ttl in ${ttls2:-0}; do
+ [ "$ttl" -eq 120 ] || ret=1
+done
+n=$((n+1))
+test "$ret" -eq 0 || echo_i "failed"
+status=$((status+ret))
+
+echo_i "testing TTL of expired RRsets with dnssec-accept-expired yes; ($n)"
+ret=0
+dig_with_answeropts +cd expired.example soa @10.53.0.4 > dig.out.ns4.1.$n
+dig_with_answeropts expired.example soa @10.53.0.4 > dig.out.ns4.2.$n
+ttls=$(awk '$1 != ";;" {print $2}' dig.out.ns4.1.$n)
+ttls2=$(awk '$1 != ";;" {print $2}' dig.out.ns4.2.$n)
+for ttl in ${ttls:-0}; do
+ [ "$ttl" -eq 300 ] || ret=1
+done
+for ttl in ${ttls2:-0}; do
+ [ "$ttl" -eq 120 ] || ret=1
+done
+n=$((n+1))
+test "$ret" -eq 0 || echo_i "failed"
+status=$((status+ret))
+
+echo_i "testing TTL is capped at RRSIG expiry time for records in the additional section with dnssec-accept-expired yes; ($n)"
+ret=0
+rndccmd 10.53.0.4 flush 2>&1 | sed 's/^/ns4 /' | cat_i
+dig_with_additionalopts +cd expiring.example mx @10.53.0.4 > dig.out.ns4.1.$n
+dig_with_additionalopts expiring.example mx @10.53.0.4 > dig.out.ns4.2.$n
+ttls=$(awk '$1 != ";;" {print $2}' dig.out.ns4.1.$n)
+ttls2=$(awk '$1 != ";;" {print $2}' dig.out.ns4.2.$n)
+for ttl in ${ttls:-300}; do
+ [ "$ttl" -le 300 ] && [ "$ttl" -gt 240 ] || ret=1
+done
+for ttl in ${ttls2:-0}; do
+ [ "$ttl" -le 120 ] && [ "$ttl" -gt 60 ] || ret=1
+done
+n=$((n+1))
+test "$ret" -eq 0 || echo_i "failed"
+status=$((status+ret))
+
+echo_i "testing DNSKEY lookup via CNAME ($n)"
+ret=0
+dig_with_opts +noauth cnameandkey.secure.example. \
+ @10.53.0.3 dnskey > dig.out.ns3.test$n || ret=1
+dig_with_opts +noauth cnameandkey.secure.example. \
+ @10.53.0.4 dnskey > dig.out.ns4.test$n || ret=1
+digcomp dig.out.ns3.test$n dig.out.ns4.test$n || ret=1
+grep "flags:.*ad.*QUERY" dig.out.ns4.test$n > /dev/null || ret=1
+grep "CNAME" dig.out.ns4.test$n > /dev/null || ret=1
+n=$((n+1))
+test "$ret" -eq 0 || echo_i "failed"
+status=$((status+ret))
+
+echo_i "testing KEY lookup at CNAME (present) ($n)"
+ret=0
+dig_with_opts +noauth cnameandkey.secure.example. \
+ @10.53.0.3 key > dig.out.ns3.test$n || ret=1
+dig_with_opts +noauth cnameandkey.secure.example. \
+ @10.53.0.4 key > dig.out.ns4.test$n || ret=1
+digcomp dig.out.ns3.test$n dig.out.ns4.test$n || ret=1
+grep "flags:.*ad.*QUERY" dig.out.ns4.test$n > /dev/null || ret=1
+grep "CNAME" dig.out.ns4.test$n > /dev/null && ret=1
+n=$((n+1))
+test "$ret" -eq 0 || echo_i "failed"
+status=$((status+ret))
+
+echo_i "testing KEY lookup at CNAME (not present) ($n)"
+ret=0
+dig_with_opts +noauth cnamenokey.secure.example. \
+ @10.53.0.3 key > dig.out.ns3.test$n || ret=1
+dig_with_opts +noauth cnamenokey.secure.example. \
+ @10.53.0.4 key > dig.out.ns4.test$n || ret=1
+digcomp dig.out.ns3.test$n dig.out.ns4.test$n || ret=1
+grep "flags:.*ad.*QUERY" dig.out.ns4.test$n > /dev/null || ret=1
+grep "CNAME" dig.out.ns4.test$n > /dev/null && ret=1
+n=$((n+1))
+test "$ret" -eq 0 || echo_i "failed"
+status=$((status+ret))
+
+echo_i "testing DNSKEY lookup via DNAME ($n)"
+ret=0
+dig_with_opts a.dnameandkey.secure.example. \
+ @10.53.0.3 dnskey > dig.out.ns3.test$n || ret=1
+dig_with_opts a.dnameandkey.secure.example. \
+ @10.53.0.4 dnskey > dig.out.ns4.test$n || ret=1
+digcomp dig.out.ns3.test$n dig.out.ns4.test$n || ret=1
+grep "flags:.*ad.*QUERY" dig.out.ns4.test$n > /dev/null || ret=1
+grep "CNAME" dig.out.ns4.test$n > /dev/null || ret=1
+grep "DNAME" dig.out.ns4.test$n > /dev/null || ret=1
+n=$((n+1))
+test "$ret" -eq 0 || echo_i "failed"
+status=$((status+ret))
+
+echo_i "testing KEY lookup via DNAME ($n)"
+ret=0
+dig_with_opts b.dnameandkey.secure.example. \
+ @10.53.0.3 key > dig.out.ns3.test$n || ret=1
+dig_with_opts b.dnameandkey.secure.example. \
+ @10.53.0.4 key > dig.out.ns4.test$n || ret=1
+digcomp dig.out.ns3.test$n dig.out.ns4.test$n || ret=1
+grep "flags:.*ad.*QUERY" dig.out.ns4.test$n > /dev/null || ret=1
+grep "DNAME" dig.out.ns4.test$n > /dev/null || ret=1
+n=$((n+1))
+test "$ret" -eq 0 || echo_i "failed"
+status=$((status+ret))
+
+echo_i "check that named doesn't loop when all private keys are not available ($n)"
+ret=0
+lines=$(grep -c "reading private key file expiring.example" ns3/named.run || true)
+test "${lines:-1000}" -lt 15 || ret=1
+n=$((n+1))
+test "$ret" -eq 0 || echo_i "failed"
+status=$((status+ret))
+
+echo_i "check against against missing nearest provable proof ($n)"
+dig_with_opts +norec b.c.d.optout-tld. \
+ @10.53.0.6 ds > dig.out.ds.ns6.test$n || ret=1
+nsec3=$(grep -c "IN.NSEC3" dig.out.ds.ns6.test$n || true)
+[ "$nsec3" -eq 2 ] || ret=1
+dig_with_opts +norec b.c.d.optout-tld. \
+ @10.53.0.6 A > dig.out.ns6.test$n || ret=1
+nsec3=$(grep -c "IN.NSEC3" dig.out.ns6.test$n || true)
+[ "$nsec3" -eq 1 ] || ret=1
+dig_with_opts optout-tld. \
+ @10.53.0.4 SOA > dig.out.soa.ns4.test$n || ret=1
+grep "flags:.*ad.*QUERY" dig.out.soa.ns4.test$n > /dev/null || ret=1
+dig_with_opts b.c.d.optout-tld. \
+ @10.53.0.4 A > dig.out.ns4.test$n || ret=1
+grep "status: NOERROR" dig.out.ns4.test$n > /dev/null || ret=1
+grep "flags:.*ad.*QUERY" dig.out.ns4.test$n > /dev/null && ret=1
+n=$((n+1))
+test "$ret" -eq 0 || echo_i "failed"
+status=$((status+ret))
+
+echo_i "check that key id are logged when dumping the cache ($n)"
+ret=0
+rndc_dumpdb ns4
+grep "; key id = " ns4/named_dump.db.test$n > /dev/null || ret=1
+n=$((n+1))
+test "$ret" -eq 0 || echo_i "failed"
+status=$((status+ret))
+
+echo_i "check KEYDATA records are printed in human readable form in key zone ($n)"
+# force the managed-keys zone to be written out
+rndccmd 10.53.0.4 managed-keys sync 2>&1 | sed 's/^/ns4 /' | cat_i
+for i in 1 2 3 4 5 6 7 8 9
+do
+ ret=0
+ if test -f ns4/managed-keys.bind
+ then
+ grep KEYDATA ns4/managed-keys.bind > /dev/null &&
+ grep "next refresh:" ns4/managed-keys.bind > /dev/null &&
+ break
+ fi
+ ret=1
+ sleep 1
+done
+n=$((n+1))
+test "$ret" -eq 0 || echo_i "failed"
+status=$((status+ret))
+
+echo_i "check dig's +nocrypto flag ($n)"
+ret=0
+dig_with_opts +norec +nocrypto DNSKEY . \
+ @10.53.0.1 > dig.out.dnskey.ns1.test$n || ret=1
+grep -E "256 [0-9]+ $DEFAULT_ALGORITHM_NUMBER \\[key id = [1-9][0-9]*]" dig.out.dnskey.ns1.test$n > /dev/null || ret=1
+grep -E "RRSIG.* \\[omitted]" dig.out.dnskey.ns1.test$n > /dev/null || ret=1
+dig_with_opts +norec +nocrypto DS example \
+ @10.53.0.1 > dig.out.ds.ns1.test$n || ret=1
+grep -E "DS.* [0-9]+ [12] \[omitted]" dig.out.ds.ns1.test$n > /dev/null || ret=1
+n=$((n+1))
+test "$ret" -eq 0 || echo_i "failed"
+status=$((status+ret))
+
+echo_i "check simultaneous inactivation and publishing of dnskeys removes inactive signature ($n)"
+ret=0
+cnt=0
+while :
+do
+dig_with_opts publish-inactive.example @10.53.0.3 dnskey > dig.out.ns3.test$n
+keys=$(awk '$5 == 257 { print; }' dig.out.ns3.test$n | wc -l)
+test "$keys" -gt 2 && break
+cnt=$((cnt+1))
+test "$cnt" -gt 120 && break
+sleep 1
+done
+test "$keys" -gt 2 || ret=1
+sigs=$(grep -c RRSIG dig.out.ns3.test$n || true)
+n=$((n+1))
+test "$sigs" -eq 2 || ret=1
+if test "$ret" -ne 0 ; then echo_i "failed"; fi
+status=$((status+ret))
+
+echo_i "check that increasing the sig-validity-interval resigning triggers re-signing ($n)"
+ret=0
+before=$($DIG axfr siginterval.example -p "$PORT" @10.53.0.3 | grep RRSIG.SOA)
+cp ns3/siginterval2.conf ns3/siginterval.conf
+rndccmd 10.53.0.3 reconfig 2>&1 | sed 's/^/ns3 /' | cat_i
+i=10
+while [ "$i" -ge 0 ]; do
+after=$($DIG axfr siginterval.example -p "$PORT" @10.53.0.3 | grep RRSIG.SOA)
+test "$before" != "$after" && break
+sleep 1
+i=$((i-1))
+done
+n=$((n+1))
+if test "$before" = "$after" ; then echo_i "failed"; ret=1; fi
+status=$((status+ret))
+
+if [ -x "$PYTHON" ]; then
+ echo_i "check dnskey-sig-validity sets longer expiry for DNSKEY ($n)"
+ ret=0
+ rndccmd 10.53.0.3 sign siginterval.example 2>&1 | sed 's/^/ns3 /' | cat_i
+ # convert expiry date to a comma-separated list of integers python can
+ # use as input to date(). strip leading 0s in months and days so
+ # python3 will recognize them as integers.
+ $DIG +dnssec +short -p "$PORT" @10.53.0.3 soa siginterval.example > dig.out.soa.test$n || ret=1
+ soaexpire=$(awk '$1 ~ /SOA/ { print $5 }' dig.out.soa.test$n |
+ sed 's/\(....\)\(..\)\(..\).*/\1, \2, \3/' |
+ sed 's/ 0/ /g')
+ $DIG +dnssec +short -p "$PORT" @10.53.0.3 dnskey siginterval.example > dig.out.dnskey.test$n || ret=1
+ dnskeyexpire=$(awk '$1 ~ /DNSKEY/ { print $5; exit 0 }' dig.out.dnskey.test$n |
+ sed 's/\(....\)\(..\)\(..\).*/\1, \2, \3/' |
+ sed 's/ 0/ /g')
+ $PYTHON > python.out.$n <<EOF
+from datetime import date;
+ke=date($dnskeyexpire)
+se=date($soaexpire)
+print((ke-se).days);
+EOF
+ diff=$(cat python.out.$n)
+ [ "$diff" -ge 55 ] || ret=1
+ n=$((n+1))
+ test "$ret" -eq 0 || echo_i "failed"
+ status=$((status+ret))
+fi
+
+copy_setports ns4/named4.conf.in ns4/named.conf
+rndccmd 10.53.0.4 reconfig 2>&1 | sed 's/^/ns4 /' | cat_i
+sleep 3
+
+echo_i "check insecure delegation between static-stub zones ($n)"
+ret=0
+dig_with_opts ns insecure.secure.example \
+ @10.53.0.4 > dig.out.ns4.1.test$n || ret=1
+grep "SERVFAIL" dig.out.ns4.1.test$n > /dev/null && ret=1
+dig_with_opts ns secure.example \
+ @10.53.0.4 > dig.out.ns4.2.test$n || ret=1
+grep "SERVFAIL" dig.out.ns4.2.test$n > /dev/null && ret=1
+n=$((n+1))
+test "$ret" -eq 0 || echo_i "failed"
+status=$((status+ret))
+
+echo_i "check the acceptance of seconds as inception and expiration times ($n)"
+ret=0
+in="NSEC 8 0 86400 1390003200 1389394800 33655 . NYWjZYBV1b+h4j0yu/SmPOOylR8P4IXKDzHX3NwEmU1SUp27aJ91dP+i+UBcnPmBib0hck4DrFVvpflCEpCnVQd2DexcN0GX+3PM7XobxhtDlmnU X1L47zJlbdHNwTqHuPaMM6Xy9HGMXps7O5JVyfggVhTz2C+G5OVxBdb2rOo="
+
+exp="NSEC 8 0 86400 20140118000000 20140110230000 33655 . NYWjZYBV1b+h4j0yu/SmPOOylR8P4IXKDzHX3NwEmU1SUp27aJ91dP+i +UBcnPmBib0hck4DrFVvpflCEpCnVQd2DexcN0GX+3PM7XobxhtDlmnU X1L47zJlbdHNwTqHuPaMM6Xy9HGMXps7O5JVyfggVhTz2C+G5OVxBdb2 rOo="
+
+out=$(echo "IN RRSIG $in" | $RRCHECKER -p | sed 's/^IN.RRSIG.//')
+[ "$out" = "$exp" ] || ret=1
+n=$((n+1))
+test "$ret" -eq 0 || echo_i "failed"
+status=$((status+ret))
+
+echo_i "check the correct resigning time is reported in zonestatus ($n)"
+ret=0
+rndccmd 10.53.0.3 \
+ zonestatus secure.example > rndc.out.ns3.test$n
+# next resign node: secure.example/DNSKEY
+qname=$(awk '/next resign node:/ { print $4 }' rndc.out.ns3.test$n | sed 's,/.*,,')
+qtype=$(awk '/next resign node:/ { print $4 }' rndc.out.ns3.test$n | sed 's,.*/,,')
+# next resign time: Thu, 24 Apr 2014 10:38:16 GMT
+time=$(awk 'BEGIN { m["Jan"] = "01"; m["Feb"] = "02"; m["Mar"] = "03";
+ m["Apr"] = "04"; m["May"] = "05"; m["Jun"] = "06";
+ m["Jul"] = "07"; m["Aug"] = "08"; m["Sep"] = "09";
+ m["Oct"] = "10"; m["Nov"] = "11"; m["Dec"] = "12";}
+ /next resign time:/ { printf "%d%s%02d%s\n", $7, m[$6], $5, $8 }' rndc.out.ns3.test$n | sed 's/://g')
+dig_with_opts +noall +answer "$qname" "$qtype" @10.53.0.3 > dig.out.test$n
+expire=$(awk '$4 == "RRSIG" { print $9 }' dig.out.test$n)
+inception=$(awk '$4 == "RRSIG" { print $10 }' dig.out.test$n)
+$PERL -e 'exit(0) if ("'"$time"'" lt "'"$expire"'" && "'"$time"'" gt "'"$inception"'"); exit(1);' || ret=1
+n=$((n+1))
+test "$ret" -eq 0 || echo_i "failed"
+status=$((status+ret))
+
+echo_i "check that split rrsigs are handled ($n)"
+ret=0
+dig_with_opts split-rrsig soa @10.53.0.7 > dig.out.test$n || ret=1
+awk 'BEGIN { ok=0; } $4 == "SOA" { if ($7 > 1) ok=1; } END { if (!ok) exit(1); }' dig.out.test$n || ret=1
+n=$((n+1))
+test "$ret" -eq 0 || echo_i "failed"
+status=$((status+ret))
+
+echo_i "check that not-at-zone-apex RRSIG(SOA) RRsets are removed from the zone after load ($n)"
+ret=0
+dig_with_opts split-rrsig AXFR @10.53.0.7 > dig.out.test$n || ret=1
+grep -q "not-at-zone-apex.*RRSIG.*SOA" dig.out.test$n && ret=1
+n=$((n+1))
+test "$ret" -eq 0 || echo_i "failed"
+status=$((status+ret))
+
+echo_i "check that 'dnssec-keygen -S' works for all supported algorithms ($n)"
+ret=0
+alg=1
+until test $alg -eq 256
+do
+ zone="keygen-$alg."
+ case $alg in
+ 2) # Diffie Helman
+ alg=$((alg+1))
+ continue;;
+ 157|160|161|162|163|164|165) # private - non standard
+ alg=$((alg+1))
+ continue;;
+ 1|5|7|8|10) # RSA algorithms
+ key1=$($KEYGEN -a "$alg" -b "1024" -n zone "$zone" 2> "keygen-$alg.err" || true)
+ ;;
+ 15|16)
+ key1=$($KEYGEN -a "$alg" -n zone "$zone" 2> "keygen-$alg.err" || true)
+ ;;
+ *)
+ key1=$($KEYGEN -a "$alg" -n zone "$zone" 2> "keygen-$alg.err" || true)
+ esac
+ if grep "unsupported algorithm" "keygen-$alg.err" > /dev/null
+ then
+ alg=$((alg+1))
+ continue
+ fi
+ if test -z "$key1"
+ then
+ echo_i "'$KEYGEN -a $alg': failed"
+ cat "keygen-$alg.err"
+ ret=1
+ alg=$((alg+1))
+ continue
+ fi
+ $SETTIME -I now+4d "$key1.private" > /dev/null
+ key2=$($KEYGEN -v 10 -i 3d -S "$key1.private" 2> /dev/null)
+ test -f "$key2.key" -a -f "$key2.private" || {
+ ret=1
+ echo_i "'dnssec-keygen -S' failed for algorithm: $alg"
+ }
+ alg=$((alg+1))
+done
+n=$((n+1))
+test "$ret" -eq 0 || echo_i "failed"
+status=$((status+ret))
+
+echo_i "check that CDS records are signed using KSK by dnssec-signzone ($n)"
+ret=0
+dig_with_opts +noall +answer @10.53.0.2 cds cds.secure > dig.out.test$n
+lines=$(awk '$4 == "RRSIG" && $5 == "CDS" {print}' dig.out.test$n | wc -l)
+test "$lines" -eq 2 || ret=1
+n=$((n+1))
+test "$ret" -eq 0 || echo_i "failed"
+status=$((status+ret))
+
+echo_i "check that CDS records are not signed using ZSK by dnssec-signzone -x ($n)"
+ret=0
+dig_with_opts +noall +answer @10.53.0.2 cds cds-x.secure > dig.out.test$n
+lines=$(awk '$4 == "RRSIG" && $5 == "CDS" {print}' dig.out.test$n | wc -l)
+test "$lines" -eq 2 || ret=1
+n=$((n+1))
+test "$ret" -eq 0 || echo_i "failed"
+status=$((status+ret))
+
+echo_i "checking that positive unknown NSEC3 hash algorithm does validate ($n)"
+ret=0
+dig_with_opts +noauth +noadd +nodnssec +adflag @10.53.0.3 nsec3-unknown.example SOA > dig.out.ns3.test$n
+dig_with_opts +noauth +noadd +nodnssec +adflag @10.53.0.4 nsec3-unknown.example SOA > dig.out.ns4.test$n
+grep "status: NOERROR," dig.out.ns3.test$n > /dev/null || ret=1
+grep "status: NOERROR," dig.out.ns4.test$n > /dev/null || ret=1
+grep "flags:.*ad.*QUERY" dig.out.ns4.test$n > /dev/null || ret=1
+grep "ANSWER: 1," dig.out.ns4.test$n > /dev/null || ret=1
+n=$((n+1))
+test "$ret" -eq 0 || echo_i "failed"
+status=$((status+ret))
+
+echo_i "check that CDS records are signed using KSK by with dnssec-auto ($n)"
+ret=0
+dig_with_opts +noall +answer @10.53.0.2 cds cds-auto.secure > dig.out.test$n
+lines=$(awk '$4 == "RRSIG" && $5 == "CDS" {print}' dig.out.test$n | wc -l)
+test "$lines" -eq 2 || ret=1
+n=$((n+1))
+test "$ret" -eq 0 || echo_i "failed"
+status=$((status+ret))
+
+echo_i "check that a CDS deletion record is accepted ($n)"
+ret=0
+(
+echo zone cds-update.secure
+echo server 10.53.0.2 "$PORT"
+echo update delete cds-update.secure CDS
+echo update add cds-update.secure 0 CDS 0 0 0 00
+echo send
+) | $NSUPDATE > nsupdate.out.test$n 2>&1
+dig_with_opts +noall +answer @10.53.0.2 cds cds-update.secure > dig.out.test$n
+lines=$(awk '$4 == "CDS" {print}' dig.out.test$n | wc -l)
+test "${lines:-10}" -eq 1 || ret=1
+lines=$(awk '$4 == "CDS" && $5 == "0" && $6 == "0" && $7 == "0" && $8 == "00" {print}' dig.out.test$n | wc -l)
+test "$lines" -eq 1 || ret=1
+n=$((n+1))
+test "$ret" -eq 0 || echo_i "failed"
+status=$((status+ret))
+
+echo_i "check that CDS records are signed using KSK when added by nsupdate ($n)"
+ret=0
+(
+echo zone cds-update.secure
+echo server 10.53.0.2 "$PORT"
+echo update delete cds-update.secure CDS
+echo send
+dig_with_opts +noall +answer @10.53.0.2 dnskey cds-update.secure |
+grep "DNSKEY.257" |
+$DSFROMKEY -12 -C -f - -T 1 cds-update.secure |
+sed "s/^/update add /"
+echo send
+) | $NSUPDATE
+dig_with_opts +noall +answer @10.53.0.2 cds cds-update.secure > dig.out.test$n
+lines=$(awk '$4 == "RRSIG" && $5 == "CDS" {print}' dig.out.test$n | wc -l)
+test "$lines" -eq 2 || ret=1
+lines=$(awk '$4 == "CDS" {print}' dig.out.test$n | wc -l)
+test "$lines" -eq 2 || ret=1
+n=$((n+1))
+test "$ret" -eq 0 || echo_i "failed"
+status=$((status+ret))
+
+echo_i "check that CDS records are signed only using KSK when added by"
+echo_ic "nsupdate when dnssec-dnskey-kskonly is yes ($n)"
+ret=0
+keyid=$(cat ns2/cds-kskonly.secure.id)
+(
+echo zone cds-kskonly.secure
+echo server 10.53.0.2 "$PORT"
+echo update delete cds-kskonly.secure CDS
+echo send
+dig_with_opts +noall +answer @10.53.0.2 dnskey cds-kskonly.secure |
+grep "DNSKEY.257" |
+$DSFROMKEY -12 -C -f - -T 1 cds-kskonly.secure |
+sed "s/^/update add /"
+echo send
+) | $NSUPDATE
+dig_with_opts +noall +answer @10.53.0.2 cds cds-kskonly.secure > dig.out.test$n
+lines=$(awk '$4 == "RRSIG" && $5 == "CDS" {print}' dig.out.test$n | wc -l)
+test "$lines" -eq 1 || ret=1
+lines=$(awk -v id="${keyid}" '$4 == "RRSIG" && $5 == "CDS" && $11 == id {print}' dig.out.test$n | wc -l)
+test "$lines" -eq 1 || ret=1
+lines=$(awk '$4 == "CDS" {print}' dig.out.test$n | wc -l)
+test "$lines" -eq 2 || ret=1
+n=$((n+1))
+test "$ret" -eq 0 || echo_i "failed"
+status=$((status+ret))
+
+echo_i "check that CDS deletion records are signed only using KSK when added by"
+echo_ic "nsupdate when dnssec-dnskey-kskonly is yes ($n)"
+ret=0
+keyid=$(cat ns2/cds-kskonly.secure.id)
+(
+echo zone cds-kskonly.secure
+echo server 10.53.0.2 "$PORT"
+echo update delete cds-kskonly.secure CDS
+echo update add cds-kskonly.secure 0 CDS 0 0 0 00
+echo send
+) | $NSUPDATE
+dig_with_opts +noall +answer @10.53.0.2 cds cds-kskonly.secure > dig.out.test$n
+lines=$(awk '$4 == "RRSIG" && $5 == "CDS" {print}' dig.out.test$n | wc -l)
+test "$lines" -eq 1 || ret=1
+lines=$(awk -v id="${keyid}" '$4 == "RRSIG" && $5 == "CDS" && $11 == id {print}' dig.out.test$n | wc -l)
+test "$lines" -eq 1 || ret=1
+lines=$(awk '$4 == "CDS" {print}' dig.out.test$n | wc -l)
+test "$lines" -eq 1 || ret=1
+lines=$(awk '$4 == "CDS" && $5 == "0" && $6 == "0" && $7 == "0" && $8 == "00" {print}' dig.out.test$n | wc -l)
+test "$lines" -eq 1 || ret=1
+n=$((n+1))
+test "$ret" -eq 0 || echo_i "failed"
+status=$((status+ret))
+
+echo_i "checking that positive unknown NSEC3 hash algorithm with OPTOUT does validate ($n)"
+ret=0
+dig_with_opts +noauth +noadd +nodnssec +adflag @10.53.0.3 optout-unknown.example SOA > dig.out.ns3.test$n
+dig_with_opts +noauth +noadd +nodnssec +adflag @10.53.0.4 optout-unknown.example SOA > dig.out.ns4.test$n
+grep "status: NOERROR," dig.out.ns3.test$n > /dev/null || ret=1
+grep "status: NOERROR," dig.out.ns4.test$n > /dev/null || ret=1
+grep "flags:.*ad.*QUERY" dig.out.ns4.test$n > /dev/null || ret=1
+grep "ANSWER: 1," dig.out.ns4.test$n > /dev/null || ret=1
+n=$((n+1))
+test "$ret" -eq 0 || echo_i "failed"
+status=$((status+ret))
+
+echo_i "check that a non matching CDS record is accepted with a matching CDS record ($n)"
+ret=0
+(
+echo zone cds-update.secure
+echo server 10.53.0.2 "$PORT"
+echo update delete cds-update.secure CDS
+echo send
+dig_with_opts +noall +answer @10.53.0.2 dnskey cds-update.secure |
+grep "DNSKEY.257" |
+$DSFROMKEY -12 -C -f - -T 1 cds-update.secure |
+sed "s/^/update add /"
+dig_with_opts +noall +answer @10.53.0.2 dnskey cds-update.secure |
+grep "DNSKEY.257" | sed 's/DNSKEY.257/DNSKEY 258/' |
+$DSFROMKEY -12 -C -A -f - -T 1 cds-update.secure |
+sed "s/^/update add /"
+echo send
+) | $NSUPDATE
+dig_with_opts +noall +answer @10.53.0.2 cds cds-update.secure > dig.out.test$n
+lines=$(awk '$4 == "RRSIG" && $5 == "CDS" {print}' dig.out.test$n | wc -l)
+test "$lines" -eq 2 || ret=1
+lines=$(awk '$4 == "CDS" {print}' dig.out.test$n | wc -l)
+test "$lines" -eq 4 || ret=1
+n=$((n+1))
+test "$ret" -eq 0 || echo_i "failed"
+status=$((status+ret))
+
+echo_i "checking that negative unknown NSEC3 hash algorithm does not validate ($n)"
+ret=0
+dig_with_opts +noauth +noadd +nodnssec +adflag @10.53.0.3 nsec3-unknown.example A > dig.out.ns3.test$n
+dig_with_opts +noauth +noadd +nodnssec +adflag @10.53.0.4 nsec3-unknown.example A > dig.out.ns4.test$n
+grep "status: NOERROR," dig.out.ns3.test$n > /dev/null || ret=1
+grep "status: SERVFAIL," dig.out.ns4.test$n > /dev/null || ret=1
+n=$((n+1))
+test "$ret" -eq 0 || echo_i "failed"
+status=$((status+ret))
+
+echo_i "check that CDNSKEY records are signed using KSK by dnssec-signzone ($n)"
+ret=0
+dig_with_opts +noall +answer @10.53.0.2 cdnskey cdnskey.secure > dig.out.test$n
+lines=$(awk '$4 == "RRSIG" && $5 == "CDNSKEY" {print}' dig.out.test$n | wc -l)
+test "$lines" -eq 2 || ret=1
+n=$((n+1))
+test "$ret" -eq 0 || echo_i "failed"
+status=$((status+ret))
+
+echo_i "check that CDNSKEY records are not signed using ZSK by dnssec-signzone -x ($n)"
+ret=0
+dig_with_opts +noall +answer @10.53.0.2 cdnskey cdnskey-x.secure > dig.out.test$n
+lines=$(awk '$4 == "RRSIG" && $5 == "CDNSKEY" {print}' dig.out.test$n | wc -l)
+test "$lines" -eq 2 || ret=1
+n=$((n+1))
+test "$ret" -eq 0 || echo_i "failed"
+status=$((status+ret))
+
+echo_i "checking that negative unknown NSEC3 hash algorithm with OPTOUT does not validate ($n)"
+ret=0
+dig_with_opts +noauth +noadd +nodnssec +adflag @10.53.0.3 optout-unknown.example A > dig.out.ns3.test$n
+dig_with_opts +noauth +noadd +nodnssec +adflag @10.53.0.4 optout-unknown.example A > dig.out.ns4.test$n
+grep "status: NOERROR," dig.out.ns3.test$n > /dev/null || ret=1
+grep "status: SERVFAIL," dig.out.ns4.test$n > /dev/null || ret=1
+n=$((n+1))
+test "$ret" -eq 0 || echo_i "failed"
+status=$((status+ret))
+
+echo_i "check that CDNSKEY records are signed using KSK by with dnssec-auto ($n)"
+ret=0
+dig_with_opts +noall +answer @10.53.0.2 cdnskey cdnskey-auto.secure > dig.out.test$n
+lines=$(awk '$4 == "RRSIG" && $5 == "CDNSKEY" {print}' dig.out.test$n | wc -l)
+test "$lines" -eq 2 || ret=1
+n=$((n+1))
+test "$ret" -eq 0 || echo_i "failed"
+status=$((status+ret))
+
+echo_i "checking that unknown DNSKEY algorithm validates as insecure ($n)"
+ret=0
+dig_with_opts +noauth +noadd +nodnssec +adflag @10.53.0.3 dnskey-unknown.example A > dig.out.ns3.test$n
+dig_with_opts +noauth +noadd +nodnssec +adflag @10.53.0.4 dnskey-unknown.example A > dig.out.ns4.test$n
+grep "status: NOERROR," dig.out.ns3.test$n > /dev/null || ret=1
+grep "status: NOERROR," dig.out.ns4.test$n > /dev/null || ret=1
+grep "flags:.*ad.*QUERY" dig.out.ns4.test$n > /dev/null && ret=1
+n=$((n+1))
+test "$ret" -eq 0 || echo_i "failed"
+status=$((status+ret))
+
+echo_i "checking that unsupported DNSKEY algorithm validates as insecure ($n)"
+ret=0
+dig_with_opts +noauth +noadd +nodnssec +adflag @10.53.0.3 dnskey-unsupported.example A > dig.out.ns3.test$n
+dig_with_opts +noauth +noadd +nodnssec +adflag @10.53.0.4 dnskey-unsupported.example A > dig.out.ns4.test$n
+grep "status: NOERROR," dig.out.ns3.test$n > /dev/null || ret=1
+grep "status: NOERROR," dig.out.ns4.test$n > /dev/null || ret=1
+grep "flags:.*ad.*QUERY" dig.out.ns4.test$n > /dev/null && ret=1
+n=$((n+1))
+test "$ret" -eq 0 || echo_i "failed"
+status=$((status+ret))
+
+echo_i "checking that unsupported DNSKEY algorithm is in DNSKEY RRset ($n)"
+ret=0
+dig_with_opts +noauth +noadd +nodnssec +adflag @10.53.0.3 dnskey-unsupported-2.example DNSKEY > dig.out.test$n
+grep "status: NOERROR," dig.out.test$n > /dev/null || ret=1
+grep "dnskey-unsupported-2\.example\..*IN.*DNSKEY.*257 3 255" dig.out.test$n > /dev/null || ret=1
+n=$((n+1))
+test "$ret" -eq 0 || echo_i "failed"
+status=$((status+ret))
+
+# TODO: test case for GL #1689.
+# If we allow the dnssec tools to use deprecated algorithms (such as RSAMD5)
+# we could write a test that signs a zone with supported and unsupported
+# algorithm, apply a fixed rrset order such that the unsupported algorithm
+# precedes the supported one in the DNSKEY RRset, and verify the result still
+# validates succesfully.
+
+echo_i "check that a CDNSKEY deletion record is accepted ($n)"
+ret=0
+(
+echo zone cdnskey-update.secure
+echo server 10.53.0.2 "$PORT"
+echo update delete cdnskey-update.secure CDNSKEY
+echo update add cdnskey-update.secure 0 CDNSKEY 0 3 0 AA==
+echo send
+) | $NSUPDATE > nsupdate.out.test$n 2>&1
+dig_with_opts +noall +answer @10.53.0.2 cdnskey cdnskey-update.secure > dig.out.test$n
+lines=$(awk '$4 == "CDNSKEY" {print}' dig.out.test$n | wc -l)
+test "${lines:-10}" -eq 1 || ret=1
+lines=$(awk '$4 == "CDNSKEY" && $5 == "0" && $6 == "3" && $7 == "0" && $8 == "AA==" {print}' dig.out.test$n | wc -l)
+test "${lines:-10}" -eq 1 || ret=1
+n=$((n+1))
+test "$ret" -eq 0 || echo_i "failed"
+status=$((status+ret))
+
+echo_i "checking that unknown DNSKEY algorithm + unknown NSEC3 has algorithm validates as insecure ($n)"
+ret=0
+dig_with_opts +noauth +noadd +nodnssec +adflag @10.53.0.3 dnskey-nsec3-unknown.example A > dig.out.ns3.test$n
+dig_with_opts +noauth +noadd +nodnssec +adflag @10.53.0.4 dnskey-nsec3-unknown.example A > dig.out.ns4.test$n
+grep "status: NOERROR," dig.out.ns3.test$n > /dev/null || ret=1
+grep "status: NOERROR," dig.out.ns4.test$n > /dev/null || ret=1
+grep "flags:.*ad.*QUERY" dig.out.ns4.test$n > /dev/null && ret=1
+n=$((n+1))
+test "$ret" -eq 0 || echo_i "failed"
+status=$((status+ret))
+
+echo_i "check that CDNSKEY records are signed using KSK when added by nsupdate ($n)"
+ret=0
+(
+echo zone cdnskey-update.secure
+echo server 10.53.0.2 "$PORT"
+echo update delete cdnskey-update.secure CDNSKEY
+dig_with_opts +noall +answer @10.53.0.2 dnskey cdnskey-update.secure |
+sed -n -e "s/^/update add /" -e 's/DNSKEY.257/CDNSKEY 257/p'
+echo send
+) | $NSUPDATE
+dig_with_opts +noall +answer @10.53.0.2 cdnskey cdnskey-update.secure > dig.out.test$n
+lines=$(awk '$4 == "RRSIG" && $5 == "CDNSKEY" {print}' dig.out.test$n | wc -l)
+test "$lines" -eq 2 || ret=1
+lines=$(awk '$4 == "CDNSKEY" {print}' dig.out.test$n | wc -l)
+test "$lines" -eq 1 || ret=1
+n=$((n+1))
+test "$ret" -eq 0 || echo_i "failed"
+status=$((status+ret))
+
+echo_i "check that CDNSKEY records are signed only using KSK when added by"
+echo_ic "nsupdate when dnssec-dnskey-kskonly is yes ($n)"
+ret=0
+keyid=$(cat ns2/cdnskey-kskonly.secure.id)
+(
+echo zone cdnskey-kskonly.secure
+echo server 10.53.0.2 "$PORT"
+echo update delete cdnskey-kskonly.secure CDNSKEY
+dig_with_opts +noall +answer @10.53.0.2 dnskey cdnskey-kskonly.secure |
+sed -n -e "s/^/update add /" -e 's/DNSKEY.257/CDNSKEY 257/p'
+echo send
+) | $NSUPDATE
+dig_with_opts +noall +answer @10.53.0.2 cdnskey cdnskey-kskonly.secure > dig.out.test$n
+lines=$(awk '$4 == "RRSIG" && $5 == "CDNSKEY" {print}' dig.out.test$n | wc -l)
+test "$lines" -eq 1 || ret=1
+lines=$(awk -v id="${keyid}" '$4 == "RRSIG" && $5 == "CDNSKEY" && $11 == id {print}' dig.out.test$n | wc -l)
+test "$lines" -eq 1 || ret=1
+lines=$(awk '$4 == "CDNSKEY" {print}' dig.out.test$n | wc -l)
+test "$lines" -eq 1 || ret=1
+n=$((n+1))
+test "$ret" -eq 0 || echo_i "failed"
+status=$((status+ret))
+
+echo_i "check that CDNSKEY deletion records are signed only using KSK when added by"
+echo_ic "nsupdate when dnssec-dnskey-kskonly is yes ($n)"
+ret=0
+keyid=$(cat ns2/cdnskey-kskonly.secure.id)
+(
+echo zone cdnskey-kskonly.secure
+echo server 10.53.0.2 "$PORT"
+echo update delete cdnskey-kskonly.secure CDNSKEY
+echo update add cdnskey-kskonly.secure 0 CDNSKEY 0 3 0 AA==
+echo send
+) | $NSUPDATE
+dig_with_opts +noall +answer @10.53.0.2 cdnskey cdnskey-kskonly.secure > dig.out.test$n
+lines=$(awk '$4 == "RRSIG" && $5 == "CDNSKEY" {print}' dig.out.test$n | wc -l)
+test "$lines" -eq 1 || ret=1
+lines=$(awk -v id="${keyid}" '$4 == "RRSIG" && $5 == "CDNSKEY" && $11 == id {print}' dig.out.test$n | wc -l)
+test "$lines" -eq 1 || ret=1
+lines=$(awk '$4 == "CDNSKEY" {print}' dig.out.test$n | wc -l)
+test "$lines" -eq 1 || ret=1
+lines=$(awk '$4 == "CDNSKEY" && $5 == "0" && $6 == "3" && $7 == "0" && $8 == "AA==" {print}' dig.out.test$n | wc -l)
+test "${lines:-10}" -eq 1 || ret=1
+n=$((n+1))
+test "$ret" -eq 0 || echo_i "failed"
+status=$((status+ret))
+
+echo_i "checking initialization with a revoked managed key ($n)"
+ret=0
+copy_setports ns5/named2.conf.in ns5/named.conf
+rndccmd 10.53.0.5 reconfig 2>&1 | sed 's/^/ns5 /' | cat_i
+sleep 3
+dig_with_opts +dnssec @10.53.0.5 SOA . > dig.out.ns5.test$n
+grep "status: SERVFAIL" dig.out.ns5.test$n > /dev/null || ret=1
+n=$((n+1))
+test "$ret" -eq 0 || echo_i "failed"
+status=$((status+ret))
+
+echo_i "check that a non matching CDNSKEY record is accepted with a matching CDNSKEY record ($n)"
+ret=0
+(
+echo zone cdnskey-update.secure
+echo server 10.53.0.2 "$PORT"
+echo update delete cdnskey-update.secure CDNSKEY
+dig_with_opts +noall +answer @10.53.0.2 dnskey cdnskey-update.secure |
+sed -n -e "s/^/update add /" -e 's/DNSKEY.257/CDNSKEY 257/p'
+dig_with_opts +noall +answer @10.53.0.2 dnskey cdnskey-update.secure |
+sed -n -e "s/^/update add /" -e 's/DNSKEY.257/CDNSKEY 258/p'
+echo send
+) | $NSUPDATE
+dig_with_opts +noall +answer @10.53.0.2 cdnskey cdnskey-update.secure > dig.out.test$n
+lines=$(awk '$4 == "RRSIG" && $5 == "CDNSKEY" {print}' dig.out.test$n | wc -l)
+test "$lines" -eq 2 || ret=1
+lines=$(awk '$4 == "CDNSKEY" {print}' dig.out.test$n | wc -l)
+test "$lines" -eq 2 || ret=1
+n=$((n+1))
+test "$ret" -eq 0 || echo_i "failed"
+status=$((status+ret))
+
+echo_i "check that RRSIGs are correctly removed from apex when RRset is removed NSEC ($n)"
+ret=0
+# generate signed zone with MX and AAAA records at apex.
+(
+cd signer || exit 1
+$KEYGEN -q -a $DEFAULT_ALGORITHM -3 -fK remove > /dev/null
+$KEYGEN -q -a $DEFAULT_ALGORITHM -33 remove > /dev/null
+echo > remove.db.signed
+$SIGNER -S -o remove -D -f remove.db.signed remove.db.in > signer.out.1.$n
+)
+grep "RRSIG MX" signer/remove.db.signed > /dev/null || {
+ ret=1 ; cp signer/remove.db.signed signer/remove.db.signed.pre$n;
+}
+# re-generate signed zone without MX and AAAA records at apex.
+(
+cd signer || exit 1
+$SIGNER -S -o remove -D -f remove.db.signed remove2.db.in > signer.out.2.$n
+)
+grep "RRSIG MX" signer/remove.db.signed > /dev/null && {
+ ret=1 ; cp signer/remove.db.signed signer/remove.db.signed.post$n;
+}
+n=$((n+1))
+test "$ret" -eq 0 || echo_i "failed"
+status=$((status+ret))
+
+echo_i "check that RRSIGs are correctly removed from apex when RRset is removed NSEC3 ($n)"
+ret=0
+# generate signed zone with MX and AAAA records at apex.
+(
+cd signer || exit 1
+echo > remove.db.signed
+$SIGNER -3 - -S -o remove -D -f remove.db.signed remove.db.in > signer.out.1.$n
+)
+grep "RRSIG MX" signer/remove.db.signed > /dev/null || {
+ ret=1 ; cp signer/remove.db.signed signer/remove.db.signed.pre$n;
+}
+# re-generate signed zone without MX and AAAA records at apex.
+(
+cd signer || exit 1
+$SIGNER -3 - -S -o remove -D -f remove.db.signed remove2.db.in > signer.out.2.$n
+)
+grep "RRSIG MX" signer/remove.db.signed > /dev/null && {
+ ret=1 ; cp signer/remove.db.signed signer/remove.db.signed.post$n;
+}
+n=$((n+1))
+test "$ret" -eq 0 || echo_i "failed"
+status=$((status+ret))
+
+echo_i "check that a named managed zone that was signed 'in-the-future' is re-signed when loaded ($n)"
+ret=0
+dig_with_opts managed-future.example. @10.53.0.4 a > dig.out.ns4.test$n || ret=1
+grep "flags:.*ad.*QUERY" dig.out.ns4.test$n > /dev/null || ret=1
+grep "status: NOERROR" dig.out.ns4.test$n > /dev/null || ret=1
+n=$((n+1))
+test "$ret" -eq 0 || echo_i "failed"
+status=$((status+ret))
+
+echo_i "check that trust-anchor-telemetry queries are logged ($n)"
+ret=0
+grep "sending trust-anchor-telemetry query '_ta-[0-9a-f]*/NULL" ns6/named.run > /dev/null || ret=1
+n=$((n+1))
+test "$ret" -eq 0 || echo_i "failed"
+status=$((status+ret))
+
+echo_i "check that _ta-XXXX trust-anchor-telemetry queries are logged ($n)"
+ret=0
+grep "trust-anchor-telemetry '_ta-[0-9a-f]*/IN' from" ns1/named.run > /dev/null || ret=1
+n=$((n+1))
+test "$ret" -eq 0 || echo_i "failed"
+status=$((status+ret))
+
+echo_i "check that _ta-AAAA trust-anchor-telemetry are not sent when disabled ($n)"
+ret=0
+grep "sending trust-anchor-telemetry query '_ta-[0-9a-f]*/IN" ns1/named.run > /dev/null && ret=1
+n=$((n+1))
+test "$ret" -eq 0 || echo_i "failed"
+status=$((status+ret))
+
+echo_i "check that KEY-TAG trust-anchor-telemetry queries are logged ($n)"
+ret=0
+dig_with_opts . dnskey +ednsopt=KEY-TAG:ffff @10.53.0.1 > dig.out.ns1.test$n || ret=1
+grep "trust-anchor-telemetry './IN' from .* 65535" ns1/named.run > /dev/null || ret=1
+n=$((n+1))
+test "$ret" -eq 0 || echo_i "failed"
+status=$((status+ret))
+
+echo_i "check that multiple KEY-TAG trust-anchor-telemetry options don't leak memory ($n)"
+ret=0
+dig_with_opts . dnskey +ednsopt=KEY-TAG:fffe +ednsopt=KEY-TAG:fffd @10.53.0.1 > dig.out.ns1.test$n || ret=1
+grep "trust-anchor-telemetry './IN' from .* 65534" ns1/named.run > /dev/null || ret=1
+grep "trust-anchor-telemetry './IN' from .* 65533" ns1/named.run > /dev/null && ret=1
+stop_server ns1 || ret=1
+nextpart ns1/named.run > /dev/null
+start_server --noclean --restart --port ${PORT} ns1 || ret=1
+n=$(($n+1))
+test "$ret" -eq 0 || echo_i "failed"
+status=$((status+ret))
+
+echo_i "waiting for root server to finish reloading ($n)"
+ret=0
+wait_for_log 20 "all zones loaded" ns1/named.run || ret=1
+n=$(($n+1))
+test "$ret" -eq 0 || echo_i "failed"
+status=$((status+ret))
+
+echo_i "check that the view is logged in messages from the validator when using views ($n)"
+ret=0
+grep "view rec: *validat" ns4/named.run > /dev/null || ret=1
+n=$((n+1))
+test "$ret" -eq 0 || echo_i "failed"
+status=$((status+ret))
+
+echo_i "check that DNAME at apex with NSEC3 is correctly signed (dnssec-signzone) ($n)"
+ret=0
+dig_with_opts txt dname-at-apex-nsec3.example @10.53.0.3 > dig.out.ns3.test$n || ret=1
+grep "RRSIG.NSEC3 $DEFAULT_ALGORITHM_NUMBER 3 600" dig.out.ns3.test$n > /dev/null || ret=1
+n=$((n+1))
+test "$ret" -eq 0 || echo_i "failed"
+status=$((status+ret))
+
+echo_i "check that DNSKEY and other occluded data are excluded from the delegating bitmap ($n)"
+ret=0
+dig_with_opts axfr occluded.example @10.53.0.3 > dig.out.ns3.test$n || ret=1
+grep "^delegation.occluded.example..*NSEC.*NS KEY DS RRSIG NSEC$" dig.out.ns3.test$n > /dev/null || ret=1
+grep "^delegation.occluded.example..*DNSKEY.*" dig.out.ns3.test$n > /dev/null || ret=1
+grep "^delegation.occluded.example..*AAAA.*" dig.out.ns3.test$n > /dev/null || ret=1
+n=$((n+1))
+test "$ret" -eq 0 || echo_i "failed"
+status=$((status+ret))
+
+echo_i "checking DNSSEC records are occluded from ANY in an insecure zone ($n)"
+ret=0
+dig_with_opts any x.insecure.example. @10.53.0.3 > dig.out.ns3.1.test$n || ret=1
+grep "status: NOERROR" dig.out.ns3.1.test$n > /dev/null || ret=1
+grep "ANSWER: 0," dig.out.ns3.1.test$n > /dev/null || ret=1
+dig_with_opts any zz.secure.example. @10.53.0.3 > dig.out.ns3.2.test$n || ret=1
+grep "status: NOERROR" dig.out.ns3.2.test$n > /dev/null || ret=1
+# DNSKEY+RRSIG, NSEC+RRSIG
+grep "ANSWER: 4," dig.out.ns3.2.test$n > /dev/null || ret=1
+n=$((n+1))
+test "$ret" -eq 0 || echo_i "failed"
+status=$((status+ret))
+
+#
+# DNSSEC tests related to unsupported, disabled and revoked trust anchors.
+#
+
+# This nameserver (ns8) is loaded with a bunch of trust anchors. Some of
+# them are good (enabled.managed, enabled.trusted, secure.managed,
+# secure.trusted), and some of them are bad (disabled.managed,
+# revoked.managed, unsupported.managed, disabled.trusted, revoked.trusted,
+# unsupported.trusted). Make sure that the bad trust anchors are ignored.
+# This is tested by looking for the corresponding lines in the logfile.
+echo_i "checking that keys with unsupported algorithms and disabled algorithms are ignored ($n)"
+ret=0
+grep -q "ignoring static-key for 'disabled\.trusted\.': algorithm is disabled" ns8/named.run || ret=1
+grep -q "ignoring static-key for 'unsupported\.trusted\.': algorithm is unsupported" ns8/named.run || ret=1
+grep -q "ignoring static-key for 'revoked\.trusted\.': bad key type" ns8/named.run || ret=1
+grep -q "ignoring initial-key for 'disabled\.managed\.': algorithm is disabled" ns8/named.run || ret=1
+grep -q "ignoring initial-key for 'unsupported\.managed\.': algorithm is unsupported" ns8/named.run || ret=1
+grep -q "ignoring initial-key for 'revoked\.managed\.': bad key type" ns8/named.run || ret=1
+n=$((n+1))
+test "$ret" -eq 0 || echo_i "failed"
+status=$((status+ret))
+
+# The next two tests are fairly normal DNSSEC queries to signed zones with a
+# default algorithm. First, a query is made against the server that is
+# authoritative for the given zone (ns3). Second, a query is made against a
+# resolver with trust anchors for the given zone (ns8). Both are expected to
+# return an authentic data positive response.
+echo_i "checking that a trusted key using a supported algorithm validates as secure ($n)"
+ret=0
+dig_with_opts @10.53.0.3 a.secure.trusted A > dig.out.ns3.test$n
+dig_with_opts @10.53.0.8 a.secure.trusted A > dig.out.ns8.test$n
+grep "status: NOERROR," dig.out.ns3.test$n > /dev/null || ret=1
+grep "status: NOERROR," dig.out.ns8.test$n > /dev/null || ret=1
+grep "flags:.*ad.*QUERY" dig.out.ns8.test$n > /dev/null || ret=1
+n=$((n+1))
+test "$ret" -eq 0 || echo_i "failed"
+status=$((status+ret))
+
+echo_i "checking that a managed key using a supported algorithm validates as secure ($n)"
+ret=0
+dig_with_opts @10.53.0.3 a.secure.managed A > dig.out.ns3.test$n
+dig_with_opts @10.53.0.8 a.secure.managed A > dig.out.ns8.test$n
+grep "status: NOERROR," dig.out.ns3.test$n > /dev/null || ret=1
+grep "status: NOERROR," dig.out.ns8.test$n > /dev/null || ret=1
+grep "flags:.*ad.*QUERY" dig.out.ns8.test$n > /dev/null || ret=1
+n=$((n+1))
+test "$ret" -eq 0 || echo_i "failed"
+status=$((status+ret))
+
+# The next two queries ensure that a zone signed with a DNSKEY with an unsupported
+# algorithm will yield insecure positive responses. These trust anchors in ns8 are
+# ignored and so this domain is treated as insecure. The AD bit should not be set
+# in the response.
+echo_i "checking that a trusted key using an unsupported algorithm validates as insecure ($n)"
+ret=0
+dig_with_opts @10.53.0.3 a.unsupported.trusted A > dig.out.ns3.test$n
+dig_with_opts @10.53.0.8 a.unsupported.trusted A > dig.out.ns8.test$n
+grep "status: NOERROR," dig.out.ns3.test$n > /dev/null || ret=1
+grep "status: NOERROR," dig.out.ns8.test$n > /dev/null || ret=1
+grep "flags:.*ad.*QUERY" dig.out.ns8.test$n > /dev/null && ret=1
+n=$((n+1))
+test "$ret" -eq 0 || echo_i "failed"
+status=$((status+ret))
+
+echo_i "checking that a managed key using an unsupported algorithm validates as insecure ($n)"
+ret=0
+dig_with_opts @10.53.0.3 a.unsupported.managed A > dig.out.ns3.test$n
+dig_with_opts @10.53.0.8 a.unsupported.managed A > dig.out.ns8.test$n
+grep "status: NOERROR," dig.out.ns3.test$n > /dev/null || ret=1
+grep "status: NOERROR," dig.out.ns8.test$n > /dev/null || ret=1
+grep "flags:.*ad.*QUERY" dig.out.ns8.test$n > /dev/null && ret=1
+n=$((n+1))
+test "$ret" -eq 0 || echo_i "failed"
+status=$((status+ret))
+
+# The next two queries ensure that a zone signed with a DNSKEY that the nameserver
+# has a disabled algorithm match for will yield insecure positive responses.
+# These trust anchors in ns8 are ignored and so this domain is treated as insecure.
+# The AD bit should not be set in the response.
+echo_i "checking that a trusted key using a disabled algorithm validates as insecure ($n)"
+ret=0
+dig_with_opts @10.53.0.3 a.disabled.trusted A > dig.out.ns3.test$n
+dig_with_opts @10.53.0.8 a.disabled.trusted A > dig.out.ns8.test$n
+grep "status: NOERROR," dig.out.ns3.test$n > /dev/null || ret=1
+grep "status: NOERROR," dig.out.ns8.test$n > /dev/null || ret=1
+grep "flags:.*ad.*QUERY" dig.out.ns8.test$n > /dev/null && ret=1
+n=$((n+1))
+test "$ret" -eq 0 || echo_i "failed"
+status=$((status+ret))
+
+echo_i "checking that a managed key using a disabled algorithm validates as insecure ($n)"
+ret=0
+dig_with_opts @10.53.0.3 a.disabled.managed A > dig.out.ns3.test$n
+dig_with_opts @10.53.0.8 a.disabled.managed A > dig.out.ns8.test$n
+grep "status: NOERROR," dig.out.ns3.test$n > /dev/null || ret=1
+grep "status: NOERROR," dig.out.ns8.test$n > /dev/null || ret=1
+grep "flags:.*ad.*QUERY" dig.out.ns8.test$n > /dev/null && ret=1
+n=$((n+1))
+test "$ret" -eq 0 || echo_i "failed"
+status=$((status+ret))
+
+# The next two queries ensure that a zone signed with a DNSKEY that the
+# nameserver has a disabled algorithm for, but for a different domain, will
+# yield secure positive responses. Since "enabled.trusted." and
+# "enabled.managed." do not match the "disable-algorithms" option, no
+# special rules apply and these zones should validate as secure, with the AD
+# bit set.
+echo_i "checking that a trusted key using an algorithm disabled for another domain validates as secure ($n)"
+ret=0
+dig_with_opts @10.53.0.3 a.enabled.trusted A > dig.out.ns3.test$n
+dig_with_opts @10.53.0.8 a.enabled.trusted A > dig.out.ns8.test$n
+grep "status: NOERROR," dig.out.ns3.test$n > /dev/null || ret=1
+grep "status: NOERROR," dig.out.ns8.test$n > /dev/null || ret=1
+grep "flags:.*ad.*QUERY" dig.out.ns8.test$n > /dev/null || ret=1
+n=$((n+1))
+test "$ret" -eq 0 || echo_i "failed"
+status=$((status+ret))
+
+echo_i "checking that a managed key using an algorithm disabled for another domain validates as secure ($n)"
+ret=0
+dig_with_opts @10.53.0.3 a.enabled.managed A > dig.out.ns3.test$n
+dig_with_opts @10.53.0.8 a.enabled.managed A > dig.out.ns8.test$n
+grep "status: NOERROR," dig.out.ns3.test$n > /dev/null || ret=1
+grep "status: NOERROR," dig.out.ns8.test$n > /dev/null || ret=1
+grep "flags:.*ad.*QUERY" dig.out.ns8.test$n > /dev/null || ret=1
+n=$((n+1))
+test "$ret" -eq 0 || echo_i "failed"
+status=$((status+ret))
+
+# A configured revoked trust anchor is ignored and thus the two queries below
+# should result in insecure responses, since no trust points for the
+# "revoked.trusted." and "revoked.managed." zones are created.
+echo_i "checking that a trusted key that is revoked validates as insecure ($n)"
+ret=0
+dig_with_opts @10.53.0.3 a.revoked.trusted A > dig.out.ns3.test$n
+dig_with_opts @10.53.0.8 a.revoked.trusted A > dig.out.ns8.test$n
+grep "status: NOERROR," dig.out.ns3.test$n > /dev/null || ret=1
+grep "status: NOERROR," dig.out.ns8.test$n > /dev/null || ret=1
+grep "flags:.*ad.*QUERY" dig.out.ns8.test$n > /dev/null && ret=1
+n=$((n+1))
+test "$ret" -eq 0 || echo_i "failed"
+status=$((status+ret))
+
+echo_i "checking that a managed key that is revoked validates as insecure ($n)"
+ret=0
+dig_with_opts @10.53.0.3 a.revoked.managed A > dig.out.ns3.test$n
+dig_with_opts @10.53.0.8 a.revoked.managed A > dig.out.ns8.test$n
+grep "status: NOERROR," dig.out.ns3.test$n > /dev/null || ret=1
+grep "status: NOERROR," dig.out.ns8.test$n > /dev/null || ret=1
+grep "flags:.*ad.*QUERY" dig.out.ns8.test$n > /dev/null && ret=1
+n=$((n+1))
+test "$ret" -eq 0 || echo_i "failed"
+status=$((status+ret))
+
+###
+### Additional checks for when the KSK is offline.
+###
+
+# Save some useful information
+zone="updatecheck-kskonly.secure"
+KSK=$(cat ns2/${zone}.ksk.key)
+ZSK=$(cat ns2/${zone}.zsk.key)
+KSK_ID=$(cat ns2/${zone}.ksk.id)
+ZSK_ID=$(cat ns2/${zone}.zsk.id)
+SECTIONS="+answer +noauthority +noadditional"
+echo_i "testing zone $zone KSK=$KSK_ID ZSK=$ZSK_ID"
+
+# Print IDs of keys used for generating RRSIG records for RRsets of type $1
+# found in dig output file $2.
+get_keys_which_signed() {
+ qtype=$1
+ output=$2
+ # The key ID is the 11th column of the RRSIG record line.
+ awk -v qt="$qtype" '$4 == "RRSIG" && $5 == qt {print $11}' < "$output"
+}
+
+# Basic checks to make sure everything is fine before the KSK is made offline.
+for qtype in "DNSKEY" "CDNSKEY" "CDS"
+do
+ echo_i "checking $qtype RRset is signed with KSK only (update-check-ksk, dnssec-ksk-only) ($n)"
+ ret=0
+ dig_with_opts $SECTIONS @10.53.0.2 $qtype $zone > dig.out.test$n
+ lines=$(get_keys_which_signed $qtype dig.out.test$n | wc -l)
+ test "$lines" -eq 1 || ret=1
+ get_keys_which_signed $qtype dig.out.test$n | grep "^$KSK_ID$" > /dev/null || ret=1
+ get_keys_which_signed $qtype dig.out.test$n | grep "^$ZSK_ID$" > /dev/null && ret=1
+ n=$((n+1))
+ test "$ret" -eq 0 || echo_i "failed"
+ status=$((status+ret))
+done
+
+echo_i "checking SOA RRset is signed with ZSK only (update-check-ksk and dnssec-ksk-only) ($n)"
+ret=0
+dig_with_opts $SECTIONS @10.53.0.2 soa $zone > dig.out.test$n
+lines=$(get_keys_which_signed "SOA" dig.out.test$n | wc -l)
+test "$lines" -eq 1 || ret=1
+get_keys_which_signed "SOA" dig.out.test$n | grep "^$KSK_ID$" > /dev/null && ret=1
+get_keys_which_signed "SOA" dig.out.test$n | grep "^$ZSK_ID$" > /dev/null || ret=1
+n=$((n+1))
+test "$ret" -eq 0 || echo_i "failed"
+status=$((status+ret))
+
+# Roll the ZSK.
+zsk2=$("$KEYGEN" -q -a "$DEFAULT_ALGORITHM" -b "$DEFAULT_BITS" -K ns2 -n zone "$zone")
+keyfile_to_key_id "$zsk2" > ns2/$zone.zsk.id2
+ZSK_ID2=$(cat ns2/$zone.zsk.id2)
+
+echo_i "load new ZSK $ZSK_ID2 for $zone ($n)"
+ret=0
+dnssec_loadkeys_on 2 $zone || ret=1
+n=$((n+1))
+test "$ret" -eq 0 || echo_i "failed"
+status=$((status+ret))
+
+# Make new ZSK active.
+echo_i "make ZSK $ZSK_ID inactive and make new ZSK $ZSK_ID2 active for zone $zone ($n)"
+ret=0
+$SETTIME -I now -K ns2 $ZSK > /dev/null
+$SETTIME -A now -K ns2 $zsk2 > /dev/null
+dnssec_loadkeys_on 2 $zone || ret=1
+n=$((n+1))
+test "$ret" -eq 0 || echo_i "failed"
+status=$((status+ret))
+
+# Remove the KSK from disk.
+echo_i "remove the KSK $KSK_ID for zone $zone from disk"
+mv ns2/$KSK.key ns2/$KSK.key.bak
+mv ns2/$KSK.private ns2/$KSK.private.bak
+
+# Update the zone that requires a resign of the SOA RRset.
+echo_i "update the zone with $zone IN TXT nsupdate added me"
+(
+echo zone $zone
+echo server 10.53.0.2 "$PORT"
+echo update add $zone. 300 in txt "nsupdate added me"
+echo send
+) | $NSUPDATE
+
+# Redo the tests now that the zone is updated and the KSK is offline.
+for qtype in "DNSKEY" "CDNSKEY" "CDS"
+do
+ echo_i "checking $qtype RRset is signed with KSK only, KSK offline (update-check-ksk, dnssec-ksk-only) ($n)"
+ ret=0
+ dig_with_opts $SECTIONS @10.53.0.2 $qtype $zone > dig.out.test$n
+ lines=$(get_keys_which_signed $qtype dig.out.test$n | wc -l)
+ test "$lines" -eq 1 || ret=1
+ get_keys_which_signed $qtype dig.out.test$n | grep "^$KSK_ID$" > /dev/null || ret=1
+ get_keys_which_signed $qtype dig.out.test$n | grep "^$ZSK_ID$" > /dev/null && ret=1
+ get_keys_which_signed $qtype dig.out.test$n | grep "^$ZSK_ID2$" > /dev/null && ret=1
+ n=$((n+1))
+ test "$ret" -eq 0 || echo_i "failed"
+ status=$((status+ret))
+done
+
+for qtype in "SOA" "TXT"
+do
+ echo_i "checking $qtype RRset is signed with ZSK only, KSK offline (update-check-ksk and dnssec-ksk-only) ($n)"
+ ret=0
+ dig_with_opts $SECTIONS @10.53.0.2 $qtype $zone > dig.out.test$n
+ lines=$(get_keys_which_signed $qtype dig.out.test$n | wc -l)
+ test "$lines" -eq 1 || ret=1
+ get_keys_which_signed $qtype dig.out.test$n | grep "^$KSK_ID$" > /dev/null && ret=1
+ get_keys_which_signed $qtype dig.out.test$n | grep "^$ZSK_ID$" > /dev/null && ret=1
+ get_keys_which_signed $qtype dig.out.test$n | grep "^$ZSK_ID2$" > /dev/null || ret=1
+ n=$((n+1))
+ test "$ret" -eq 0 || echo_i "failed"
+ status=$((status+ret))
+done
+
+# Put back the KSK.
+echo_i "put back the KSK $KSK_ID for zone $zone from disk"
+mv ns2/$KSK.key.bak ns2/$KSK.key
+mv ns2/$KSK.private.bak ns2/$KSK.private
+
+# Roll the ZSK again.
+zsk3=$("$KEYGEN" -q -a "$DEFAULT_ALGORITHM" -b "$DEFAULT_BITS" -K ns2 -n zone "$zone")
+keyfile_to_key_id "$zsk3" > ns2/$zone.zsk.id3
+ZSK_ID3=$(cat ns2/$zone.zsk.id3)
+
+# Schedule the new ZSK (ZSK3) to become active.
+echo_i "delete old ZSK $ZSK_ID schedule ZSK $ZSK_ID2 inactive and new ZSK $ZSK_ID3 active for zone $zone ($n)"
+$SETTIME -D now -K ns2 $ZSK > /dev/null
+$SETTIME -I +3600 -K ns2 $zsk2 > /dev/null
+$SETTIME -A +3600 -K ns2 $zsk3 > /dev/null
+dnssec_loadkeys_on 2 $zone || ret=1
+n=$((n+1))
+test "$ret" -eq 0 || echo_i "failed"
+status=$((status+ret))
+
+# Remove the KSK from disk.
+echo_i "remove the KSK $KSK_ID for zone $zone from disk"
+mv ns2/$KSK.key ns2/$KSK.key.bak
+mv ns2/$KSK.private ns2/$KSK.private.bak
+
+# Update the zone that requires a resign of the SOA RRset.
+echo_i "update the zone with $zone IN TXT nsupdate added me again"
+(
+echo zone $zone
+echo server 10.53.0.2 "$PORT"
+echo update add $zone. 300 in txt "nsupdate added me again"
+echo send
+) | $NSUPDATE
+
+# Redo the tests now that the ZSK roll has deleted the old key.
+for qtype in "DNSKEY" "CDNSKEY" "CDS"
+do
+ echo_i "checking $qtype RRset is signed with KSK only, old ZSK deleted (update-check-ksk, dnssec-ksk-only) ($n)"
+ ret=0
+ dig_with_opts $SECTIONS @10.53.0.2 $qtype $zone > dig.out.test$n
+ lines=$(get_keys_which_signed $qtype dig.out.test$n | wc -l)
+ test "$lines" -eq 1 || ret=1
+ get_keys_which_signed $qtype dig.out.test$n | grep "^$KSK_ID$" > /dev/null || ret=1
+ get_keys_which_signed $qtype dig.out.test$n | grep "^$ZSK_ID$" > /dev/null && ret=1
+ get_keys_which_signed $qtype dig.out.test$n | grep "^$ZSK_ID2$" > /dev/null && ret=1
+ get_keys_which_signed $qtype dig.out.test$n | grep "^$ZSK_ID3$" > /dev/null && ret=1
+ n=$((n+1))
+ test "$ret" -eq 0 || echo_i "failed"
+ status=$((status+ret))
+done
+
+for qtype in "SOA" "TXT"
+do
+ echo_i "checking $qtype RRset is signed with ZSK only, old ZSK deleted (update-check-ksk and dnssec-ksk-only) ($n)"
+ ret=0
+ dig_with_opts $SECTIONS @10.53.0.2 $qtype $zone > dig.out.test$n
+ lines=$(get_keys_which_signed $qtype dig.out.test$n | wc -l)
+ test "$lines" -eq 1 || ret=1
+ get_keys_which_signed $qtype dig.out.test$n | grep "^$KSK_ID$" > /dev/null && ret=1
+ get_keys_which_signed $qtype dig.out.test$n | grep "^$ZSK_ID$" > /dev/null && ret=1
+ get_keys_which_signed $qtype dig.out.test$n | grep "^$ZSK_ID2$" > /dev/null || ret=1
+ get_keys_which_signed $qtype dig.out.test$n | grep "^$ZSK_ID3$" > /dev/null && ret=1
+ n=$((n+1))
+ test "$ret" -eq 0 || echo_i "failed"
+ status=$((status+ret))
+done
+
+# Make the new ZSK (ZSK3) active.
+echo_i "make new ZSK $ZSK_ID3 active for zone $zone ($n)"
+$SETTIME -I +1 -K ns2 $zsk2 > /dev/null
+$SETTIME -A +1 -K ns2 $zsk3 > /dev/null
+dnssec_loadkeys_on 2 $zone || ret=1
+n=$((n+1))
+test "$ret" -eq 0 || echo_i "failed"
+status=$((status+ret))
+
+# Wait for newest ZSK to become active.
+echo_i "wait until new ZSK $ZSK_ID3 active and ZSK $ZSK_ID2 inactive"
+for i in 1 2 3 4 5 6 7 8 9 10; do
+ ret=0
+ grep "DNSKEY $zone/$DEFAULT_ALGORITHM/$ZSK_ID3 (ZSK) is now active" ns2/named.run > /dev/null || ret=1
+ grep "DNSKEY $zone/$DEFAULT_ALGORITHM/$ZSK_ID2 (ZSK) is now inactive" ns2/named.run > /dev/null || ret=1
+ [ "$ret" -eq 0 ] && break
+ sleep 1
+done
+n=$((n+1))
+test "$ret" -eq 0 || echo_i "failed"
+status=$((status+ret))
+
+# Update the zone that requires a resign of the SOA RRset.
+echo_i "update the zone with $zone IN TXT nsupdate added me one more time"
+(
+echo zone $zone
+echo server 10.53.0.2 "$PORT"
+echo update add $zone. 300 in txt "nsupdate added me one more time"
+echo send
+) | $NSUPDATE
+n=$((n+1))
+test "$ret" -eq 0 || echo_i "failed"
+status=$((status+ret))
+
+# Redo the tests one more time.
+for qtype in "DNSKEY" "CDNSKEY" "CDS"
+do
+ echo_i "checking $qtype RRset is signed with KSK only, new ZSK active (update-check-ksk, dnssec-ksk-only) ($n)"
+ ret=0
+ dig_with_opts $SECTIONS @10.53.0.2 $qtype $zone > dig.out.test$n
+ lines=$(get_keys_which_signed $qtype dig.out.test$n | wc -l)
+ test "$lines" -eq 1 || ret=1
+ get_keys_which_signed $qtype dig.out.test$n | grep "^$KSK_ID$" > /dev/null || ret=1
+ get_keys_which_signed $qtype dig.out.test$n | grep "^$ZSK_ID$" > /dev/null && ret=1
+ get_keys_which_signed $qtype dig.out.test$n | grep "^$ZSK_ID2$" > /dev/null && ret=1
+ get_keys_which_signed $qtype dig.out.test$n | grep "^$ZSK_ID3$" > /dev/null && ret=1
+ n=$((n+1))
+ test "$ret" -eq 0 || echo_i "failed"
+ status=$((status+ret))
+done
+
+for qtype in "SOA" "TXT"
+do
+ echo_i "checking $qtype RRset is signed with ZSK only, new ZSK active (update-check-ksk and dnssec-ksk-only) ($n)"
+ ret=0
+ dig_with_opts $SECTIONS @10.53.0.2 $qtype $zone > dig.out.test$n
+ lines=$(get_keys_which_signed $qtype dig.out.test$n | wc -l)
+ test "$lines" -eq 1 || ret=1
+ get_keys_which_signed $qtype dig.out.test$n | grep "^$KSK_ID$" > /dev/null && ret=1
+ get_keys_which_signed $qtype dig.out.test$n | grep "^$ZSK_ID$" > /dev/null && ret=1
+ get_keys_which_signed $qtype dig.out.test$n | grep "^$ZSK_ID2$" > /dev/null && ret=1
+ get_keys_which_signed $qtype dig.out.test$n | grep "^$ZSK_ID3$" > /dev/null || ret=1
+ n=$((n+1))
+ test "$ret" -eq 0 || echo_i "failed"
+ status=$((status+ret))
+done
+
+echo_i "checking secroots output with multiple views ($n)"
+ret=0
+rndccmd 10.53.0.4 secroots 2>&1 | sed 's/^/ns4 /' | cat_i
+cp ns4/named.secroots named.secroots.test$n
+check_secroots_layout named.secroots.test$n || ret=1
+n=$((n+1))
+test "$ret" -eq 0 || echo_i "failed"
+status=$((status+ret))
+
+echo_i "checking sig-validity-interval second field hours vs days ($n)"
+ret=0
+# zone configured with 'sig-validity-interval 500 499;'
+# 499 days in the future w/ a 20 minute runtime to now allowance
+min=$(TZ=UTC $PERL -e '@lt=localtime(time() + 499*3600*24 - 20*60); printf "%.4d%0.2d%0.2d%0.2d%0.2d%0.2d\n",$lt[5]+1900,$lt[4]+1,$lt[3],$lt[2],$lt[1],$lt[0];')
+dig_with_opts @10.53.0.2 hours-vs-days AXFR > dig.out.ns2.test$n
+awk -v min=$min '$4 == "RRSIG" { if ($9 < min) { exit(1); } }' dig.out.ns2.test$n || ret=1
+n=$((n+1))
+test "$ret" -eq 0 || echo_i "failed"
+status=$((status+ret))
+
+echo_i "checking validation succeeds during transition to signed ($n)"
+ret=0
+dig_with_opts @10.53.0.4 inprogress A > dig.out.ns4.test$n || ret=1
+grep "flags: qr rd ra;" dig.out.ns4.test$n >/dev/null || ret=1
+grep "status: NOERROR" dig.out.ns4.test$n >/dev/null || ret=1
+grep 'A.10\.53\.0\.10' dig.out.ns4.test$n >/dev/null || ret=1
+n=$((n+1))
+test "$ret" -eq 0 || echo_i "failed"
+status=$((status+ret))
+
+echo_i "checking excessive NSEC3 iteration warnings in named.run ($n)"
+ret=0
+grep "zone too-many-iterations/IN: excessive NSEC3PARAM iterations [0-9]* > 150" ns2/named.run >/dev/null 2>&1 || ret=1
+grep "zone too-many-iterations/IN: excessive NSEC3PARAM iterations [0-9]* > 150" ns3/named.run >/dev/null 2>&1 || ret=1
+n=$((n+1))
+test "$ret" -eq 0 || echo_i "failed"
+status=$((status+ret))
+
+# Check that the validating resolver will fallback to insecure if the answer
+# contains NSEC3 records with high iteration count.
+echo_i "checking fallback to insecure when NSEC3 iterations is too high (nxdomain) ($n)"
+ret=0
+dig_with_opts @10.53.0.2 does-not-exist.too-many-iterations > dig.out.ns2.test$n || ret=1
+dig_with_opts @10.53.0.4 does-not-exist.too-many-iterations > dig.out.ns4.test$n || ret=1
+digcomp dig.out.ns2.test$n dig.out.ns4.test$n || ret=1
+grep "flags: qr rd ra;" dig.out.ns4.test$n >/dev/null || ret=1
+grep "status: NXDOMAIN" dig.out.ns4.test$n >/dev/null || ret=1
+grep "ANSWER: 0, AUTHORITY: 6" dig.out.ns4.test$n > /dev/null || ret=1
+n=$((n+1))
+test "$ret" -eq 0 || echo_i "failed"
+status=$((status+ret))
+
+echo_i "checking fallback to insecure when NSEC3 iterations is too high (nodata) ($n)"
+ret=0
+dig_with_opts @10.53.0.2 a.too-many-iterations txt > dig.out.ns2.test$n || ret=1
+dig_with_opts @10.53.0.4 a.too-many-iterations txt > dig.out.ns4.test$n || ret=1
+digcomp dig.out.ns2.test$n dig.out.ns4.test$n || ret=1
+grep "flags: qr rd ra;" dig.out.ns4.test$n >/dev/null || ret=1
+grep "status: NOERROR" dig.out.ns4.test$n >/dev/null || ret=1
+grep "ANSWER: 0, AUTHORITY: 4" dig.out.ns4.test$n > /dev/null || ret=1
+n=$((n+1))
+test "$ret" -eq 0 || echo_i "failed"
+status=$((status+ret))
+
+echo_i "checking fallback to insecure when NSEC3 iterations is too high (wildcard) ($n)"
+ret=0
+dig_with_opts @10.53.0.2 wild.a.too-many-iterations > dig.out.ns2.test$n || ret=1
+dig_with_opts @10.53.0.4 wild.a.too-many-iterations > dig.out.ns4.test$n || ret=1
+digcomp dig.out.ns2.test$n dig.out.ns4.test$n || ret=1
+grep "flags: qr rd ra;" dig.out.ns4.test$n >/dev/null || ret=1
+grep "status: NOERROR" dig.out.ns4.test$n >/dev/null || ret=1
+grep 'wild\.a\.too-many-iterations\..*A.10\.0\.0\.3' dig.out.ns4.test$n >/dev/null || ret=1
+grep "ANSWER: 2, AUTHORITY: 4" dig.out.ns4.test$n > /dev/null || ret=1
+n=$((n+1))
+test "$ret" -eq 0 || echo_i "failed"
+status=$((status+ret))
+
+echo_i "checking fallback to insecure when NSEC3 iterations is too high (wildcard nodata) ($n)"
+ret=0
+dig_with_opts @10.53.0.2 type100 wild.a.too-many-iterations > dig.out.ns2.test$n || ret=1
+dig_with_opts @10.53.0.4 type100 wild.a.too-many-iterations > dig.out.ns4.test$n || ret=1
+digcomp dig.out.ns2.test$n dig.out.ns4.test$n || ret=1
+grep "flags: qr rd ra;" dig.out.ns4.test$n >/dev/null || ret=1
+grep "status: NOERROR" dig.out.ns4.test$n >/dev/null || ret=1
+grep "ANSWER: 0, AUTHORITY: 8" dig.out.ns4.test$n > /dev/null || ret=1
+n=$((n+1))
+test "$ret" -eq 0 || echo_i "failed"
+status=$((status+ret))
+
+# Check that a query against a validating resolver succeeds when there is
+# a negative cache entry with trust level "pending" for the DS. Prime
+# with a +cd DS query to produce the negative cache entry, then send a
+# query that uses that entry as part of the validation process. [GL #3279]
+echo_i "check that pending negative DS cache entry validates ($n)"
+ret=0
+dig_with_opts @10.53.0.4 +cd insecure2.example. ds > dig.out.prime.ns4.test$n || ret=1
+grep "flags: qr rd ra cd;" dig.out.prime.ns4.test$n >/dev/null || ret=1
+grep "status: NOERROR" dig.out.prime.ns4.test$n >/dev/null || ret=1
+grep "ANSWER: 0, AUTHORITY: 4, " dig.out.prime.ns4.test$n > /dev/null || ret=1
+dig_with_opts @10.53.0.4 a.insecure2.example. a > dig.out.ns4.test$n || ret=1
+grep "ANSWER: 1, AUTHORITY: 1, " dig.out.ns4.test$n > /dev/null || ret=1
+grep "flags: qr rd ra;" dig.out.ns4.test$n >/dev/null || ret=1
+grep "status: NOERROR" dig.out.ns4.test$n >/dev/null || ret=1
+n=$((n+1))
+if [ "$ret" -ne 0 ]; then echo_i "failed"; fi
+status=$((status+ret))
+
+echo_i "exit status: $status"
+[ $status -eq 0 ] || exit 1
diff --git a/bin/tests/system/dnssec/tests_sh_dnssec.py b/bin/tests/system/dnssec/tests_sh_dnssec.py
new file mode 100644
index 0000000..65c3d43
--- /dev/null
+++ b/bin/tests/system/dnssec/tests_sh_dnssec.py
@@ -0,0 +1,14 @@
+# Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+#
+# SPDX-License-Identifier: MPL-2.0
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, you can obtain one at https://mozilla.org/MPL/2.0/.
+#
+# See the COPYRIGHT file distributed with this work for additional
+# information regarding copyright ownership.
+
+
+def test_dnssec(run_tests_sh):
+ run_tests_sh()