@@ -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"
@@ -2291,6 +2300,33 @@ static void TestKexDhInitEmptyESendsDisconnect(void)
22912300}
22922301#endif /* REGRESS_TRUNC_KEX_ALGO */
22932302
2303+ #ifdef REGRESS_HYBRID_KEX_ALGO
2304+ /* A hybrid KEX failure on the client also ends with KEY_EXCHANGE_FAILED. The
2305+ * short f leaves the classical peer key one byte short. */
2306+ static void TestKexHybridReplyTruncatedFSendsDisconnect(void)
2307+ {
2308+ KexReplyHarness harness;
2309+ KexReplyRunResult result;
2310+
2311+ InitKexReplyHarnessKex(&harness, REGRESS_HYBRID_KEX_ALGO,
2312+ REGRESS_DEFAULT_KEY_ALGO, REGRESS_DEFAULT_KEY_PATH, 1,
2313+ REGRESS_MUTATE_F_TRUNC, NULL, 0);
2314+ RunKexReplyHandshake(&harness, &result);
2315+
2316+ AssertIntEQ(harness.mutator.parseError, 0);
2317+ AssertIntEQ(harness.mutator.mutatedPackets, 1);
2318+ AssertFalse(result.clientSuccess);
2319+ AssertFalse(harness.client->connectState >= CONNECT_KEYED);
2320+ AssertTrue(result.clientRet == WS_FATAL_ERROR);
2321+ AssertIntEQ(result.clientErr, WS_CRYPTO_FAILED);
2322+ AssertTrue(harness.clientIo.sawDisconnect);
2323+ AssertIntEQ(harness.clientIo.disconnectReason,
2324+ WOLFSSH_DISCONNECT_KEY_EXCHANGE_FAILED);
2325+
2326+ FreeKexReplyHarness(&harness);
2327+ }
2328+ #endif /* REGRESS_HYBRID_KEX_ALGO */
2329+
22942330#ifdef REGRESS_GEX_KEX_ALGO
22952331/* A GEX group below the floor this client enforces (RFC 8270) ends the key
22962332 * exchange. Covers the WS_DH_SIZE_E arm of the client's guard, which no
@@ -18665,6 +18701,9 @@ int main(int argc, char** argv)
1866518701 TestKexDhInitTruncatedESendsDisconnect();
1866618702 TestKexDhInitEmptyESendsDisconnect();
1866718703 #endif
18704+ #ifdef REGRESS_HYBRID_KEX_ALGO
18705+ TestKexHybridReplyTruncatedFSendsDisconnect();
18706+ #endif
1866818707 #ifdef REGRESS_GEX_KEX_ALGO
1866918708 TestKexDhGexGroupShrunkPrimeSendsDisconnect();
1867018709 TestKexDhGexGroupBadGeneratorSendsDisconnect();
0 commit comments