Skip to content

[Bug]: RFC 8446 violation : WolfSSL server accept ClientHello with incorrect KeyShare after HelloRetryRequest #9362

@aeyno

Description

@aeyno

Contact Details

No response

Version

5.8.2

Description

A WolfSSL TLS 1.3 server sending a HelloRetryRequest requesting a specific KeyShare can accept a second ClientHello with a KeyShare not present in the HelloRetryRequest.

According to the RFC 8446 section 4.2.8 : when sending the new ClientHello, the client MUST replace the original "key_share" extension with one containing only a new KeyShareEntry for the group indicated in the selected_group field of the triggering HelloRetryRequest. So here the client is sending an incorrect KeyShare that should be rejected by the server.

Impact

Ability to do a TLS 1.3 handshake while ignoring the server KeyShare preference.

Expected behavior

WolfSSL server should send an "illegal_parameter" Alert and abort the connection.

Reproduction steps

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

  • Send first ClientHello
    TLSv1.3 Record Layer: Handshake Protocol: Client Hello
    • Content Type: Handshake (22)
    • Version: TLS 1.2 (0x0303)
    • Length: 150
    • Handshake Protocol: Client Hello
      • Handshake Type: Client Hello (1)
      • Length: 146
      • Version: TLS 1.2 (0x0303)
      • Random: 0101010101010101010101010101010101010101010101010101010101010101
      • Session ID Length: 32
      • Session ID: 0303030303030303030303030303030303030303030303030303030303030303
      • Cipher Suites Length: 2
      • Cipher Suites (1 suite)
      • Compression Methods Length: 1
      • Compression Methods (1 method)
      • Extensions Length: 71
      • Extension: supported_groups (len=8)
        -Type: supported_groups (10)
        -Length: 8
        -Supported Groups List Length: 6
        -Supported Groups (3 groups)
      • Extension: signature_algorithms (len=6)
        • Type: signature_algorithms (13)
        • Length: 6
        • Signature Hash Algorithms Length: 4
        • Signature Hash Algorithms (2 algorithms)
      • Extension: key_share (len=38) x25519
        • Type: key_share (51)
        • Length: 38
        • Key Share extension
          • Client Key Share Length: 36
          • Key Share Entry: Group: x25519, Key Exchange length: 32
            • Group: x25519 (29)
            • Key Exchange Length: 32
            • Key Exchange: 07aaff3e9fc167275544f4c3a6a17cd837f2ec6e78cd8a57b1e3dfb3cc035a76
      • Extension: supported_versions (len=3) TLS 1.3
        • Type: supported_versions (43)
        • Length: 3
        • Supported Versions length: 2
        • Supported Version: TLS 1.3 (0x0304)
          In raw hex : 160303009601000092030301010101010101010101010101010101010101010101010101010101010101012003030303030303030303030303030303030303030303030303030303030303030002130101000047000a0008000600180017001d000d0006000404010804003300260024001d002007aaff3e9fc167275544f4c3a6a17cd837f2ec6e78cd8a57b1e3dfb3cc035a76002b0003020304
  • Wait for HRR : with the default build of WolfSSL (when x25519 is not supported), the HelloRetryRequests asks for secp384r1 KeyShare
  • Send the second ClientHello with a secp256r1 KeyShare
    TLSv1.3 Record Layer: Handshake Protocol: Client Hello
    • Content Type: Handshake (22)
    • Version: TLS 1.2 (0x0303)
    • Length: 183
    • Handshake Protocol: Client Hello
      • Handshake Type: Client Hello (1)
      • Length: 179
      • Version: TLS 1.2 (0x0303)
      • Random: 0101010101010101010101010101010101010101010101010101010101010101
      • Session ID Length: 32
      • Session ID: 0303030303030303030303030303030303030303030303030303030303030303
      • Cipher Suites Length: 2
      • Cipher Suites (1 suite)
      • Compression Methods Length: 1
      • Compression Methods (1 method)
      • Extensions Length: 104
      • Extension: supported_groups (len=8)
        • Type: supported_groups (10)
        • Length: 8
        • Supported Groups List Length: 6
        • Supported Groups (3 groups)
      • Extension: signature_algorithms (len=6)
        • Type: signature_algorithms (13)
        • Length: 6
        • Signature Hash Algorithms Length: 4
        • Signature Hash Algorithms (2 algorithms)
      • Extension: key_share (len=71) secp256r1
        • Type: key_share (51)
        • Length: 71
        • Key Share extension
          • Client Key Share Length: 69
          • Key Share Entry: Group: secp256r1, Key Exchange length: 65
            • Group: secp256r1 (23)
            • Key Exchange Length: 65
            • Key Exchange: 040c901d423c831ca85e27c73c263ba132721bb9d7a84c4f0380b2a6756fd601331c8870234dec878504c174144fa4b14b66a651691606d8173e55bd37e381569e
      • Extension: supported_versions (len=3) TLS 1.3
        • Type: supported_versions (43)
        • Length: 3
        • Supported Versions length: 2
        • Supported Version: TLS 1.3 (0x0304)
          In raw hex : 16030300b7010000b3030301010101010101010101010101010101010101010101010101010101010101012003030303030303030303030303030303030303030303030303030303030303030002130101000068000a0008000600180017001d000d000600040401080400330047004500170041040c901d423c831ca85e27c73c263ba132721bb9d7a84c4f0380b2a6756fd601331c8870234dec878504c174144fa4b14b66a651691606d8173e55bd37e381569e002b0003020304
  • The server should send a ServerHello

Then start a TLS 1.3 WolfSSL server :

./examples/server/server -v 4 -l 'TLS_AES_128_GCM_SHA256'  -p 3000

Start the following Python TCP client :

import socket

HOST = "0.0.0.0"
PORT = 3000

payload1 = bytes.fromhex(
    "160303009601000092030301010101010101010101010101010101010101010101010101010101010101012003030303030303030303030303030303030303030303030303030303030303030002130101000047000a0008000600180017001d000d0006000404010804003300260024001d002007aaff3e9fc167275544f4c3a6a17cd837f2ec6e78cd8a57b1e3dfb3cc035a76002b0003020304"
)
payload2 = bytes.fromhex(
    "16030300b7010000b3030301010101010101010101010101010101010101010101010101010101010101012003030303030303030303030303030303030303030303030303030303030303030002130101000068000a0008000600180017001d000d000600040401080400330047004500170041040c901d423c831ca85e27c73c263ba132721bb9d7a84c4f0380b2a6756fd601331c8870234dec878504c174144fa4b14b66a651691606d8173e55bd37e381569e002b0003020304"
)

with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as client_socket:
    conn = client_socket.connect((HOST, PORT))
    print(f"[*] connecting to {HOST}:{PORT} ...")

    client_socket.sendall(payload1)
    print(f"[<] Sent: {payload1.hex()}")

    # receive HRR
    data = client_socket.recv(1024)
    print(f"[>] Received: {data.hex()}")

    # Send second client hello
    client_socket.sendall(payload2)
    print(f"[<] Sent: {payload2.hex()}")

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

You should see the WolfSSL server sending its ServerHello and encrypted extensions, waiting for the client to send a Finished message.

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