+++ /dev/null
-#!/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
-
-. ../conf.sh
-failed() {
- cat verify.out.$n | sed 's/^/D:/'
- echo_i "failed"
- status=1
-}
-
-n=0
-status=0
-
-for file in zones/*.good; do
- n=$((n + 1))
- zone=$(expr "$file" : 'zones/\(.*\).good')
- echo_i "checking supposedly good zone: $zone ($n)"
- ret=0
- case $zone in
- zsk-only.*) only=-z ;;
- ksk-only.*) only=-z ;;
- *) only= ;;
- esac
- $VERIFY ${only} -o $zone $file >verify.out.$n 2>&1 || ret=1
- [ $ret = 0 ] || failed
-done
-
-for file in zones/*.bad; do
- n=$((n + 1))
- zone=$(expr "$file" : 'zones/\(.*\).bad')
- echo_i "checking supposedly bad zone: $zone ($n)"
- ret=0
- dumpit=0
- case $zone in
- zsk-only.*) only=-z ;;
- ksk-only.*) only=-z ;;
- *) only= ;;
- esac
- expect1= expect2=
- case $zone in
- *.dnskeyonly)
- expect1="DNSKEY is not signed"
- ;;
- *.expired)
- expect1="signature has expired"
- expect2="No self-signed .*DNSKEY found"
- ;;
- *.ksk-expired)
- expect1="signature has expired"
- expect2="No self-signed .*DNSKEY found"
- ;;
- *.out-of-zone-nsec | *.below-bottom-of-zone-nsec | *.below-dname-nsec)
- expect1="unexpected NSEC RRset at"
- ;;
- *.nsec.broken-chain)
- expect1="Bad NSEC record for.*, next name mismatch"
- ;;
- *.bad-bitmap)
- expect1="bit map mismatch"
- ;;
- *.missing-empty)
- expect1="Missing NSEC3 record for"
- ;;
- unsigned)
- expect1="Zone contains no DNSSEC keys"
- ;;
- *.extra-nsec3)
- expect1="Expected and found NSEC3 chains not equal"
- ;;
- *)
- dumpit=1
- ;;
- esac
- $VERIFY ${only} -o $zone $file >verify.out.$n 2>&1 && ret=1
- grep "${expect1:-.}" verify.out.$n >/dev/null || ret=1
- grep "${expect2:-.}" verify.out.$n >/dev/null || ret=1
- [ $ret = 0 ] || failed
- [ $dumpit = 1 ] && cat verify.out.$n
-done
-
-n=$((n + 1))
-echo_i "checking error message when -o is not used and a SOA record not at top of zone is found ($n)"
-ret=0
-# When -o is not used, origin is set to zone file name, which should cause an error in this case
-$VERIFY zones/ksk+zsk.nsec.good >verify.out.$n 2>&1 && ret=1
-grep "not at top of zone" verify.out.$n >/dev/null || ret=1
-grep "use -o to specify a different zone origin" verify.out.$n >/dev/null || ret=1
-[ $ret = 0 ] || failed
-
-n=$((n + 1))
-echo_i "checking error message when an invalid -o is specified and a SOA record not at top of zone is found ($n)"
-ret=0
-$VERIFY -o invalid.origin zones/ksk+zsk.nsec.good >verify.out.$n 2>&1 && ret=1
-grep "not at top of zone" verify.out.$n >/dev/null || ret=1
-grep "use -o to specify a different zone origin" verify.out.$n >/dev/null && ret=1
-[ $ret = 0 ] || failed
-
-echo_i "exit status: $status"
-[ $status -eq 0 ] || exit 1
--- /dev/null
+# 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.
+
+import os
+import re
+
+import pytest
+
+import isctest
+
+VERIFY = os.environ.get("VERIFY")
+
+
+@pytest.mark.parametrize(
+ "zone",
+ [
+ "ksk-only.nsec3",
+ "ksk-only.nsec",
+ "ksk+zsk.nsec3.apex-dname",
+ "ksk+zsk.nsec3",
+ "ksk+zsk.nsec.apex-dname",
+ "ksk+zsk.nsec",
+ "ksk+zsk.optout",
+ "zsk-only.nsec3",
+ "zsk-only.nsec",
+ ],
+)
+def test_verify_good_zone_files(zone):
+ isctest.run.cmd([VERIFY, "-z", "-o", zone, f"zones/{zone}.good"], log_stdout=True)
+
+
+def test_verify_good_zone_nsec_next_name_case_mismatch():
+ isctest.run.cmd(
+ [
+ VERIFY,
+ "-o",
+ "nsec-next-name-case-mismatch",
+ "zones/nsec-next-name-case-mismatch.good",
+ ],
+ log_stdout=True,
+ )
+
+
+def get_bad_zone_output(zone):
+ only_opt = ["-z"] if re.match(r"[zk]sk-only", zone) else []
+ output = isctest.run.cmd(
+ [VERIFY, *only_opt, "-o", zone, f"zones/{zone}.bad"],
+ raise_on_exception=False,
+ log_stdout=True,
+ )
+ stream = (output.stdout + output.stderr).decode("utf-8").replace("\n", "")
+ return stream
+
+
+@pytest.mark.parametrize(
+ "zone",
+ [
+ "ksk-only.dnskeyonly",
+ "ksk+zsk.dnskeyonly",
+ "zsk-only.dnskeyonly",
+ ],
+)
+def test_verify_bad_zone_files_dnskeyonly(zone):
+ assert re.match(r".*DNSKEY is not signed.*", get_bad_zone_output(zone))
+
+
+@pytest.mark.parametrize(
+ "zone",
+ [
+ "ksk-only.nsec3.expired",
+ "ksk-only.nsec.expired",
+ "ksk+zsk.nsec3.expired",
+ "ksk+zsk.nsec.expired",
+ "ksk+zsk.nsec.ksk-expired",
+ "zsk-only.nsec3.expired",
+ "zsk-only.nsec.expired",
+ "ksk+zsk.nsec3.ksk-expired",
+ ],
+)
+def test_verify_bad_zone_files_expired(zone):
+ assert re.match(
+ r".*signature has expired.*|.*No self-signed .*DNSKEY found.*",
+ get_bad_zone_output(zone),
+ )
+
+
+@pytest.mark.parametrize(
+ "zone",
+ [
+ "ksk+zsk.nsec.out-of-zone-nsec",
+ "ksk+zsk.nsec.below-bottom-of-zone-nsec",
+ "ksk+zsk.nsec.below-dname-nsec",
+ ],
+)
+def test_verify_bad_zone_files_unexpected_nsec_rrset(zone):
+ assert re.match(r".*unexpected NSEC RRset at.*", get_bad_zone_output(zone))
+
+
+def test_verify_bad_zone_files_bad_nsec_record():
+ assert re.match(
+ r".*Bad NSEC record for.*, next name mismatch.*",
+ get_bad_zone_output("ksk+zsk.nsec.broken-chain"),
+ )
+
+
+def test_verify_bad_zone_files_bad_bitmap():
+ assert re.match(
+ r".*bit map mismatch.*", get_bad_zone_output("ksk+zsk.nsec.bad-bitmap")
+ )
+
+
+def test_verify_bad_zone_files_missing_nsec3_record():
+ assert re.match(
+ r".*Missing NSEC3 record for.*",
+ get_bad_zone_output("ksk+zsk.nsec3.missing-empty"),
+ )
+
+
+def test_verify_bad_zone_files_no_dnssec_keys():
+ assert re.match(
+ r".*Zone contains no DNSSEC keys.*", get_bad_zone_output("unsigned")
+ )
+
+
+def test_verify_bad_zone_files_unequal_nsec3_chains():
+ assert re.match(
+ r".*Expected and found NSEC3 chains not equal.*",
+ get_bad_zone_output("ksk+zsk.nsec3.extra-nsec3"),
+ )
+
+
+# checking error message when -o is not used
+# and a SOA record not at top of zone is found
+def test_verify_soa_not_at_top_error():
+ # when -o is not used, origin is set to zone file name,
+ # which should cause an error in this case
+ output = isctest.run.cmd(
+ [VERIFY, "zones/ksk+zsk.nsec.good"], raise_on_exception=False
+ ).stderr.decode("utf-8")
+ assert "not at top of zone" in output
+ assert "use -o to specify a different zone origin" in output
+
+
+# checking error message when an invalid -o is specified
+# and a SOA record not at top of zone is found
+def test_verify_invalid_o_option_soa_not_at_top_error():
+ output = isctest.run.cmd(
+ [VERIFY, "-o", "invalid.origin", "zones/ksk+zsk.nsec.good"],
+ raise_on_exception=False,
+ ).stderr.decode("utf-8")
+ assert "not at top of zone" in output
+ assert "use -o to specify a different zone origin" not in output