ClientHello: add `.raw_bytes()`, refs #4877 (#5075)

This commit is contained in:
Maximilian Hils 2022-01-18 12:34:09 +01:00 committed by GitHub
parent 1abb8f6921
commit d47fd3e9c3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 28 additions and 3 deletions

View File

@ -16,16 +16,39 @@ class ClientHello:
A TLS ClientHello is the first message sent by the client when initiating TLS.
"""
raw_bytes: bytes
"""The raw ClientHello bytes as seen on the wire"""
_raw_bytes: bytes
def __init__(self, raw_client_hello: bytes):
"""Create a TLS ClientHello object from raw bytes."""
self.raw_bytes = raw_client_hello
self._raw_bytes = raw_client_hello
self._client_hello = tls_client_hello.TlsClientHello(
KaitaiStream(io.BytesIO(raw_client_hello))
)
def raw_bytes(self, wrap_in_record: bool = True) -> bytes:
"""
The raw ClientHello bytes as seen on the wire.
If `wrap_in_record` is True, the ClientHello will be wrapped in a synthetic TLS record
(`0x160303 + len(chm) + 0x01 + len(ch)`), which is the format expected by some tools.
The synthetic record assumes TLS version (`0x0303`), which may be different from what has been sent over the
wire. JA3 hashes are unaffected by this as they only use the TLS version from the ClientHello data structure.
A future implementation may return not just the exact ClientHello, but also the exact record(s) as seen on the
wire.
"""
if wrap_in_record:
return (
# record layer
b"\x16\x03\x03" + (len(self._raw_bytes) + 4).to_bytes(2, byteorder="big") +
# handshake header
b"\x01" + len(self._raw_bytes).to_bytes(3, byteorder="big") +
# ClientHello as defined in https://datatracker.ietf.org/doc/html/rfc8446#section-4.1.2.
self._raw_bytes
)
else:
return self._raw_bytes
@property
def cipher_suites(self) -> List[int]:
"""The cipher suites offered by the client (as raw ints)."""

View File

@ -21,6 +21,8 @@ class TestClientHello:
assert c.cipher_suites == [53, 47, 10, 5, 4, 9, 3, 6, 8, 96, 97, 98, 100]
assert c.alpn_protocols == []
assert c.extensions == []
assert c.raw_bytes(False) == CLIENT_HELLO_NO_EXTENSIONS
assert c.raw_bytes(True) == FULL_CLIENT_HELLO_NO_EXTENSIONS
def test_extensions(self):
data = bytes.fromhex(