-
-
Notifications
You must be signed in to change notification settings - Fork 2.2k
Description
Brief description
Trying to parse a TLS 1.3 ClientHello followed by a HelloRetryRequest leads to an AttributeError.
The example code is found below.
The same error occurs when using .mirror() on the TLSSession
Scapy version
2.6.1
Python version
3.10
Operating system
Ubuntu 22.04.5
Additional environment information
The streams have been recorded with a nginx docker server and successfully been parsed with wireshark
How to reproduce
from scapy.layers.tls.all import *
m1 = bytes.fromhex(
"1603010200010001fc03035909822da030a9cebbc655dc694f96470ecd9fb87a66678fd6d701160c35999d20704bb9bc0d3e1fe1c3a4705740b50a1a446a52069cb6d2e68eeb3c0595a32bcd003e130213031301c02cc030009fcca9cca8ccaac02bc02f009ec024c028006bc023c0270067c00ac0140039c009c0130033009d009c003d003c0035002f00ff01000175000000190017000014646f636b65722e636f6d706f73652e6c6f63616c000b000403000102000a00160014001d0017001e0019001801000101010201030104337400000010000e000c02683208687474702f312e31001600000017000000310000000d002a0028040305030603080708080809080a080b080408050806040105010601030303010302040205020602002b00050403040303002d00020101003300260024001d00202bda851f00ad81c626007a3dcbfa8f2f7c859aa77ebc9a69661e350e52843428001500a900000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"
)
m2 = bytes.fromhex(
"1603030058020000540303cf21ad74e59a6111be1d8c021e65b891c2a211167abb8c5e079e09e2c8a8339c20704bb9bc0d3e1fe1c3a4705740b50a1a446a52069cb6d2e68eeb3c0595a32bcd130200000c002b00020304003300020019140303000101"
)
# this yields a TLSClientHello
# we can also transform it into a TLS13ClientHello, the error is the same
parsed1 = TLS(m1)
print("client hello")
parsed1.show()
# raw result and thus not very useful
parsed2_raw = TLS(m2)
print("raw (not parsed TLS13HelloRetryRequest) and change cipher spec")
parsed2_raw.show()
# this works
parsed2_direct_hrr = TLS13HelloRetryRequest(TLS(m2).msg[0].original)
print("Directly as TLS13HelloRetryRequest")
parsed2_direct_hrr.show()
parsed2_direct_ccs = TLSChangeCipherSpec(TLS(m2).msg[0].payload)
print("Also handle ChangeCipherSpec")
parsed2_direct_ccs.show()
# This errors
parsed2_with_session = TLS(m2, tls_session=parsed1.tls_session)
print("session")
parsed2_with_session.show()
Actual result
Traceback (most recent call last):
File "./scapy_error_example.py", line 34, in <module>
parsed2_with_session = TLS(m2, tls_session=parsed1.tls_session)
File "/pypoetry/virtualenvs/grpc-tls-parser-wNP1jB8a-py3.10/lib/python3.10/site-packages/scapy/base_classes.py", line 481, in __call__
i.__init__(*args, **kargs)
File "/pypoetry/virtualenvs/grpc-tls-parser-wNP1jB8a-py3.10/lib/python3.10/site-packages/scapy/layers/tls/record.py", line 303, in __init__
super(TLS, self).__init__(*args, **kargs)
File "/pypoetry/virtualenvs/grpc-tls-parser-wNP1jB8a-py3.10/lib/python3.10/site-packages/scapy/layers/tls/session.py", line 1075, in __init__
Packet.__init__(self, _pkt=_pkt, post_transform=post_transform,
File "/pypoetry/virtualenvs/grpc-tls-parser-wNP1jB8a-py3.10/lib/python3.10/site-packages/scapy/packet.py", line 186, in __init__
self.dissect(_pkt)
File "/pypoetry/virtualenvs/grpc-tls-parser-wNP1jB8a-py3.10/lib/python3.10/site-packages/scapy/packet.py", line 1102, in dissect
s = self.do_dissect(s)
File "/pypoetry/virtualenvs/grpc-tls-parser-wNP1jB8a-py3.10/lib/python3.10/site-packages/scapy/packet.py", line 1040, in do_dissect
s, fval = f.getfield(self, s)
File "/pypoetry/virtualenvs/grpc-tls-parser-wNP1jB8a-py3.10/lib/python3.10/site-packages/scapy/layers/tls/record.py", line 167, in getfield
p.post_dissection_tls_session_update(raw_msg)
File "/pypoetry/virtualenvs/grpc-tls-parser-wNP1jB8a-py3.10/lib/python3.10/site-packages/scapy/layers/tls/session.py", line 1099, in post_dissection_tls_session_update
self.tls_session_update(msg_str)
File "/pypoetry/virtualenvs/grpc-tls-parser-wNP1jB8a-py3.10/lib/python3.10/site-packages/scapy/layers/tls/handshake.py", line 732, in tls_session_update
hkdf = TLS13_HKDF(cs_cls.hash_alg.name.lower())
AttributeError: type object 'TLS_AES_256_GCM_SHA384' has no attribute 'hash_alg'
Expected result
a correctly parsed HelloRetryRequest and ChangeCipherSpec
Related resources
The logic should be possible according to
https://scapy.readthedocs.io/en/latest/api/scapy.layers.tls.record.html
The behavior is the same if you replace the given test TLS streams with server_hello and client_hello used here:
https://github.com/secdev/scapy/blob/master/test/scapy/layers/tls/tls13.uts
TLS13 HelloRetryRequest Specification: https://datatracker.ietf.org/doc/html/rfc8446#section-4.1.3