Skip to content

feat(tls): add key_exchange field to expose negotiated key exchange group#946

Open
usernametooshort wants to merge 1 commit intoprojectdiscovery:mainfrom
usernametooshort:feat/key-exchange-group
Open

feat(tls): add key_exchange field to expose negotiated key exchange group#946
usernametooshort wants to merge 1 commit intoprojectdiscovery:mainfrom
usernametooshort:feat/key-exchange-group

Conversation

@usernametooshort
Copy link

@usernametooshort usernametooshort commented Mar 5, 2026

Closes #935

What

Adds a new key_exchange field to the JSON output that reports the negotiated key exchange group after the TLS handshake (e.g. X25519, X25519MLKEM768, CurveP256).

Why

In TLS 1.3 the cipher suite name no longer encodes the key agreement mechanism — both X25519 (classical) and X25519MLKEM768 (post-quantum) report the same TLS_AES_128_GCM_SHA256. The CurveID field in Go’s ConnectionState (populated from Go 1.24+) is the only way to tell them apart.

This matters for:

  • Auditing post-quantum readiness (FIPS 203 / ML-KEM already deployed by Chrome + Cloudflare as X25519MLKEM768, CurveID 4588)
  • Detecting servers that still use older curves (CurveP256 only)
  • General TLS configuration auditing beyond cipher suites

Example output

{
  "host": "cloudflare.com",
  "tls_version": "tls13",
  "cipher": "TLS_AES_128_GCM_SHA256",
  "key_exchange": "X25519MLKEM768"
}

Implementation

  • clients/clients.go: adds KeyExchange string \json:"key_exchange,omitempty"`toResponse`
  • pkg/tlsx/tls/tls.go (ctls): reads connectionState.CurveID and calls .String() after the handshake

ztls (zcrypto) does not expose the selected key exchange group in its ServerHello log structure and is TLS 1.2-only — left unchanged.

Summary by CodeRabbit

Release Notes

  • New Features
    • Added TLS key-exchange group reporting to scan results. The negotiated key-exchange information is now captured and included in TLS analysis output, providing additional details about the TLS handshake.

…roup

In TLS 1.3 the cipher suite name (e.g. TLS_AES_128_GCM_SHA256) no
longer encodes the key agreement mechanism — it is negotiated via the
supported_groups extension and reported in ConnectionState.CurveID
(populated from Go 1.24+).

Without this field, tlsx cannot distinguish:
  - X25519 (classical key exchange)
  - X25519MLKEM768 (post-quantum, already default in Chrome + Cloudflare)
  - CurveP256 / CurveP384 / CurveP521

This matters for auditing post-quantum readiness (FIPS 203 / ML-KEM) and
for detecting servers that only support older EC curves.

Changes:
  - clients.go: add KeyExchange string field with json tag key_exchange
  - tls/tls.go (ctls): read connectionState.CurveID after the handshake
    and call .String() to get the human-readable group name

ztls (zcrypto) does not expose the selected key exchange group in its
ServerHello log structure and is TLS 1.2-only, so it is unchanged.

Closes projectdiscovery#935
@neo-by-projectdiscovery-dev
Copy link

neo-by-projectdiscovery-dev bot commented Mar 5, 2026

Neo - PR Security Review

No security issues found

Highlights

  • Adds key_exchange field to JSON output to expose the negotiated TLS key exchange group (e.g. X25519, X25519MLKEM768, CurveP256)
  • Enables post-quantum readiness auditing by distinguishing classical vs post-quantum key exchange mechanisms in TLS 1.3
  • Reads connectionState.CurveID from Go's standard library after successful handshake and converts to string via .String() method

Comment @neo help for available commands. · Open in Neo

@coderabbitai
Copy link

coderabbitai bot commented Mar 5, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: fbe3f9bd-c9b5-4364-97f1-37f6e76543b0

📥 Commits

Reviewing files that changed from the base of the PR and between d13b67f and 2563510.

📒 Files selected for processing (2)
  • pkg/tlsx/clients/clients.go
  • pkg/tlsx/tls/tls.go

Walkthrough

A new KeyExchange field is added to the TLS response structure to expose the negotiated key exchange group (curve) from Go 1.24+ ConnectionState.CurveID. The implementation reads the curve ID during handshake processing and populates the response object with a string representation of the negotiated curve.

Changes

Cohort / File(s) Summary
Response Struct Definition
pkg/tlsx/clients/clients.go
Adds new exported field KeyExchange to Response struct with JSON tag key_exchange,omitempty to hold the negotiated TLS curve group.
TLS Handshake Processing
pkg/tlsx/tls/tls.go
Reads ConnectionState.CurveID after TLS handshake, derives string representation of the key exchange group, and assigns it to Response.KeyExchange field.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

Poem

🐰 A new field hops into view,
Key exchange curves now shine through,
Post-quantum dreams and curves so bright,
TLS audits now see the light!

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately and concisely describes the primary change: adding a key_exchange field to expose the negotiated TLS key exchange group.
Linked Issues check ✅ Passed The pull request implements all coding requirements from issue #935: adding KeyExchange field to Response struct and reading CurveID in the ctls client to populate the field.
Out of Scope Changes check ✅ Passed All changes are directly scoped to implementing the key_exchange field feature; no unrelated modifications are present in the changeset.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

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

1 participant