Skip to content

Commit b641d5d

Browse files
committed
Client: check first_packet_follows guess in DoKexDhReply
When a server sends first_kex_packet_follows=TRUE with an incorrect KEX algorithm guess, the client now silently discards the server's speculative KEXDH_REPLY message by checking ignoreNextKexMsg at the top of DoKexDhReply, matching the existing server-side handling in DoKexDhInit. Add regression test covering the client-side skip path. Affected functions: DoKexDhReply. Issue: F-2863
1 parent 7241f4e commit b641d5d

3 files changed

Lines changed: 35 additions & 8 deletions

File tree

src/internal.c

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5823,6 +5823,17 @@ static int DoKexDhReply(WOLFSSH* ssh, byte* buf, word32 len, word32* idx)
58235823
return ret;
58245824
}
58255825

5826+
if (ret == WS_SUCCESS) {
5827+
if (ssh->handshake->ignoreNextKexMsg) {
5828+
/* skip this message. */
5829+
WLOG(WS_LOG_DEBUG, "Skipping server's KEXDH_REPLY message due to "
5830+
"first_packet_follows guess mismatch.");
5831+
ssh->handshake->ignoreNextKexMsg = 0;
5832+
*idx += len;
5833+
return WS_SUCCESS;
5834+
}
5835+
}
5836+
58265837
if (ret == WS_SUCCESS && len < LENGTH_SZ*2 + *idx) {
58275838
ret = WS_BUFFER_E;
58285839
}
@@ -17901,6 +17912,11 @@ int wolfSSH_TestDoKexDhInit(WOLFSSH* ssh, byte* buf, word32 len, word32* idx)
1790117912
return DoKexDhInit(ssh, buf, len, idx);
1790217913
}
1790317914

17915+
int wolfSSH_TestDoKexDhReply(WOLFSSH* ssh, byte* buf, word32 len, word32* idx)
17916+
{
17917+
return DoKexDhReply(ssh, buf, len, idx);
17918+
}
17919+
1790417920
int wolfSSH_TestChannelPutData(WOLFSSH_CHANNEL* channel, byte* data,
1790517921
word32 dataSz)
1790617922
{

tests/regress.c

Lines changed: 17 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2072,27 +2072,30 @@ typedef int (*FirstPacketFollowsSkipFn)(WOLFSSH* ssh, byte* buf, word32 len,
20722072
word32* idx);
20732073

20742074
/* With ignoreNextKexMsg set, the target Do* handler must consume the packet,
2075-
* clear the flag, and not advance clientState past CLIENT_KEXINIT_DONE. */
2075+
* clear the flag, and not advance the peer's state past KEXINIT_DONE. */
20762076
static void RunFirstPacketFollowsSkipCase(FirstPacketFollowsSkipFn fn,
2077-
const char* label)
2077+
const char* label, byte endpointType, byte initState)
20782078
{
20792079
WOLFSSH_CTX* ctx;
20802080
WOLFSSH* ssh;
20812081
byte payload[8];
20822082
word32 idx = 0;
20832083
int ret;
20842084

2085-
ctx = wolfSSH_CTX_new(WOLFSSH_ENDPOINT_SERVER, NULL);
2085+
ctx = wolfSSH_CTX_new(endpointType, NULL);
20862086
AssertNotNull(ctx);
20872087

20882088
ssh = wolfSSH_new(ctx);
20892089
AssertNotNull(ssh);
20902090
AssertNotNull(ssh->handshake);
20912091

20922092
ssh->handshake->ignoreNextKexMsg = 1;
2093-
ssh->clientState = CLIENT_KEXINIT_DONE;
2093+
if (endpointType == WOLFSSH_ENDPOINT_SERVER)
2094+
ssh->clientState = initState;
2095+
else
2096+
ssh->serverState = initState;
20942097

2095-
/* Garbage payload must never be parsed when skipped. */
2098+
/* Garbage payload that must never be parsed when skipped. */
20962099
WMEMSET(payload, 0xAB, sizeof(payload));
20972100

20982101
ret = fn(ssh, payload, sizeof(payload), &idx);
@@ -2101,19 +2104,25 @@ static void RunFirstPacketFollowsSkipCase(FirstPacketFollowsSkipFn fn,
21012104
}
21022105
AssertIntEQ(idx, sizeof(payload));
21032106
AssertIntEQ(ssh->handshake->ignoreNextKexMsg, 0);
2104-
AssertIntEQ(ssh->clientState, CLIENT_KEXINIT_DONE);
2107+
if (endpointType == WOLFSSH_ENDPOINT_SERVER)
2108+
AssertIntEQ(ssh->clientState, initState);
2109+
else
2110+
AssertIntEQ(ssh->serverState, initState);
21052111

21062112
wolfSSH_free(ssh);
21072113
wolfSSH_CTX_free(ctx);
21082114
}
21092115

21102116
static void TestFirstPacketFollowsSkipped(void)
21112117
{
2112-
RunFirstPacketFollowsSkipCase(wolfSSH_TestDoKexDhInit, "DoKexDhInit");
2118+
RunFirstPacketFollowsSkipCase(wolfSSH_TestDoKexDhInit,
2119+
"DoKexDhInit", WOLFSSH_ENDPOINT_SERVER, CLIENT_KEXINIT_DONE);
21132120
#ifndef WOLFSSH_NO_DH_GEX_SHA256
21142121
RunFirstPacketFollowsSkipCase(wolfSSH_TestDoKexDhGexRequest,
2115-
"DoKexDhGexRequest");
2122+
"DoKexDhGexRequest", WOLFSSH_ENDPOINT_SERVER, CLIENT_KEXINIT_DONE);
21162123
#endif
2124+
RunFirstPacketFollowsSkipCase(wolfSSH_TestDoKexDhReply,
2125+
"DoKexDhReply", WOLFSSH_ENDPOINT_CLIENT, SERVER_KEXINIT_DONE);
21172126
}
21182127

21192128
static void TestFirstPacketFollows(void)

wolfssh/internal.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1337,6 +1337,8 @@ enum WS_MessageIdLimits {
13371337
word32 len, word32* idx);
13381338
WOLFSSH_API int wolfSSH_TestDoKexDhInit(WOLFSSH* ssh, byte* buf,
13391339
word32 len, word32* idx);
1340+
WOLFSSH_API int wolfSSH_TestDoKexDhReply(WOLFSSH* ssh, byte* buf,
1341+
word32 len, word32* idx);
13401342
WOLFSSH_API int wolfSSH_TestChannelPutData(WOLFSSH_CHANNEL*, byte*, word32);
13411343
#ifndef WOLFSSH_NO_DH_GEX_SHA256
13421344
WOLFSSH_API int wolfSSH_TestDoKexDhGexRequest(WOLFSSH* ssh, byte* buf,

0 commit comments

Comments
 (0)