1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
|
# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license
import io
import textwrap
import unittest
import dns.rdata
import dns.rrset
import dns.zone
class ZoneDigestTestCase(unittest.TestCase):
# Examples from RFC 8976, fixed per errata.
simple_example = textwrap.dedent(
"""
example. 86400 IN SOA ns1 admin 2018031900 (
1800 900 604800 86400 )
86400 IN NS ns1
86400 IN NS ns2
86400 IN ZONEMD 2018031900 1 1 (
c68090d90a7aed71
6bc459f9340e3d7c
1370d4d24b7e2fc3
a1ddc0b9a87153b9
a9713b3c9ae5cc27
777f98b8e730044c )
ns1 3600 IN A 203.0.113.63
ns2 3600 IN AAAA 2001:db8::63
"""
)
complex_example = textwrap.dedent(
"""
example. 86400 IN SOA ns1 admin 2018031900 (
1800 900 604800 86400 )
86400 IN NS ns1
86400 IN NS ns2
86400 IN ZONEMD 2018031900 1 1 (
a3b69bad980a3504
e1cffcb0fd6397f9
3848071c93151f55
2ae2f6b1711d4bd2
d8b39808226d7b9d
b71e34b72077f8fe )
ns1 3600 IN A 203.0.113.63
NS2 3600 IN AAAA 2001:db8::63
occluded.sub 7200 IN TXT "I'm occluded but must be digested"
sub 7200 IN NS ns1
duplicate 300 IN TXT "I must be digested just once"
duplicate 300 IN TXT "I must be digested just once"
foo.test. 555 IN TXT "out-of-zone data must be excluded"
UPPERCASE 3600 IN TXT "canonicalize uppercase owner names"
* 777 IN PTR dont-forget-about-wildcards
mail 3600 IN MX 20 MAIL1
mail 3600 IN MX 10 Mail2.Example.
sortme 3600 IN AAAA 2001:db8::5:61
sortme 3600 IN AAAA 2001:db8::3:62
sortme 3600 IN AAAA 2001:db8::4:63
sortme 3600 IN AAAA 2001:db8::1:65
sortme 3600 IN AAAA 2001:db8::2:64
non-apex 900 IN ZONEMD 2018031900 1 1 (
616c6c6f77656420
6275742069676e6f
7265642e20616c6c
6f77656420627574
2069676e6f726564
2e20616c6c6f7765 )
"""
)
multiple_digests_example = textwrap.dedent(
"""
example. 86400 IN SOA ns1 admin 2018031900 (
1800 900 604800 86400 )
example. 86400 IN NS ns1.example.
example. 86400 IN NS ns2.example.
example. 86400 IN ZONEMD 2018031900 1 1 (
62e6cf51b02e54b9
b5f967d547ce4313
6792901f9f88e637
493daaf401c92c27
9dd10f0edb1c56f8
080211f8480ee306 )
example. 86400 IN ZONEMD 2018031900 1 2 (
08cfa1115c7b948c
4163a901270395ea
226a930cd2cbcf2f
a9a5e6eb85f37c8a
4e114d884e66f176
eab121cb02db7d65
2e0cc4827e7a3204
f166b47e5613fd27 )
example. 86400 IN ZONEMD 2018031900 1 240 (
e2d523f654b9422a
96c5a8f44607bbee )
example. 86400 IN ZONEMD 2018031900 241 1 (
e1846540e33a9e41
89792d18d5d131f6
05fc283eaaaaaaaa
aaaaaaaaaaaaaaaa
aaaaaaaaaaaaaaaa
aaaaaaaaaaaaaaaa)
ns1.example. 3600 IN A 203.0.113.63
ns2.example. 86400 IN TXT "This example has multiple digests"
NS2.EXAMPLE. 3600 IN AAAA 2001:db8::63
"""
)
def _get_zonemd(self, zone):
return zone.get_rdataset(zone.origin, "ZONEMD")
def test_zonemd_simple(self):
zone = dns.zone.from_text(self.simple_example, origin="example")
zone.verify_digest()
zonemd = self._get_zonemd(zone)
self.assertEqual(zonemd[0], zone.compute_digest(zonemd[0].hash_algorithm))
def test_zonemd_simple_absolute(self):
zone = dns.zone.from_text(
self.simple_example, origin="example", relativize=False
)
zone.verify_digest()
zonemd = self._get_zonemd(zone)
self.assertEqual(zonemd[0], zone.compute_digest(zonemd[0].hash_algorithm))
def test_zonemd_complex(self):
zone = dns.zone.from_text(self.complex_example, origin="example")
zone.verify_digest()
zonemd = self._get_zonemd(zone)
self.assertEqual(zonemd[0], zone.compute_digest(zonemd[0].hash_algorithm))
def test_zonemd_multiple_digests(self):
zone = dns.zone.from_text(self.multiple_digests_example, origin="example")
zone.verify_digest()
zonemd = self._get_zonemd(zone)
for rr in zonemd:
if rr.scheme == 1 and rr.hash_algorithm in (1, 2):
zone.verify_digest(rr)
self.assertEqual(rr, zone.compute_digest(rr.hash_algorithm))
else:
with self.assertRaises(dns.zone.DigestVerificationFailure):
zone.verify_digest(rr)
def test_zonemd_no_digest(self):
zone = dns.zone.from_text(self.simple_example, origin="example")
zone.delete_rdataset(dns.name.empty, "ZONEMD")
with self.assertRaises(dns.zone.NoDigest):
zone.verify_digest()
sha384_hash = "ab" * 48
sha512_hash = "ab" * 64
def test_zonemd_parse_rdata(self):
dns.rdata.from_text("IN", "ZONEMD", "100 1 1 " + self.sha384_hash)
dns.rdata.from_text("IN", "ZONEMD", "100 1 2 " + self.sha512_hash)
dns.rdata.from_text("IN", "ZONEMD", "100 100 1 " + self.sha384_hash)
dns.rdata.from_text("IN", "ZONEMD", "100 1 100 abcd")
def test_zonemd_unknown_scheme(self):
zone = dns.zone.from_text(self.simple_example, origin="example")
with self.assertRaises(dns.zone.UnsupportedDigestScheme):
zone.compute_digest(dns.zone.DigestHashAlgorithm.SHA384, 2)
def test_zonemd_unknown_hash_algorithm(self):
zone = dns.zone.from_text(self.simple_example, origin="example")
with self.assertRaises(dns.zone.UnsupportedDigestHashAlgorithm):
zone.compute_digest(5)
def test_zonemd_invalid_digest_length(self):
with self.assertRaises(dns.exception.SyntaxError):
dns.rdata.from_text("IN", "ZONEMD", "100 1 2 " + self.sha384_hash)
with self.assertRaises(dns.exception.SyntaxError):
dns.rdata.from_text("IN", "ZONEMD", "100 2 1 " + self.sha512_hash)
def test_zonemd_parse_rdata_reserved(self):
with self.assertRaises(dns.exception.SyntaxError):
dns.rdata.from_text("IN", "ZONEMD", "100 0 1 " + self.sha384_hash)
with self.assertRaises(dns.exception.SyntaxError):
dns.rdata.from_text("IN", "ZONEMD", "100 1 0 " + self.sha384_hash)
sorting_zone = textwrap.dedent(
"""
@ 86400 IN SOA ns1 admin 2018031900 (
1800 900 604800 86400 )
86400 IN NS ns1
86400 IN NS ns2
86400 IN RP n1.example. a.
86400 IN RP n1. b.
"""
)
def test_relative_zone_sorting(self):
z1 = dns.zone.from_text(self.sorting_zone, "example.", relativize=True)
z2 = dns.zone.from_text(self.sorting_zone, "example.", relativize=False)
zmd1 = z1.compute_digest(dns.zone.DigestHashAlgorithm.SHA384)
zmd2 = z2.compute_digest(dns.zone.DigestHashAlgorithm.SHA384)
self.assertEqual(zmd1, zmd2)
|