Skip to content

Add the negotiated key exchange group (TLS curve) to tlsx JSON output. #935

@jasonp0

Description

@jasonp0

In TLS 1.3, the cipher suite name (e.g. TLS_AES_128_GCM_SHA256) no longer encodes the key exchange mechanism — it is negotiated separately via the supported_groups extension. tlsx currently reads ConnectionState.Version and
ConnectionState.CipherSuite but does not read ConnectionState.CurveID, so the negotiated key exchange is not reported.

Since Go 1.24, ConnectionState.CurveID is populated after the handshake. A new field like key_exchange in the JSON output would expose this value (e.g. X25519MLKEM768, X25519, CurveP256).

Suggested change in the ctls client (pkg/tlsx/tls/tls.go) — read connectionState.CurveID alongside the existing Version and CipherSuite reads, and add a corresponding field to the Response struct in
pkg/tlsx/clients/clients.go:

KeyExchange string json:"key_exchange,omitempty"

Describe the use case of this feature:

NIST/IEFT post-quantum cryptography standards (FIPS 203 / ML-KEM) are being deployed in production. Chrome and Cloudflare already negotiate X25519MLKEM768 (CurveID 4588) by default in TLS 1.3 handshakes.

Security teams need to audit which hosts in their environment support post-quantum key exchange and which are still using classical-only key agreement. Without the key exchange group in tlsx output, there is no way to distinguish a PQ-secured connection from a classical one — both report the same cipher suite name.

This would also be useful for detecting servers that only support older curves (e.g. CurveP256 without X25519) or for general TLS configuration auditing beyond cipher suites.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type: EnhancementMost issues will probably ask for additions or changes.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions