Skip to content

Enhancement: Public extension manager for ECH#10568

Open
sebastian-carpenter wants to merge 5 commits into
wolfSSL:masterfrom
sebastian-carpenter:tls-ech-ext-public
Open

Enhancement: Public extension manager for ECH#10568
sebastian-carpenter wants to merge 5 commits into
wolfSSL:masterfrom
sebastian-carpenter:tls-ech-ext-public

Conversation

@sebastian-carpenter

@sebastian-carpenter sebastian-carpenter commented Jun 1, 2026

Copy link
Copy Markdown
Contributor

Description

Reworks ECH public-vs-private extension handling. The old path swapped a single SNI string in place on the live extension list - this was fragile and SNI-only. This PR generalizes it to a public-extension list on the ECH struct that's swapped by extension type, so the outer ClientHello can carry arbitrary public extensions.

ZD#21931

Public extension manager

  • Add TLSX* extensions to WOLFSSL_ECH holding the public extensions (e.g. the public-name SNI), populated in TLSX_ECH_Use from echConfig->publicName.
  • Replace TLSX_EchChangeSNI/TLSX_EchRestoreSNI with:
    • TLSX_EchShouldHideInner - true when ECH is the outer type.
    • TLSX_EchSwapExtensions - swaps matching extension types between ssl->extensions and ech->extensions; unmatched public exts are prepended; popCount reverses leading nodes to preserve OuterExtensions ordering.
    • TLSX_EchReplaceExtensions - accept: free the public list; reject: swap public exts into ssl->extensions.
  • TLSX_GetSizeWithEch/TLSX_WriteWithEch install the public exts before size/write and swap back after.
  • ForceZero the hpke; free ech->extensions in TLSX_ECH_Free.

SNI changes

  • Remove the old SNI-state machinery: drop the EchStateSNI enum and the sniState/privateName fields, plus the sniState transitions in DoTls13HandShakeMsgType.
  • TLSX_SNI_Parse: drop the sniState-based private-name save/restore. On outer-CH parse, match against any echConfig->publicName and write a matched public SNI to ech->extensions, not ssl->extensions; simplify the matched/cacheOnly and response-flag logic.
  • Inner SNI is now optional - removed the client-side "inner SNI must be present" requirement enforced by TLSX_EchChangeSNI.
  • SendTls13ClientHello: read padding length via TLSX_SNI_GetRequest instead of ech->privateName.
  • Call TLSX_EchReplaceExtensions at the accept/reject points (EchCheckAcceptance, DoTls13ServerHello reject fallback, DoTls13ClientHello). This installs the correct SNI for use later in the handshake.

Padding

  • If the client ssl had no SNI then it would take the generic no SNI path. Updated padding calculation to fallback to ctx's SNI if it is available.

Testing

  • Add test_wolfSSL_Tls13_ECH_wire_sni: drive the handshake manually and assert the public name is present and the private name absent in raw CH1/CH2 bytes, across accept/reject.
  • Update test_wolfSSL_Tls13_ECH_no_private_name: no-inner-SNI now succeeds against a permissive server (ACCEPTED); rejected only with ABORT_ON_ABSENCE.
  • Add b64MandatoryFirst config case; test_ech_server_sni_callback rejects a wrong public name; add a double-public-SNI scenario to bad_configs_ex.
  • Remove obsolete test_wolfSSL_Tls13_ECH_long_SNI (its overflow target - the deleted swap helpers - no longer exist) and relocate the over-long-SNI BAD_LENGTH_E check into test_wolfSSL_UseSNI_params.
  • Testing for the new TLSX_EchSwapExtensions function: test_TLSX_EchSwapExtensions. This emulates the swap between ssl->extensions and ech->extensions with various configs: 'match', 'no match', 'match and non-match', 'match and no-match + out of order'. This required qualifying the function with WOLFSSL_TEST_VIS.
  • SNI test vectors. Enumerated many possible SNI configurations / possibilities for ECH connections (test_wolfSSL_Tls13_ECH_sni_parse).

Added testing from #10542:

  • More efficient *_wire_sni test
    • Updated further to test with SNI installed on CTX and to strictly check for Hostname SNI only.
  • Interop testing for when ECH is rejected

Follow-ups

  • Lays groundwork for managing multiple public extensions and multiple SNI's in the outer ClientHello.

Checklist

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

@sebastian-carpenter sebastian-carpenter self-assigned this Jun 1, 2026
Copilot AI review requested due to automatic review settings June 1, 2026 20:48

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

This PR refactors TLS 1.3 ECH public-vs-private extension handling by introducing a dedicated “public extensions” list on the WOLFSSL_ECH object and swapping extensions by type, replacing the previous SNI-only in-place string swap approach. It also updates SNI/ECH parsing and handshake flow to install the correct extensions on accept/reject paths, and adds/updates tests to validate wire visibility of public vs private SNI.

Changes:

  • Add WOLFSSL_ECH::extensions to hold “public” extensions and implement swapping/replacement helpers used during ClientHello size/write and accept/reject handling.
  • Rework SNI parsing and ECH handshake transitions to remove the old sniState/privateName machinery and support public-name matching for outer ClientHello.
  • Update API tests to cover new behaviors (wire-SNI visibility, no-inner-SNI behavior, new bad config cases) and relocate long-SNI length validation coverage.

Reviewed changes

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

File Description
wolfssl/internal.h Removes old SNI-state fields and adds WOLFSSL_ECH::extensions plus TLSX_EchReplaceExtensions() prototype.
src/tls.c Implements public-extension swapping/replacement, updates SNI parsing, and updates ECH lifecycle management.
src/tls13.c Adjusts ClientHello padding derivation and installs correct extension sets at ECH accept/reject points (incl. HRR).
tests/api.c Adds/updates ECH/SNI tests (wire visibility, no-private-name behavior, new config cases) and relocates length checks.

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

Comment thread src/tls.c
Comment thread src/tls.c
Comment thread tests/api.c Outdated
@github-actions

github-actions Bot commented Jun 8, 2026

Copy link
Copy Markdown

retest this please

@github-actions

github-actions Bot commented Jun 8, 2026

Copy link
Copy Markdown

MemBrowse Memory Report

gcc-arm-cortex-m4-openssl-compat

  • FLASH: .text +64 B (+0.0%, 768,196 B / 1,048,576 B, total: 73% used)

gcc-arm-cortex-m4-pq

  • FLASH: .text +64 B (+0.0%, 278,000 B / 1,048,576 B, total: 27% used)

gcc-arm-cortex-m7-pq

  • FLASH: .text +64 B (+0.0%, 278,576 B / 1,048,576 B, total: 27% used)

gcc-arm-cortex-m7-tls13

  • FLASH: .text +64 B (+0.0%, 234,814 B / 262,144 B, total: 90% used)

linuxkm-standard

@sebastian-carpenter sebastian-carpenter force-pushed the tls-ech-ext-public branch 2 times, most recently from 8c2fa10 to 61e1638 Compare June 9, 2026 16:25
@dgarske dgarske requested a review from Copilot June 9, 2026 17:48

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 6 out of 6 changed files in this pull request and generated 2 comments.

Comment thread src/tls.c Outdated
Comment thread src/tls13.c Outdated
@sebastian-carpenter

sebastian-carpenter commented Jun 9, 2026

Copy link
Copy Markdown
Contributor Author

Jenkins retest this please.

@dgarske dgarske left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Skoll Code Review

Scan type: reviewOverall recommendation: COMMENT
Findings: 4 total — 4 posted, 0 skipped
4 finding(s) posted as inline comments (see file-level comments below)

Posted findings

  • [Medium] Multi-public-extension swap/reversal path is untestedsrc/tls.c:16682-16734
  • [Low] ECH padding length only considers ssl-extensions, not ctx-level inner SNIsrc/tls13.c:4844-4855
  • [Info] Pointer declaration style inconsistent with repo conventionsrc/tls.c:2378
  • [Info] TLSX_EchShouldHideInner can be a single boolean expressionsrc/tls.c:16665-16671

Review generated by Skoll

Comment thread src/tls.c Outdated
Comment thread src/tls13.c
Comment thread src/tls.c Outdated
Comment thread src/tls.c
@sebastian-carpenter sebastian-carpenter force-pushed the tls-ech-ext-public branch 2 times, most recently from 4eef82d to b4058e9 Compare June 10, 2026 16:52

@dgarske dgarske left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Skoll Code Review

Scan type: reviewOverall recommendation: COMMENT
Findings: 2 total — 2 posted, 0 skipped
2 finding(s) posted as inline comments (see file-level comments below)

Posted findings

  • [Low] TLSX_FreeAll echList tracks only a single ECH extension per listsrc/tls.c:15190-15216
  • [Low] BAD_STATE_E on restore-swap leaves ssl-extensions inconsistent without repairsrc/tls.c:16895-16901, 17111-17117

Review generated by Skoll

Comment thread src/tls.c
Comment thread src/tls.c Outdated
@sebastian-carpenter sebastian-carpenter removed their assignment Jun 11, 2026
@sebastian-carpenter sebastian-carpenter added the For This Release Release version 5.9.2 label Jun 11, 2026
@sebastian-carpenter sebastian-carpenter self-assigned this Jun 11, 2026

@dgarske dgarske left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Skoll Code Review

Scan type: reviewOverall recommendation: REQUEST_CHANGES
Findings: 6 total — 6 posted, 0 skipped
5 finding(s) posted as inline comments (see file-level comments below)

Posted findings

  • [High] Servers with WOLFSSL_SNI_ABORT_ON_ABSENCE now abort every ECH handshake at the outer ClientHello, even when a valid inner SNI is presentsrc/tls.c:2520-2557
  • [Medium] test_wolfSSL_Tls13_ECH_no_private_name ABORT_ON_ABSENCE case encodes the outer-parse abort; missing test for ABORT_ON_ABSENCE with inner SNI presenttests/api.c:14625-14639
  • [Low] BAD_STATE_E restore-failure paths log with WOLFSSL_MSG only, no WOLFSSL_ERROR_VERBOSEsrc/tls.c:16900-16907, src/tls.c:17117-17124
  • [Low] Inline reimplementation of TLSX_SetResponse in TLSX_SNI_Parsesrc/tls.c:2550-2557
  • [Low] EchCheckAcceptance calls TLSX_EchReplaceExtensions even when EchCalcAcceptance failedsrc/tls13.c:5310-5314
  • [Info] PUB_NAME changed to example.com for all interop scenarios, not just the new reject tests.github/scripts/openssl-ech.sh:97-99

Review generated by Skoll

Comment thread src/tls.c
Comment thread tests/api.c Outdated
Comment thread src/tls.c Outdated
Comment thread src/tls13.c
Comment thread .github/scripts/openssl-ech.sh

@dgarske dgarske left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

See these skoll review items -> #10568 (review)

@sebastian-carpenter sebastian-carpenter removed their assignment Jun 12, 2026
@dgarske dgarske self-requested a review June 12, 2026 15:24

@dgarske dgarske left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Skoll Code Review

Scan type: reviewOverall recommendation: COMMENT
Findings: 2 total — 2 posted, 0 skipped
2 finding(s) posted as inline comments (see file-level comments below)

Posted findings

  • [Medium] ECH reconciliation block in TLSX_Parse omits the TLS1.3 version guard used by sibling SNI logicsrc/tls.c:18715-18717
  • [Low] Duplicated client/server invocation block in openssl-ech.sh reject branches.github/scripts/openssl-ech.sh:175-197,275-307

Review generated by Skoll

Comment thread src/tls.c
Comment thread .github/scripts/openssl-ech.sh

@dgarske dgarske left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

#10568 (review)
Make sure you rebase to latest master to pull in CI optimizations.

@dgarske dgarske left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Skoll Multi-Scan Review

Modes: review + review-securityOverall recommendation: COMMENT
Findings: 4 total — 4 posted, 0 skipped
3 finding(s) posted as inline comments (see file-level comments below)

Posted findings

  • [Medium] [review] Server now hard-rejects an accepted ECH handshake when the outer ClientHello SNI did not match a publicNamesrc/tls.c:18724-18741
  • [Medium] [review] New UNKNOWN_SNI_HOST_NAME_E error path is not exercised by testssrc/tls.c:18727-18734
  • [Low] [review] Duplicated install/restore swap boilerplate in TLSX_GetSizeWithEch and TLSX_WriteWithEchsrc/tls.c:16911-16935, 17076-17152
  • [Info] [review-security] CTX-level private SNI suppression in ECH outer hello relies on implicit semaphore ordering and is untestedsrc/tls.c:16896-16937 (TLSX_GetSizeWithEch), src/tls.c:17062-17153 (TLSX_WriteWithEch)

Review generated by Skoll

Comment thread src/tls.c
Comment thread src/tls.c
Comment thread src/tls.c Outdated

@dgarske dgarske left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Skoll Multi-Scan Review

Modes: review + review-securityOverall recommendation: COMMENT
Findings: 3 total — 3 posted, 0 skipped
3 finding(s) posted as inline comments (see file-level comments below)

Posted findings

  • [Medium] [review+review-security] ECH outer ClientHello reconciliation may falsely reject valid handshakes (new public-name SNI gate)src/tls.c:18766-18784
  • [Low] [review] Redundant TLSX_Find(TLSX_ECH) lookups in TLSX_SNI_Parsesrc/tls.c:2456-2458, 2513-2519
  • [Info] [review] ForceZero used to zero-initialize a non-secret Hpke structsrc/tls.c:13890

Review generated by Skoll

Comment thread src/tls.c
Comment thread src/tls.c Outdated
Comment thread src/tls.c Outdated
@dgarske dgarske requested a review from Copilot June 12, 2026 21:53

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

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

Comments suppressed due to low confidence (1)

tests/api.c:1

  • This helper will underflow storage-- when called with count == 0, causing an out-of-bounds write to storage->next. Even if current call sites always pass count > 0, it’s brittle for future edits. Add an early return when count <= 0.

Comment thread src/tls.c
Comment thread src/tls.c Outdated
Comment thread src/tls.c Outdated
Comment thread src/tls.c
Comment thread src/tls.c
Comment thread .github/scripts/openssl-ech.sh
@dgarske

dgarske commented Jun 12, 2026

Copy link
Copy Markdown
Member

This PR has many changes too late in release process. There are a few minor good things that @sebastian-carpenter is going to pull out into a smaller PR to see if it can go into the release.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 6 out of 6 changed files in this pull request and generated 1 comment.

Comment thread tests/api.c
- *_wire_sni test is now more efficient
- openssl-ech workflow now does interop with ECH rejection

extra improvements:
- tested TLSX_EchSwapExtensions
- added ctx level SNI to padding calculation
- Improvement of SNI handling for ECH
- Changed EchSwapExtensions to append instead of prepend
- Reworked ECH testing
@sebastian-carpenter sebastian-carpenter removed their assignment Jun 26, 2026
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.

4 participants