@@ -729,6 +729,15 @@ static word32 LoadFileBuffer(const char* path, byte* buf, word32 bufSz)
729729 #define REGRESS_TRUNC_KEX_ALGO "ecdh-sha2-nistp256"
730730#endif
731731
732+ /* Hybrid KEX algorithm for the truncated hybrid f test */
733+ #if !defined(WOLFSSH_NO_CURVE25519_MLKEM768_SHA256)
734+ #define REGRESS_HYBRID_KEX_ALGO "mlkem768x25519-sha256"
735+ #elif !defined(WOLFSSH_NO_NISTP256_MLKEM768_SHA256)
736+ #define REGRESS_HYBRID_KEX_ALGO "mlkem768nistp256-sha256"
737+ #elif !defined(WOLFSSH_NO_NISTP384_MLKEM1024_SHA384)
738+ #define REGRESS_HYBRID_KEX_ALGO "mlkem1024nistp384-sha384"
739+ #endif
740+
732741/* KEX algorithm for the GEX group test */
733742#ifndef WOLFSSH_NO_DH_GEX_SHA256
734743 #define REGRESS_GEX_KEX_ALGO "diffie-hellman-group-exchange-sha256"
@@ -2381,6 +2390,33 @@ static void TestKexDhInitEmptyESendsDisconnect(void)
23812390}
23822391#endif /* REGRESS_TRUNC_KEX_ALGO */
23832392
2393+ #ifdef REGRESS_HYBRID_KEX_ALGO
2394+ /* A hybrid KEX failure on the client also ends with KEY_EXCHANGE_FAILED. The
2395+ * short f leaves the classical peer key one byte short. */
2396+ static void TestKexHybridReplyTruncatedFSendsDisconnect(void)
2397+ {
2398+ KexReplyHarness harness;
2399+ KexReplyRunResult result;
2400+
2401+ InitKexReplyHarnessKex(&harness, REGRESS_HYBRID_KEX_ALGO,
2402+ REGRESS_DEFAULT_KEY_ALGO, REGRESS_DEFAULT_KEY_PATH, 1,
2403+ REGRESS_MUTATE_F_TRUNC, NULL, 0);
2404+ RunKexReplyHandshake(&harness, &result);
2405+
2406+ AssertIntEQ(harness.mutator.parseError, 0);
2407+ AssertIntEQ(harness.mutator.mutatedPackets, 1);
2408+ AssertFalse(result.clientSuccess);
2409+ AssertFalse(harness.client->connectState >= CONNECT_KEYED);
2410+ AssertTrue(result.clientRet == WS_FATAL_ERROR);
2411+ AssertIntEQ(result.clientErr, WS_CRYPTO_FAILED);
2412+ AssertTrue(harness.clientIo.sawDisconnect);
2413+ AssertIntEQ(harness.clientIo.disconnectReason,
2414+ WOLFSSH_DISCONNECT_KEY_EXCHANGE_FAILED);
2415+
2416+ FreeKexReplyHarness(&harness);
2417+ }
2418+ #endif /* REGRESS_HYBRID_KEX_ALGO */
2419+
23842420#ifdef REGRESS_GEX_KEX_ALGO
23852421/* A GEX group below the floor this client enforces (RFC 8270) ends the key
23862422 * exchange. Covers the WS_DH_SIZE_E arm of the client's guard, which no
@@ -19605,6 +19641,9 @@ int main(int argc, char** argv)
1960519641 TestKexDhInitTruncatedESendsDisconnect();
1960619642 TestKexDhInitEmptyESendsDisconnect();
1960719643 #endif
19644+ #ifdef REGRESS_HYBRID_KEX_ALGO
19645+ TestKexHybridReplyTruncatedFSendsDisconnect();
19646+ #endif
1960819647 #ifdef REGRESS_GEX_KEX_ALGO
1960919648 TestKexDhGexGroupShrunkPrimeSendsDisconnect();
1961019649 TestKexDhGexGroupBadGeneratorSendsDisconnect();
0 commit comments