@@ -761,6 +761,7 @@ typedef struct DuplexEndpoint {
761761 word32 disconnectReason;
762762 byte isServer;
763763 byte sawDisconnect;
764+ byte failSendMsgId; /* nonzero: fail the send of a packet with this id */
764765} DuplexEndpoint;
765766
766767typedef struct {
@@ -1278,6 +1279,12 @@ static int DuplexSend(WOLFSSH* ssh, void* buf, word32 sz, void* ctx)
12781279 return WS_CBIO_ERR_GENERAL;
12791280 }
12801281
1282+ if (endpoint->failSendMsgId != 0 &&
1283+ outputSz > UINT32_SZ + PAD_LENGTH_SZ &&
1284+ output[UINT32_SZ + PAD_LENGTH_SZ] == endpoint->failSendMsgId) {
1285+ return WS_CBIO_ERR_GENERAL;
1286+ }
1287+
12811288 if (endpoint->mutator != NULL &&
12821289 endpoint->mutator->enabled &&
12831290 MutatorTargetsEndpoint(endpoint->mutator->mode,
@@ -1501,29 +1508,34 @@ static void RunKexReplyHandshake(KexReplyHarness* harness,
15011508}
15021509
15031510/* The shared secret K does not outlive the key exchange. */
1504- static void AssertKexSecretWiped (const WOLFSSH* ssh)
1511+ static int KexSecretWiped (const WOLFSSH* ssh)
15051512{
15061513 word32 i;
15071514
1508- AssertIntEQ(ssh->kSz, 0);
1515+ if (ssh->kSz != 0)
1516+ return 0;
15091517 for (i = 0; i < (word32)sizeof(ssh->k); i++) {
1510- AssertIntEQ(ssh->k[i], 0);
1518+ if (ssh->k[i] != 0)
1519+ return 0;
15111520 }
1521+ return 1;
15121522}
15131523
1514- static void AssertHandshakeSucceeds(const char* keyAlgo, const char* keyPath)
1524+ /* A NULL kexAlgo uses the harness default. */
1525+ static void AssertHandshakeSucceedsKex(const char* kexAlgo,
1526+ const char* keyAlgo, const char* keyPath)
15151527{
15161528 KexReplyHarness harness;
15171529 KexReplyRunResult result;
15181530
1519- InitKexReplyHarnessEx (&harness, keyAlgo, keyPath, 0,
1531+ InitKexReplyHarnessKex (&harness, kexAlgo , keyAlgo, keyPath, 0,
15201532 REGRESS_MUTATE_SIG_NAME, NULL, 0);
15211533 RunKexReplyHandshake(&harness, &result);
15221534
15231535 AssertTrue(result.clientSuccess);
15241536 AssertTrue(result.serverSuccess);
1525- AssertKexSecretWiped( harness.client);
1526- AssertKexSecretWiped( harness.server);
1537+ AssertTrue(KexSecretWiped( harness.client) );
1538+ AssertTrue(KexSecretWiped( harness.server) );
15271539 AssertIntEQ(harness.mutator.mutatedPackets, 0);
15281540 AssertIntEQ(harness.client->connectState, CONNECT_SERVER_CHANNEL_REQUEST_DONE);
15291541 AssertIntEQ(harness.server->acceptState, ACCEPT_CLIENT_SESSION_ESTABLISHED);
@@ -1535,6 +1547,11 @@ static void AssertHandshakeSucceeds(const char* keyAlgo, const char* keyPath)
15351547 FreeKexReplyHarness(&harness);
15361548}
15371549
1550+ static void AssertHandshakeSucceeds(const char* keyAlgo, const char* keyPath)
1551+ {
1552+ AssertHandshakeSucceedsKex(NULL, keyAlgo, keyPath);
1553+ }
1554+
15381555static void AssertHandshakeRejectsMutatedReply(const char* keyAlgo,
15391556 const char* keyPath, const char* replaceName, int expectedErr)
15401557{
@@ -1933,7 +1950,7 @@ static void AssertHandshakeRejectsCorruptedSig(const char* keyAlgo,
19331950 result.clientErr != WS_WANT_WRITE);
19341951 AssertIntEQ(result.clientErr, expectedErr);
19351952 /* K was agreed before the verify failed. */
1936- AssertKexSecretWiped( harness.client);
1953+ AssertTrue(KexSecretWiped( harness.client) );
19371954
19381955 FreeKexReplyHarness(&harness);
19391956}
@@ -1962,23 +1979,35 @@ static void TestKexSecretWipedPerKex(void)
19621979#endif
19631980 NULL
19641981 };
1965- KexReplyHarness harness;
1966- KexReplyRunResult result;
19671982 word32 i;
19681983
19691984 for (i = 0; kexAlgos[i] != NULL; i++) {
1970- InitKexReplyHarnessKex(&harness, kexAlgos[i],
1971- REGRESS_DEFAULT_KEY_ALGO, REGRESS_DEFAULT_KEY_PATH, 0,
1972- REGRESS_MUTATE_SIG_NAME, NULL, 0);
1973- RunKexReplyHandshake(&harness, &result);
1985+ printf(" KEX secret wipe with %s.\n", kexAlgos[i]);
1986+ AssertHandshakeSucceedsKex(kexAlgos[i],
1987+ REGRESS_DEFAULT_KEY_ALGO, REGRESS_DEFAULT_KEY_PATH);
1988+ }
1989+ }
19741990
1975- AssertTrue(result.clientSuccess);
1976- AssertTrue(result.serverSuccess);
1977- AssertKexSecretWiped(harness.client);
1978- AssertKexSecretWiped(harness.server);
1991+ /* The server wipes K when sending its KEXDH_REPLY fails after key
1992+ * agreement. */
1993+ static void TestKexSecretWipedOnServerSendFail(void)
1994+ {
1995+ KexReplyHarness harness;
1996+ KexReplyRunResult result;
19791997
1980- FreeKexReplyHarness(&harness);
1981- }
1998+ InitKexReplyHarness(&harness, REGRESS_DEFAULT_KEY_ALGO,
1999+ REGRESS_DEFAULT_KEY_PATH, 0, NULL);
2000+ harness.serverIo.failSendMsgId = MSGID_KEXDH_REPLY;
2001+ RunKexReplyHandshake(&harness, &result);
2002+
2003+ AssertFalse(result.serverSuccess);
2004+ AssertTrue(result.serverErr != WS_WANT_READ &&
2005+ result.serverErr != WS_WANT_WRITE);
2006+ /* H is hashed over K, so K was agreed. */
2007+ AssertTrue(harness.server->sessionIdSz > 0);
2008+ AssertTrue(KexSecretWiped(harness.server));
2009+
2010+ FreeKexReplyHarness(&harness);
19822011}
19832012
19842013#ifndef WOLFSSH_NO_RSA_SHA2_256
@@ -15800,12 +15829,26 @@ static void TestGenerateKeysSplit(void)
1580015829 AssertTrue(WMEMCMP(ssh->handshake->peerKeys.encKey,
1580115830 ssh->handshake->keys.encKey, AES_128_KEY_SIZE) != 0);
1580215831
15803- /* A failed derivation leaves no key material behind. */
15832+ /* A failed derivation leaves no key material behind but keeps the
15833+ * negotiated sizes. */
1580415834 AssertTrue(wolfSSH_TestGenerateKeys(ssh, WC_HASH_TYPE_NONE) != WS_SUCCESS);
1580515835 WMEMSET(&zeroKeys, 0, sizeof(zeroKeys));
15806- AssertTrue(WMEMCMP(&ssh->handshake->keys, &zeroKeys, sizeof(Keys)) == 0);
15807- AssertTrue(WMEMCMP(&ssh->handshake->peerKeys, &zeroKeys,
15808- sizeof(Keys)) == 0);
15836+ AssertTrue(WMEMCMP(ssh->handshake->keys.iv, zeroKeys.iv,
15837+ sizeof(zeroKeys.iv)) == 0);
15838+ AssertTrue(WMEMCMP(ssh->handshake->keys.encKey, zeroKeys.encKey,
15839+ sizeof(zeroKeys.encKey)) == 0);
15840+ AssertTrue(WMEMCMP(ssh->handshake->keys.macKey, zeroKeys.macKey,
15841+ sizeof(zeroKeys.macKey)) == 0);
15842+ AssertTrue(WMEMCMP(ssh->handshake->peerKeys.iv, zeroKeys.iv,
15843+ sizeof(zeroKeys.iv)) == 0);
15844+ AssertTrue(WMEMCMP(ssh->handshake->peerKeys.encKey, zeroKeys.encKey,
15845+ sizeof(zeroKeys.encKey)) == 0);
15846+ AssertTrue(WMEMCMP(ssh->handshake->peerKeys.macKey, zeroKeys.macKey,
15847+ sizeof(zeroKeys.macKey)) == 0);
15848+ AssertIntEQ(ssh->handshake->peerKeys.encKeySz, AES_128_KEY_SIZE);
15849+ AssertIntEQ(ssh->handshake->peerKeys.macKeySz, WC_SHA_DIGEST_SIZE);
15850+ AssertIntEQ(ssh->handshake->keys.encKeySz, AES_256_KEY_SIZE);
15851+ AssertIntEQ(ssh->handshake->keys.macKeySz, WC_SHA256_DIGEST_SIZE);
1580915852
1581015853 wolfSSH_free(ssh);
1581115854
@@ -17473,6 +17516,7 @@ int main(int argc, char** argv)
1747317516 #endif
1747417517 TestKexDhReplyRejectsSigNameOverrun();
1747517518 TestKexSecretWipedPerKex();
17519+ TestKexSecretWipedOnServerSendFail();
1747617520 #ifdef REGRESS_TRUNC_KEX_ALGO
1747717521 TestKexDhReplyTruncatedFSendsDisconnect();
1747817522 TestKexDhInitTruncatedESendsDisconnect();
0 commit comments