diff --git a/cryptoparser/dnsrec/record.py b/cryptoparser/dnsrec/record.py index 699c8c5..0a45d1c 100644 --- a/cryptoparser/dnsrec/record.py +++ b/cryptoparser/dnsrec/record.py @@ -20,7 +20,7 @@ from cryptodatahub.dnsrec.algorithm import DnsRrType, DnsSecAlgorithm, DnsSecDigestType -from cryptoparser.common.base import OneByteEnumParsable, Serializable, TwoByteEnumParsable +from cryptoparser.common.base import NumericRangeParsableBase, OneByteEnumParsable, Serializable, TwoByteEnumParsable from cryptoparser.common.exception import NotEnoughData from cryptoparser.common.parse import ByteOrder, ComposerBinary, ParsableBase, ParserBinary @@ -318,6 +318,20 @@ def compose(self): raise NotImplementedError() +class DnsRrTypePrivate(NumericRangeParsableBase): + @classmethod + def _get_value_min(cls): + return 0xff00 + + @classmethod + def _get_value_max(cls): + return 0xfffe + + @classmethod + def _get_value_length(cls): + return 2 + + @attr.s class DnsNameUncompressed(ParsableBase, Serializable): labels = attr.ib( @@ -373,7 +387,7 @@ def compose(self): class DnsRecordRrsig(ParsableBase): # pylint: disable=too-many-instance-attributes HEADER_SIZE = 24 - type_covered = attr.ib(validator=attr.validators.instance_of(DnsRrType)) + type_covered = attr.ib(validator=attr.validators.instance_of((DnsRrType, DnsRrTypePrivate))) algorithm = attr.ib(validator=attr.validators.instance_of(DnsSecAlgorithm)) labels = attr.ib(validator=attr.validators.instance_of(six.integer_types)) original_ttl = attr.ib( @@ -396,7 +410,10 @@ def _parse(cls, parsable): parser = ParserBinary(parsable) - parser.parse_parsable('type_covered', DnsRrTypeFactory) + try: + parser.parse_parsable('type_covered', DnsRrTypeFactory) + except InvalidValue: + parser.parse_parsable('type_covered', DnsRrTypePrivate) parser.parse_parsable('algorithm', DnsSecAlgorithmFactory) parser.parse_numeric('labels', 1) parser.parse_numeric('original_ttl', 4) @@ -411,7 +428,10 @@ def _parse(cls, parsable): def compose(self): composer = ComposerBinary() - composer.compose_numeric_enum_coded(self.type_covered) + if isinstance(self.type_covered, DnsRrType): + composer.compose_numeric_enum_coded(self.type_covered) + else: + composer.compose_parsable(self.type_covered) composer.compose_numeric_enum_coded(self.algorithm) composer.compose_numeric(self.labels, 1) composer.compose_numeric(self.original_ttl, 4) diff --git a/test/dnsrec/test_record.py b/test/dnsrec/test_record.py index 6cd1587..d003f56 100644 --- a/test/dnsrec/test_record.py +++ b/test/dnsrec/test_record.py @@ -28,6 +28,7 @@ DnsRecordMx, DnsRecordRrsig, DnsRecordTxt, + DnsRrTypePrivate, DnsSecFlag, DnsSecProtocol, ) @@ -447,6 +448,30 @@ def setUp(self): signature=32 * b'\xff', ) + self.record_private_type_bytes = bytes( + b'\xff\xfe' + # type_covered: A + b'\x01' + # algorithm: RSAMD5 + b'\x03' + # labels + b'\x00\x00\x0e\x10' + # original_ttl: 3600 + b'\x00\x00\x00\x01' + # signature_expiration + b'\x00\x00\x00\x02' + # signature_inception + b'\xab\xcd' + # key_tag + b'\x06signer\x00' + # signers_name + 32 * b'\xff' + # signature + b'' + ) + self.record_private_types = DnsRecordRrsig( + type_covered=DnsRrTypePrivate(0xfffe), + algorithm=DnsSecAlgorithm.RSAMD5, + labels=3, + original_ttl=3600, + signature_expiration=datetime.datetime(1970, 1, 1, 0, 0, 1, tzinfo=dateutil.tz.UTC), + signature_inception=datetime.datetime(1970, 1, 1, 0, 0, 2, tzinfo=dateutil.tz.UTC), + key_tag=0xabcd, + signers_name='signer', + signature=32 * b'\xff', + ) + def test_error_not_enough_data(self): with self.assertRaises(NotEnoughData) as context_manager: DnsRecordRrsig.parse_exact_size(b'\x00') @@ -458,9 +483,11 @@ def test_error_not_enough_data(self): def test_parse(self): self.assertEqual(DnsRecordRrsig.parse_exact_size(self.record_bytes), self.record) + self.assertEqual(DnsRecordRrsig.parse_exact_size(self.record_private_type_bytes), self.record_private_types) def test_compose(self): self.assertEqual(self.record.compose(), self.record_bytes) + self.assertEqual(self.record_private_types.compose(), self.record_private_type_bytes) class TestDnsRecordMx(unittest.TestCase):