1 1.1 christos # Copyright (C) Internet Systems Consortium, Inc. ("ISC") 2 1.1 christos # 3 1.1 christos # SPDX-License-Identifier: MPL-2.0 4 1.1 christos # 5 1.1 christos # This Source Code Form is subject to the terms of the Mozilla Public 6 1.1 christos # License, v. 2.0. If a copy of the MPL was not distributed with this 7 1.1 christos # file, you can obtain one at https://mozilla.org/MPL/2.0/. 8 1.1 christos # 9 1.1 christos # See the COPYRIGHT file distributed with this work for additional 10 1.1 christos # information regarding copyright ownership. 11 1.1 christos 12 1.1 christos import os 13 1.1 christos import re 14 1.1.1.3 christos from re import compile as Re 15 1.1 christos 16 1.1 christos import pytest 17 1.1 christos 18 1.1 christos import isctest 19 1.1 christos 20 1.1 christos pytestmark = pytest.mark.extra_artifacts( 21 1.1 christos [ 22 1.1 christos "verify.out.*", 23 1.1 christos "zones/K*", 24 1.1 christos "zones/dsset-*", 25 1.1 christos "zones/*.bad", 26 1.1 christos "zones/*.good", 27 1.1 christos "zones/*.out*", 28 1.1 christos "zones/*.tmp", 29 1.1 christos "zones/updated*", 30 1.1 christos ] 31 1.1 christos ) 32 1.1 christos 33 1.1 christos VERIFY = os.environ.get("VERIFY") 34 1.1 christos 35 1.1 christos 36 1.1 christos @pytest.mark.parametrize( 37 1.1 christos "zone", 38 1.1 christos [ 39 1.1 christos "ksk-only.nsec3", 40 1.1 christos "ksk-only.nsec", 41 1.1 christos "ksk+zsk.nsec3.apex-dname", 42 1.1 christos "ksk+zsk.nsec3", 43 1.1 christos "ksk+zsk.nsec.apex-dname", 44 1.1 christos "ksk+zsk.nsec", 45 1.1 christos "ksk+zsk.optout", 46 1.1 christos "zsk-only.nsec3", 47 1.1 christos "zsk-only.nsec", 48 1.1 christos ], 49 1.1 christos ) 50 1.1 christos def test_verify_good_zone_files(zone): 51 1.1.1.2 christos isctest.run.cmd([VERIFY, "-z", "-o", zone, f"zones/{zone}.good"]) 52 1.1 christos 53 1.1 christos 54 1.1 christos def test_verify_good_zone_nsec_next_name_case_mismatch(): 55 1.1 christos isctest.run.cmd( 56 1.1 christos [ 57 1.1 christos VERIFY, 58 1.1 christos "-o", 59 1.1 christos "nsec-next-name-case-mismatch", 60 1.1 christos "zones/nsec-next-name-case-mismatch.good", 61 1.1 christos ], 62 1.1 christos ) 63 1.1 christos 64 1.1 christos 65 1.1.1.3 christos def verify_bad_zone(zone): 66 1.1.1.3 christos only_opt = ["-z"] if re.search(r"^[zk]sk-only", zone) else [] 67 1.1.1.3 christos cmd = isctest.run.cmd( 68 1.1 christos [VERIFY, *only_opt, "-o", zone, f"zones/{zone}.bad"], 69 1.1 christos raise_on_exception=False, 70 1.1 christos ) 71 1.1.1.3 christos assert cmd.rc != 0 72 1.1.1.3 christos return cmd 73 1.1 christos 74 1.1 christos 75 1.1 christos @pytest.mark.parametrize( 76 1.1 christos "zone", 77 1.1 christos [ 78 1.1 christos "ksk-only.dnskeyonly", 79 1.1 christos "ksk+zsk.dnskeyonly", 80 1.1 christos "zsk-only.dnskeyonly", 81 1.1 christos ], 82 1.1 christos ) 83 1.1 christos def test_verify_bad_zone_files_dnskeyonly(zone): 84 1.1.1.3 christos cmd = verify_bad_zone(zone) 85 1.1.1.3 christos assert "DNSKEY is not signed" in cmd.err 86 1.1 christos 87 1.1 christos 88 1.1 christos @pytest.mark.parametrize( 89 1.1 christos "zone", 90 1.1 christos [ 91 1.1 christos "ksk-only.nsec3.expired", 92 1.1 christos "ksk-only.nsec.expired", 93 1.1 christos "ksk+zsk.nsec3.expired", 94 1.1 christos "ksk+zsk.nsec.expired", 95 1.1 christos "ksk+zsk.nsec.ksk-expired", 96 1.1 christos "zsk-only.nsec3.expired", 97 1.1 christos "zsk-only.nsec.expired", 98 1.1 christos "ksk+zsk.nsec3.ksk-expired", 99 1.1 christos ], 100 1.1 christos ) 101 1.1 christos def test_verify_bad_zone_files_expired(zone): 102 1.1.1.3 christos cmd = verify_bad_zone(zone) 103 1.1.1.3 christos assert Re("signature has expired|No self-signed DNSKEY found") in cmd.err 104 1.1 christos 105 1.1 christos 106 1.1 christos @pytest.mark.parametrize( 107 1.1 christos "zone", 108 1.1 christos [ 109 1.1 christos "ksk+zsk.nsec.out-of-zone-nsec", 110 1.1 christos "ksk+zsk.nsec.below-bottom-of-zone-nsec", 111 1.1 christos "ksk+zsk.nsec.below-dname-nsec", 112 1.1 christos ], 113 1.1 christos ) 114 1.1 christos def test_verify_bad_zone_files_unexpected_nsec_rrset(zone): 115 1.1.1.3 christos cmd = verify_bad_zone(zone) 116 1.1.1.3 christos assert "unexpected NSEC RRset at" in cmd.err 117 1.1 christos 118 1.1 christos 119 1.1 christos def test_verify_bad_zone_files_bad_nsec_record(): 120 1.1.1.3 christos cmd = verify_bad_zone("ksk+zsk.nsec.broken-chain") 121 1.1.1.3 christos assert Re("Bad NSEC record for.*, next name mismatch") in cmd.err 122 1.1 christos 123 1.1 christos 124 1.1 christos def test_verify_bad_zone_files_bad_bitmap(): 125 1.1.1.3 christos cmd = verify_bad_zone("ksk+zsk.nsec.bad-bitmap") 126 1.1.1.3 christos assert "bit map mismatch" in cmd.err 127 1.1 christos 128 1.1 christos 129 1.1 christos def test_verify_bad_zone_files_missing_nsec3_record(): 130 1.1.1.3 christos cmd = verify_bad_zone("ksk+zsk.nsec3.missing-empty") 131 1.1.1.3 christos assert "Missing NSEC3 record for" in cmd.err 132 1.1 christos 133 1.1 christos 134 1.1 christos def test_verify_bad_zone_files_no_dnssec_keys(): 135 1.1.1.3 christos cmd = verify_bad_zone("unsigned") 136 1.1.1.3 christos assert "Zone contains no DNSSEC keys" in cmd.err 137 1.1 christos 138 1.1 christos 139 1.1 christos def test_verify_bad_zone_files_unequal_nsec3_chains(): 140 1.1.1.3 christos cmd = verify_bad_zone("ksk+zsk.nsec3.extra-nsec3") 141 1.1.1.3 christos assert "Expected and found NSEC3 chains not equal" in cmd.err 142 1.1 christos 143 1.1 christos 144 1.1 christos # checking error message when -o is not used 145 1.1 christos # and a SOA record not at top of zone is found 146 1.1 christos def test_verify_soa_not_at_top_error(): 147 1.1 christos # when -o is not used, origin is set to zone file name, 148 1.1 christos # which should cause an error in this case 149 1.1.1.3 christos cmd = isctest.run.cmd([VERIFY, "zones/ksk+zsk.nsec.good"], raise_on_exception=False) 150 1.1.1.3 christos assert "not at top of zone" in cmd.err 151 1.1.1.3 christos assert "use -o to specify a different zone origin" in cmd.err 152 1.1 christos 153 1.1 christos 154 1.1 christos # checking error message when an invalid -o is specified 155 1.1 christos # and a SOA record not at top of zone is found 156 1.1 christos def test_verify_invalid_o_option_soa_not_at_top_error(): 157 1.1.1.3 christos cmd = isctest.run.cmd( 158 1.1 christos [VERIFY, "-o", "invalid.origin", "zones/ksk+zsk.nsec.good"], 159 1.1 christos raise_on_exception=False, 160 1.1.1.3 christos ) 161 1.1.1.3 christos assert "not at top of zone" in cmd.err 162 1.1.1.3 christos assert "use -o to specify a different zone origin" not in cmd.err 163 1.1 christos 164 1.1 christos 165 1.1 christos # checking dnssec-verify -J reads journal file 166 1.1 christos def test_verify_j_reads_journal_file(): 167 1.1.1.3 christos cmd = isctest.run.cmd( 168 1.1 christos [ 169 1.1 christos VERIFY, 170 1.1 christos "-o", 171 1.1 christos "updated", 172 1.1 christos "-J", 173 1.1 christos "zones/updated.other.jnl", 174 1.1 christos "zones/updated.other", 175 1.1 christos ] 176 1.1.1.3 christos ) 177 1.1.1.3 christos assert "Loading zone 'updated' from file 'zones/updated.other'" in cmd.out 178