Skip to content

DH GEX group selection hardening#1056

Open
ejohnstown wants to merge 3 commits into
wolfSSL:masterfrom
ejohnstown:dh-gex
Open

DH GEX group selection hardening#1056
ejohnstown wants to merge 3 commits into
wolfSSL:masterfrom
ejohnstown:dh-gex

Conversation

@ejohnstown

Copy link
Copy Markdown
Contributor

This fixes the server-side Diffie-Hellman Group Exchange (RFC 4419) group selection, which previously ignored the client's requested size window and always sent group 14, and adds a 2048-bit floor to prevent downgrade.

  • Discard a guessed KEX packet in DoKexDhGexGroup: honor ignoreNextKexMsg so a wrong first_kex_packet_follows guess is silently discarded rather than parsed as a real group and errored, matching DoKexDhReply / DoKexDhInit (RFC 4253 7.1). (Issue: F-2866)
  • Select the DH GEX group from the client's [min, preferred, max] size window instead of always sending group 14: add SelectKexDhGexGroup() to pick the closest fitting built-in group, reject with WS_DH_SIZE_E when none fits, and thread the WOLFSSH through GetDHPrimeGroup() so the sent group, exchange hash, and shared secret stay consistent. (Issue: F-55)
  • Enforce a 2048-bit floor (WOLFSSH_DH_GEX_MIN_BITS) on group selection: clamp the client's lower bound up before the scan, reject windows whose max is below the floor, cap the window to MAX_KEX_KEY_SZ, and extend the unit tests for the rejection, clamp-up, and cache-miss fallback paths. (Issue: F-55)

- DoKexDhGexGroup didn't check ignoreNextKexMsg, so a wrong
  first_kex_packet_follows guess was parsed as a real group and
  errored instead of being silently discarded (RFC 4253 7.1).
- Add the guard already used by DoKexDhReply / DoKexDhInit:
  consume the packet, clear the flag, return WS_SUCCESS.
- Extend TestFirstPacketFollowsSkipped via a new
  wolfSSH_TestDoKexDhGexGroup wrapper.

Issue: F-2866
- Server GEX ignored the client's min/preferred/max and always
  sent group 14, silently downgrading a 4096-min client (RFC 4419).
- Add SelectKexDhGexGroup(): pick the built-in group within
  [min, max] closest to preferred, ties favoring the smaller.
- Reject with WS_DH_SIZE_E when no built-in group fits.
- GetDHPrimeGroup() now takes the WOLFSSH so the group sent, the
  exchange hash, and the shared secret all reselect consistently.
- Add a unit test (default, max-cap, out-of-window, 4096-min,
  1024-only).

Issue: F-55
Copilot AI review requested due to automatic review settings June 24, 2026 00: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

Hardens server-side Diffie-Hellman Group Exchange (DH-GEX, RFC 4419/8270) by selecting a built-in DH group that actually matches the client’s requested size window (with a 2048-bit minimum floor), and ensures consistency between the group sent on the wire and the group used for exchange-hash / shared-secret computation. It also aligns DH-GEX message handlers with existing first_packet_follows skip behavior.

Changes:

  • Add server-side DH-GEX group selection (SelectKexDhGexGroup) honoring the client’s [min, preferred, max] window, with a 2048-bit floor and rejection when no built-in group fits.
  • Cache and reuse the exact selected DH group via the handshake to keep wire-group, exchange hash, and key agreement consistent (updates GetDHPrimeGroup to take WOLFSSH*).
  • Extend internal/regression/unit tests to cover selection, skip-on-first_packet_follows, send-vs-hash consistency, and cache-miss fallback.

Reviewed changes

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

File Description
wolfssh/internal.h Exposes new internal-test wrappers for DH-GEX group selection, group handler, and DH prime-group retrieval.
src/internal.c Implements DH-GEX group selection + 2048-bit floor, caches selected group for consistency, updates GetDHPrimeGroup signature, and adds ignoreNextKexMsg handling for DoKexDhGexGroup.
tests/unit.c Adds unit tests for selection behavior, wire-vs-hash consistency, and cache-miss fallback.
tests/regress.c Extends first_packet_follows skip regression coverage to include DoKexDhGexGroup.

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

Comment thread src/internal.c
- Clamp client's lower bound up to WOLFSSH_DH_GEX_MIN_BITS (default
  2048) before the candidate scan; prevents downgrade to group 1.
- Reject a window whose max is below the floor with WS_DH_SIZE_E.
- Keep group 1 in the candidate set so a lowered floor stays usable.
- Cap the client window to MAX_KEX_KEY_SZ so selection can never pick a
  group larger than the server's own key buffers (defense-in-depth for
  builds enabling group 16 with a lowered WOLFSSH_DEFAULT_GEXDH_MAX).
- Relabel the no-candidate log "effective window" so the clamped min is
  not mistaken for the raw client request.
- Note the client-side DoKexDhGexGroup ignoreNextKexMsg skip as
  defensive symmetry not expected to fire.
- Update test_DhGexGroupSelect for rejection and clamp-up cases; add
  test_DhGexGroupCacheMissFallback covering the GetDHPrimeGroup
  cache-miss re-selection path.

Issue: F-55
@ejohnstown ejohnstown marked this pull request as ready for review June 24, 2026 16:47
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.

3 participants