Skip to content

Commit

Permalink
Merge branch '86-tls-addextension-messages-used-by-most-modern-browsers'
Browse files Browse the repository at this point in the history
Closes: #86
  • Loading branch information
c0r0n3r committed Dec 8, 2024
2 parents 8c6da41 + 51992ae commit 55fa783
Show file tree
Hide file tree
Showing 3 changed files with 170 additions and 1 deletion.
98 changes: 98 additions & 0 deletions cryptoparser/tls/extension.py
Original file line number Diff line number Diff line change
Expand Up @@ -1191,6 +1191,101 @@ def compose(self):
return header_bytes + payload_composer.composed_bytes


class TlsEncryptedClientHelloType(enum.IntEnum):
OUTER = 0
INNER = 1


@attr.s
class TlsExtensionEncryptedClientHelloBase(TlsExtensionParsed):
@classmethod
def get_extension_type(cls):
return TlsExtensionType.ENCRYPTED_CLIENT_HELLO

@classmethod
@abc.abstractmethod
def _parse(cls, parsable):
raise NotImplementedError()

@abc.abstractmethod
def compose(self):
raise NotImplementedError()

@classmethod
@abc.abstractmethod
def get_encrypted_client_hello_type(cls):
raise NotImplementedError()

@classmethod
def _parse_header(cls, parsable):
parser = super(TlsExtensionEncryptedClientHelloBase, cls)._parse_header(parsable)

parser.parse_numeric('client_hello_type', 1, TlsEncryptedClientHelloType)
if parser['client_hello_type'] != cls.get_encrypted_client_hello_type():
raise InvalidType()

return parser

def compose_type(self):
composer = ComposerBinary()

composer.compose_numeric(self.get_encrypted_client_hello_type(), 1)

return composer


@attr.s
class TlsExtensionEncryptedClientHelloInner(TlsExtensionEncryptedClientHelloBase):
@classmethod
def get_encrypted_client_hello_type(cls):
return TlsEncryptedClientHelloType.INNER

@classmethod
def _parse(cls, parsable):
parser = cls._parse_header(parsable)

return cls(), parser.parsed_length

def compose(self):
payload_composer = self.compose_type()

header_bytes = self._compose_header(payload_composer.composed_length)

return header_bytes + payload_composer.composed_bytes


@attr.s
class TlsExtensionEncryptedClientHelloOuter(TlsExtensionEncryptedClientHelloBase):
data = attr.ib(validator=attr.validators.instance_of((bytes, bytearray)))

@classmethod
def get_encrypted_client_hello_type(cls):
return TlsEncryptedClientHelloType.OUTER

@classmethod
def _parse(cls, parsable):
parser = cls._parse_header(parsable)

parser.parse_raw('data', parser.unparsed_length)

return cls(parser['data']), parser.parsed_length

def compose(self):
payload_composer = self.compose_type()

payload_composer.compose_raw(self.data)

header_bytes = self._compose_header(payload_composer.composed_length)

return header_bytes + payload_composer.composed_bytes


class TlsExtensionPostHandshakeAuthentication(TlsExtensionUnusedData):
@classmethod
def get_extension_type(cls):
return TlsExtensionType.POST_HANDSHAKE_AUTH


class TlsExtensionVariantBase(VariantParsable):
@classmethod
@abc.abstractmethod
Expand Down Expand Up @@ -1233,13 +1328,16 @@ def get_parsed_extensions(cls):
(TlsExtensionType.EC_POINT_FORMATS, [TlsExtensionECPointFormats, ]),
(TlsExtensionType.KEY_SHARE, [TlsExtensionKeyShareClient, ]),
(TlsExtensionType.KEY_SHARE_RESERVED, [TlsExtensionKeyShareReservedClient, ]),
(TlsExtensionType.POST_HANDSHAKE_AUTH, [TlsExtensionPostHandshakeAuthentication, ]),
(TlsExtensionType.PSK_KEY_EXCHANGE_MODES, [TlsExtensionPskKeyExchangeModes, ]),
(TlsExtensionType.RECORD_SIZE_LIMIT, [TlsExtensionRecordSizeLimit, ]),
(TlsExtensionType.SHORT_RECORD_HEADER, [TlsExtensionShortRecordHeader, ]),
(TlsExtensionType.SIGNATURE_ALGORITHMS, [TlsExtensionSignatureAlgorithms, ]),
(TlsExtensionType.SIGNATURE_ALGORITHMS_CERT, [TlsExtensionSignatureAlgorithmsCert, ]),
(TlsExtensionType.SIGNED_CERTIFICATE_TIMESTAMP, [TlsExtensionSignedCertificateTimestampClient, ]),
(TlsExtensionType.SUPPORTED_VERSIONS, [TlsExtensionSupportedVersionsClient, ]),
(TlsExtensionType.ENCRYPTED_CLIENT_HELLO, [TlsExtensionEncryptedClientHelloInner,
TlsExtensionEncryptedClientHelloOuter]),
(TlsExtensionType.TOKEN_BINDING, [TlsExtensionTokenBinding, ]),
])

Expand Down
2 changes: 1 addition & 1 deletion submodules/cryptodatahub
Submodule cryptodatahub updated from 648124 to ed6b4d
71 changes: 71 additions & 0 deletions test/tls/test_extension.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@
TlsExtensionCompressCertificate,
TlsExtensionECPointFormats,
TlsExtensionEllipticCurves,
TlsExtensionEncryptedClientHelloInner,
TlsExtensionEncryptedClientHelloOuter,
TlsExtensionEncryptThenMAC,
TlsExtensionExtendedMasterSecret,
TlsExtensionKeyShareClient,
Expand All @@ -45,6 +47,7 @@
TlsExtensionNextProtocolNegotiationClient,
TlsExtensionNextProtocolNegotiationServer,
TlsExtensionPadding,
TlsExtensionPostHandshakeAuthentication,
TlsExtensionPskKeyExchangeModes,
TlsExtensionRecordSizeLimit,
TlsExtensionRenegotiationInfo,
Expand Down Expand Up @@ -884,3 +887,71 @@ def test_parse(self):

extension_padding_with_data = TlsExtensionPadding.parse_exact_size(extension_padding_with_data_bytes)
self.assertEqual(extension_padding_with_data.compose(), extension_padding_with_data_bytes)


class ExtensionEncryptedClientHelloBase(unittest.TestCase):
def test_parse(self):
extension_encrypted_client_hello_dict = collections.OrderedDict([
('extension_type', b'\xfe\x0d'),
('extension_length', b'\x00\x01'),
('hello_type', b'\x00'),
])
extension_encrypted_client_hello_bytes = b''.join(extension_encrypted_client_hello_dict.values())

with self.assertRaises(InvalidType):
# pylint: disable=expression-not-assigned
TlsExtensionEncryptedClientHelloInner.parse_exact_size(extension_encrypted_client_hello_bytes)


class ExtensionEncryptedClientHelloInner(unittest.TestCase):
def test_parse(self):
extension_encrypted_client_hello_dict = collections.OrderedDict([
('extension_type', b'\xfe\x0d'),
('extension_length', b'\x00\x01'),
('hello_type', b'\x01'),
])
extension_encrypted_client_hello_bytes = b''.join(extension_encrypted_client_hello_dict.values())

extension_encrypted_client_hello = TlsExtensionEncryptedClientHelloInner.parse_exact_size(
extension_encrypted_client_hello_bytes
)
self.assertEqual(
extension_encrypted_client_hello.compose(),
extension_encrypted_client_hello_bytes
)


class ExtensionEncryptedClientHelloOuter(unittest.TestCase):
def test_parse(self):
extension_encrypted_client_hello_dict = collections.OrderedDict([
('extension_type', b'\xfe\x0d'),
('extension_length', b'\x00\x11'),
('hello_type', b'\x00'),
('hello_data', b'\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f'),
])
extension_encrypted_client_hello_bytes = b''.join(extension_encrypted_client_hello_dict.values())

extension_encrypted_client_hello = TlsExtensionEncryptedClientHelloOuter.parse_exact_size(
extension_encrypted_client_hello_bytes
)
self.assertEqual(
extension_encrypted_client_hello.compose(),
extension_encrypted_client_hello_bytes
)


class TestExtensionPostHandshakeAuthentication(unittest.TestCase):
def test_parse(self):
extension_post_handshake_authentication_dict = collections.OrderedDict([
('extension_type', b'\x00\x31'),
('extension_length', b'\x00\x00'),
])
extension_post_handshake_authentication_bytes = b''.join(extension_post_handshake_authentication_dict.values())

extension_post_handshake_authentication = TlsExtensionPostHandshakeAuthentication.parse_exact_size(
extension_post_handshake_authentication_bytes
)
self.assertEqual(
extension_post_handshake_authentication.compose(),
extension_post_handshake_authentication_bytes
)

0 comments on commit 55fa783

Please sign in to comment.