feat(tls): add key_exchange field to expose negotiated key exchange group#946
Conversation
…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 - PR Security ReviewNo security issues found Highlights
Comment |
|
Important Review skippedAuto reviews are disabled on base/target branches other than the default branch. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
WalkthroughA new Changes
Estimated code review effort🎯 2 (Simple) | ⏱️ ~10 minutes Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
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. Comment |
Mzack9999
left a comment
There was a problem hiding this comment.
Thanks for the contribution — the feature itself is solid and we'd like to merge it.
However, there are a couple of issues that need to be addressed:
-
Go version compatibility:
ConnectionState.CurveIDrequires Go 1.25+, but the CI workflows andgo.modcurrently target Go 1.24.x. The PR needs to also bump the Go version to 1.25 in:go.mod.github/workflows/build-test.yml.github/workflows/lint-test.yml.github/workflows/release-test.yml.github/workflows/release-binary.ymlREADME.md(install requirements section)
-
CI checks are failing: All build and lint checks fail with
connectionState.CurveID undefined (type "crypto/tls".ConnectionState has no field or method CurveID)because of the Go version mismatch above.
Please update the Go version references and ensure CI passes. Once that's done we'll merge.
Closes #935
What
Adds a new
key_exchangefield 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. TheCurveIDfield in Go’sConnectionState(populated from Go 1.24+) is the only way to tell them apart.This matters for:
X25519MLKEM768, CurveID 4588)CurveP256only)Example output
{ "host": "cloudflare.com", "tls_version": "tls13", "cipher": "TLS_AES_128_GCM_SHA256", "key_exchange": "X25519MLKEM768" }Implementation
clients/clients.go: addsKeyExchange string \json:"key_exchange,omitempty"`toResponse`pkg/tlsx/tls/tls.go(ctls): readsconnectionState.CurveIDand calls.String()after the handshakeztls (zcrypto) does not expose the selected key exchange group in its
ServerHellolog structure and is TLS 1.2-only — left unchanged.Summary by CodeRabbit
Release Notes