Browse Source

fix(api): require correct digest length for CDS/DLV/DS records

Related:
- https://github.com/rthalley/dnspython/pull/625
- https://github.com/PowerDNS/pdns/issues/9988
Peter Thomassen 4 năm trước cách đây
mục cha
commit
738bd6f83b

+ 38 - 0
api/desecapi/dns.py

@@ -2,6 +2,7 @@ import struct
 
 import dns
 import dns.rdtypes.txtbase, dns.rdtypes.svcbbase
+import dns.rdtypes.ANY.CDS, dns.rdtypes.ANY.DLV, dns.rdtypes.ANY.DS
 
 
 def _strip_quotes_decorator(func):
@@ -54,3 +55,40 @@ class LongQuotedTXT(dns.rdtypes.txtbase.TXTBase):
                 assert l < 256
                 file.write(struct.pack('!B', l))
                 file.write(s)
+
+
+# TODO remove when https://github.com/rthalley/dnspython/pull/625 is in the main codebase
+class _DigestLengthMixin():
+    _digest_length_by_type = {
+        1: 20,  # SHA-1, RFC 3658 Sec. 2.4
+        2: 32,  # SHA-256, RFC 4509 Sec. 2.2
+        3: 32,  # GOST R 34.11-94, RFC 5933 Sec. 4 in conjunction with RFC 4490 Sec. 2.1
+        4: 48,  # SHA-384, RFC 6605 Sec. 2
+    }
+
+    def __init__(self, *args, **kwargs):
+        super().__init__(*args, **kwargs)
+
+        try:
+            if self.digest_type == 0:  # reserved, RFC 3658 Sec. 2.4
+                raise ValueError('digest type 0 is reserved')
+            expected_length = _DigestLengthMixin._digest_length_by_type[self.digest_type]
+        except KeyError:
+            raise ValueError('unknown digest type')
+        if len(self.digest) != expected_length:
+            raise ValueError('digest length inconsistent with digest type')
+
+
+@dns.immutable.immutable
+class CDS(_DigestLengthMixin, dns.rdtypes.ANY.CDS.CDS):
+    pass
+
+
+@dns.immutable.immutable
+class DLV(_DigestLengthMixin, dns.rdtypes.ANY.DLV.DLV):
+    pass
+
+
+@dns.immutable.immutable
+class DS(_DigestLengthMixin, dns.rdtypes.ANY.DS.DS):
+    pass

+ 4 - 1
api/desecapi/models.py

@@ -39,7 +39,7 @@ from rest_framework.exceptions import APIException
 
 from desecapi import metrics
 from desecapi import pdns
-from desecapi.dns import LongQuotedTXT
+from desecapi.dns import CDS, DLV, DS, LongQuotedTXT
 
 logger = logging.getLogger(__name__)
 psl = psl_dns.PSL(resolver=settings.PSL_RESOLVER, timeout=.5)
@@ -662,6 +662,9 @@ class RR(ExportModelOperationsMixin('RR'), models.Model):
     objects = RRManager()
 
     _type_map = {
+        dns.rdatatype.CDS: CDS,  # TODO remove when https://github.com/rthalley/dnspython/pull/625 is in main codebase
+        dns.rdatatype.DLV: DLV,  # TODO remove when https://github.com/rthalley/dnspython/pull/625 is in main codebase
+        dns.rdatatype.DS: DS,  # TODO remove when https://github.com/rthalley/dnspython/pull/625 is in main codebase
         dns.rdatatype.TXT: LongQuotedTXT,  # we slightly deviate from RFC 1035 and allow tokens longer than 255 bytes
         dns.rdatatype.SPF: LongQuotedTXT,  # we slightly deviate from RFC 1035 and allow tokens longer than 255 bytes
     }

+ 36 - 4
api/desecapi/tests/test_rrsets.py

@@ -469,13 +469,23 @@ class AuthenticatedRRSetTestCase(AuthenticatedRRSetBaseTestCase):
             ],
             'CNAME': ['example.com.'],
             'DHCID': ['aaaaaaaaaaaa', 'aa aaa  aaaa a a a'],
-            'DLV': ['39556 13 1 aabbccddeeff'],
+            'DLV': [
+                '6454 8 1 24396E17E36D031F71C354B06A979A67A01F503E',
+                '6454 8 2 5CBA665A006F6487625C6218522F09BD3673C25FA10F25CB18459AA1 0DF1F520',
+                '62703 13 2 085BF1EE0ADBBC99D4D9328229EBDCAEC5FAB20E38610072AD055474 4C7AF4A0',
+                '61655 13 4 C838A5C66FCBF83B8B6B50C3CEEC3524777FE4AF8A9FE0172ECAD242 48B0CA1A216DD0D538F20C130DD3059538204B04',
+            ],
             'DNSKEY': [
                 '256 3 8 AwEAAday3UX323uVzQqtOMQ7EHQYfD5Ofv4akjQGN2zY5AgB/2jmdR/+ 1PvXFqzKCAGJv4wjABEBNWLLFm7ew1hHMDZEKVL17aml0EBKI6Dsz6Mx t6n7ScvLtHaFRKaxT4i2JxiuVhKdQR9XGMiWAPQKrRM5SLG0P+2F+TLK l3D0L/cD',
                 '257 3 8 AwEAAcw5QLr0IjC0wKbGoBPQv4qmeqHy9mvL5qGQTuaG5TSrNqEAR6b/ qvxDx6my4JmEmjUPA1JeEI9YfTUieMr2UZflu7aIbZFLw0vqiYrywCGr CHXLalOrEOmrvAxLvq4vHtuTlH7JIszzYBSes8g1vle6KG7xXiP3U5Ll 96Qiu6bZ31rlMQSPB20xbqJJh6psNSrQs41QvdcXAej+K2Hl1Wd8kPri ec4AgiBEh8sk5Pp8W9ROLQ7PcbqqttFaW2m7N/Wy4qcFU13roWKDEAst bxH5CHPoBfZSbIwK4KM6BK/uDHpSPIbiOvOCW+lvu9TAiZPc0oysY6as lO7jXv16Gws=',
                 '257 3 13 aCoEWYBBVsP9Fek2oC8yqU8ocKmnS1iDSFZNORnQuHKtJ9Wpyz+kNryq uB78Pyk/NTEoai5bxoipVQQXzHlzyg==',
             ],
-            'DS': ['39556 13 1 aabbccddeeff'],
+            'DS': [
+                '6454 8 1 24396E17E36D031F71C354B06A979A67A01F503E',
+                '6454 8 2 5CBA665A006F6487625C6218522F09BD3673C25FA10F25CB18459AA1 0DF1F520',
+                '62703 13 2 085BF1EE0ADBBC99D4D9328229EBDCAEC5FAB20E38610072AD055474 4C7AF4A0',
+                '61655 13 4 C838A5C66FCBF83B8B6B50C3CEEC3524777FE4AF8A9FE0172ECAD242 48B0CA1A216DD0D538F20C130DD3059538204B04',
+            ],
             'EUI48': ['aa-bb-cc-dd-ee-ff', 'AA-BB-CC-DD-EE-FF'],
             'EUI64': ['aa-bb-cc-dd-ee-ff-00-11', 'AA-BB-CC-DD-EE-FF-00-11'],
             'HINFO': ['"ARMv8-A" "Linux"'],
@@ -561,20 +571,42 @@ class AuthenticatedRRSetTestCase(AuthenticatedRRSetBaseTestCase):
             ],
             'CDS': [
                 'a 8 1 24396E17E36D031F71C354B06A979A67A01F503E',
+                '-6454 8 1 24396E17E36D031F71C354B06A979A67A01F503E',
                 '6454 b 1 24396E17E36D031F71C354B06A979A67A01F503E',
                 '6454 8 c 24396E17E36D031F71C354B06A979A67A01F503E',
                 '6454 8 1 d',
+                '6454 8 0 24396E17E36D031F71C354B06A979A67A01F503E',
+                '6454 8 5 24396E17E36D031F71C354B06A979A67A01F503E',
+                '6454 8 1 aabbccddeeff',
             ],
             'CNAME': ['example.com', '10 example.com.'],
             'DHCID': ['x', 'xx', 'xxx'],
-            'DLV': ['-34 13 1 aabbccddeeff'],
+            'DLV': [
+                'a 8 1 24396E17E36D031F71C354B06A979A67A01F503E',
+                '-6454 8 1 24396E17E36D031F71C354B06A979A67A01F503E',
+                '6454 b 1 24396E17E36D031F71C354B06A979A67A01F503E',
+                '6454 8 c 24396E17E36D031F71C354B06A979A67A01F503E',
+                '6454 8 1 d',
+                '6454 8 0 24396E17E36D031F71C354B06A979A67A01F503E',
+                '6454 8 5 24396E17E36D031F71C354B06A979A67A01F503E',
+                '6454 8 1 aabbccddeeff',
+            ],
             'DNSKEY': [
                 'a 3 13 aCoEWYBBVsP9Fek2oC8yqU8ocKmnS1iDSFZNORnQuHKtJ9Wpyz+kNryq uB78Pyk/NTEoai5bxoipVQQXzHlzyg=='
                 '257 b 13 aCoEWYBBVsP9Fek2oC8yqU8ocKmnS1iDSFZNORnQuHKtJ9Wpyz+kNryq uB78Pyk/NTEoai5bxoipVQQXzHlzyg=='
                 '257 3 c aCoEWYBBVsP9Fek2oC8yqU8ocKmnS1iDSFZNORnQuHKtJ9Wpyz+kNryq uB78Pyk/NTEoai5bxoipVQQXzHlzyg=='
                 '257 3 13 d'
             ],
-            'DS': ['-34 13 1 aabbccddeeff'],
+            'DS': [
+                'a 8 1 24396E17E36D031F71C354B06A979A67A01F503E',
+                '-6454 8 1 24396E17E36D031F71C354B06A979A67A01F503E',
+                '6454 b 1 24396E17E36D031F71C354B06A979A67A01F503E',
+                '6454 8 c 24396E17E36D031F71C354B06A979A67A01F503E',
+                '6454 8 1 d',
+                '6454 8 0 24396E17E36D031F71C354B06A979A67A01F503E',
+                '6454 8 5 24396E17E36D031F71C354B06A979A67A01F503E',
+                '6454 8 1 aabbccddeeff',
+            ],
             'EUI48': ['aa-bb-ccdd-ee-ff', 'AA-BB-CC-DD-EE-GG'],
             'EUI64': ['aa-bb-cc-dd-ee-ff-gg-11', 'AA-BB-C C-DD-EE-FF-00-11'],
             'HINFO': ['"ARMv8-A"', f'"a" "{"b"*256}"'],

+ 17 - 8
test/e2e2/spec/test_api_rr_validation.py

@@ -36,19 +36,19 @@ VALID_RECORDS_CANONICAL = {
     ],
     'CDS': [
         None,
-        '39556 13 1 aabbccddeeff',
+        '6454 8 1 24396e17e36d031f71c354b06a979a67a01f503e',
     ],
     'CERT': ['6 0 0 sadfdQ=='],
     'CNAME': ['example.com.'],
     'DHCID': ['aaaaaaaaaaaa', 'xxxx'],
-    'DLV': ['39556 13 1 aabbccddeeff'],
+    'DLV': ['6454 8 1 24396e17e36d031f71c354b06a979a67a01f503e'],
     'DNSKEY': [
         None,
         '256 3 8 AwEAAday3UX323uVzQqtOMQ7EHQYfD5O fv4akjQGN2zY5AgB/2jmdR/+1PvXFqzK CAGJv4wjABEBNWLLFm7ew1hHMDZEKVL1 7aml0EBKI6Dsz6Mxt6n7ScvLtHaFRKax T4i2JxiuVhKdQR9XGMiWAPQKrRM5SLG0 P+2F+TLKl3D0L/cD',
         '257 3 8 AwEAAcw5QLr0IjC0wKbGoBPQv4qmeqHy 9mvL5qGQTuaG5TSrNqEAR6b/qvxDx6my 4JmEmjUPA1JeEI9YfTUieMr2UZflu7aI bZFLw0vqiYrywCGrCHXLalOrEOmrvAxL vq4vHtuTlH7JIszzYBSes8g1vle6KG7x XiP3U5Ll96Qiu6bZ31rlMQSPB20xbqJJ h6psNSrQs41QvdcXAej+K2Hl1Wd8kPri ec4AgiBEh8sk5Pp8W9ROLQ7PcbqqttFa W2m7N/Wy4qcFU13roWKDEAstbxH5CHPo BfZSbIwK4KM6BK/uDHpSPIbiOvOCW+lv u9TAiZPc0oysY6aslO7jXv16Gws=',
         '257 3 13 aCoEWYBBVsP9Fek2oC8yqU8ocKmnS1iD SFZNORnQuHKtJ9Wpyz+kNryquB78Pyk/ NTEoai5bxoipVQQXzHlzyg==',
     ],
-    'DS': ['39556 13 1 aabbccddeeff'],
+    'DS': ['6454 8 1 24396e17e36d031f71c354b06a979a67a01f503e'],
     'EUI48': ['aa-bb-cc-dd-ee-ff'],
     'EUI64': ['aa-bb-cc-dd-ee-ff-00-11'],
     'HINFO': ['"ARMv8-A" "Linux"'],
@@ -154,12 +154,15 @@ VALID_RECORDS_NON_CANONICAL = {
         '257 03  8 AwEAAcw5QLr0IjC0wKbGoBPQv4qmeqHy9mvL5qGQTuaG5TSrNqEAR6b/qvxDx6my4JmEmjUPA1JeEI9YfTUieMr2UZflu7aIbZFLw0vqiYrywCGrCHXLalOrEOmrvAxLvq4vHtuTlH7JIszzYBSes8g1vle6KG7xXiP3U5Ll96Qiu6bZ31rlMQSPB20xbqJJh6psNSrQs41QvdcXAej+K2Hl1Wd8kPriec4AgiBEh8sk5Pp8W9ROLQ7PcbqqttFaW2m7N/Wy4qcFU13roWKDEAstbxH5CHPoBfZSbIwK4KM6BK/uDHpSPIbiOvOCW+lvu9TAiZPc0oysY6aslO7jXv16Gws=',
         '257 3 013  aCoEWYBBVsP9Fek2oC8yqU8ocKmnS1iDSFZNORnQuHKtJ9Wpyz+kNryquB78Pyk/NTEoai5bxoipVQQXzHlzyg==',
     ],
-    'CDS': ['039556  013  01  aabbccddeeff'],
+    'CDS': [
+        '06454  08   01    24396e17e36d031f71c354b06a979a67a01f503e',
+        '6454 8 2 5C BA665A006F6487625C6218522F09BD3673C25FA10F25CB18459AA1 0DF1F520',
+    ],
     'CERT': ['06 00 00 sadfee=='],
     'CNAME': ['EXAMPLE.TEST.'],
     'DHCID': ['aa aaa  aaaa a a a', 'xxxx'],
     'DLV': [
-        '6454 8 2 5CBA665A006F6487625C6218522F09BD3673C25FA10F25CB18459AA1 0DF1F520',
+        '06454  08   01    24396e17e36d031f71c354b06a979a67a01f503e',
         '6454 8 2 5C BA665A006F6487625C6218522F09BD3673C25FA10F25CB18459AA1 0DF1F520',
     ],
     'DNSKEY': [
@@ -168,7 +171,7 @@ VALID_RECORDS_NON_CANONICAL = {
         '257 3 013  aCoEWYBBVsP9Fek2oC8yqU8ocKmnS1iDSFZNORnQuHKtJ9Wpyz+kNryquB78Pyk/NTEoai5bxoipVQQXzHlzyg==',
     ],
     'DS': [
-        '6454 8 2 5CBA665A006F6487625C6218522F09BD3673C25FA10F25CB18459AA1 0DF1F520',
+        '06454  08   01    24396e17e36d031f71c354b06a979a67a01f503e',
         '6454 8 2 5C BA665A006F6487625C6218522F09BD3673C25FA10F25CB18459AA1 0DF1F520',
     ],
     'EUI48': ['AA-BB-CC-DD-EE-F1'],
@@ -284,13 +287,19 @@ INVALID_RECORDS = {
     ],
     'CAA': ['43235 issue "letsencrypt.org"'],
     'CDNSKEY': ['a 3 13 aCoEWYBBVsP9Fek2oC8yqU8ocKmnS1iDSFZNORnQuHKtJ9Wpyz+kNryq uB78Pyk/NTEoai5bxoipVQQXzHlzyg=='],
-    'CDS': ['a 8 1 24396E17E36D031F71C354B06A979A67A01F503E'],
+    'CDS': [
+        'a 8 1 24396E17E36D031F71C354B06A979A67A01F503E',
+        '6454 8 1 aabbccddeeff',
+    ],
     'CERT': ['6 0 sadfdd=='],
     'CNAME': ['example.com', '10 example.com.'],
     'DHCID': ['x', 'xx', 'xxx'],
     'DLV': ['-34 13 1 aabbccddeeff'],
     'DNSKEY': ['a 3 13 aCoEWYBBVsP9Fek2oC8yqU8ocKmnS1iDSFZNORnQuHKtJ9Wpyz+kNryq uB78Pyk/NTEoai5bxoipVQQXzHlzyg=='],
-    'DS': ['-34 13 1 aabbccddeeff'],
+    'DS': [
+        '-34 13 1 24396E17E36D031F71C354B06A979A67A01F503E',
+        '6454 8 1 aabbccddeeff',
+    ],
     'EUI48': ['aa-bb-ccdd-ee-ff', 'AA-BB-CC-DD-EE-GG'],
     'EUI64': ['aa-bb-cc-dd-ee-ff-gg-11', 'AA-BB-C C-DD-EE-FF-00-11'],
     'HINFO': ['"ARMv8-A"', f'"a" "{"b" * 256}"'],