Skip to content

[Bug]: RFC 8446 violation : Incorrect HelloRetryRequest triggers WolfSSL to send identical ClientHello #9240

@aeyno

Description

@aeyno

Version

5.8.2

Description

When receiving a HelloRetryRequest (ServerHello with magic random value) which should trigger no change in the ClientHello (the HRR only contains a SupportedVersion extension), WolfSSL TLS 1.3 client sends a ClientHello that is identical to its first ClientHello.

According to RFC 8446 section 4.1.4 : Clients MUST abort the handshake with an "illegal_parameter" alert if the HelloRetryRequest would not result in any change in the ClientHello.

Note that is some variants of our experiments, the two ClientHello had the same set of extensions with the same respective values but those extensions were in a different order.

Impact

Unknown, we were able to perform a full handshake after the second ClientHello but no other problem was detected.

Expected behavior

WolfSSL client should abort the handshake since the HRR doesn't cause any change in the ClientHello.

Reproduction steps

Here is an example of a TLS 1.3 HelloRetryRequest that triggers the described behavior

  • Record Layer:
    • ContentType: Handshake
    • Version: TLS 1.2 (legacy marker)
    • Length: 50
  • Handshake:
    • Type: ServerHello
    • Length: 46
    • Version: 0x0303
    • Random: cf21ad74e59a6111be1d8c021e65b891c2a211167abb8c5e079e09e2c8a8339c (HelloRetryRequest magic value)
    • SessionID: empty
    • CipherSuite: TLS_AES_128_GCM_SHA256 (0x1301)
    • Compression: null
    • Extensions:
      • supported_versions = TLS 1.3 (0x0304)

In raw hex :
16030300320200002e0303cf21ad74e59a6111be1d8c021e65b891c2a211167abb8c5e079e09e2c8a8339c001301000006002b00020304

Start the following Python TCP server :

import socket

HOST = "0.0.0.0"
PORT = 3000

payload = bytes.fromhex(
    "16030300320200002e0303cf21ad74e59a6111be1d8c021e65b891c2a211167abb8c5e079e09e2c8a8339c001301000006002b00020304"
)

with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as server_socket:
    server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
    server_socket.bind((HOST, PORT))
    server_socket.listen(1)
    print(f"[*] Listening on {HOST}:{PORT} ...")

    # Accept client connection
    conn, addr = server_socket.accept()
    with conn:
        print(f"[+] Connection from {addr}")

        data = conn.recv(1024)
        print(f"[>] Received: {data.hex()}")

        # Send decoded payload
        conn.sendall(payload)
        print(f"[<] Sent: {payload.hex()}")

        while True:
            data = conn.recv(1024)
            print(f"[>] Received: {data.hex()}")

Then start TLS 1.3 handshake with WolfSSL client :

./build/examples/client/client -p 3000 -v 4

You should see two identical ClientHello sent by WolfSSL client.

Acknowledgements

This bug was found thanks to the tlspuffin fuzzer designed and developed by the tlspuffin team:

  • Max Ammann
  • Olivier Demengeon - Loria, Inria
  • Tom Gouville - Loria, Inria
  • Lucca Hirschi - Loria, Inria
  • Steve Kremer - Loria, Inria
  • Michael Mera - Loria, Inria

Metadata

Metadata

Assignees

Labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions