# 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 test_zonemd_simple(self): zone = dns.zone.from_text(self.simple_example, origin='example') zone.verify_digest() def test_zonemd_complex(self): zone = dns.zone.from_text(self.complex_example, origin='example') zone.verify_digest() def test_zonemd_multiple_digests(self): zone = dns.zone.from_text(self.multiple_digests_example, origin='example') zone.verify_digest() zonemd = zone.get_rdataset(zone.origin, 'ZONEMD') for rr in zonemd: if rr.scheme == 1 and rr.hash_algorithm in (1, 2): zone.verify_digest(rr) else: with self.assertRaises(ValueError): zone.verify_digest(rr) 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(ValueError): 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(ValueError): 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)