Skip to content

AttributeError when Parsing TLS13HelloRetryRequest with session #4863

@abwesend890

Description

@abwesend890

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions