Files
ESP32_Serial_Swiss_Army_Knife/tools/wolfssh_order/793.patch
T
Commander1024 bea33e1c95 Add restricted wolfSSH ordering fix
Apply hash-pinned generated edits for CVE-2025-14942 while keeping
wolfSSH 1.4.20 managed sources unchanged. Add the ABI header overlay,
provenance records, and real state-machine interoperability contracts.
2026-09-16 14:04:34 +02:00

883 lines
33 KiB
Diff

From 5fa6c0fce30a421879b355a007ef843eb48332d3 Mon Sep 17 00:00:00 2001
From: JacobBarthelmeh <jacob@wolfssl.com>
Date: Thu, 27 Mar 2025 08:54:23 -0600
Subject: [PATCH 1/8] sanity checks on message types during rekey
---
src/internal.c | 55 +++++++++++++++++++++++++++++++++++++++++++---
wolfssh/internal.h | 5 ++++-
2 files changed, 56 insertions(+), 4 deletions(-)
diff --git a/src/internal.c b/src/internal.c
index 63f0e1af7..739a9bad2 100644
--- a/src/internal.c
+++ b/src/internal.c
@@ -595,6 +595,40 @@ static void HandshakeInfoFree(HandshakeInfo* hs, void* heap)
}
+/* RFC 4253 section 7.1, Once having sent SSH_MSG_KEXINIT the only messages
+* that can be sent are 1-19 (except SSH_MSG_SERVICE_REQUEST and
+* SSH_MSG_SERVICE_ACCEPT), 20-29 (except SSH_MSG_KEXINIT again), and 30-49
+*/
+INLINE static int IsMessageAllowedKeying(WOLFSSH *ssh, byte msg)
+{
+ if (ssh->isKeying == 0) {
+ return 1;
+ }
+
+ /* case of servie request or accept in 1-19 */
+ if (msg == MSGID_SERVICE_REQUEST || msg == MSGID_SERVICE_ACCEPT) {
+ WLOG(WS_LOG_DEBUG, "Message ID %u not allowed by during rekeying", msg);
+ ssh->error = WS_REKEYING;
+ return 0;
+ }
+
+ /* case of resending SSH_MSG_KEXINIT */
+ if (msg == MSGID_KEXINIT) {
+ WLOG(WS_LOG_DEBUG, "Message ID %u not allowed by during rekeying", msg);
+ ssh->error = WS_REKEYING;
+ return 0;
+ }
+
+ /* case where message id greater than 49 */
+ if (msg >= MSGID_USERAUTH_REQUEST) {
+ WLOG(WS_LOG_DEBUG, "Message ID %u not allowed by during rekeying", msg);
+ ssh->error = WS_REKEYING;
+ return 0;
+ }
+ return 1;
+}
+
+
#ifndef NO_WOLFSSH_SERVER
INLINE static int IsMessageAllowedServer(WOLFSSH *ssh, byte msg)
{
@@ -673,8 +707,12 @@ INLINE static int IsMessageAllowedClient(WOLFSSH *ssh, byte msg)
#endif /* NO_WOLFSSH_CLIENT */
-INLINE static int IsMessageAllowed(WOLFSSH *ssh, byte msg)
+INLINE static int IsMessageAllowed(WOLFSSH *ssh, byte msg, byte state)
{
+ if (state == WS_MSG_SEND && !IsMessageAllowedKeying(ssh, msg)) {
+ return 0;
+ }
+
#ifndef NO_WOLFSSH_SERVER
if (ssh->ctx->side == WOLFSSH_ENDPOINT_SERVER) {
return IsMessageAllowedServer(ssh, msg);
@@ -5905,7 +5943,6 @@ static int DoNewKeys(WOLFSSH* ssh, byte* buf, word32 len, word32* idx)
HandshakeInfoFree(ssh->handshake, ssh->ctx->heap);
ssh->handshake = NULL;
WLOG(WS_LOG_DEBUG, "Keying completed");
-
if (ssh->ctx->keyingCompletionCb)
ssh->ctx->keyingCompletionCb(ssh->keyingCompletionCtx);
}
@@ -9309,7 +9346,7 @@ static int DoPacket(WOLFSSH* ssh, byte* bufferConsumed)
return WS_OVERFLOW_E;
}
- if (!IsMessageAllowed(ssh, msg)) {
+ if (!IsMessageAllowed(ssh, msg, WS_MSG_RECV)) {
return WS_MSGID_NOT_ALLOWED_E;
}
@@ -15649,6 +15686,12 @@ int SendChannelEof(WOLFSSH* ssh, word32 peerChannelId)
if (ssh == NULL)
ret = WS_BAD_ARGUMENT;
+ if (ret == WS_SUCCESS) {
+ if (!IsMessageAllowed(ssh, MSGID_CHANNEL_EOF, WS_MSG_SEND)) {
+ ret = WS_MSGID_NOT_ALLOWED_E;
+ }
+ }
+
if (ret == WS_SUCCESS) {
channel = ChannelFind(ssh, peerChannelId, WS_CHANNEL_ID_PEER);
if (channel == NULL)
@@ -16077,6 +16120,12 @@ int SendChannelWindowAdjust(WOLFSSH* ssh, word32 channelId,
if (ssh == NULL)
ret = WS_BAD_ARGUMENT;
+ if (ret == WS_SUCCESS) {
+ if (!IsMessageAllowed(ssh, MSGID_CHANNEL_WINDOW_ADJUST, WS_MSG_SEND)) {
+ ret = WS_MSGID_NOT_ALLOWED_E;
+ }
+ }
+
channel = ChannelFind(ssh, channelId, WS_CHANNEL_ID_SELF);
if (channel == NULL) {
WLOG(WS_LOG_DEBUG, "Invalid channel");
diff --git a/wolfssh/internal.h b/wolfssh/internal.h
index 261ae6d42..29a6f8ef8 100644
--- a/wolfssh/internal.h
+++ b/wolfssh/internal.h
@@ -1249,6 +1249,10 @@ enum WS_MessageIds {
#define CHANNEL_EXTENDED_DATA_STDERR WOLFSSH_EXT_DATA_STDERR
+/* Used when checking IsMessageAllowed() to determine if createing and sending
+ * the message or receiving the message is allowed */
+#define WS_MSG_SEND 1
+#define WS_MSG_RECV 2
/* dynamic memory types */
enum WS_DynamicTypes {
@@ -1442,4 +1446,3 @@ enum TerminalModes {
#endif
#endif /* _WOLFSSH_INTERNAL_H_ */
-
From af45bc3719ddeac112d9d70b2e6a969f1aa3f3e7 Mon Sep 17 00:00:00 2001
From: JacobBarthelmeh <jacob@wolfssl.com>
Date: Tue, 13 May 2025 16:01:01 -0600
Subject: [PATCH 2/8] update example client for rekey and sanity check on
window update after read attempt
---
examples/client/client.c | 11 +++++++++++
src/ssh.c | 12 +++++++++++-
2 files changed, 22 insertions(+), 1 deletion(-)
diff --git a/examples/client/client.c b/examples/client/client.c
index e27305f72..f415bd801 100644
--- a/examples/client/client.c
+++ b/examples/client/client.c
@@ -342,6 +342,9 @@ static THREAD_RET readInput(void* in)
ret = wolfSSH_stream_send(args->ssh, buf, sz);
wc_UnLockMutex(&args->lock);
if (ret <= 0) {
+ if (ret == WS_REKEYING) {
+ continue;
+ }
fprintf(stderr, "Couldn't send data\n");
return THREAD_RET_SUCCESS;
}
@@ -472,8 +475,16 @@ static THREAD_RET readPeer(void* in)
continue;
}
#endif /* WOLFSSH_AGENT */
+ else if (ret == WS_REKEYING) {
+ wolfSSH_worker(args->ssh, NULL);
+ ret = 0;
+ }
}
else if (ret != WS_EOF) {
+ if (ret == 0) {
+ bytes = 0;
+ continue;
+ }
err_sys("Stream read failed.");
}
}
diff --git a/src/ssh.c b/src/ssh.c
index 05c1a7b3e..2ed75d1bc 100644
--- a/src/ssh.c
+++ b/src/ssh.c
@@ -1135,6 +1135,11 @@ int wolfSSH_stream_read(WOLFSSH* ssh, byte* buf, word32 bufSz)
return WS_ERROR;
}
+ if (ssh->isKeying) {
+ ssh->error = WS_REKEYING;
+ return WS_FATAL_ERROR;
+ }
+
inputBuffer = &ssh->channelList->inputBuffer;
ssh->error = WS_SUCCESS;
@@ -1164,7 +1169,7 @@ int wolfSSH_stream_read(WOLFSSH* ssh, byte* buf, word32 bufSz)
}
/* update internal input buffer based on data read */
- if (ret == WS_SUCCESS) {
+ if (ret == WS_SUCCESS && !ssh->isKeying) {
int n;
n = min(bufSz, inputBuffer->length - inputBuffer->idx);
@@ -2901,6 +2906,11 @@ int wolfSSH_ChannelRead(WOLFSSH_CHANNEL* channel, byte* buf, word32 bufSz)
if (channel == NULL || buf == NULL || bufSz == 0)
return WS_BAD_ARGUMENT;
+ if (channel->ssh->isKeying) {
+ channel->ssh->error = WS_REKEYING;
+ return WS_REKEYING;
+ }
+
bufSz = _ChannelRead(channel, buf, bufSz);
WLOG(WS_LOG_DEBUG, "Leaving wolfSSH_ChannelRead(), bytesRxd = %d",
From d74c942c84d44fb46d3a10cb56233b704733e466 Mon Sep 17 00:00:00 2001
From: JacobBarthelmeh <jacob@wolfssl.com>
Date: Thu, 15 May 2025 11:38:45 -0600
Subject: [PATCH 3/8] refactor SFTP to use NoticeError
---
examples/sftpclient/sftpclient.c | 8 +++++++-
src/ssh.c | 2 +-
src/wolfsftp.c | 25 +++++++++++--------------
3 files changed, 19 insertions(+), 16 deletions(-)
diff --git a/examples/sftpclient/sftpclient.c b/examples/sftpclient/sftpclient.c
index 779baff1f..a990bc14e 100644
--- a/examples/sftpclient/sftpclient.c
+++ b/examples/sftpclient/sftpclient.c
@@ -1119,7 +1119,7 @@ static int doCmds(func_args* args)
/* alternate main loop for the autopilot get/receive */
static int doAutopilot(int cmd, char* local, char* remote)
{
- int err;
+ int err = 0;
int ret = WS_SUCCESS;
char fullpath[128] = ".";
WS_SFTPNAME* name = NULL;
@@ -1156,6 +1156,12 @@ static int doAutopilot(int cmd, char* local, char* remote)
}
do {
+ if (err == WS_REKEYING) { /* handle rekeying state */
+ do {
+ ret = wolfSSH_worker(ssh, NULL);
+ } while (ret == WS_REKEYING);
+ }
+
if (cmd == AUTOPILOT_PUT) {
ret = wolfSSH_SFTP_Put(ssh, local, fullpath, 0, NULL);
}
diff --git a/src/ssh.c b/src/ssh.c
index 2ed75d1bc..56c248589 100644
--- a/src/ssh.c
+++ b/src/ssh.c
@@ -1201,7 +1201,7 @@ int wolfSSH_stream_send(WOLFSSH* ssh, byte* buf, word32 bufSz)
if (ssh->isKeying) {
ssh->error = WS_REKEYING;
- return WS_REKEYING;
+ return WS_FATAL_ERROR;
}
bytesTxd = SendChannelData(ssh, ssh->channelList->channel, buf, bufSz);
diff --git a/src/wolfsftp.c b/src/wolfsftp.c
index 761830a34..a95428fd0 100644
--- a/src/wolfsftp.c
+++ b/src/wolfsftp.c
@@ -1418,7 +1418,11 @@ int wolfSSH_SFTP_read(WOLFSSH* ssh)
ret = wolfSSH_SFTP_buffer_read(ssh, &state->buffer,
state->buffer.sz);
if (ret < 0) {
- if (!NoticeError(ssh)) {
+ if (NoticeError(ssh)) {
+ /* keep state for returning to */
+ ret = WS_FATAL_ERROR;
+ }
+ else {
wolfSSH_SFTP_ClearState(ssh, STATE_ID_RECV);
}
return ret;
@@ -7452,8 +7456,7 @@ int wolfSSH_SFTP_SendWritePacket(WOLFSSH* ssh, byte* handle, word32 handleSz,
/* send header and type specific data */
ret = wolfSSH_SFTP_buffer_send(ssh, &state->buffer);
if (ret < 0) {
- if (ssh->error == WS_WANT_READ ||
- ssh->error == WS_WANT_WRITE) {
+ if (NoticeError(ssh)) {
return WS_FATAL_ERROR;
}
state->state = STATE_SEND_WRITE_CLEANUP;
@@ -7465,12 +7468,8 @@ int wolfSSH_SFTP_SendWritePacket(WOLFSSH* ssh, byte* handle, word32 handleSz,
case STATE_SEND_WRITE_SEND_BODY:
WLOG(WS_LOG_SFTP, "SFTP SEND_WRITE STATE: SEND_BODY");
state->sentSz = wolfSSH_stream_send(ssh, in, inSz);
- if (state->sentSz == WS_WINDOW_FULL ||
- state->sentSz == WS_REKEYING ||
- state->sentSz == WS_WANT_READ ||
- state->sentSz == WS_WANT_WRITE) {
- ret = wolfSSH_worker(ssh, NULL);
- continue; /* skip past rest and send more */
+ if (NoticeError(ssh)) {
+ return WS_FATAL_ERROR;
}
if (state->sentSz <= 0) {
ssh->error = state->sentSz;
@@ -7496,8 +7495,7 @@ int wolfSSH_SFTP_SendWritePacket(WOLFSSH* ssh, byte* handle, word32 handleSz,
state->maxSz = SFTP_GetHeader(ssh, &state->reqId, &type,
&state->buffer);
if (state->maxSz <= 0) {
- if (ssh->error == WS_WANT_READ ||
- ssh->error == WS_WANT_WRITE) {
+ if (NoticeError(ssh)) {
return WS_FATAL_ERROR;
}
ssh->error = WS_SFTP_BAD_HEADER;
@@ -9167,10 +9165,9 @@ int wolfSSH_SFTP_Put(WOLFSSH* ssh, char* from, char* to, byte resume,
state->handle, state->handleSz, state->pOfst,
state->r, state->rSz);
if (sz <= 0) {
- if (ssh->error == WS_WANT_READ ||
- ssh->error == WS_WANT_WRITE ||
- ssh->error == WS_WINDOW_FULL)
+ if (NoticeError(ssh)) {
return WS_FATAL_ERROR;
+ }
}
else {
AddAssign64(state->pOfst, sz);
From ff95f3c3029d766b114a91d98b013e0a1636a6c1 Mon Sep 17 00:00:00 2001
From: JacobBarthelmeh <jacob@wolfssl.com>
Date: Thu, 15 May 2025 13:32:33 -0600
Subject: [PATCH 4/8] increase timeout time on test, fix spelling, add comment
on new arg
---
.github/workflows/sshd-test.yml | 2 +-
src/internal.c | 2 ++
wolfssh/internal.h | 2 +-
3 files changed, 4 insertions(+), 2 deletions(-)
diff --git a/.github/workflows/sshd-test.yml b/.github/workflows/sshd-test.yml
index 3fbe3daf8..eb075a6f1 100644
--- a/.github/workflows/sshd-test.yml
+++ b/.github/workflows/sshd-test.yml
@@ -66,7 +66,7 @@ jobs:
wolfssl: ${{ fromJson(needs.create_matrix.outputs['versions']) }}
name: Build and test wolfsshd
runs-on: ${{ matrix.os }}
- timeout-minutes: 10
+ timeout-minutes: 15
steps:
- name: Checking cache for wolfssl
uses: actions/cache@v4
diff --git a/src/internal.c b/src/internal.c
index 739a9bad2..ff912ef74 100644
--- a/src/internal.c
+++ b/src/internal.c
@@ -707,6 +707,8 @@ INLINE static int IsMessageAllowedClient(WOLFSSH *ssh, byte msg)
#endif /* NO_WOLFSSH_CLIENT */
+/* 'state' argument is for if trying to send a message or receive one.
+ * Returns 1 if allowed 0 if not allowed. */
INLINE static int IsMessageAllowed(WOLFSSH *ssh, byte msg, byte state)
{
if (state == WS_MSG_SEND && !IsMessageAllowedKeying(ssh, msg)) {
diff --git a/wolfssh/internal.h b/wolfssh/internal.h
index 29a6f8ef8..ad5e00b0e 100644
--- a/wolfssh/internal.h
+++ b/wolfssh/internal.h
@@ -1249,7 +1249,7 @@ enum WS_MessageIds {
#define CHANNEL_EXTENDED_DATA_STDERR WOLFSSH_EXT_DATA_STDERR
-/* Used when checking IsMessageAllowed() to determine if createing and sending
+/* Used when checking IsMessageAllowed() to determine if creating and sending
* the message or receiving the message is allowed */
#define WS_MSG_SEND 1
#define WS_MSG_RECV 2
From 2a11471bb717a2ee6f06b3e1beab8a3e2b0ef261 Mon Sep 17 00:00:00 2001
From: JacobBarthelmeh <jacob@wolfssl.com>
Date: Tue, 16 Sep 2025 13:30:25 -0600
Subject: [PATCH 5/8] refactor introducing more use of NoticeError
---
examples/echoserver/echoserver.c | 5 +-
examples/sftpclient/sftpclient.c | 81 ++++++++++++++++++++++++++++----
src/wolfsftp.c | 35 +++++++-------
tests/api.c | 5 ++
4 files changed, 100 insertions(+), 26 deletions(-)
diff --git a/examples/echoserver/echoserver.c b/examples/echoserver/echoserver.c
index 1fbd58a0c..8d14a7c95 100644
--- a/examples/echoserver/echoserver.c
+++ b/examples/echoserver/echoserver.c
@@ -1416,8 +1416,11 @@ static int sftp_worker(thread_ctx_t* threadCtx)
}
else if (ret < 0) {
error = wolfSSH_get_error(ssh);
- if (error == WS_EOF)
+ if (error == WS_EOF) {
+ /* shutdown is happening, clear peek error */
+ ret = 0;
break;
+ }
}
if (ret == WS_FATAL_ERROR && error == 0) {
diff --git a/examples/sftpclient/sftpclient.c b/examples/sftpclient/sftpclient.c
index a990bc14e..b735c0d51 100644
--- a/examples/sftpclient/sftpclient.c
+++ b/examples/sftpclient/sftpclient.c
@@ -566,11 +566,8 @@ static int doCmds(func_args* args)
}
do {
- while (ret == WS_REKEYING || ssh->error == WS_REKEYING) {
+ while (wolfSSH_get_error(ssh) == WS_REKEYING) {
ret = wolfSSH_worker(ssh, NULL);
- if (ret != WS_SUCCESS && ret == WS_FATAL_ERROR) {
- ret = wolfSSH_get_error(ssh);
- }
}
ret = wolfSSH_SFTP_Get(ssh, pt, to, resume, &myStatusCb);
@@ -747,6 +744,13 @@ static int doCmds(func_args* args)
/* check directory is valid */
do {
+ while (ret == WS_REKEYING || ssh->error == WS_REKEYING) {
+ ret = wolfSSH_worker(ssh, NULL);
+ if (ret != WS_SUCCESS && ret == WS_FATAL_ERROR) {
+ ret = wolfSSH_get_error(ssh);
+ }
+ }
+
ret = wolfSSH_SFTP_STAT(ssh, pt, &atrb);
err = wolfSSH_get_error(ssh);
} while ((err == WS_WANT_READ || err == WS_WANT_WRITE)
@@ -828,6 +832,13 @@ static int doCmds(func_args* args)
/* update permissions */
do {
+ while (ret == WS_REKEYING || ssh->error == WS_REKEYING) {
+ ret = wolfSSH_worker(ssh, NULL);
+ if (ret != WS_SUCCESS && ret == WS_FATAL_ERROR) {
+ ret = wolfSSH_get_error(ssh);
+ }
+ }
+
ret = wolfSSH_SFTP_CHMOD(ssh, pt, mode);
err = wolfSSH_get_error(ssh);
} while ((err == WS_WANT_READ || err == WS_WANT_WRITE)
@@ -878,6 +889,13 @@ static int doCmds(func_args* args)
}
do {
+ while (ret == WS_REKEYING || ssh->error == WS_REKEYING) {
+ ret = wolfSSH_worker(ssh, NULL);
+ if (ret != WS_SUCCESS && ret == WS_FATAL_ERROR) {
+ ret = wolfSSH_get_error(ssh);
+ }
+ }
+
ret = wolfSSH_SFTP_RMDIR(ssh, pt);
err = wolfSSH_get_error(ssh);
} while ((err == WS_WANT_READ || err == WS_WANT_WRITE)
@@ -924,6 +942,13 @@ static int doCmds(func_args* args)
}
do {
+ while (ret == WS_REKEYING || ssh->error == WS_REKEYING) {
+ ret = wolfSSH_worker(ssh, NULL);
+ if (ret != WS_SUCCESS && ret == WS_FATAL_ERROR) {
+ ret = wolfSSH_get_error(ssh);
+ }
+ }
+
ret = wolfSSH_SFTP_Remove(ssh, pt);
err = wolfSSH_get_error(ssh);
} while ((err == WS_WANT_READ || err == WS_WANT_WRITE)
@@ -1458,14 +1483,52 @@ THREAD_RETURN WOLFSSH_THREAD sftpclient_test(void* args)
WFREE(workingDir, NULL, DYNAMIC_TYPE_TMP_BUFFER);
if (ret == WS_SUCCESS) {
- if (wolfSSH_shutdown(ssh) != WS_SUCCESS) {
- int rc;
- rc = wolfSSH_get_error(ssh);
+ int err;
+ ret = wolfSSH_shutdown(ssh);
+
+ /* peer hung up, stop trying to shutdown */
+ if (ret == WS_SOCKET_ERROR_E) {
+ ret = 0;
+ }
+
+ err = wolfSSH_get_error(ssh);
+ if (err != WS_SOCKET_ERROR_E &&
+ (err == WS_WANT_READ || err == WS_WANT_WRITE)) {
+ int maxAttempt = 10; /* make 10 attempts max before giving up */
+ int attempt;
+
+ for (attempt = 0; attempt < maxAttempt; attempt++) {
+ ret = wolfSSH_worker(ssh, NULL);
+ err = wolfSSH_get_error(ssh);
+
+ /* peer succesfully closed down gracefully */
+ if (ret == WS_CHANNEL_CLOSED) {
+ ret = 0;
+ break;
+ }
- if (rc != WS_SOCKET_ERROR_E && rc != WS_EOF)
- printf("error with wolfSSH_shutdown()\n");
+ /* peer hung up, stop shutdown */
+ if (ret == WS_SOCKET_ERROR_E) {
+ ret = 0;
+ break;
+ }
+
+ if (err == WS_WANT_READ || err == WS_WANT_WRITE) {
+ /* Wanting read or wanting write. Clear ret. */
+ ret = 0;
+ }
+ else {
+ break;
+ }
+ }
+
+ if (attempt == maxAttempt) {
+ printf("SFTP client gave up on gracefull shutdown,"
+ "closing the socket\n");
+ }
}
}
+
WCLOSESOCKET(sockFd);
wolfSSH_free(ssh);
wolfSSH_CTX_free(ctx);
diff --git a/src/wolfsftp.c b/src/wolfsftp.c
index a95428fd0..53c5dfd1a 100644
--- a/src/wolfsftp.c
+++ b/src/wolfsftp.c
@@ -865,6 +865,7 @@ static int SFTP_GetHeader(WOLFSSH* ssh, word32* reqId, byte* type,
*/
static int SFTP_SetHeader(WOLFSSH* ssh, word32 reqId, byte type, word32 len,
byte* buf) {
+
c32toa(len + LENGTH_SZ + MSG_ID_SZ, buf);
buf[LENGTH_SZ] = type;
c32toa(reqId, buf + LENGTH_SZ + MSG_ID_SZ);
@@ -1170,8 +1171,9 @@ int wolfSSH_SFTP_accept(WOLFSSH* ssh)
case SFTP_EXT:
ret = SFTP_ServerRecvInit(ssh);
if (ret != WS_SUCCESS) {
- if (ssh->error != WS_WANT_READ && ssh->error != WS_WANT_WRITE)
+ if (!NoticeError(ssh)) {
wolfSSH_SFTP_ClearState(ssh, STATE_ID_ALL);
+ }
return ret;
}
ssh->sftpState = SFTP_RECV;
@@ -1573,8 +1575,9 @@ int wolfSSH_SFTP_read(WOLFSSH* ssh)
/* break out if encountering an error with nothing stored to send */
if (ret < 0 && !state->toSend) {
- if (ssh->error != WS_WANT_READ && ssh->error != WS_WANT_WRITE)
+ if (!NoticeError(ssh)) {
wolfSSH_SFTP_ClearState(ssh, STATE_ID_RECV);
+ }
return ret;
}
state->buffer.idx = 0;
@@ -7674,8 +7677,8 @@ int wolfSSH_SFTP_SendReadPacket(WOLFSSH* ssh, byte* handle, word32 handleSz,
/* send header and type specific data */
ret = wolfSSH_SFTP_buffer_send(ssh, &state->buffer);
if (ret < 0) {
- if (ret == WS_REKEYING) {
- return ret;
+ if (NoticeError(ssh)) {
+ return WS_FATAL_ERROR;
}
if (ssh->error != WS_WANT_READ &&
ssh->error != WS_WANT_WRITE) {
@@ -7693,14 +7696,12 @@ int wolfSSH_SFTP_SendReadPacket(WOLFSSH* ssh, byte* handle, word32 handleSz,
/* Get response */
if ((ret = SFTP_GetHeader(ssh, &state->reqId, &state->type,
&state->buffer)) <= 0) {
- if (ssh->error != WS_WANT_READ &&
- ssh->error != WS_WANT_WRITE) {
+ if (!NoticeError(ssh)) {
state->state = STATE_SEND_READ_CLEANUP;
continue;
}
return WS_FATAL_ERROR;
}
-
ret = wolfSSH_SFTP_buffer_create(ssh, &state->buffer, ret);
if (ret != WS_SUCCESS) {
state->state = STATE_SEND_READ_CLEANUP;
@@ -7718,8 +7719,9 @@ int wolfSSH_SFTP_SendReadPacket(WOLFSSH* ssh, byte* handle, word32 handleSz,
state->state = STATE_SEND_READ_CLEANUP;
continue;
}
- else
+ else {
ssh->reqId++;
+ }
if (state->type == WOLFSSH_FTP_DATA)
state->state = STATE_SEND_READ_FTP_DATA;
@@ -7737,8 +7739,7 @@ int wolfSSH_SFTP_SendReadPacket(WOLFSSH* ssh, byte* handle, word32 handleSz,
/* get size of string and place it into out buffer */
ret = wolfSSH_stream_read(ssh, szFlat, UINT32_SZ);
if (ret < 0) {
- if (ssh->error != WS_WANT_READ &&
- ssh->error != WS_WANT_WRITE) {
+ if (!NoticeError(ssh)) {
state->state = STATE_SEND_READ_CLEANUP;
continue;
}
@@ -7917,8 +7918,9 @@ int wolfSSH_SFTP_MKDIR(WOLFSSH* ssh, char* dir, WS_SFTP_FILEATRB* atr)
/* send header and type specific data */
ret = wolfSSH_SFTP_buffer_send(ssh, &state->buffer);
if (ret < 0) {
- if (ssh->error != WS_WANT_READ && ssh->error != WS_WANT_WRITE)
+ if (!NoticeError(ssh)) {
wolfSSH_SFTP_ClearState(ssh, STATE_ID_MKDIR);
+ }
return ret;
}
@@ -7931,8 +7933,9 @@ int wolfSSH_SFTP_MKDIR(WOLFSSH* ssh, char* dir, WS_SFTP_FILEATRB* atr)
/* Get response */
if ((ret = SFTP_GetHeader(ssh, &state->reqId, &type,
&state->buffer)) <= 0) {
- if (ssh->error != WS_WANT_READ && ssh->error != WS_WANT_WRITE)
+ if (!NoticeError(ssh)) {
wolfSSH_SFTP_ClearState(ssh, STATE_ID_MKDIR);
+ }
return WS_FATAL_ERROR;
}
@@ -7963,8 +7966,9 @@ int wolfSSH_SFTP_MKDIR(WOLFSSH* ssh, char* dir, WS_SFTP_FILEATRB* atr)
ret = wolfSSH_SFTP_buffer_read(ssh, &state->buffer,
wolfSSH_SFTP_buffer_size(&state->buffer));
if (ret < 0) {
- if (ssh->error != WS_WANT_READ && ssh->error != WS_WANT_WRITE)
- wolfSSH_SFTP_ClearState(ssh, STATE_ID_MKDIR);
+ if (!NoticeError(ssh)) {
+ wolfSSH_SFTP_ClearState(ssh, STATE_ID_MKDIR);
+ }
return WS_FATAL_ERROR;
}
@@ -8031,8 +8035,7 @@ WS_SFTPNAME* wolfSSH_SFTP_ReadDir(WOLFSSH* ssh, byte* handle,
case STATE_READDIR_NAME:
name = wolfSSH_SFTP_DoName(ssh);
if (name == NULL) {
- if (ssh->error != WS_WANT_READ
- && ssh->error != WS_WANT_WRITE) {
+ if (!NoticeError(ssh)) {
wolfSSH_SFTP_ClearState(ssh, STATE_ID_READDIR);
}
return NULL;
diff --git a/tests/api.c b/tests/api.c
index 2bef34998..701425d20 100644
--- a/tests/api.c
+++ b/tests/api.c
@@ -1075,6 +1075,11 @@ static void test_wolfSSH_SFTP_SendReadPacket(void)
}
}
+ /* take care of re-keying state before shutdown call */
+ while (wolfSSH_get_error(ssh) == WS_REKEYING) {
+ wolfSSH_worker(ssh, NULL);
+ }
+
argsCount = wolfSSH_shutdown(ssh);
if (argsCount == WS_SOCKET_ERROR_E) {
/* If the socket is closed on shutdown, peer is gone, this is OK. */
From 813ec263cc56e7c9093135d854b3fc887633d368 Mon Sep 17 00:00:00 2001
From: JacobBarthelmeh <jacob@wolfssl.com>
Date: Tue, 16 Sep 2025 13:52:12 -0600
Subject: [PATCH 6/8] fix for scan-build report of unused return value
---
examples/sftpclient/sftpclient.c | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/examples/sftpclient/sftpclient.c b/examples/sftpclient/sftpclient.c
index b735c0d51..1194b0de5 100644
--- a/examples/sftpclient/sftpclient.c
+++ b/examples/sftpclient/sftpclient.c
@@ -566,8 +566,11 @@ static int doCmds(func_args* args)
}
do {
- while (wolfSSH_get_error(ssh) == WS_REKEYING) {
+ while (ret == WS_REKEYING || ssh->error == WS_REKEYING) {
ret = wolfSSH_worker(ssh, NULL);
+ if (ret != WS_SUCCESS && ret == WS_FATAL_ERROR) {
+ ret = wolfSSH_get_error(ssh);
+ }
}
ret = wolfSSH_SFTP_Get(ssh, pt, to, resume, &myStatusCb);
From cc17941a6125daefbadb8c236fdeaeb1a21ec786 Mon Sep 17 00:00:00 2001
From: JacobBarthelmeh <jacob@wolfssl.com>
Date: Tue, 16 Sep 2025 14:16:16 -0600
Subject: [PATCH 7/8] adjust test case to account for re-keying return
---
tests/api.c | 8 +++++---
1 file changed, 5 insertions(+), 3 deletions(-)
diff --git a/tests/api.c b/tests/api.c
index 701425d20..9da02849b 100644
--- a/tests/api.c
+++ b/tests/api.c
@@ -1057,14 +1057,16 @@ static void test_wolfSSH_SFTP_SendReadPacket(void)
outSz = WOLFSSH_MAX_SFTP_RW / 2;
rxSz = wolfSSH_SFTP_SendReadPacket(ssh, handle, handleSz,
ofst, out, outSz);
- AssertIntGT(rxSz, 0);
- AssertIntLE(rxSz, outSz);
+ if (wolfSSH_get_error(ssh) != WS_REKEYING) {
+ AssertIntGT(rxSz, 0);
+ AssertIntLE(rxSz, outSz);
+ }
/* read all */
outSz = WOLFSSH_MAX_SFTP_RW;
rxSz = wolfSSH_SFTP_SendReadPacket(ssh, handle, handleSz,
ofst, out, outSz);
- if (rxSz != WS_REKEYING) {
+ if (wolfSSH_get_error(ssh) != WS_REKEYING) {
AssertIntGT(rxSz, 0);
AssertIntLE(rxSz, outSz);
}
From 4862400a374253216e596ff5c3b018b857015cbb Mon Sep 17 00:00:00 2001
From: JacobBarthelmeh <jacob@wolfssl.com>
Date: Mon, 6 Oct 2025 00:42:05 -0600
Subject: [PATCH 8/8] fix spelling issues and SFTP send state
---
.github/workflows/sshd-test.yml | 2 +-
examples/client/client.c | 4 ++--
examples/sftpclient/sftpclient.c | 7 ++++---
src/internal.c | 2 +-
src/wolfsftp.c | 15 +++++++++------
5 files changed, 17 insertions(+), 13 deletions(-)
diff --git a/.github/workflows/sshd-test.yml b/.github/workflows/sshd-test.yml
index eb075a6f1..3fbe3daf8 100644
--- a/.github/workflows/sshd-test.yml
+++ b/.github/workflows/sshd-test.yml
@@ -66,7 +66,7 @@ jobs:
wolfssl: ${{ fromJson(needs.create_matrix.outputs['versions']) }}
name: Build and test wolfsshd
runs-on: ${{ matrix.os }}
- timeout-minutes: 15
+ timeout-minutes: 10
steps:
- name: Checking cache for wolfssl
uses: actions/cache@v4
diff --git a/examples/client/client.c b/examples/client/client.c
index f415bd801..49d00f44f 100644
--- a/examples/client/client.c
+++ b/examples/client/client.c
@@ -481,10 +481,10 @@ static THREAD_RET readPeer(void* in)
}
}
else if (ret != WS_EOF) {
- if (ret == 0) {
+ if (ret == 0) {
bytes = 0;
continue;
- }
+ }
err_sys("Stream read failed.");
}
}
diff --git a/examples/sftpclient/sftpclient.c b/examples/sftpclient/sftpclient.c
index 1194b0de5..e074b3d13 100644
--- a/examples/sftpclient/sftpclient.c
+++ b/examples/sftpclient/sftpclient.c
@@ -1184,7 +1184,7 @@ static int doAutopilot(int cmd, char* local, char* remote)
}
do {
- if (err == WS_REKEYING) { /* handle rekeying state */
+ if (err == WS_REKEYING || err == WS_WINDOW_FULL) { /* handle rekeying state */
do {
ret = wolfSSH_worker(ssh, NULL);
} while (ret == WS_REKEYING);
@@ -1198,7 +1198,8 @@ static int doAutopilot(int cmd, char* local, char* remote)
}
err = wolfSSH_get_error(ssh);
} while ((err == WS_WANT_READ || err == WS_WANT_WRITE ||
- err == WS_CHAN_RXD || err == WS_REKEYING) &&
+ err == WS_CHAN_RXD || err == WS_REKEYING ||
+ err == WS_WINDOW_FULL) &&
ret == WS_FATAL_ERROR);
if (ret != WS_SUCCESS) {
@@ -1504,7 +1505,7 @@ THREAD_RETURN WOLFSSH_THREAD sftpclient_test(void* args)
ret = wolfSSH_worker(ssh, NULL);
err = wolfSSH_get_error(ssh);
- /* peer succesfully closed down gracefully */
+ /* peer successfully closed down gracefully */
if (ret == WS_CHANNEL_CLOSED) {
ret = 0;
break;
diff --git a/src/internal.c b/src/internal.c
index ff912ef74..b9e3a3432 100644
--- a/src/internal.c
+++ b/src/internal.c
@@ -605,7 +605,7 @@ INLINE static int IsMessageAllowedKeying(WOLFSSH *ssh, byte msg)
return 1;
}
- /* case of servie request or accept in 1-19 */
+ /* case of service request or accept in 1-19 */
if (msg == MSGID_SERVICE_REQUEST || msg == MSGID_SERVICE_ACCEPT) {
WLOG(WS_LOG_DEBUG, "Message ID %u not allowed by during rekeying", msg);
ssh->error = WS_REKEYING;
diff --git a/src/wolfsftp.c b/src/wolfsftp.c
index 53c5dfd1a..998806aef 100644
--- a/src/wolfsftp.c
+++ b/src/wolfsftp.c
@@ -416,6 +416,7 @@ static INLINE int NoticeError(WOLFSSH* ssh)
return (ssh->error == WS_WANT_READ ||
ssh->error == WS_WANT_WRITE ||
ssh->error == WS_CHAN_RXD ||
+ ssh->error == WS_WINDOW_FULL ||
ssh->error == WS_REKEYING);
}
@@ -865,7 +866,6 @@ static int SFTP_GetHeader(WOLFSSH* ssh, word32* reqId, byte* type,
*/
static int SFTP_SetHeader(WOLFSSH* ssh, word32 reqId, byte type, word32 len,
byte* buf) {
-
c32toa(len + LENGTH_SZ + MSG_ID_SZ, buf);
buf[LENGTH_SZ] = type;
c32toa(reqId, buf + LENGTH_SZ + MSG_ID_SZ);
@@ -7471,12 +7471,15 @@ int wolfSSH_SFTP_SendWritePacket(WOLFSSH* ssh, byte* handle, word32 handleSz,
case STATE_SEND_WRITE_SEND_BODY:
WLOG(WS_LOG_SFTP, "SFTP SEND_WRITE STATE: SEND_BODY");
state->sentSz = wolfSSH_stream_send(ssh, in, inSz);
- if (NoticeError(ssh)) {
- return WS_FATAL_ERROR;
- }
if (state->sentSz <= 0) {
- ssh->error = state->sentSz;
ret = WS_FATAL_ERROR;
+ if (NoticeError(ssh)) {
+ ret = wolfSSH_worker(ssh,NULL);
+ continue;
+ }
+
+ /* if it was not a notice error then clean up the state and
+ * exit out */
state->state = STATE_SEND_WRITE_CLEANUP;
continue;
}
@@ -9170,7 +9173,7 @@ int wolfSSH_SFTP_Put(WOLFSSH* ssh, char* from, char* to, byte resume,
if (sz <= 0) {
if (NoticeError(ssh)) {
return WS_FATAL_ERROR;
- }
+ }
}
else {
AddAssign64(state->pOfst, sz);