@@ -1731,6 +1731,8 @@ static int test_DoReceive_VerifyMacFailure(void)
17311731 ssh->curSz = 0;
17321732 ssh->processReplyState = PROCESS_INIT;
17331733 ssh->error = 0;
1734+ ssh->highwaterFlag = 0;
1735+ ssh->msgHighwaterFlag = 0;
17341736
17351737 flatSeq[0] = (byte)(ssh->peerSeq >> 24);
17361738 flatSeq[1] = (byte)(ssh->peerSeq >> 16);
@@ -1781,6 +1783,10 @@ static int test_DoReceive_VerifyMacFailure(void)
17811783 result = -207;
17821784 goto done;
17831785 }
1786+ if (!ssh->highwaterFlag || !ssh->msgHighwaterFlag) {
1787+ result = -209;
1788+ goto done;
1789+ }
17841790 }
17851791
17861792done:
@@ -1886,6 +1892,10 @@ static int test_DoReceive_AeadTagFailure(void)
18861892 result = -229;
18871893 goto done;
18881894 }
1895+ if (!ssh->highwaterFlag || !ssh->msgHighwaterFlag) {
1896+ result = -230;
1897+ goto done;
1898+ }
18891899
18901900done:
18911901 if (aesInited)
@@ -2130,6 +2140,10 @@ static int test_DoReceive_RejectsShortPadding(void)
21302140 result = -764;
21312141 goto done2;
21322142 }
2143+ if (!ssh->highwaterFlag || !ssh->msgHighwaterFlag) {
2144+ result = -765;
2145+ goto done2;
2146+ }
21332147
21342148done2:
21352149 wolfSSH_free(ssh);
@@ -2138,6 +2152,58 @@ static int test_DoReceive_RejectsShortPadding(void)
21382152}
21392153
21402154
2155+ /* Verify DoReceive rejects a cleartext packet whose padding_length leaves no
2156+ * room for the message id, returning WS_OVERFLOW_E, and stops the highwater
2157+ * callback. Layout: packet_length=4, padding_length=4 => 8 bytes total. */
2158+ static int test_DoReceive_RejectsPaddingUnderflow(void)
2159+ {
2160+ WOLFSSH_CTX* ctx = NULL;
2161+ WOLFSSH* ssh = NULL;
2162+ int ret;
2163+ int result = 0;
2164+ byte pkt[8];
2165+ word32 totalLen = (word32)sizeof(pkt);
2166+
2167+ ctx = wolfSSH_CTX_new(WOLFSSH_ENDPOINT_CLIENT, NULL);
2168+ if (ctx == NULL)
2169+ return -766;
2170+ ssh = wolfSSH_new(ctx);
2171+ if (ssh == NULL) {
2172+ wolfSSH_CTX_free(ctx);
2173+ return -767;
2174+ }
2175+
2176+ WMEMSET(pkt, 0, sizeof(pkt));
2177+ pkt[3] = 4; /* packet_length */
2178+ pkt[4] = MIN_PAD_LENGTH;
2179+
2180+ ShrinkBuffer(&ssh->inputBuffer, 1);
2181+ ret = GrowBuffer(&ssh->inputBuffer, totalLen);
2182+ if (ret != WS_SUCCESS) {
2183+ result = -768;
2184+ goto done;
2185+ }
2186+ WMEMCPY(ssh->inputBuffer.buffer, pkt, totalLen);
2187+ ssh->inputBuffer.length = totalLen;
2188+ ssh->inputBuffer.idx = 0;
2189+
2190+ ret = wolfSSH_TestDoReceive(ssh);
2191+ if (ret != WS_FATAL_ERROR || ssh->error != WS_OVERFLOW_E) {
2192+ result = -769;
2193+ goto done;
2194+ }
2195+ if (!ssh->highwaterFlag || !ssh->msgHighwaterFlag) {
2196+ result = -793;
2197+ goto done;
2198+ }
2199+
2200+ done:
2201+ wolfSSH_free(ssh);
2202+ wolfSSH_CTX_free(ctx);
2203+ return result;
2204+ }
2205+
2206+
21412207/* Verify DoReceive rejects a cleartext binary packet whose length field is
21422208 * not block aligned. The packet is valid in every other respect, so the
21432209 * RFC 4253 section 6 alignment check is the only thing that can reject it. */
@@ -2197,6 +2263,10 @@ static int test_DoReceive_RejectsMisalignedPacket(void)
21972263 result = -774;
21982264 goto done3;
21992265 }
2266+ if (!ssh->highwaterFlag || !ssh->msgHighwaterFlag) {
2267+ result = -794;
2268+ goto done3;
2269+ }
22002270
22012271done3:
22022272 wolfSSH_free(ssh);
@@ -6606,6 +6676,117 @@ static int test_WorkerReportsExtDataChannelKeying(void)
66066676 return result;
66076677}
66086678
6679+ #if defined(WOLFSSH_TEST_INTERNAL) && !defined(WOLFSSH_NO_HMAC_SHA2_256)
6680+ /* An inbound packet that fails its checks starts no highwater rekey, neither
6681+ * from the worker's flush on that pass nor from a later send. */
6682+ static int test_HighwaterQuietAfterBadPacket(void)
6683+ {
6684+ WOLFSSH_CTX* ctx = NULL;
6685+ WOLFSSH* ssh = NULL;
6686+ HwTestCtx hc;
6687+ Hmac hmac;
6688+ int result = 0;
6689+ int ret;
6690+ word32 prefixLen;
6691+ byte seq[LENGTH_SZ];
6692+ byte macKey[WC_SHA256_DIGEST_SIZE];
6693+ byte digest[WC_SHA256_DIGEST_SIZE];
6694+ byte pkt[UINT32_SZ + 12 + WC_SHA256_DIGEST_SIZE];
6695+
6696+ WMEMSET(&hc, 0, sizeof(hc));
6697+ s_extSendCount = 0;
6698+
6699+ ctx = wolfSSH_CTX_new(WOLFSSH_ENDPOINT_SERVER, NULL);
6700+ if (ctx == NULL)
6701+ return -1950;
6702+ wolfSSH_SetIOSend(ctx, CountIoSend);
6703+ wolfSSH_SetIORecv(ctx, PacketIoRecv);
6704+ wolfSSH_SetHighwaterCb(ctx, 1, HwTestCb);
6705+
6706+ ssh = wolfSSH_new(ctx);
6707+ if (ssh == NULL) { result = -1951; goto done; }
6708+ hc.ssh = ssh;
6709+ wolfSSH_SetHighwaterCtx(ssh, &hc);
6710+ wolfSSH_SetMsgHighwater(ssh, 1);
6711+ ssh->txCount = 1;
6712+ ssh->txMsgCount = 1;
6713+
6714+ /* Control: the flush after an idle receive fires the callback. */
6715+ ssh->outputBuffer.length = 1;
6716+ ssh->outputBuffer.idx = 0;
6717+ ssh->outputBuffer.buffer[0] = 0;
6718+ ret = wolfSSH_worker(ssh, NULL);
6719+ if (ret != WS_FATAL_ERROR || wolfSSH_get_error(ssh) != WS_WANT_READ) {
6720+ result = -1952;
6721+ goto done;
6722+ }
6723+ if (hc.count != 1) { result = -1953; goto done; }
6724+
6725+ /* A new key epoch clears both flags. */
6726+ ssh->highwaterFlag = 0;
6727+ ssh->msgHighwaterFlag = 0;
6728+ hc.count = 0;
6729+
6730+ /* An IGNORE packet under HMAC-SHA2-256 at peerSeq 0, one MAC bit off. */
6731+ prefixLen = BuildMacTestPacketPrefix(MSGID_IGNORE, 10, pkt, sizeof(pkt));
6732+ if (prefixLen == 0) { result = -1954; goto done; }
6733+ WMEMSET(macKey, 0xA5, sizeof(macKey));
6734+ WMEMSET(seq, 0, sizeof(seq));
6735+ ret = wc_HmacInit(&hmac, ssh->ctx->heap, INVALID_DEVID);
6736+ if (ret == 0) {
6737+ ret = wc_HmacSetKey(&hmac, WC_SHA256, macKey, sizeof(macKey));
6738+ if (ret == 0)
6739+ ret = wc_HmacUpdate(&hmac, seq, sizeof(seq));
6740+ if (ret == 0)
6741+ ret = wc_HmacUpdate(&hmac, pkt, prefixLen);
6742+ if (ret == 0)
6743+ ret = wc_HmacFinal(&hmac, digest);
6744+ wc_HmacFree(&hmac);
6745+ }
6746+ if (ret != 0) { result = -1955; goto done; }
6747+ WMEMCPY(pkt + prefixLen, digest, sizeof(digest));
6748+ pkt[prefixLen] ^= 0x01;
6749+
6750+ ssh->peerMacId = ID_HMAC_SHA2_256;
6751+ ssh->peerMacSz = WC_SHA256_DIGEST_SIZE;
6752+ WMEMCPY(ssh->peerKeys.macKey, macKey, sizeof(macKey));
6753+ ssh->peerKeys.macKeySz = sizeof(macKey);
6754+ s_recvPkt = pkt;
6755+ s_recvPktSz = prefixLen + WC_SHA256_DIGEST_SIZE;
6756+ s_recvPktOff = 0;
6757+
6758+ /* The worker still flushes what was queued, but fires nothing. */
6759+ ssh->outputBuffer.length = 1;
6760+ ssh->outputBuffer.idx = 0;
6761+ ssh->outputBuffer.buffer[0] = 0;
6762+ s_extSendCount = 0;
6763+ ret = wolfSSH_worker(ssh, NULL);
6764+ if (ret != WS_FATAL_ERROR || wolfSSH_get_error(ssh) != WS_VERIFY_MAC_E) {
6765+ result = -1957;
6766+ goto done;
6767+ }
6768+ if (wolfSSH_OutputPending(ssh) || s_extSendCount == 0) {
6769+ result = -1958;
6770+ goto done;
6771+ }
6772+ if (hc.count != 0) { result = -1959; goto done; }
6773+
6774+ /* Nor does the next send, as a teardown would make. */
6775+ ret = wolfSSH_SendIgnore(ssh, NULL, 0);
6776+ if (ret != WS_SUCCESS) { result = -1960; goto done; }
6777+ if (hc.count != 0) { result = -1961; goto done; }
6778+
6779+ done:
6780+ s_recvPkt = NULL;
6781+ s_recvPktSz = 0;
6782+ s_recvPktOff = 0;
6783+ s_extSendCount = 0;
6784+ wolfSSH_free(ssh);
6785+ wolfSSH_CTX_free(ctx);
6786+ return result;
6787+ }
6788+ #endif /* WOLFSSH_TEST_INTERNAL && !WOLFSSH_NO_HMAC_SHA2_256 */
6789+
66096790/* channelId=0, type=1 (stderr), dataSz=10, payload all 0x44. */
66106791static const byte s_workerExtBlob[] = {
66116792 0x00, 0x00, 0x00, 0x00,
@@ -6811,6 +6992,10 @@ static int test_WorkerHardRecvErrorOutranksFlush(void)
68116992 ret = wolfSSH_worker(ssh, NULL);
68126993 if (ret != WS_FATAL_ERROR) { result = -1735; goto done; }
68136994 if (wolfSSH_get_error(ssh) != WS_OVERFLOW_E) { result = -1736; goto done; }
6995+ if (!ssh->highwaterFlag || !ssh->msgHighwaterFlag) {
6996+ result = -1784;
6997+ goto done;
6998+ }
68146999
68157000done:
68167001 s_recvPkt = NULL;
@@ -22806,6 +22991,11 @@ int wolfSSH_UnitTest(int argc, char** argv)
2280622991 printf("DoReceiveRejectsShortPadding: %s\n",
2280722992 (unitResult == 0 ? "SUCCESS" : "FAILED"));
2280822993 testResult = testResult || unitResult;
22994+
22995+ unitResult = test_DoReceive_RejectsPaddingUnderflow();
22996+ printf("DoReceiveRejectsPaddingUnderflow: %s\n",
22997+ (unitResult == 0 ? "SUCCESS" : "FAILED"));
22998+ testResult = testResult || unitResult;
2280922999#endif
2281023000
2281123001#ifdef WOLFSSH_TEST_INTERNAL
@@ -23034,6 +23224,13 @@ int wolfSSH_UnitTest(int argc, char** argv)
2303423224 (unitResult == 0 ? "SUCCESS" : "FAILED"));
2303523225 testResult = testResult || unitResult;
2303623226
23227+ #if defined(WOLFSSH_TEST_INTERNAL) && !defined(WOLFSSH_NO_HMAC_SHA2_256)
23228+ unitResult = test_HighwaterQuietAfterBadPacket();
23229+ printf("HighwaterQuietAfterBadPacket: %s\n",
23230+ (unitResult == 0 ? "SUCCESS" : "FAILED"));
23231+ testResult = testResult || unitResult;
23232+ #endif
23233+
2303723234 unitResult = test_WorkerFlushesOnIdleReceive();
2303823235 printf("WorkerFlushesOnIdleReceive: %s\n",
2303923236 (unitResult == 0 ? "SUCCESS" : "FAILED"));
0 commit comments