Skip to content

TLS ECH keylogging#10259

Draft
sebastian-carpenter wants to merge 1 commit intowolfSSL:masterfrom
sebastian-carpenter:tls-ech-keylog
Draft

TLS ECH keylogging#10259
sebastian-carpenter wants to merge 1 commit intowolfSSL:masterfrom
sebastian-carpenter:tls-ech-keylog

Conversation

@sebastian-carpenter
Copy link
Copy Markdown
Contributor

Description

Adds keylog support for TLS 1.3 ECH by exposing the HPKE shared secret and ECHConfig as new ECH_SECRET / ECH_CONFIG labels via the existing tls13SecretCb and OpenSSL tls13KeyLogCb callbacks. Enables Wireshark decryption of ECH-protected ClientHellos.

Changes

  • New Tls13Secret enum values, wired into keylog label tables.
  • hpke.c: capture HPKE shared secret when echSecret is allocated; new wc_HpkeInit/FreeEchSecret helpers.
  • tls.c: EchWriteKeyLog() emits both labels; TLSX_FinalizeEch/TLSX_ExtractEch now take WOLFSSL* and log after HPKE setup.
  • Gated on HAVE_SECRET_CALLBACK + HAVE_ECH; no overhead when unused.

Testing

  • Extended the existing test_wolfSSL_Tls13_Key_Logging_test to run an ECH handshake and assert the keylog file contains ECH_SECRET and ECH_CONFIG (and also EXPORTER_SECRET, which was previously unchecked).

Checklist

  • added tests
  • updated/added doxygen
  • updated appropriate READMEs
  • Updated manual and documentation

@sebastian-carpenter sebastian-carpenter self-assigned this Apr 19, 2026
Copilot AI review requested due to automatic review settings April 19, 2026 03:32
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds TLS 1.3 ECH keylog support by exposing the HPKE shared secret and ECHConfig through existing TLS 1.3 secret/keylog callbacks to enable ECH ClientHello decryption in external tooling (e.g., Wireshark).

Changes:

  • Introduces new Tls13Secret labels (ECH_SECRET, ECH_CONFIG) and wires them into TLS 1.3 keylog label mapping.
  • Captures the HPKE shared secret during HPKE sender/receiver setup and logs ECH secret/config at ECH finalize/extract points.
  • Extends the TLS 1.3 keylog API test to validate presence of ECH labels (and now also checks EXPORTER_SECRET).

Reviewed changes

Copilot reviewed 8 out of 8 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
wolfssl/wolfcrypt/hpke.h Adds optional Hpke::echSecret storage and local init/free helpers under HAVE_SECRET_CALLBACK && HAVE_ECH.
wolfcrypt/src/hpke.c Copies HPKE shared secret into echSecret when allocated; implements wc_HpkeInitEchSecret / wc_HpkeFreeEchSecret.
wolfssl/ssl.h Extends enum Tls13Secret with ECH_SECRET / ECH_CONFIG under HAVE_ECH.
wolfssl/internal.h Updates TLSX_FinalizeEch signature to accept WOLFSSL* ssl.
src/tls.c Adds EchWriteKeyLog() and logs ECH secret/config in TLSX_FinalizeEch (client) and TLSX_ExtractEch (server).
src/tls13.c Updates ECH finalize callsite; updates tls13ShowSecrets() string mapping for new labels.
src/internal.c Updates OpenSSL-extra TLS 1.3 keylog label mapping to include ECH labels.
tests/api.c Extends TLS 1.3 keylog test to expect ECH labels (and now EXPORTER_SECRET).

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/tls.c
#ifdef HAVE_SECRET_CALLBACK
if (ret == 0 && ech->hpke->echSecret != NULL) {
ret = EchWriteKeyLog(ssl, ech->hpke->echSecret, ech->hpke->Nsecret,
ech->echConfig->raw, ech->echConfig->rawLen);
Copy link

Copilot AI Apr 19, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

After successfully emitting ECH_SECRET/ECH_CONFIG, the HPKE shared secret remains allocated in ech->hpke->echSecret until TLSX_ECH_Free(). Since this buffer contains key material, it should be wiped and freed immediately after logging to minimize secret lifetime (e.g., call the existing wc_HpkeFreeEchSecret(ech->hpke) once EchWriteKeyLog() succeeds).

Suggested change
ech->echConfig->raw, ech->echConfig->rawLen);
ech->echConfig->raw, ech->echConfig->rawLen);
if (ret == 0) {
wc_HpkeFreeEchSecret(ech->hpke);
}

Copilot uses AI. Check for mistakes.
Comment thread src/tls.c
ret = GetEchConfig(echConfig, echConfigRaw, &echConfigRawSz);
if (ret == 0) {
ret = EchWriteKeyLog(ssl, ech->hpke->echSecret, ech->hpke->Nsecret,
echConfigRaw, echConfigRawSz);
Copy link

Copilot AI Apr 19, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TLSX_ExtractEch() logs the HPKE shared secret when ech->hpke->echSecret is set, but leaves echSecret populated afterward. Consider wiping/freeing ech->hpke->echSecret immediately after EchWriteKeyLog() succeeds (wc_HpkeFreeEchSecret) to reduce the amount of time key material stays resident in memory.

Suggested change
echConfigRaw, echConfigRawSz);
echConfigRaw, echConfigRawSz);
if (ret == 0) {
wc_HpkeFreeEchSecret(ech->hpke);
}

Copilot uses AI. Check for mistakes.
Comment thread tests/api.c
Comment on lines +14185 to +14189
#ifdef HAVE_ECH
const int label_count = 7;
#else
const int label_count = 5;
#endif
Copy link

Copilot AI Apr 19, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This test now requires EXPORTER_SECRET to be present, but TLS 1.3 only derives/logs EXPORTER_SECRET when HAVE_KEYING_MATERIAL is enabled and saveArrays is set (e.g., wolfSSL_KeepArrays()). The test is currently guarded only by WOLFSSL_TLS13/OPENSSL_EXTRA/HAVE_SECRET_CALLBACK, so it can fail in builds where HAVE_KEYING_MATERIAL is off or arrays aren’t kept. Consider gating the expectation/label_count on HAVE_KEYING_MATERIAL and ensuring the client calls wolfSSL_KeepArrays() before the handshake if you want to assert on EXPORTER_SECRET.

Copilot uses AI. Check for mistakes.
@github-actions
Copy link
Copy Markdown

MemBrowse Memory Report

No memory changes detected for:

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.

2 participants