cryptoparser 0.10.2__tar.gz → 0.10.3__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {CryptoParser-0.10.2 → CryptoParser-0.10.3}/CHANGELOG.rst +10 -0
- {CryptoParser-0.10.2 → CryptoParser-0.10.3/CryptoParser.egg-info}/PKG-INFO +3 -3
- {CryptoParser-0.10.2 → CryptoParser-0.10.3}/CryptoParser.egg-info/SOURCES.txt +3 -0
- {CryptoParser-0.10.2 → CryptoParser-0.10.3}/CryptoParser.egg-info/requires.txt +1 -1
- {CryptoParser-0.10.2/CryptoParser.egg-info → CryptoParser-0.10.3}/PKG-INFO +3 -3
- {CryptoParser-0.10.2 → CryptoParser-0.10.3}/cryptoparser/__setup__.py +1 -1
- CryptoParser-0.10.3/cryptoparser/dnsrec/record.py +478 -0
- CryptoParser-0.10.3/cryptoparser/dnsrec/txt.py +911 -0
- CryptoParser-0.10.3/cryptoparser/tls/__init__.py +0 -0
- {CryptoParser-0.10.2 → CryptoParser-0.10.3}/requirements.txt +1 -1
- {CryptoParser-0.10.2 → CryptoParser-0.10.3}/setup.py +2 -1
- {CryptoParser-0.10.2 → CryptoParser-0.10.3}/CONTRIBUTING.rst +0 -0
- {CryptoParser-0.10.2 → CryptoParser-0.10.3}/CryptoParser.egg-info/dependency_links.txt +0 -0
- {CryptoParser-0.10.2 → CryptoParser-0.10.3}/CryptoParser.egg-info/top_level.txt +0 -0
- {CryptoParser-0.10.2 → CryptoParser-0.10.3}/LICENSE.txt +0 -0
- {CryptoParser-0.10.2 → CryptoParser-0.10.3}/MANIFEST.in +0 -0
- {CryptoParser-0.10.2 → CryptoParser-0.10.3}/README.rst +0 -0
- {CryptoParser-0.10.2 → CryptoParser-0.10.3}/cryptoparser/__init__.py +0 -0
- {CryptoParser-0.10.2 → CryptoParser-0.10.3}/cryptoparser/common/__init__.py +0 -0
- {CryptoParser-0.10.2 → CryptoParser-0.10.3}/cryptoparser/common/base.py +0 -0
- {CryptoParser-0.10.2 → CryptoParser-0.10.3}/cryptoparser/common/classes.py +0 -0
- {CryptoParser-0.10.2 → CryptoParser-0.10.3}/cryptoparser/common/exception.py +0 -0
- {CryptoParser-0.10.2 → CryptoParser-0.10.3}/cryptoparser/common/field.py +0 -0
- {CryptoParser-0.10.2 → CryptoParser-0.10.3}/cryptoparser/common/parse.py +0 -0
- {CryptoParser-0.10.2 → CryptoParser-0.10.3}/cryptoparser/common/utils.py +0 -0
- {CryptoParser-0.10.2 → CryptoParser-0.10.3}/cryptoparser/common/x509.py +0 -0
- {CryptoParser-0.10.2/cryptoparser/httpx → CryptoParser-0.10.3/cryptoparser/dnsrec}/__init__.py +0 -0
- {CryptoParser-0.10.2/cryptoparser/ssh → CryptoParser-0.10.3/cryptoparser/httpx}/__init__.py +0 -0
- {CryptoParser-0.10.2 → CryptoParser-0.10.3}/cryptoparser/httpx/header.py +0 -0
- {CryptoParser-0.10.2 → CryptoParser-0.10.3}/cryptoparser/httpx/parse.py +0 -0
- {CryptoParser-0.10.2 → CryptoParser-0.10.3}/cryptoparser/httpx/version.py +0 -0
- {CryptoParser-0.10.2/cryptoparser/tls → CryptoParser-0.10.3/cryptoparser/ssh}/__init__.py +0 -0
- {CryptoParser-0.10.2 → CryptoParser-0.10.3}/cryptoparser/ssh/key.py +0 -0
- {CryptoParser-0.10.2 → CryptoParser-0.10.3}/cryptoparser/ssh/record.py +0 -0
- {CryptoParser-0.10.2 → CryptoParser-0.10.3}/cryptoparser/ssh/subprotocol.py +0 -0
- {CryptoParser-0.10.2 → CryptoParser-0.10.3}/cryptoparser/ssh/version.py +0 -0
- {CryptoParser-0.10.2 → CryptoParser-0.10.3}/cryptoparser/tls/algorithm.py +0 -0
- {CryptoParser-0.10.2 → CryptoParser-0.10.3}/cryptoparser/tls/ciphersuite.py +0 -0
- {CryptoParser-0.10.2 → CryptoParser-0.10.3}/cryptoparser/tls/extension.py +0 -0
- {CryptoParser-0.10.2 → CryptoParser-0.10.3}/cryptoparser/tls/grease.py +0 -0
- {CryptoParser-0.10.2 → CryptoParser-0.10.3}/cryptoparser/tls/ldap.py +0 -0
- {CryptoParser-0.10.2 → CryptoParser-0.10.3}/cryptoparser/tls/mysql.py +0 -0
- {CryptoParser-0.10.2 → CryptoParser-0.10.3}/cryptoparser/tls/openvpn.py +0 -0
- {CryptoParser-0.10.2 → CryptoParser-0.10.3}/cryptoparser/tls/postgresql.py +0 -0
- {CryptoParser-0.10.2 → CryptoParser-0.10.3}/cryptoparser/tls/rdp.py +0 -0
- {CryptoParser-0.10.2 → CryptoParser-0.10.3}/cryptoparser/tls/record.py +0 -0
- {CryptoParser-0.10.2 → CryptoParser-0.10.3}/cryptoparser/tls/subprotocol.py +0 -0
- {CryptoParser-0.10.2 → CryptoParser-0.10.3}/cryptoparser/tls/version.py +0 -0
- {CryptoParser-0.10.2 → CryptoParser-0.10.3}/setup.cfg +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: CryptoParser
|
|
3
|
-
Version: 0.10.
|
|
3
|
+
Version: 0.10.3
|
|
4
4
|
Summary: Fast and flexible security protocol parser and generator
|
|
5
5
|
Author: Szilárd Pfeiffer
|
|
6
6
|
Author-email: coroner@pfeifferszilard.hu
|
|
@@ -12,7 +12,7 @@ Project-URL: Changelog, https://cryptoparser.readthedocs.io/en/latest/changelog
|
|
|
12
12
|
Project-URL: Documentation, https://cryptoparser.readthedocs.io/en/latest/
|
|
13
13
|
Project-URL: Issues, https://gitlab.com/coroner/cryptoparser/-/issues
|
|
14
14
|
Project-URL: Source, https://gitlab.com/coroner/cryptoparser
|
|
15
|
-
Keywords: ssl tls gost ja3 ldap rdp ssh hsts
|
|
15
|
+
Keywords: ssl tls gost ja3 ldap rdp ssh hsts dns
|
|
16
16
|
Classifier: Development Status :: 4 - Beta
|
|
17
17
|
Classifier: Environment :: Console
|
|
18
18
|
Classifier: Framework :: tox
|
|
@@ -48,7 +48,7 @@ Description-Content-Type: text/x-rst
|
|
|
48
48
|
License-File: LICENSE.txt
|
|
49
49
|
Requires-Dist: asn1crypto
|
|
50
50
|
Requires-Dist: attrs<22.0.1,>=20.3.0
|
|
51
|
-
Requires-Dist: cryptodatahub>=0.10.
|
|
51
|
+
Requires-Dist: cryptodatahub>=0.10.3
|
|
52
52
|
Requires-Dist: python-dateutil
|
|
53
53
|
Requires-Dist: py2-ipaddress; python_version < "3.4"
|
|
54
54
|
Requires-Dist: typing; python_version < "3.5"
|
|
@@ -20,6 +20,9 @@ cryptoparser/common/field.py
|
|
|
20
20
|
cryptoparser/common/parse.py
|
|
21
21
|
cryptoparser/common/utils.py
|
|
22
22
|
cryptoparser/common/x509.py
|
|
23
|
+
cryptoparser/dnsrec/__init__.py
|
|
24
|
+
cryptoparser/dnsrec/record.py
|
|
25
|
+
cryptoparser/dnsrec/txt.py
|
|
23
26
|
cryptoparser/httpx/__init__.py
|
|
24
27
|
cryptoparser/httpx/header.py
|
|
25
28
|
cryptoparser/httpx/parse.py
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: CryptoParser
|
|
3
|
-
Version: 0.10.
|
|
3
|
+
Version: 0.10.3
|
|
4
4
|
Summary: Fast and flexible security protocol parser and generator
|
|
5
5
|
Author: Szilárd Pfeiffer
|
|
6
6
|
Author-email: coroner@pfeifferszilard.hu
|
|
@@ -12,7 +12,7 @@ Project-URL: Changelog, https://cryptoparser.readthedocs.io/en/latest/changelog
|
|
|
12
12
|
Project-URL: Documentation, https://cryptoparser.readthedocs.io/en/latest/
|
|
13
13
|
Project-URL: Issues, https://gitlab.com/coroner/cryptoparser/-/issues
|
|
14
14
|
Project-URL: Source, https://gitlab.com/coroner/cryptoparser
|
|
15
|
-
Keywords: ssl tls gost ja3 ldap rdp ssh hsts
|
|
15
|
+
Keywords: ssl tls gost ja3 ldap rdp ssh hsts dns
|
|
16
16
|
Classifier: Development Status :: 4 - Beta
|
|
17
17
|
Classifier: Environment :: Console
|
|
18
18
|
Classifier: Framework :: tox
|
|
@@ -48,7 +48,7 @@ Description-Content-Type: text/x-rst
|
|
|
48
48
|
License-File: LICENSE.txt
|
|
49
49
|
Requires-Dist: asn1crypto
|
|
50
50
|
Requires-Dist: attrs<22.0.1,>=20.3.0
|
|
51
|
-
Requires-Dist: cryptodatahub>=0.10.
|
|
51
|
+
Requires-Dist: cryptodatahub>=0.10.3
|
|
52
52
|
Requires-Dist: python-dateutil
|
|
53
53
|
Requires-Dist: py2-ipaddress; python_version < "3.4"
|
|
54
54
|
Requires-Dist: typing; python_version < "3.5"
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
__title__ = 'CryptoParser'
|
|
4
4
|
__technical_name__ = __title__.lower()
|
|
5
|
-
__version__ = '0.10.
|
|
5
|
+
__version__ = '0.10.3'
|
|
6
6
|
__description__ = 'Fast and flexible security protocol parser and generator'
|
|
7
7
|
__author__ = 'Szilárd Pfeiffer'
|
|
8
8
|
__author_email__ = 'coroner@pfeifferszilard.hu'
|
|
@@ -0,0 +1,478 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
|
|
3
|
+
import abc
|
|
4
|
+
import collections
|
|
5
|
+
import datetime
|
|
6
|
+
import enum
|
|
7
|
+
|
|
8
|
+
import attr
|
|
9
|
+
import six
|
|
10
|
+
|
|
11
|
+
from cryptodatahub.common.algorithm import Authentication, NamedGroup, Signature
|
|
12
|
+
from cryptodatahub.common.exception import InvalidValue
|
|
13
|
+
from cryptodatahub.common.key import (
|
|
14
|
+
PublicKey,
|
|
15
|
+
PublicKeyParamsDsa,
|
|
16
|
+
PublicKeyParamsEcdsa,
|
|
17
|
+
PublicKeyParamsEddsa,
|
|
18
|
+
PublicKeyParamsRsa,
|
|
19
|
+
)
|
|
20
|
+
|
|
21
|
+
from cryptodatahub.dnsrec.algorithm import DnsRrType, DnsSecAlgorithm, DnsSecDigestType
|
|
22
|
+
|
|
23
|
+
from cryptoparser.common.base import OneByteEnumParsable, Serializable, TwoByteEnumParsable
|
|
24
|
+
from cryptoparser.common.exception import NotEnoughData
|
|
25
|
+
from cryptoparser.common.parse import ByteOrder, ComposerBinary, ParsableBase, ParserBinary
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
class DnsSecProtocol(enum.Enum):
|
|
29
|
+
V3 = 3
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
class DnsSecFlag(enum.IntEnum):
|
|
33
|
+
SECURE_ENTRY_POINT = 0x0001
|
|
34
|
+
REVOKE = 0x0080
|
|
35
|
+
DNS_ZONE_KEY = 0x0100
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
class DnsSecAlgorithmFactory(OneByteEnumParsable):
|
|
39
|
+
@classmethod
|
|
40
|
+
def get_enum_class(cls):
|
|
41
|
+
return DnsSecAlgorithm
|
|
42
|
+
|
|
43
|
+
@abc.abstractmethod
|
|
44
|
+
def compose(self):
|
|
45
|
+
raise NotImplementedError()
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
@attr.s
|
|
49
|
+
class DnsRecordDnskey(ParsableBase, Serializable):
|
|
50
|
+
HEADER_SIZE = 4
|
|
51
|
+
|
|
52
|
+
flags = attr.ib(validator=attr.validators.deep_iterable(attr.validators.instance_of(DnsSecFlag)))
|
|
53
|
+
algorithm = attr.ib(validator=attr.validators.instance_of(DnsSecAlgorithm))
|
|
54
|
+
key = attr.ib(validator=attr.validators.instance_of(PublicKey))
|
|
55
|
+
protocol = attr.ib(validator=attr.validators.instance_of(DnsSecProtocol))
|
|
56
|
+
|
|
57
|
+
def __attrs_post_init__(self):
|
|
58
|
+
if not isinstance(self.algorithm.value.algorithm, Signature):
|
|
59
|
+
raise InvalidValue(self.algorithm.value.algorithm, type(self), 'algorithm_type')
|
|
60
|
+
|
|
61
|
+
algorithm_key_type = self.algorithm.value.algorithm.value.key_type
|
|
62
|
+
algorithm_incompatible = self.key.key_type != algorithm_key_type
|
|
63
|
+
algorithm_compatible_gost = (
|
|
64
|
+
self.algorithm == DnsSecAlgorithm.ECCGOST and
|
|
65
|
+
self.key.key_type == Authentication.ECDSA and
|
|
66
|
+
self.key.params.named_group == NamedGroup.GC256B
|
|
67
|
+
)
|
|
68
|
+
if (algorithm_incompatible and not algorithm_compatible_gost):
|
|
69
|
+
raise InvalidValue(algorithm_key_type, type(self), 'key_type')
|
|
70
|
+
|
|
71
|
+
@property
|
|
72
|
+
def key_tag(self):
|
|
73
|
+
if self.algorithm == DnsSecAlgorithm.RSAMD5:
|
|
74
|
+
return (self.key.params.modulus & 0xffffff) >> 8
|
|
75
|
+
|
|
76
|
+
key_tag = 0
|
|
77
|
+
parser = ParserBinary(self.compose(), byte_order=ByteOrder.BIG_ENDIAN)
|
|
78
|
+
|
|
79
|
+
while parser.unparsed_length > 1:
|
|
80
|
+
parser.parse_numeric('value', 2)
|
|
81
|
+
key_tag += parser['value']
|
|
82
|
+
if parser.unparsed_length:
|
|
83
|
+
parser.parse_numeric('value', 1)
|
|
84
|
+
key_tag += parser['value']
|
|
85
|
+
|
|
86
|
+
key_tag += (key_tag >> 16) & 0xffff
|
|
87
|
+
return key_tag & 0xffff
|
|
88
|
+
|
|
89
|
+
def _asdict(self):
|
|
90
|
+
dict_value = super(DnsRecordDnskey, self)._asdict()
|
|
91
|
+
return collections.OrderedDict([('key_tag', self.key_tag)] + list(dict_value.items()))
|
|
92
|
+
|
|
93
|
+
@classmethod
|
|
94
|
+
def _parse_public_key_rsa(cls, key_parser):
|
|
95
|
+
key_parser.parse_numeric('exponent_length_one_octet', 1)
|
|
96
|
+
exponent_length = key_parser['exponent_length_one_octet']
|
|
97
|
+
if exponent_length == 0:
|
|
98
|
+
key_parser.parse_numeric('exponent_length_two_octets', 2)
|
|
99
|
+
exponent_length = key_parser['exponent_length_two_octets']
|
|
100
|
+
key_parser.parse_mpint('public_exponent', exponent_length)
|
|
101
|
+
key_parser.parse_mpint('modulus', key_parser.unparsed_length)
|
|
102
|
+
|
|
103
|
+
return PublicKey.from_params(PublicKeyParamsRsa(
|
|
104
|
+
public_exponent=key_parser['public_exponent'],
|
|
105
|
+
modulus=key_parser['modulus'],
|
|
106
|
+
))
|
|
107
|
+
|
|
108
|
+
@classmethod
|
|
109
|
+
def _parse_public_key_ecdsa(cls, dnssec_algorithm, key_parser):
|
|
110
|
+
if dnssec_algorithm == DnsSecAlgorithm.ECDSAP256SHA256:
|
|
111
|
+
named_group = NamedGroup.SECP256K1
|
|
112
|
+
elif dnssec_algorithm == DnsSecAlgorithm.ECDSAP384SHA384:
|
|
113
|
+
named_group = NamedGroup.SECP384R1
|
|
114
|
+
elif dnssec_algorithm == DnsSecAlgorithm.ECCGOST:
|
|
115
|
+
named_group = NamedGroup.GC256B
|
|
116
|
+
else:
|
|
117
|
+
raise NotImplementedError(dnssec_algorithm)
|
|
118
|
+
|
|
119
|
+
key_size = named_group.value.size // 8
|
|
120
|
+
key_parser.parse_mpint('x', key_size)
|
|
121
|
+
key_parser.parse_mpint('y', key_size)
|
|
122
|
+
|
|
123
|
+
return PublicKey.from_params(PublicKeyParamsEcdsa(
|
|
124
|
+
point_x=key_parser['x'], point_y=key_parser['y'], named_group=named_group,
|
|
125
|
+
))
|
|
126
|
+
|
|
127
|
+
@classmethod
|
|
128
|
+
def _parse_public_key_eddsa(cls, public_key_type, key_parser):
|
|
129
|
+
if public_key_type == Authentication.ED25519:
|
|
130
|
+
key_parser.parse_raw('public_key', 256 // 8)
|
|
131
|
+
elif public_key_type == Authentication.ED448:
|
|
132
|
+
key_parser.parse_raw('public_key', 448 // 8)
|
|
133
|
+
else:
|
|
134
|
+
raise NotImplementedError(public_key_type)
|
|
135
|
+
|
|
136
|
+
return PublicKey.from_params(PublicKeyParamsEddsa(
|
|
137
|
+
key_data=key_parser['public_key'], key_type=public_key_type,
|
|
138
|
+
))
|
|
139
|
+
|
|
140
|
+
@classmethod
|
|
141
|
+
def _parse_public_key_dss(cls, key_parser):
|
|
142
|
+
key_parser.parse_numeric('t', 1)
|
|
143
|
+
key_parser.parse_mpint('q', 20)
|
|
144
|
+
|
|
145
|
+
mpint_length = 64 + key_parser['t'] * 8
|
|
146
|
+
key_parser.parse_mpint('p', mpint_length)
|
|
147
|
+
key_parser.parse_mpint('g', mpint_length)
|
|
148
|
+
key_parser.parse_mpint('y', mpint_length)
|
|
149
|
+
|
|
150
|
+
return PublicKey.from_params(PublicKeyParamsDsa(
|
|
151
|
+
prime=key_parser['p'],
|
|
152
|
+
generator=key_parser['g'],
|
|
153
|
+
order=key_parser['q'],
|
|
154
|
+
public_key_value=key_parser['y'],
|
|
155
|
+
))
|
|
156
|
+
|
|
157
|
+
@classmethod
|
|
158
|
+
def parse_key(cls, parsable, dnssec_algorithm):
|
|
159
|
+
key_parser = ParserBinary(parsable)
|
|
160
|
+
|
|
161
|
+
public_key_type = dnssec_algorithm.value.algorithm.value.key_type
|
|
162
|
+
if public_key_type == Authentication.RSA:
|
|
163
|
+
public_key = cls._parse_public_key_rsa(key_parser)
|
|
164
|
+
elif public_key_type in [Authentication.ECDSA, Authentication.GOST_R3410_01]:
|
|
165
|
+
public_key = cls._parse_public_key_ecdsa(dnssec_algorithm, key_parser)
|
|
166
|
+
elif public_key_type in [Authentication.ED25519, Authentication.ED448]:
|
|
167
|
+
public_key = cls._parse_public_key_eddsa(public_key_type, key_parser)
|
|
168
|
+
elif public_key_type == Authentication.DSS:
|
|
169
|
+
public_key = cls._parse_public_key_dss(key_parser)
|
|
170
|
+
else:
|
|
171
|
+
raise NotImplementedError(dnssec_algorithm)
|
|
172
|
+
|
|
173
|
+
return public_key
|
|
174
|
+
|
|
175
|
+
@classmethod
|
|
176
|
+
def _parse(cls, parsable):
|
|
177
|
+
if len(parsable) < cls.HEADER_SIZE:
|
|
178
|
+
raise NotEnoughData(cls.HEADER_SIZE - len(parsable))
|
|
179
|
+
|
|
180
|
+
parser = ParserBinary(parsable)
|
|
181
|
+
|
|
182
|
+
parser.parse_numeric_flags('flags', 2, DnsSecFlag)
|
|
183
|
+
parser.parse_numeric('protocol', 1, DnsSecProtocol)
|
|
184
|
+
|
|
185
|
+
parser.parse_parsable('algorithm', DnsSecAlgorithmFactory)
|
|
186
|
+
parser.parse_raw('key', parser.unparsed_length)
|
|
187
|
+
|
|
188
|
+
public_key = cls.parse_key(parser['key'], parser['algorithm'])
|
|
189
|
+
|
|
190
|
+
return cls(
|
|
191
|
+
parser['flags'],
|
|
192
|
+
parser['algorithm'],
|
|
193
|
+
public_key,
|
|
194
|
+
parser['protocol'],
|
|
195
|
+
), parser.parsed_length
|
|
196
|
+
|
|
197
|
+
@staticmethod
|
|
198
|
+
def _compose_public_key_rsa(key_composer, key):
|
|
199
|
+
key_params = key.params
|
|
200
|
+
exponent_length = (key_params.public_exponent.bit_length() + 7) // 8
|
|
201
|
+
if exponent_length > 255:
|
|
202
|
+
key_composer.compose_numeric(0, 1)
|
|
203
|
+
key_composer.compose_numeric(exponent_length, 2)
|
|
204
|
+
else:
|
|
205
|
+
key_composer.compose_numeric(exponent_length, 1)
|
|
206
|
+
|
|
207
|
+
key_composer.compose_mpint(key_params.public_exponent, exponent_length)
|
|
208
|
+
key_composer.compose_mpint(key_params.modulus, key.key_size // 8)
|
|
209
|
+
|
|
210
|
+
@staticmethod
|
|
211
|
+
def _compose_public_key_ecdsa(key_composer, key):
|
|
212
|
+
key_params = key.params
|
|
213
|
+
key_size = key.key_size // 8
|
|
214
|
+
key_composer.compose_mpint(key_params.point_x, key_size)
|
|
215
|
+
key_composer.compose_mpint(key_params.point_y, key_size)
|
|
216
|
+
|
|
217
|
+
@staticmethod
|
|
218
|
+
def _compose_public_key_eddsa(key_composer, key):
|
|
219
|
+
key_params = key.params
|
|
220
|
+
key_composer.compose_raw(key_params.key_data)
|
|
221
|
+
|
|
222
|
+
@staticmethod
|
|
223
|
+
def _compose_public_key_dss(key_composer, key):
|
|
224
|
+
key_params = key.params
|
|
225
|
+
key_size = key.key_size // 8
|
|
226
|
+
|
|
227
|
+
key_composer.compose_numeric((key_size - 64) // 8, 1)
|
|
228
|
+
key_composer.compose_mpint(key_params.order, 20)
|
|
229
|
+
|
|
230
|
+
key_composer.compose_mpint(key_params.prime, key_size)
|
|
231
|
+
key_composer.compose_mpint(key_params.generator, key_size)
|
|
232
|
+
key_composer.compose_mpint(key_params.public_key_value, key_size)
|
|
233
|
+
|
|
234
|
+
@staticmethod
|
|
235
|
+
def compose_key(key):
|
|
236
|
+
key_composer = ComposerBinary()
|
|
237
|
+
public_key_type = key.key_type
|
|
238
|
+
|
|
239
|
+
if public_key_type == Authentication.RSA:
|
|
240
|
+
DnsRecordDnskey._compose_public_key_rsa(key_composer, key)
|
|
241
|
+
elif public_key_type in [Authentication.ECDSA, Authentication.GOST_R3410_01]:
|
|
242
|
+
DnsRecordDnskey._compose_public_key_ecdsa(key_composer, key)
|
|
243
|
+
elif public_key_type in [Authentication.ED25519, Authentication.ED448]:
|
|
244
|
+
DnsRecordDnskey._compose_public_key_eddsa(key_composer, key)
|
|
245
|
+
elif public_key_type == Authentication.DSS:
|
|
246
|
+
DnsRecordDnskey._compose_public_key_dss(key_composer, key)
|
|
247
|
+
else:
|
|
248
|
+
raise NotImplementedError(public_key_type)
|
|
249
|
+
|
|
250
|
+
return key_composer.composed_bytes
|
|
251
|
+
|
|
252
|
+
def compose(self):
|
|
253
|
+
composer = ComposerBinary()
|
|
254
|
+
|
|
255
|
+
composer.compose_numeric_flags(self.flags, 2)
|
|
256
|
+
composer.compose_numeric(self.protocol.value, 1)
|
|
257
|
+
|
|
258
|
+
composer.compose_numeric_enum_coded(self.algorithm)
|
|
259
|
+
|
|
260
|
+
key_bytes = self.compose_key(self.key)
|
|
261
|
+
|
|
262
|
+
return composer.composed_bytes + key_bytes
|
|
263
|
+
|
|
264
|
+
|
|
265
|
+
class DnsSecDigestTypeFactory(OneByteEnumParsable):
|
|
266
|
+
@classmethod
|
|
267
|
+
def get_enum_class(cls):
|
|
268
|
+
return DnsSecDigestType
|
|
269
|
+
|
|
270
|
+
@abc.abstractmethod
|
|
271
|
+
def compose(self):
|
|
272
|
+
raise NotImplementedError()
|
|
273
|
+
|
|
274
|
+
|
|
275
|
+
@attr.s
|
|
276
|
+
class DnsRecordDs(ParsableBase):
|
|
277
|
+
HEADER_SIZE = 4
|
|
278
|
+
|
|
279
|
+
key_tag = attr.ib(validator=attr.validators.instance_of(six.integer_types))
|
|
280
|
+
algorithm = attr.ib(validator=attr.validators.instance_of(DnsSecAlgorithm))
|
|
281
|
+
digest_type = attr.ib(validator=attr.validators.instance_of(DnsSecDigestType))
|
|
282
|
+
digest = attr.ib(validator=attr.validators.instance_of((bytes, bytearray)))
|
|
283
|
+
|
|
284
|
+
@classmethod
|
|
285
|
+
def _parse(cls, parsable):
|
|
286
|
+
if len(parsable) < cls.HEADER_SIZE:
|
|
287
|
+
raise NotEnoughData(cls.HEADER_SIZE - len(parsable))
|
|
288
|
+
|
|
289
|
+
parser = ParserBinary(parsable)
|
|
290
|
+
|
|
291
|
+
parser.parse_numeric('key_tag', 2)
|
|
292
|
+
parser.parse_parsable('algorithm', DnsSecAlgorithmFactory)
|
|
293
|
+
parser.parse_parsable('digest_type', DnsSecDigestTypeFactory)
|
|
294
|
+
parser.parse_raw('digest', parser.unparsed_length)
|
|
295
|
+
|
|
296
|
+
return cls(**parser), parser.parsed_length
|
|
297
|
+
|
|
298
|
+
def compose(self):
|
|
299
|
+
composer = ComposerBinary()
|
|
300
|
+
|
|
301
|
+
composer.compose_numeric(self.key_tag, 2)
|
|
302
|
+
composer.compose_numeric_enum_coded(self.algorithm)
|
|
303
|
+
composer.compose_numeric_enum_coded(self.digest_type)
|
|
304
|
+
composer.compose_raw(self.digest)
|
|
305
|
+
|
|
306
|
+
return composer.composed_bytes
|
|
307
|
+
|
|
308
|
+
|
|
309
|
+
class DnsRrTypeFactory(TwoByteEnumParsable):
|
|
310
|
+
@classmethod
|
|
311
|
+
def get_enum_class(cls):
|
|
312
|
+
return DnsRrType
|
|
313
|
+
|
|
314
|
+
@abc.abstractmethod
|
|
315
|
+
def compose(self):
|
|
316
|
+
raise NotImplementedError()
|
|
317
|
+
|
|
318
|
+
|
|
319
|
+
@attr.s
|
|
320
|
+
class DnsNameUncompressed(ParsableBase, Serializable):
|
|
321
|
+
labels = attr.ib(
|
|
322
|
+
validator=attr.validators.deep_iterable(member_validator=attr.validators.instance_of(six.string_types))
|
|
323
|
+
)
|
|
324
|
+
|
|
325
|
+
def __str__(self):
|
|
326
|
+
return six.u('.').join(self.labels)
|
|
327
|
+
|
|
328
|
+
def _as_markdown(self, level):
|
|
329
|
+
return self._markdown_result(str(self), level)
|
|
330
|
+
|
|
331
|
+
@classmethod
|
|
332
|
+
def convert(cls, value):
|
|
333
|
+
if isinstance(value, cls):
|
|
334
|
+
return value
|
|
335
|
+
if isinstance(value, six.string_types):
|
|
336
|
+
if not value:
|
|
337
|
+
return cls([])
|
|
338
|
+
|
|
339
|
+
return cls(value.split('.'))
|
|
340
|
+
|
|
341
|
+
raise InvalidValue(value, cls, 'labels')
|
|
342
|
+
|
|
343
|
+
@classmethod
|
|
344
|
+
def _parse(cls, parsable):
|
|
345
|
+
parser = ParserBinary(parsable)
|
|
346
|
+
|
|
347
|
+
labels = []
|
|
348
|
+
while True:
|
|
349
|
+
parser.parse_string('label', 1, encoding='idna')
|
|
350
|
+
label = parser['label']
|
|
351
|
+
|
|
352
|
+
if not label:
|
|
353
|
+
break
|
|
354
|
+
|
|
355
|
+
labels.append(label)
|
|
356
|
+
|
|
357
|
+
return cls(labels), parser.parsed_length
|
|
358
|
+
|
|
359
|
+
def compose(self):
|
|
360
|
+
composer = ComposerBinary()
|
|
361
|
+
|
|
362
|
+
for label in self.labels:
|
|
363
|
+
composer.compose_string(label, 'idna', 1)
|
|
364
|
+
|
|
365
|
+
composer.compose_numeric(0, 1)
|
|
366
|
+
|
|
367
|
+
return composer.composed_bytes
|
|
368
|
+
|
|
369
|
+
|
|
370
|
+
@attr.s
|
|
371
|
+
class DnsRecordRrsig(ParsableBase): # pylint: disable=too-many-instance-attributes
|
|
372
|
+
HEADER_SIZE = 24
|
|
373
|
+
|
|
374
|
+
type_covered = attr.ib(validator=attr.validators.instance_of(DnsRrType))
|
|
375
|
+
algorithm = attr.ib(validator=attr.validators.instance_of(DnsSecAlgorithm))
|
|
376
|
+
labels = attr.ib(validator=attr.validators.instance_of(six.integer_types))
|
|
377
|
+
original_ttl = attr.ib(
|
|
378
|
+
validator=attr.validators.instance_of(six.integer_types),
|
|
379
|
+
metadata={'human_readable_name': 'Original TTL'}
|
|
380
|
+
)
|
|
381
|
+
signature_expiration = attr.ib(validator=attr.validators.instance_of(datetime.datetime))
|
|
382
|
+
signature_inception = attr.ib(validator=attr.validators.instance_of(datetime.datetime))
|
|
383
|
+
key_tag = attr.ib(validator=attr.validators.instance_of(six.integer_types))
|
|
384
|
+
signers_name = attr.ib(
|
|
385
|
+
converter=DnsNameUncompressed.convert,
|
|
386
|
+
validator=attr.validators.instance_of(DnsNameUncompressed)
|
|
387
|
+
)
|
|
388
|
+
signature = attr.ib(validator=attr.validators.instance_of((bytes, bytearray)))
|
|
389
|
+
|
|
390
|
+
@classmethod
|
|
391
|
+
def _parse(cls, parsable):
|
|
392
|
+
if len(parsable) < cls.HEADER_SIZE:
|
|
393
|
+
raise NotEnoughData(cls.HEADER_SIZE - len(parsable))
|
|
394
|
+
|
|
395
|
+
parser = ParserBinary(parsable)
|
|
396
|
+
|
|
397
|
+
parser.parse_parsable('type_covered', DnsRrTypeFactory)
|
|
398
|
+
parser.parse_parsable('algorithm', DnsSecAlgorithmFactory)
|
|
399
|
+
parser.parse_numeric('labels', 1)
|
|
400
|
+
parser.parse_numeric('original_ttl', 4)
|
|
401
|
+
parser.parse_timestamp('signature_expiration', item_size=4)
|
|
402
|
+
parser.parse_timestamp('signature_inception', item_size=4)
|
|
403
|
+
parser.parse_numeric('key_tag', 2)
|
|
404
|
+
parser.parse_parsable('signers_name', DnsNameUncompressed)
|
|
405
|
+
parser.parse_raw('signature', parser.unparsed_length)
|
|
406
|
+
|
|
407
|
+
return cls(**parser), parser.parsed_length
|
|
408
|
+
|
|
409
|
+
def compose(self):
|
|
410
|
+
composer = ComposerBinary()
|
|
411
|
+
|
|
412
|
+
composer.compose_numeric_enum_coded(self.type_covered)
|
|
413
|
+
composer.compose_numeric_enum_coded(self.algorithm)
|
|
414
|
+
composer.compose_numeric(self.labels, 1)
|
|
415
|
+
composer.compose_numeric(self.original_ttl, 4)
|
|
416
|
+
composer.compose_timestamp(self.signature_expiration, item_size=4)
|
|
417
|
+
composer.compose_timestamp(self.signature_inception, item_size=4)
|
|
418
|
+
composer.compose_numeric(self.key_tag, 2)
|
|
419
|
+
composer.compose_parsable(self.signers_name)
|
|
420
|
+
composer.compose_raw(self.signature)
|
|
421
|
+
|
|
422
|
+
return composer.composed_bytes
|
|
423
|
+
|
|
424
|
+
|
|
425
|
+
@attr.s
|
|
426
|
+
class DnsRecordMx(ParsableBase):
|
|
427
|
+
HEADER_SIZE = 2
|
|
428
|
+
|
|
429
|
+
priority = attr.ib(validator=attr.validators.instance_of(six.integer_types))
|
|
430
|
+
exchange = attr.ib(
|
|
431
|
+
converter=DnsNameUncompressed.convert,
|
|
432
|
+
validator=attr.validators.instance_of(DnsNameUncompressed)
|
|
433
|
+
)
|
|
434
|
+
|
|
435
|
+
@classmethod
|
|
436
|
+
def _parse(cls, parsable):
|
|
437
|
+
if len(parsable) < cls.HEADER_SIZE:
|
|
438
|
+
raise NotEnoughData(cls.HEADER_SIZE - len(parsable))
|
|
439
|
+
|
|
440
|
+
parser = ParserBinary(parsable)
|
|
441
|
+
|
|
442
|
+
parser.parse_numeric('priority', 2)
|
|
443
|
+
parser.parse_parsable('exchange', DnsNameUncompressed)
|
|
444
|
+
|
|
445
|
+
return cls(**parser), parser.parsed_length
|
|
446
|
+
|
|
447
|
+
def compose(self):
|
|
448
|
+
composer = ComposerBinary()
|
|
449
|
+
|
|
450
|
+
composer.compose_numeric(self.priority, 2)
|
|
451
|
+
composer.compose_parsable(self.exchange)
|
|
452
|
+
|
|
453
|
+
return composer.composed_bytes
|
|
454
|
+
|
|
455
|
+
|
|
456
|
+
@attr.s
|
|
457
|
+
class DnsRecordTxt(ParsableBase):
|
|
458
|
+
HEADER_SIZE = 1
|
|
459
|
+
|
|
460
|
+
value = attr.ib(validator=attr.validators.instance_of(six.string_types))
|
|
461
|
+
|
|
462
|
+
@classmethod
|
|
463
|
+
def _parse(cls, parsable):
|
|
464
|
+
if len(parsable) < cls.HEADER_SIZE:
|
|
465
|
+
raise NotEnoughData(cls.HEADER_SIZE - len(parsable))
|
|
466
|
+
|
|
467
|
+
parser = ParserBinary(parsable)
|
|
468
|
+
|
|
469
|
+
parser.parse_string('value', 1, encoding='ascii')
|
|
470
|
+
|
|
471
|
+
return cls(**parser), parser.parsed_length
|
|
472
|
+
|
|
473
|
+
def compose(self):
|
|
474
|
+
composer = ComposerBinary()
|
|
475
|
+
|
|
476
|
+
composer.compose_string(self.value, 'ascii', 1)
|
|
477
|
+
|
|
478
|
+
return composer.composed_bytes
|