Skip to content

Fix hybrid ML-KEM client secret sizing - #1282

Open
ejohnstown wants to merge 3 commits into
wolfSSL:masterfrom
ejohnstown:sf30
Open

ejohnstown wants to merge 3 commits into
wolfSSL:masterfrom
ejohnstown:sf30

Conversation

@ejohnstown

Copy link
Copy Markdown
Contributor

The hybrid ML-KEM client offered the classical key agreement the full ssh->k capacity although the ML-KEM secret already sits in front of it, and did not check the ML-KEM private key decode. The hybrid KEXes are also now gated on the ML-KEM parameter set each one needs.

  • KeyAgreeEcdhMlKem_client() bounds the classical secret by the remaining capacity and checks the decode result before decapsulation (F-14225, F-10559).
  • WOLFSSH_NO_MLKEM768 and WOLFSSH_NO_MLKEM1024 follow wolfSSL's WOLFSSL_NO_ML_KEM* macros, so a wolfSSL built without a set no longer advertises that hybrid.
  • tests: unit test of the capacity bound and a corrupted key; regress test that a hybrid failure sends KEY_EXCHANGE_FAILED.

KeyAgreeEcdhMlKem_client() writes the classical shared secret after the
ML-KEM secret in ssh->k, so it now offers the classical call only the
capacity left after that prefix, as the server side does. The ML-KEM
private key decode result is now checked before decapsulation.

- reject a ssh->k capacity that cannot hold the ML-KEM secret
- add wolfSSH_TestKeyAgreeEcdhMlKem_client() and a unit test that runs
  each hybrid KEX at, below and above the capacity bound, and with a
  corrupted private key, and checks the derived secret

Issue: F-14225, F-10559
wolfSSL can build ML-KEM without one of its parameter sets, or without
FIPS 203 ML-KEM at all. The hybrid KEX gates now follow the set each
one needs, so a missing set is neither advertised nor negotiated.

- add WOLFSSH_NO_MLKEM768 and WOLFSSH_NO_MLKEM1024 from
  WOLFSSL_NO_ML_KEM, WOLFSSL_NO_ML_KEM_768 and WOLFSSL_NO_ML_KEM_1024
- derive the three hybrid KEX gates from them
DoKexDhReply() maps any KeyAgree_client() failure to WS_CRYPTO_FAILED
and sends KEY_EXCHANGE_FAILED. Pin that for the hybrid ML-KEM KEXes,
whose client agreement returns raw wolfCrypt codes.

- truncate f in a hybrid KEXDH_REPLY and check the client's error and
  disconnect reason
Copilot AI balanced review requested due to automatic review settings September 29, 2026 23:07

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.

Copilot review overview

🟢 Approval recommended

The implementation is correctly bounded, consistently gated, and covered by focused unit and regression tests.

Review effort: Balanced
Findings: None

What changed in this PR

Fixes ML-KEM hybrid client key agreement sizing and decode-error handling while respecting enabled parameter sets.

Changes:

  • Bounds classical secrets by remaining buffer capacity.
  • Propagates ML-KEM private-key decode failures.
  • Adds parameter-set gating and regression coverage.
File Description
wolfssh/​internal.h Adds ML-KEM parameter-set guards and test API.
src/​internal.c Corrects hybrid secret sizing and decode handling.
tests/​unit.c Tests capacity boundaries and corrupted keys.
tests/​regress.c Tests disconnect behavior after hybrid KEX failure.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

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