@@ -721,6 +721,15 @@ static word32 LoadFileBuffer(const char* path, byte* buf, word32 bufSz)
721721 #define REGRESS_TRUNC_KEX_ALGO "ecdh-sha2-nistp256"
722722#endif
723723
724+ /* Hybrid KEX algorithm for the truncated hybrid f test */
725+ #if !defined(WOLFSSH_NO_CURVE25519_MLKEM768_SHA256)
726+ #define REGRESS_HYBRID_KEX_ALGO "mlkem768x25519-sha256"
727+ #elif !defined(WOLFSSH_NO_NISTP256_MLKEM768_SHA256)
728+ #define REGRESS_HYBRID_KEX_ALGO "mlkem768nistp256-sha256"
729+ #elif !defined(WOLFSSH_NO_NISTP384_MLKEM1024_SHA384)
730+ #define REGRESS_HYBRID_KEX_ALGO "mlkem1024nistp384-sha384"
731+ #endif
732+
724733/* KEX algorithm for the GEX group test */
725734#ifndef WOLFSSH_NO_DH_GEX_SHA256
726735 #define REGRESS_GEX_KEX_ALGO "diffie-hellman-group-exchange-sha256"
@@ -2051,6 +2060,33 @@ static void TestKexDhInitEmptyESendsDisconnect(void)
20512060}
20522061#endif /* REGRESS_TRUNC_KEX_ALGO */
20532062
2063+ #ifdef REGRESS_HYBRID_KEX_ALGO
2064+ /* A hybrid KEX failure on the client also ends with KEY_EXCHANGE_FAILED. The
2065+ * short f leaves the classical peer key one byte short. */
2066+ static void TestKexHybridReplyTruncatedFSendsDisconnect(void)
2067+ {
2068+ KexReplyHarness harness;
2069+ KexReplyRunResult result;
2070+
2071+ InitKexReplyHarnessKex(&harness, REGRESS_HYBRID_KEX_ALGO,
2072+ REGRESS_DEFAULT_KEY_ALGO, REGRESS_DEFAULT_KEY_PATH, 1,
2073+ REGRESS_MUTATE_F_TRUNC, NULL, 0);
2074+ RunKexReplyHandshake(&harness, &result);
2075+
2076+ AssertIntEQ(harness.mutator.parseError, 0);
2077+ AssertIntEQ(harness.mutator.mutatedPackets, 1);
2078+ AssertFalse(result.clientSuccess);
2079+ AssertFalse(harness.client->connectState >= CONNECT_KEYED);
2080+ AssertTrue(result.clientRet == WS_FATAL_ERROR);
2081+ AssertIntEQ(result.clientErr, WS_CRYPTO_FAILED);
2082+ AssertTrue(harness.clientIo.sawDisconnect);
2083+ AssertIntEQ(harness.clientIo.disconnectReason,
2084+ WOLFSSH_DISCONNECT_KEY_EXCHANGE_FAILED);
2085+
2086+ FreeKexReplyHarness(&harness);
2087+ }
2088+ #endif /* REGRESS_HYBRID_KEX_ALGO */
2089+
20542090#ifdef REGRESS_GEX_KEX_ALGO
20552091/* A GEX group below the floor this client enforces (RFC 8270) ends the key
20562092 * exchange. Covers the WS_DH_SIZE_E arm of the client's guard, which no
@@ -17411,6 +17447,9 @@ int main(int argc, char** argv)
1741117447 TestKexDhInitTruncatedESendsDisconnect();
1741217448 TestKexDhInitEmptyESendsDisconnect();
1741317449 #endif
17450+ #ifdef REGRESS_HYBRID_KEX_ALGO
17451+ TestKexHybridReplyTruncatedFSendsDisconnect();
17452+ #endif
1741417453 #ifdef REGRESS_GEX_KEX_ALGO
1741517454 TestKexDhGexGroupShrunkPrimeSendsDisconnect();
1741617455 TestKexDhGexGroupBadGeneratorSendsDisconnect();
0 commit comments