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.
This commit is contained in:
2026-09-16 14:04:34 +02:00
parent 4d3bb490c9
commit bea33e1c95
28 changed files with 4653 additions and 64 deletions
+882
View File
@@ -0,0 +1,882 @@
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);
+46
View File
@@ -0,0 +1,46 @@
From 201029797b260eee894b12d488bce6022290bf67 Mon Sep 17 00:00:00 2001
From: JacobBarthelmeh <jacob@wolfssl.com>
Date: Fri, 18 Jul 2025 15:43:26 -0600
Subject: [PATCH] only send ext info once after SSH_MSG_NEWKEYS
---
src/internal.c | 6 +++++-
wolfssh/internal.h | 1 +
2 files changed, 6 insertions(+), 1 deletion(-)
diff --git a/src/internal.c b/src/internal.c
index 080ded6f3..912315ca2 100644
--- a/src/internal.c
+++ b/src/internal.c
@@ -4080,7 +4080,7 @@ static int DoKexInit(WOLFSSH* ssh, byte* buf, word32 len, word32* idx)
if (ret == WS_SUCCESS) {
/* Only checking for this is we are server. Our client does
* not have anything to say to a server, yet. */
- if (side == WOLFSSH_ENDPOINT_SERVER) {
+ if (side == WOLFSSH_ENDPOINT_SERVER && !ssh->extInfoSent) {
byte extInfo;
/* Match the client accepts extInfo. */
@@ -13216,6 +13216,10 @@ int SendExtInfo(WOLFSSH* ssh)
}
if (ret == WS_SUCCESS) {
+ ssh->sendExtInfo = 0;
+ ssh->extInfoSent = 1; /* RFC 8308 section 2.4 ext. info should only be
+ * sent after SSH_MSG_NEWKEYS or after
+ * SSH_MSG_USERAUTH_SUCCESS. Not on re-key */
ret = wolfSSH_SendPacket(ssh);
}
diff --git a/wolfssh/internal.h b/wolfssh/internal.h
index 1b60139a1..26c3a05b0 100644
--- a/wolfssh/internal.h
+++ b/wolfssh/internal.h
@@ -844,6 +844,7 @@ struct WOLFSSH {
byte sendTerminalRequest;
byte userAuthPkDone;
byte sendExtInfo;
+ byte extInfoSent; /* track if the ext info has already been sent */
byte* peerSigId;
word32 peerSigIdSz;
+147
View File
@@ -0,0 +1,147 @@
From 9dc1071da7e560db2ea899fa23aab885a25ea862 Mon Sep 17 00:00:00 2001
From: JacobBarthelmeh <jacob@wolfssl.com>
Date: Mon, 13 Oct 2025 09:44:29 -0600
Subject: [PATCH 1/2] improvements to keying and track side
---
src/internal.c | 35 ++++++++++++++++++++++++++++++-----
wolfssh/internal.h | 5 +++++
2 files changed, 35 insertions(+), 5 deletions(-)
diff --git a/src/internal.c b/src/internal.c
index edab14eb4..230904489 100644
--- a/src/internal.c
+++ b/src/internal.c
@@ -1096,7 +1096,7 @@ WOLFSSH* SshInit(WOLFSSH* ssh, WOLFSSH_CTX* ctx)
ssh->fs = NULL;
ssh->acceptState = ACCEPT_BEGIN;
ssh->clientState = CLIENT_BEGIN;
- ssh->isKeying = 1;
+ ssh->isKeying = 0; /* initial state of not keying yet */
ssh->authId = ID_USERAUTH_PUBLICKEY;
ssh->supportedAuth[0] = ID_USERAUTH_PUBLICKEY;
ssh->supportedAuth[1] = ID_USERAUTH_PASSWORD;
@@ -4058,6 +4058,15 @@ static int DoKexInit(WOLFSSH* ssh, byte* buf, word32 len, word32* idx)
ret = WS_BAD_ARGUMENT;
}
+ if (ret == WS_SUCCESS) {
+ /* Check if already in process of keying and error out if so. */
+ if (ssh->isKeying & WOLFSSH_PEER_IS_KEYING) {
+ WLOG(WS_LOG_ERROR,
+ "Already in keying process and got KEX init");
+ ret = WS_INVALID_STATE_E;
+ }
+ }
+
/*
* I don't need to save what the client sends here. I should decode
* each list into a local array of IDs, and pick the one the peer is
@@ -4067,6 +4076,8 @@ static int DoKexInit(WOLFSSH* ssh, byte* buf, word32 len, word32* idx)
*/
if (ret == WS_SUCCESS) {
+ /* Set peer is keying flag after receiving SSH_MSG_KEX_INIT */
+ ssh->isKeying |= WOLFSSH_PEER_IS_KEYING;
if (ssh->handshake == NULL) {
ssh->handshake = HandshakeInfoNew(ssh->ctx->heap);
if (ssh->handshake == NULL) {
@@ -5881,6 +5892,13 @@ static int DoNewKeys(WOLFSSH* ssh, byte* buf, word32 len, word32* idx)
if (ssh == NULL || ssh->handshake == NULL)
ret = WS_BAD_ARGUMENT;
+ if (ret == WS_SUCCESS) {
+ if (ssh->isKeying & WOLFSSH_SELF_IS_KEYING) {
+ WLOG(WS_LOG_ERROR, "Keying failed");
+ ret = WS_INVALID_STATE_E;
+ }
+ }
+
if (ret == WS_SUCCESS) {
ssh->peerEncryptId = ssh->handshake->encryptId;
ssh->peerMacId = ssh->handshake->macId;
@@ -5941,7 +5959,9 @@ static int DoNewKeys(WOLFSSH* ssh, byte* buf, word32 len, word32* idx)
if (ret == WS_SUCCESS) {
ssh->rxCount = 0;
ssh->highwaterFlag = 0;
- ssh->isKeying = 0;
+
+ /* Clear peer is keying flag */
+ ssh->isKeying &= ~WOLFSSH_PEER_IS_KEYING;
HandshakeInfoFree(ssh->handshake, ssh->ctx->heap);
ssh->handshake = NULL;
WLOG(WS_LOG_DEBUG, "Keying completed");
@@ -9405,7 +9425,7 @@ static int DoPacket(WOLFSSH* ssh, byte* bufferConsumed)
case MSGID_KEXINIT:
WLOG(WS_LOG_DEBUG, "Decoding MSGID_KEXINIT");
ret = DoKexInit(ssh, buf + idx, payloadSz, &payloadIdx);
- if (ssh->isKeying == 1 &&
+ if (ssh->isKeying &&
ssh->connectState == CONNECT_SERVER_CHANNEL_REQUEST_DONE) {
if (ssh->handshake->kexId == ID_DH_GEX_SHA256) {
#if !defined(WOLFSSH_NO_DH) && !defined(WOLFSSH_NO_DH_GEX_SHA256)
@@ -10501,7 +10521,8 @@ int SendKexInit(WOLFSSH* ssh)
}
if (ret == WS_SUCCESS) {
- ssh->isKeying = 1;
+ /* Set self is keying flag since we started sending the KEX init msg */
+ ssh->isKeying |= WOLFSSH_SELF_IS_KEYING;
if (ssh->handshake == NULL) {
ssh->handshake = HandshakeInfoNew(ssh->ctx->heap);
if (ssh->handshake == NULL) {
@@ -12534,9 +12555,13 @@ int SendNewKeys(WOLFSSH* ssh)
ssh->txCount = 0;
}
- if (ret == WS_SUCCESS)
+ if (ret == WS_SUCCESS) {
ret = wolfSSH_SendPacket(ssh);
+ /* Clear self is keying flag */
+ ssh->isKeying &= ~WOLFSSH_SELF_IS_KEYING;
+ }
+
WLOG(WS_LOG_DEBUG, "Leaving SendNewKeys(), ret = %d", ret);
return ret;
}
diff --git a/wolfssh/internal.h b/wolfssh/internal.h
index 1b7dada16..6df5f1147 100644
--- a/wolfssh/internal.h
+++ b/wolfssh/internal.h
@@ -473,6 +473,11 @@ enum NameIdType {
#define WOLFSSH_KEY_QUANTITY_REQ 1
#endif
+/* Keep track of keying state for both sides of the connection.
+ * WOLFSSH_SELF_IS_KEYING gets set on sending KEX init and
+ * WOLFSSH_PEER_IS_KEYING gets set on receiving KEX init */
+#define WOLFSSH_PEER_IS_KEYING 0x01
+#define WOLFSSH_SELF_IS_KEYING 0x02
WOLFSSH_LOCAL byte NameToId(const char* name, word32 nameSz);
WOLFSSH_LOCAL const char* IdToName(byte id);
From 024b14124aa2434e90468408b94121c897311f37 Mon Sep 17 00:00:00 2001
From: JacobBarthelmeh <jacob@wolfssl.com>
Date: Mon, 13 Oct 2025 22:47:45 -0600
Subject: [PATCH 2/2] update Kex Init response after adding keying track sides
---
src/internal.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/src/internal.c b/src/internal.c
index 230904489..db70d0f6f 100644
--- a/src/internal.c
+++ b/src/internal.c
@@ -4338,7 +4338,8 @@ static int DoKexInit(WOLFSSH* ssh, byte* buf, word32 len, word32* idx)
byte scratchLen[LENGTH_SZ];
word32 strSz = 0;
- if (!ssh->isKeying) {
+ /* respond with KEX Init message if not having initiated the keying */
+ if ((ssh->isKeying & WOLFSSH_SELF_IS_KEYING) == 0) {
WLOG(WS_LOG_DEBUG, "Keying initiated");
ret = SendKexInit(ssh);
}
File diff suppressed because it is too large Load Diff
+32
View File
@@ -0,0 +1,32 @@
From e9d288ec603531a1d544e77fb1bbdf634cb2a57f Mon Sep 17 00:00:00 2001
From: John Safranek <john@wolfssl.com>
Date: Mon, 13 Apr 2026 15:05:48 -0700
Subject: [PATCH] Server Does Not Set expectMsgId to MSGID_NEWKEYS
In the server code, the server is not setting the expectedMsgId to
MSGID_NEWKEYS before sending its new keys message. Update DoKexDhReply()
to set expectMsgId to MSGID_NEWKEYS.
Affected function: DoKeyDhReply.
Issue: F-1275
---
src/internal.c | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/src/internal.c b/src/internal.c
index 970bece9b..511d77ef2 100644
--- a/src/internal.c
+++ b/src/internal.c
@@ -12914,8 +12914,11 @@ int SendKexDhReply(WOLFSSH* ssh)
ret = BundlePacket(ssh);
}
- if (ret == WS_SUCCESS)
+ if (ret == WS_SUCCESS) {
+ ssh->handshake->expectMsgId = MSGID_NEWKEYS;
+ WLOG_EXPECT_MSGID(ssh->handshake->expectMsgId);
ret = SendNewKeys(ssh);
+ }
if (ret == WS_SUCCESS && ssh->sendExtInfo) {
ret = SendExtInfo(ssh);
+155
View File
@@ -0,0 +1,155 @@
# wolfSSH 1.4.20 restricted ordering correction
Project modification: **2026-09-16**. This is a bounded project-profile correction
for the CVE-2025-14942 ordering defect, **not a complete wolfSSH 1.4.22/1.5.0
backport or general-purpose upstream-fix claim**. wolfSSH remains pinned to
1.4.20; wolfSSL and all existing password/parser/crypto protections remain pinned
and intact. No managed source is edited.
## Inputs and provenance
`793.patch`, `819.patch`, `840.patch`, `855.patch`, and `921.patch` are the exact
upstream mail-patch responses fetched on 2026-09-16. `provenance.json` records
URLs, byte SHA-256 hashes, and every embedded full commit ID. PR endpoints can
change: the archived bytes and commit identities, not a future PR response,
identify this review. Commit pages are recoverable as
`https://github.com/wolfSSL/wolfssh/commit/<commit>`.
`delta.json` is the **authoritative executable consolidated delta**, not a claim
that all archived hunks apply. Its exact old/new edits are applied before the
existing parser/password edits by `tools/security_overrides.py`; every anchor
must occur exactly once. It pins:
| Input | Original SHA-256 |
| --- | --- |
| `src/internal.c` | `81ff1f9166708abd5c2911e9fe57c0aee01c88b5d3f68c909ee8a856d37f36a9` |
| `src/ssh.c` | `a4f479ff87eea0980ec1ebdf2c7dd090da473780181b695a56799cb9611f4366` |
| `wolfssh/internal.h` | `8e417149a68f8a6c0506957adf014b3e6c1727a723536826ce5fb0c9e1f1aba3` |
Original copyright/license notices remain in each generated file, preceded by
project modification/provenance notices. Configuration needs no network,
`patch(1)`, Git, or fuzzy matching. All inputs validate before outputs are written.
### Prerequisite disposition
- **PR793:** retain stream/channel read rekey fencing, stream-send fatal/error
convention, EOF/window-adjust send checks and send/receive direction constants.
Exclude example, SFTP, workflow and upstream-test changes. The intermediate
`IsMessageAllowedKeying` implementation was removed by PR855 itself; it is not
resurrected. Local send checks are distinct from receive checks. The follow-up
corrects a misapplied EOF hunk: `SendChannelEof` now checks before lookup,
serialization or `eofTxd` mutation. The extra `SendChannelExit` guard is retained
intentionally as local hardening, using `MSGID_CHANNEL_REQUEST` (exit-status),
not falsely attributed to PR793's EOF hunk. Real shutdown/rekey tests cover both.
- **PR819:** retain `extInfoSent` ABI field, but supersede its negotiation/send
logic by disabling EXT_INFO uniformly. The field stays zero; no reset-on-rekey
or exactly-once extension continuation is needed.
- **PR840:** initialize keying to zero; maintain independent SELF/PEER bits;
reject duplicate peer KEXINIT; respond only if SELF was not already keying;
reject peer NEWKEYS while SELF still owes NEWKEYS; clear PEER and release the
handshake only after successful incoming key installation.
- **PR855:** retain `expectMsgId`, message IDs/ranges, and expected-reply writes
**before** nonblocking sends. Adapt the client `DoKexDhReply` hunk to 1.4.20's
`useEccKyber` spelling; no PQ algorithm is enabled. Replace permissive range
fallthrough with the explicit restricted gates described below. Upstream
test-only entry points/build rules are not imported. Its new log macro is
local to generated `internal.c`: the pinned `log.h` has a different WLOG
implementation, so neither `log.h` nor `log.c` needs an ABI/source change.
- **PR921:** set server `expectMsgId = MSGID_NEWKEYS` before `SendNewKeys`, including
WANT_WRITE. The former post-NEWKEYS EXT_INFO call is deliberately removed.
Local additions also set the server's expected INIT after valid KEXINIT, retain
that expectation after skipping a wrong optimistic INIT guess, reject absent
expectations instead of accepting arbitrary KEX packets, and only allow client
rekey dispatch after successful/queued KEXINIT with a live handshake. Client
rekey dispatch includes the final `CONNECT_DONE` state.
## Restricted protocol contract
- Negotiate only the existing project KEX profile: **Curve25519-SHA256 and
ECDH-P256**. A caller trying to widen the algorithm list to DH/GEX/PQ gets a
negotiation error. Those continuation paths are not represented as supported.
- Receive transport notifications 14 without consuming an expected KEX reply.
KEXINIT is legal only before the peer has begun this exchange; other KEX
messages require a live handshake and an exact nonzero expectation. Acceptance
consumes that expectation once; the handler sets the next expectation.
- Reject authentication/service/connection traffic after **peer** KEXINIT until
peer NEWKEYS. When only SELF has initiated rekey, pre-peer-KEXINIT in-flight
traffic remains legal according to the authentication phase (RFC4253).
- Server requires keyed service request, then service acceptance before userauth
requests, then completed authentication before connection messages. Reject
wrong-direction and repeated authentication/service messages. Client rejects
premature auth results/channel messages and accepts auth responses only in
its request phase. Keyboard-interactive is outside the project profile and
incoming INFO_RESPONSE is rejected before dispatch.
- Send-side EOF/window-adjust checks never mutate receive expectations. Existing
channel-data rekey fencing is preserved.
### NEWKEYS/backpressure and the EXT_INFO choice
`SendNewKeys` bundles NEWKEYS with the old sending keys, installs the new sending
keys, then calls `wolfSSH_SendPacket`. `WS_WANT_WRITE` means that **same bundled
packet** remains in the bounded output buffer. Clear SELF on SUCCESS or
WANT_WRITE, retain PEER and the expected peer NEWKEYS. The existing
accept/connect/worker flush paths send the remaining bytes; they must not call
`SendNewKeys` again. A fatal send does not clear SELF. Peer NEWKEYS installs the
receive keys and releases the handshake once; premature/duplicate NEWKEYS fails.
Previously `SendKexDhReply` called `SendExtInfo` only on SUCCESS from NEWKEYS. A
partial send skipped it with no continuation. Rather than invent another pending
send state and its handshake-lifetime rules, this profile:
1. Does not append `ext-info-c` to client KEXINIT.
2. Ignores peers' extension willingness; sets `sendExtInfo` to zero on KEXINIT.
3. Removes the post-NEWKEYS extension send and makes `SendExtInfo` return
`WS_NOT_COMPILED` even if called directly.
4. Rejects incoming EXT_INFO in every phase, since it was never negotiated.
This follows RFC8308's optional-negotiation model. **There is no
`server-sig-algs` advertisement.** The existing KeyAccepted setter remains valid
but no longer produces that extension on the wire. This matters particularly to
RSA-SHA2 discovery: RSA user keys are outside the project's enrolled/advertised
profile, and RSA interoperability is not claimed. Host tests establish that
OpenSSH 10.2p1 still authenticates using Ed25519, P-256 and passwords with both
project KEX algorithms, initial KEX and rekeys, without receiving EXT_INFO.
Other clients and hardware remain validation work.
## Header overlay and build ownership
The ABI changes require **all** consumers to use the generated header, not only
the relocated C file. `cmake/security_overrides.cmake` installs
`security_overrides/wolfssh_include/wolfssh/internal.h` with BEFORE PUBLIC include
propagation and a PUBLIC forced include. The original header's include guard
prevents a later vendor-first include path from defining a stale layout. A dated
ABI marker rejects an original header forcibly included *before* the overlay,
rather than silently skipping the corrected layout. Existing
unmodified wolfSSH files and transitive application consumers therefore use the
same layout. Source properties are retained; header originals, generated header,
and `delta.json` are configure dependencies. Compiler dependencies track the
forced header too. There are now **eight source overrides plus one header**.
Tests intentionally put the original include root before the overlay when
compiling full host translation units. The SDK CMake fixture checks PUBLIC
propagation to library, direct and transitive consumers. Forced headers use joined
`-include/path` arguments: PlatformIO sorts app flags and deduplicates component
flags, which breaks split option/operand pairs. The installed adapter/SCons test
compiles a real Xtensa consumer and reproduces the failure with a split-option
mutation. The crypto guard remains enabled with its existing joined argument.
The obsolete unused EXT_INFO name constant is removed, without relaxing warnings.
## Validation and boundaries
Run `python3 tests/wolfssh_order_contract/run.py --interop` and the related
commands listed in that test's README. Tests execute the actual generated full
`internal.c` and `ssh.c` with real wolfCrypt, bounded host IO, hostile message-ID
matrices, partial writes, both roles and all three rekey initiation directions.
Guard-removal mutations must fail. The parser/password suites separately preserve
prior protections; SDK tests exercise real override/overlay CMake wiring.
Follow-up validation on 2026-09-16: authorized `pio run` PASS in 21.31 seconds,
**94,340 B linked RAM / 1,768,701 B flash**. Strict auth, protocol, crypto and
SDK override tests against the rebuilt production artifacts PASS. Ordering tests
PASS 8,028 checks and seven rejected mutations; parser tests PASS 3,124 cases in
each stack mode. No upload, erase, dependency upgrade or device operation.
This does not establish stack/heap reserve, timing, arbitrary-algorithm,
strict-KEX-extension, full-client compatibility or phase-wide security sign-off.
+161
View File
@@ -0,0 +1,161 @@
{
"src/internal.c": {
"sha256": "81ff1f9166708abd5c2911e9fe57c0aee01c88b5d3f68c909ee8a856d37f36a9",
"edits": [
{
"old": " * API calls into this module to do the work of processing the connections.\n */\n\n\n#ifdef HAVE_CONFIG_H\n #include <config.h>\n#endif\n\n#include <stdio.h>\n#include <wolfssh/ssh.h>\n#include <wolfssh/internal.h>\n#include <wolfssh/log.h>\n#include <wolfssl/version.h>\n#include <wolfssl/wolfcrypt/asn.h>\n#ifndef WOLFSSH_NO_DH\n #include <wolfssl/wolfcrypt/dh.h>\n#endif\n#include <wolfssl/wolfcrypt/curve25519.h>\n#include <wolfssl/wolfcrypt/ed25519.h>\n#ifdef WOLFSSH_CERTS\n #include <wolfssl/wolfcrypt/error-crypt.h>\n#endif\n#include <wolfssl/wolfcrypt/rsa.h>\n#include <wolfssl/wolfcrypt/ecc.h>\n",
"new": " * API calls into this module to do the work of processing the connections.\n */\n\n\n#ifdef HAVE_CONFIG_H\n #include <config.h>\n#endif\n\n#include <stdio.h>\n#include <wolfssh/ssh.h>\n#include <wolfssh/internal.h>\n#include <wolfssh/log.h>\n#define WLOG_EXPECT_MSGID(x) WLOG(WS_LOG_DEBUG, \"Expecting message %d\", (x))\n#include <wolfssl/version.h>\n#include <wolfssl/wolfcrypt/asn.h>\n#ifndef WOLFSSH_NO_DH\n #include <wolfssl/wolfcrypt/dh.h>\n#endif\n#include <wolfssl/wolfcrypt/curve25519.h>\n#include <wolfssl/wolfcrypt/ed25519.h>\n#ifdef WOLFSSH_CERTS\n #include <wolfssl/wolfcrypt/error-crypt.h>\n#endif\n#include <wolfssl/wolfcrypt/rsa.h>\n#include <wolfssl/wolfcrypt/ecc.h>\n"
},
{
"old": " WFREE(hs->primeGroup, heap, DYNTYPE_MPINT);\n WFREE(hs->generator, heap, DYNTYPE_MPINT);\n#endif\n if (hs->kexHashId != WC_HASH_TYPE_NONE) {\n wc_HashFree(&hs->kexHash, (enum wc_HashType)hs->kexHashId);\n }\n ForceZero(hs, sizeof(HandshakeInfo));\n WFREE(hs, heap, DYNTYPE_HS);\n }\n}\n\n\n#ifndef NO_WOLFSSH_SERVER\nINLINE static int IsMessageAllowedServer(WOLFSSH *ssh, byte msg)\n{\n /* Has client userauth started? */\n if (ssh->acceptState < ACCEPT_KEYED) {\n if (msg > MSGID_KEXDH_LIMIT) {\n return 0;\n }\n }\n /* Is server userauth complete? */\n if (ssh->acceptState < ACCEPT_SERVER_USERAUTH_SENT) {\n /* Explicitly check for messages not allowed before user\n * authentication has comleted. */\n if (msg >= MSGID_USERAUTH_LIMIT) {\n WLOG(WS_LOG_DEBUG, \"Message ID %u not allowed by server \"\n \"before user authentication is complete\", msg);\n return 0;\n }\n /* Explicitly check for the user authentication messages that\n * only the server sends, it shouldn't receive them. */\n if ((msg > MSGID_USERAUTH_RESTRICT) &&\n (msg != MSGID_USERAUTH_INFO_RESPONSE)) {\n WLOG(WS_LOG_DEBUG, \"Message ID %u not allowed by server \"\n \"during user authentication\", msg);\n return 0;\n }\n }\n else {\n if (msg >= MSGID_USERAUTH_RESTRICT && msg < MSGID_USERAUTH_LIMIT) {\n WLOG(WS_LOG_DEBUG, \"Message ID %u not allowed by server \"\n \"after user authentication\", msg);\n return 0;\n }\n }\n\n return 1;\n}\n#endif /* NO_WOLFSSH_SERVER */\n\n\n#ifndef NO_WOLFSSH_CLIENT\nINLINE static int IsMessageAllowedClient(WOLFSSH *ssh, byte msg)\n{\n /* Has client userauth started? */\n if (ssh->connectState < CONNECT_CLIENT_KEXDH_INIT_SENT) {\n if (msg >= MSGID_KEXDH_LIMIT) {\n return 0;\n }\n }\n /* Is client userauth complete? */\n if (ssh->connectState < CONNECT_SERVER_USERAUTH_ACCEPT_DONE) {\n /* Explicitly check for messages not allowed before user\n * authentication has comleted. */\n if (msg >= MSGID_USERAUTH_LIMIT) {\n WLOG(WS_LOG_DEBUG, \"Message ID %u not allowed by client \"\n \"before user authentication is complete\", msg);\n return 0;\n }\n /* Explicitly check for the user authentication message that\n * only the client sends, it shouldn't receive it. */\n if (msg == MSGID_USERAUTH_RESTRICT) {\n WLOG(WS_LOG_DEBUG, \"Message ID %u not allowed by client \"\n \"during user authentication\", msg);\n return 0;\n }\n }\n else {\n if (msg >= MSGID_USERAUTH_RESTRICT && msg < MSGID_USERAUTH_LIMIT) {\n WLOG(WS_LOG_DEBUG, \"Message ID %u not allowed by client \"\n \"after user authentication\", msg);\n return 0;\n }\n }\n return 1;\n}\n#endif /* NO_WOLFSSH_CLIENT */\n\n\nINLINE static int IsMessageAllowed(WOLFSSH *ssh, byte msg)\n{\n#ifndef NO_WOLFSSH_SERVER\n if (ssh->ctx->side == WOLFSSH_ENDPOINT_SERVER) {\n return IsMessageAllowedServer(ssh, msg);\n }\n#endif /* NO_WOLFSSH_SERVER */\n#ifndef NO_WOLFSSH_CLIENT\n if (ssh->ctx->side == WOLFSSH_ENDPOINT_CLIENT) {\n return IsMessageAllowedClient(ssh, msg);\n }\n#endif /* NO_WOLFSSH_CLIENT */\n return 0;\n}\n\n\nstatic const char cannedKexAlgoNames[] =\n#if !defined(WOLFSSH_NO_ECDH_NISTP256_KYBER_LEVEL1_SHA256)\n \"ecdh-nistp256-kyber-512r3-sha256-d00@openquantumsafe.org,\"\n#endif\n#ifndef WOLFSSH_NO_CURVE25519_SHA256\n \"curve25519-sha256,\"\n#endif\n#if !defined(WOLFSSH_NO_ECDH_SHA2_NISTP521)\n",
"new": " WFREE(hs->primeGroup, heap, DYNTYPE_MPINT);\n WFREE(hs->generator, heap, DYNTYPE_MPINT);\n#endif\n if (hs->kexHashId != WC_HASH_TYPE_NONE) {\n wc_HashFree(&hs->kexHash, (enum wc_HashType)hs->kexHashId);\n }\n ForceZero(hs, sizeof(HandshakeInfo));\n WFREE(hs, heap, DYNTYPE_HS);\n }\n}\n\n\n/* Project restricted ordering profile, derived from wolfSSH PR855.\n * EXT_INFO is deliberately not negotiated. See README.md for scope.\n * This fragment is installed into the pinned internal.c by the exact delta.\n */\n#ifndef NO_WOLFSSH_SERVER\nINLINE static int IsMessageAllowedServer(WOLFSSH* ssh, byte msg)\n{\n if (msg == MSGID_SERVICE_REQUEST)\n return ssh->acceptState == ACCEPT_KEYED;\n if (msg == MSGID_USERAUTH_REQUEST)\n return ssh->acceptState >= ACCEPT_SERVER_USERAUTH_ACCEPT_SENT &&\n ssh->acceptState < ACCEPT_SERVER_USERAUTH_SENT;\n /* Keyboard-interactive is not part of the project profile. */\n return MSGIDLIMIT_POST_USERAUTH(msg) &&\n ssh->acceptState >= ACCEPT_SERVER_USERAUTH_SENT;\n}\n#endif\n\n#ifndef NO_WOLFSSH_CLIENT\nINLINE static int IsMessageAllowedClient(WOLFSSH* ssh, byte msg)\n{\n if (msg == MSGID_SERVICE_ACCEPT)\n return ssh->connectState == CONNECT_CLIENT_USERAUTH_REQUEST_SENT;\n if (msg == MSGID_USERAUTH_FAILURE || msg == MSGID_USERAUTH_SUCCESS ||\n msg == MSGID_USERAUTH_BANNER || msg == MSGID_USERAUTH_PK_OK)\n return ssh->connectState >= CONNECT_CLIENT_USERAUTH_SENT &&\n ssh->connectState < CONNECT_SERVER_USERAUTH_ACCEPT_DONE;\n return MSGIDLIMIT_POST_USERAUTH(msg) &&\n ssh->connectState >= CONNECT_SERVER_USERAUTH_ACCEPT_DONE;\n}\n#endif\n\nINLINE static int IsMessageAllowed(WOLFSSH* ssh, byte msg, byte state)\n{\n int allowed = 0;\n if (state == WS_MSG_SEND) {\n /* EOF/window-adjust callers must not consume receive expectations. */\n allowed = !ssh->isKeying;\n if (!allowed)\n ssh->error = WS_REKEYING;\n return allowed;\n }\n if (state != WS_MSG_RECV)\n goto reject;\n\n /* RFC4253 transport notifications may interrupt an expected KEX message. */\n if (msg >= MSGID_DISCONNECT && msg <= MSGID_DEBUG)\n return 1;\n\n /* No RFC8308 negotiation, including during rekey or after authentication. */\n if (msg == MSGID_EXT_INFO)\n goto reject;\n\n if (MSGIDLIMIT_TRANS_ALGO(msg) || MSGIDLIMIT_TRANS_KEX(msg)) {\n if (msg == MSGID_KEXINIT) {\n allowed = !(ssh->isKeying & WOLFSSH_PEER_IS_KEYING);\n }\n else if ((ssh->isKeying & WOLFSSH_PEER_IS_KEYING) &&\n ssh->handshake != NULL &&\n ssh->handshake->expectMsgId != MSGID_NONE &&\n ssh->handshake->expectMsgId == msg) {\n ssh->handshake->expectMsgId = MSGID_NONE;\n return 1;\n }\n if (allowed)\n return 1;\n goto reject;\n }\n\n /* Locally initiated rekey can have old, in-flight peer traffic. Once the\n * peer KEXINIT arrives, only transport/KEX is legal until peer NEWKEYS. */\n if (ssh->isKeying & WOLFSSH_PEER_IS_KEYING)\n goto reject;\n#ifndef NO_WOLFSSH_SERVER\n if (ssh->ctx->side == WOLFSSH_ENDPOINT_SERVER)\n allowed = IsMessageAllowedServer(ssh, msg);\n#endif\n#ifndef NO_WOLFSSH_CLIENT\n if (ssh->ctx->side == WOLFSSH_ENDPOINT_CLIENT)\n allowed = IsMessageAllowedClient(ssh, msg);\n#endif\n if (allowed)\n return 1;\nreject:\n ssh->error = WS_MSGID_NOT_ALLOWED_E;\n return 0;\n}\n\n\nstatic const char cannedKexAlgoNames[] =\n#if !defined(WOLFSSH_NO_ECDH_NISTP256_KYBER_LEVEL1_SHA256)\n \"ecdh-nistp256-kyber-512r3-sha256-d00@openquantumsafe.org,\"\n#endif\n#ifndef WOLFSSH_NO_CURVE25519_SHA256\n \"curve25519-sha256,\"\n#endif\n#if !defined(WOLFSSH_NO_ECDH_SHA2_NISTP521)\n"
},
{
"old": "#else\n ssh->rfd = -1; /* set to invalid */\n ssh->wfd = -1; /* set to invalid */\n#endif\n ssh->ioReadCtx = &ssh->rfd; /* prevent invalid access if not correctly */\n ssh->ioWriteCtx = &ssh->wfd; /* set */\n ssh->highwaterMark = ctx->highwaterMark;\n ssh->highwaterCtx = (void*)ssh;\n ssh->reqSuccessCtx = (void*)ssh;\n ssh->fs = NULL;\n ssh->acceptState = ACCEPT_BEGIN;\n ssh->clientState = CLIENT_BEGIN;\n ssh->isKeying = 1;\n ssh->authId = ID_USERAUTH_PUBLICKEY;\n ssh->supportedAuth[0] = ID_USERAUTH_PUBLICKEY;\n ssh->supportedAuth[1] = ID_USERAUTH_PASSWORD;\n ssh->supportedAuth[2] = ID_USERAUTH_KEYBOARD;\n ssh->supportedAuth[3] = ID_NONE; /* ID_NONE is treated as empty slot */\n ssh->nextChannel = DEFAULT_NEXT_CHANNEL;\n ssh->blockSz = MIN_BLOCK_SZ;\n ssh->encryptId = ID_NONE;\n ssh->macId = ID_NONE;\n ssh->peerBlockSz = MIN_BLOCK_SZ;\n ssh->rng = rng;\n ssh->kSz = (word32)sizeof(ssh->k);\n",
"new": "#else\n ssh->rfd = -1; /* set to invalid */\n ssh->wfd = -1; /* set to invalid */\n#endif\n ssh->ioReadCtx = &ssh->rfd; /* prevent invalid access if not correctly */\n ssh->ioWriteCtx = &ssh->wfd; /* set */\n ssh->highwaterMark = ctx->highwaterMark;\n ssh->highwaterCtx = (void*)ssh;\n ssh->reqSuccessCtx = (void*)ssh;\n ssh->fs = NULL;\n ssh->acceptState = ACCEPT_BEGIN;\n ssh->clientState = CLIENT_BEGIN;\n ssh->isKeying = 0; /* initial state of not keying yet */\n ssh->authId = ID_USERAUTH_PUBLICKEY;\n ssh->supportedAuth[0] = ID_USERAUTH_PUBLICKEY;\n ssh->supportedAuth[1] = ID_USERAUTH_PASSWORD;\n ssh->supportedAuth[2] = ID_USERAUTH_KEYBOARD;\n ssh->supportedAuth[3] = ID_NONE; /* ID_NONE is treated as empty slot */\n ssh->nextChannel = DEFAULT_NEXT_CHANNEL;\n ssh->blockSz = MIN_BLOCK_SZ;\n ssh->encryptId = ID_NONE;\n ssh->macId = ID_NONE;\n ssh->peerBlockSz = MIN_BLOCK_SZ;\n ssh->rng = rng;\n ssh->kSz = (word32)sizeof(ssh->k);\n"
},
{
"old": " word32 cannedAlgoNamesSz;\n word32 skipSz = 0;\n word32 begin;\n\n WLOG(WS_LOG_DEBUG, \"Entering DoKexInit()\");\n\n if (ssh == NULL || ssh->ctx == NULL ||\n buf == NULL || len == 0 || idx == NULL) {\n\n ret = WS_BAD_ARGUMENT;\n }\n\n /*\n * I don't need to save what the client sends here. I should decode\n * each list into a local array of IDs, and pick the one the peer is\n * using that's on my known list, or verify that the one the peer can\n * support the other direction is on my known list. All I need to do\n * is save the actual values.\n */\n\n if (ret == WS_SUCCESS) {\n if (ssh->handshake == NULL) {\n ssh->handshake = HandshakeInfoNew(ssh->ctx->heap);\n if (ssh->handshake == NULL) {\n WLOG(WS_LOG_DEBUG, \"Couldn't allocate handshake info\");\n ret = WS_MEMORY_E;\n }\n }\n }\n\n if (ret == WS_SUCCESS) {\n begin = *idx;\n side = ssh->ctx->side;\n",
"new": " word32 cannedAlgoNamesSz;\n word32 skipSz = 0;\n word32 begin;\n\n WLOG(WS_LOG_DEBUG, \"Entering DoKexInit()\");\n\n if (ssh == NULL || ssh->ctx == NULL ||\n buf == NULL || len == 0 || idx == NULL) {\n\n ret = WS_BAD_ARGUMENT;\n }\n\n if (ret == WS_SUCCESS) {\n /* Check if already in process of keying and error out if so. */\n if (ssh->isKeying & WOLFSSH_PEER_IS_KEYING) {\n WLOG(WS_LOG_ERROR,\n \"Already in keying process and got KEX init\");\n ret = WS_INVALID_STATE_E;\n }\n }\n\n /*\n * I don't need to save what the client sends here. I should decode\n * each list into a local array of IDs, and pick the one the peer is\n * using that's on my known list, or verify that the one the peer can\n * support the other direction is on my known list. All I need to do\n * is save the actual values.\n */\n\n if (ret == WS_SUCCESS) {\n /* Set peer is keying flag after receiving SSH_MSG_KEX_INIT */\n ssh->isKeying |= WOLFSSH_PEER_IS_KEYING;\n if (ssh->handshake == NULL) {\n ssh->handshake = HandshakeInfoNew(ssh->ctx->heap);\n if (ssh->handshake == NULL) {\n WLOG(WS_LOG_DEBUG, \"Couldn't allocate handshake info\");\n ret = WS_MEMORY_E;\n }\n }\n }\n\n if (ret == WS_SUCCESS) {\n begin = *idx;\n side = ssh->ctx->side;\n"
},
{
"old": " (const byte*)ssh->algoListKex, cannedAlgoNamesSz);\n }\n if (ret == WS_SUCCESS) {\n ssh->handshake->kexIdGuess = list[0];\n algoId = MatchIdLists(side, list, listSz,\n cannedList, cannedListSz);\n if (algoId == ID_UNKNOWN) {\n WLOG(WS_LOG_DEBUG, \"Unable to negotiate KEX Algo\");\n ret = WS_MATCH_KEX_ALGO_E;\n }\n }\n if (ret == WS_SUCCESS) {\n ssh->kexId = ssh->handshake->kexId = algoId;\n ssh->handshake->kexHashId = HashForId(algoId);\n }\n /* Extension Info Flag */\n if (ret == WS_SUCCESS) {\n /* Only checking for this is we are server. Our client does\n * not have anything to say to a server, yet. */\n if (side == WOLFSSH_ENDPOINT_SERVER) {\n byte extInfo;\n\n /* Match the client accepts extInfo. */\n algoId = ID_EXTINFO_C;\n extInfo = MatchIdLists(side, list, listSz, &algoId, 1);\n ssh->sendExtInfo = extInfo == algoId;\n }\n }\n\n /* Server Host Key Algorithms */\n if (ret == WS_SUCCESS) {\n WLOG(WS_LOG_DEBUG, \"DKI: Server Host Key Algorithms\");\n listSz = (word32)sizeof(list);\n ret = GetNameList(list, &listSz, buf, len, &begin);\n }\n if (ret == WS_SUCCESS) {\n if (side == WOLFSSH_ENDPOINT_SERVER && !ssh->algoListKey) {\n cannedListSz = ssh->ctx->publicKeyAlgoCount;\n WMEMCPY(cannedList, ssh->ctx->publicKeyAlgo, cannedListSz);\n }\n",
"new": " (const byte*)ssh->algoListKex, cannedAlgoNamesSz);\n }\n if (ret == WS_SUCCESS) {\n ssh->handshake->kexIdGuess = list[0];\n algoId = MatchIdLists(side, list, listSz,\n cannedList, cannedListSz);\n if (algoId == ID_UNKNOWN) {\n WLOG(WS_LOG_DEBUG, \"Unable to negotiate KEX Algo\");\n ret = WS_MATCH_KEX_ALGO_E;\n }\n }\n if (ret == WS_SUCCESS) {\n /* The reviewed project profile has only these two KEX algorithms.\n * Do not silently enable an untested GEX/PQ continuation. */\n if (algoId != ID_CURVE25519_SHA256 && algoId != ID_ECDH_SHA2_NISTP256)\n ret = WS_MATCH_KEX_ALGO_E;\n ssh->kexId = ssh->handshake->kexId = algoId;\n ssh->handshake->kexHashId = HashForId(algoId);\n }\n /* RFC8308 is optional. This profile never sends EXT_INFO, including\n * after a nonblocking NEWKEYS send or on subsequent rekeys. */\n ssh->sendExtInfo = 0;\n\n /* Server Host Key Algorithms */\n if (ret == WS_SUCCESS) {\n WLOG(WS_LOG_DEBUG, \"DKI: Server Host Key Algorithms\");\n listSz = (word32)sizeof(list);\n ret = GetNameList(list, &listSz, buf, len, &begin);\n }\n if (ret == WS_SUCCESS) {\n if (side == WOLFSSH_ENDPOINT_SERVER && !ssh->algoListKey) {\n cannedListSz = ssh->ctx->publicKeyAlgoCount;\n WMEMCPY(cannedList, ssh->ctx->publicKeyAlgo, cannedListSz);\n }\n"
},
{
"old": " WLOG(WS_LOG_DEBUG, \"DKI: For Future Use\");\n ret = GetUint32(&skipSz, buf, len, &begin);\n if (ret == WS_SUCCESS)\n begin += skipSz;\n }\n\n if (ret == WS_SUCCESS) {\n wc_HashAlg* hash = &ssh->handshake->kexHash;\n enum wc_HashType hashId = (enum wc_HashType)ssh->handshake->kexHashId;\n byte scratchLen[LENGTH_SZ];\n word32 strSz = 0;\n\n if (!ssh->isKeying) {\n WLOG(WS_LOG_DEBUG, \"Keying initiated\");\n ret = SendKexInit(ssh);\n }\n\n /* account for possible want write case from SendKexInit */\n if (ret == WS_SUCCESS || ret == WS_WANT_WRITE)\n ret = wc_HashInit(hash, hashId);\n\n if (ret == WS_SUCCESS) {\n if (ssh->ctx->side == WOLFSSH_ENDPOINT_SERVER) {\n ret = HashUpdate(hash, hashId,\n ssh->peerProtoId, ssh->peerProtoIdSz);\n",
"new": " WLOG(WS_LOG_DEBUG, \"DKI: For Future Use\");\n ret = GetUint32(&skipSz, buf, len, &begin);\n if (ret == WS_SUCCESS)\n begin += skipSz;\n }\n\n if (ret == WS_SUCCESS) {\n wc_HashAlg* hash = &ssh->handshake->kexHash;\n enum wc_HashType hashId = (enum wc_HashType)ssh->handshake->kexHashId;\n byte scratchLen[LENGTH_SZ];\n word32 strSz = 0;\n\n /* respond with KEX Init message if not having initiated the keying */\n if ((ssh->isKeying & WOLFSSH_SELF_IS_KEYING) == 0) {\n WLOG(WS_LOG_DEBUG, \"Keying initiated\");\n ret = SendKexInit(ssh);\n }\n\n /* account for possible want write case from SendKexInit */\n if (ret == WS_SUCCESS || ret == WS_WANT_WRITE)\n ret = wc_HashInit(hash, hashId);\n\n if (ret == WS_SUCCESS) {\n if (ssh->ctx->side == WOLFSSH_ENDPOINT_SERVER) {\n ret = HashUpdate(hash, hashId,\n ssh->peerProtoId, ssh->peerProtoIdSz);\n"
},
{
"old": "\n if (ret == WS_SUCCESS)\n ret = HashUpdate(hash, hashId, buf, len);\n\n if (ret == WS_SUCCESS) {\n if (ssh->ctx->side == WOLFSSH_ENDPOINT_SERVER)\n ret = HashUpdate(hash, hashId,\n ssh->handshake->kexInit, ssh->handshake->kexInitSz);\n }\n\n if (ret == WS_SUCCESS) {\n *idx = begin;\n if (ssh->ctx->side == WOLFSSH_ENDPOINT_SERVER)\n ssh->clientState = CLIENT_KEXINIT_DONE;\n else\n ssh->serverState = SERVER_KEXINIT_DONE;\n\n /* Propagate potential want write case from SendKexInit. */\n if (ssh->error != 0)\n ret = ssh->error;\n }\n }\n WLOG(WS_LOG_DEBUG, \"Leaving DoKexInit(), ret = %d\", ret);\n return ret;\n}\n\n",
"new": "\n if (ret == WS_SUCCESS)\n ret = HashUpdate(hash, hashId, buf, len);\n\n if (ret == WS_SUCCESS) {\n if (ssh->ctx->side == WOLFSSH_ENDPOINT_SERVER)\n ret = HashUpdate(hash, hashId,\n ssh->handshake->kexInit, ssh->handshake->kexInitSz);\n }\n\n if (ret == WS_SUCCESS) {\n *idx = begin;\n if (ssh->ctx->side == WOLFSSH_ENDPOINT_SERVER) {\n ssh->handshake->expectMsgId = MSGID_KEXDH_INIT;\n ssh->clientState = CLIENT_KEXINIT_DONE;\n }\n else\n ssh->serverState = SERVER_KEXINIT_DONE;\n\n /* Propagate potential want write case from SendKexInit. */\n if (ssh->error != 0)\n ret = ssh->error;\n }\n }\n WLOG(WS_LOG_DEBUG, \"Leaving DoKexInit(), ret = %d\", ret);\n return ret;\n}\n\n"
},
{
"old": "\n if (ssh == NULL || ssh->handshake == NULL || buf == NULL || len == 0 ||\n idx == NULL)\n ret = WS_BAD_ARGUMENT;\n\n if (ret == WS_SUCCESS) {\n if (ssh->handshake->kexPacketFollows\n && ssh->handshake->kexIdGuess != ssh->handshake->kexId) {\n\n /* skip this message. */\n WLOG(WS_LOG_DEBUG, \"Skipping the client's KEX init function.\");\n ssh->handshake->kexPacketFollows = 0;\n *idx += len;\n return WS_SUCCESS;\n }\n }\n\n if (ret == WS_SUCCESS) {\n begin = *idx;\n ret = GetUint32(&eSz, buf, len, &begin);\n }\n\n if (ret == WS_SUCCESS) {\n /* Validate eSz */\n",
"new": "\n if (ssh == NULL || ssh->handshake == NULL || buf == NULL || len == 0 ||\n idx == NULL)\n ret = WS_BAD_ARGUMENT;\n\n if (ret == WS_SUCCESS) {\n if (ssh->handshake->kexPacketFollows\n && ssh->handshake->kexIdGuess != ssh->handshake->kexId) {\n\n /* skip this message. */\n WLOG(WS_LOG_DEBUG, \"Skipping the client's KEX init function.\");\n ssh->handshake->kexPacketFollows = 0;\n ssh->handshake->expectMsgId = MSGID_KEXDH_INIT;\n *idx += len;\n return WS_SUCCESS;\n }\n }\n\n if (ret == WS_SUCCESS) {\n begin = *idx;\n ret = GetUint32(&eSz, buf, len, &begin);\n }\n\n if (ret == WS_SUCCESS) {\n /* Validate eSz */\n"
},
{
"old": " ret = WS_INVALID_ALGO_ID;\n }\n }\n }\n FreePubKey(sigKeyBlock_ptr);\n }\n\n if (ret == WS_SUCCESS) {\n /* If we aren't using EccKyber, use padding. */\n ret = GenerateKeys(ssh, hashId, !ssh->handshake->useEccKyber);\n }\n\n if (ret == WS_SUCCESS)\n ret = SendNewKeys(ssh);\n\n if (sigKeyBlock_ptr)\n WFREE(sigKeyBlock_ptr, ssh->ctx->heap, DYNTYPE_PRIVKEY);\n WLOG(WS_LOG_DEBUG, \"Leaving DoKexDhReply(), ret = %d\", ret);\n return ret;\n}\n\n\nstatic int DoNewKeys(WOLFSSH* ssh, byte* buf, word32 len, word32* idx)\n{\n int ret = WS_SUCCESS;\n\n WOLFSSH_UNUSED(buf);\n WOLFSSH_UNUSED(len);\n WOLFSSH_UNUSED(idx);\n\n if (ssh == NULL || ssh->handshake == NULL)\n ret = WS_BAD_ARGUMENT;\n\n if (ret == WS_SUCCESS) {\n ssh->peerEncryptId = ssh->handshake->encryptId;\n ssh->peerMacId = ssh->handshake->macId;\n ssh->peerBlockSz = ssh->handshake->blockSz;\n ssh->peerMacSz = ssh->handshake->macSz;\n ssh->peerAeadMode = ssh->handshake->aeadMode;\n WMEMCPY(&ssh->peerKeys, &ssh->handshake->peerKeys, sizeof(Keys));\n\n switch (ssh->peerEncryptId) {\n case ID_NONE:\n WLOG(WS_LOG_DEBUG, \"DNK: peer using cipher none\");\n",
"new": " ret = WS_INVALID_ALGO_ID;\n }\n }\n }\n FreePubKey(sigKeyBlock_ptr);\n }\n\n if (ret == WS_SUCCESS) {\n /* If we aren't using EccKyber, use padding. */\n ret = GenerateKeys(ssh, hashId, !ssh->handshake->useEccKyber);\n }\n\n if (ret == WS_SUCCESS) {\n ssh->handshake->expectMsgId = MSGID_NEWKEYS;\n WLOG_EXPECT_MSGID(ssh->handshake->expectMsgId);\n ret = SendNewKeys(ssh);\n }\n\n if (sigKeyBlock_ptr)\n WFREE(sigKeyBlock_ptr, ssh->ctx->heap, DYNTYPE_PRIVKEY);\n WLOG(WS_LOG_DEBUG, \"Leaving DoKexDhReply(), ret = %d\", ret);\n return ret;\n}\n\n\nstatic int DoNewKeys(WOLFSSH* ssh, byte* buf, word32 len, word32* idx)\n{\n int ret = WS_SUCCESS;\n\n WOLFSSH_UNUSED(buf);\n WOLFSSH_UNUSED(len);\n WOLFSSH_UNUSED(idx);\n\n if (ssh == NULL || ssh->handshake == NULL)\n ret = WS_BAD_ARGUMENT;\n\n if (ret == WS_SUCCESS) {\n if ((ssh->isKeying & WOLFSSH_SELF_IS_KEYING) ||\n !(ssh->isKeying & WOLFSSH_PEER_IS_KEYING)) {\n WLOG(WS_LOG_ERROR, \"Keying failed\");\n ret = WS_INVALID_STATE_E;\n }\n }\n\n if (ret == WS_SUCCESS) {\n ssh->peerEncryptId = ssh->handshake->encryptId;\n ssh->peerMacId = ssh->handshake->macId;\n ssh->peerBlockSz = ssh->handshake->blockSz;\n ssh->peerMacSz = ssh->handshake->macSz;\n ssh->peerAeadMode = ssh->handshake->aeadMode;\n WMEMCPY(&ssh->peerKeys, &ssh->handshake->peerKeys, sizeof(Keys));\n\n switch (ssh->peerEncryptId) {\n case ID_NONE:\n WLOG(WS_LOG_DEBUG, \"DNK: peer using cipher none\");\n"
},
{
"old": " break;\n }\n\n if (ret == 0)\n ret = WS_SUCCESS;\n else\n ret = WS_CRYPTO_FAILED;\n }\n\n if (ret == WS_SUCCESS) {\n ssh->rxCount = 0;\n ssh->highwaterFlag = 0;\n ssh->isKeying = 0;\n HandshakeInfoFree(ssh->handshake, ssh->ctx->heap);\n ssh->handshake = NULL;\n WLOG(WS_LOG_DEBUG, \"Keying completed\");\n\n if (ssh->ctx->keyingCompletionCb)\n ssh->ctx->keyingCompletionCb(ssh->keyingCompletionCtx);\n }\n\n return ret;\n}\n\n\n#ifndef WOLFSSH_NO_DH_GEX_SHA256\nstatic int DoKexDhGexRequest(WOLFSSH* ssh,\n byte* buf, word32 len, word32* idx)\n{\n",
"new": " break;\n }\n\n if (ret == 0)\n ret = WS_SUCCESS;\n else\n ret = WS_CRYPTO_FAILED;\n }\n\n if (ret == WS_SUCCESS) {\n ssh->rxCount = 0;\n ssh->highwaterFlag = 0;\n\n /* Clear peer is keying flag */\n ssh->isKeying &= ~WOLFSSH_PEER_IS_KEYING;\n HandshakeInfoFree(ssh->handshake, ssh->ctx->heap);\n ssh->handshake = NULL;\n WLOG(WS_LOG_DEBUG, \"Keying completed\");\n if (ssh->ctx->keyingCompletionCb)\n ssh->ctx->keyingCompletionCb(ssh->keyingCompletionCtx);\n }\n\n return ret;\n}\n\n\n#ifndef WOLFSSH_NO_DH_GEX_SHA256\nstatic int DoKexDhGexRequest(WOLFSSH* ssh,\n byte* buf, word32 len, word32* idx)\n{\n"
},
{
"old": "\n msg = buf[idx++];\n /* At this point, payload starts at \"buf + idx\". */\n\n /* sanity check on payloadSz. Uses \"or\" condition because of the case when\n * adding idx to payloadSz causes it to overflow.\n */\n if ((ssh->inputBuffer.bufferSz < payloadSz + idx) ||\n (payloadSz + idx < payloadSz)) {\n return WS_OVERFLOW_E;\n }\n\n if (!IsMessageAllowed(ssh, msg)) {\n return WS_MSGID_NOT_ALLOWED_E;\n }\n\n switch (msg) {\n\n case MSGID_DISCONNECT:\n WLOG(WS_LOG_DEBUG, \"Decoding MSGID_DISCONNECT\");\n ret = DoDisconnect(ssh, buf + idx, payloadSz, &payloadIdx);\n break;\n\n case MSGID_IGNORE:\n WLOG(WS_LOG_DEBUG, \"Decoding MSGID_IGNORE\");\n",
"new": "\n msg = buf[idx++];\n /* At this point, payload starts at \"buf + idx\". */\n\n /* sanity check on payloadSz. Uses \"or\" condition because of the case when\n * adding idx to payloadSz causes it to overflow.\n */\n if ((ssh->inputBuffer.bufferSz < payloadSz + idx) ||\n (payloadSz + idx < payloadSz)) {\n return WS_OVERFLOW_E;\n }\n\n if (!IsMessageAllowed(ssh, msg, WS_MSG_RECV)) {\n return WS_MSGID_NOT_ALLOWED_E;\n }\n\n switch (msg) {\n\n case MSGID_DISCONNECT:\n WLOG(WS_LOG_DEBUG, \"Decoding MSGID_DISCONNECT\");\n ret = DoDisconnect(ssh, buf + idx, payloadSz, &payloadIdx);\n break;\n\n case MSGID_IGNORE:\n WLOG(WS_LOG_DEBUG, \"Decoding MSGID_IGNORE\");\n"
},
{
"old": " WLOG(WS_LOG_DEBUG, \"Decoding MSGID_DEBUG\");\n ret = DoDebug(ssh, buf + idx, payloadSz, &payloadIdx);\n break;\n\n case MSGID_EXT_INFO:\n WLOG(WS_LOG_DEBUG, \"Decoding MSGID_EXT_INFO\");\n ret = DoExtInfo(ssh, buf + idx, payloadSz, &payloadIdx);\n break;\n\n case MSGID_KEXINIT:\n WLOG(WS_LOG_DEBUG, \"Decoding MSGID_KEXINIT\");\n ret = DoKexInit(ssh, buf + idx, payloadSz, &payloadIdx);\n if (ssh->isKeying == 1 &&\n ssh->connectState == CONNECT_SERVER_CHANNEL_REQUEST_DONE) {\n if (ssh->handshake->kexId == ID_DH_GEX_SHA256) {\n#if !defined(WOLFSSH_NO_DH) && !defined(WOLFSSH_NO_DH_GEX_SHA256)\n ssh->error = SendKexDhGexRequest(ssh);\n#endif\n }\n else\n ssh->error = SendKexDhInit(ssh);\n }\n break;\n\n case MSGID_NEWKEYS:\n WLOG(WS_LOG_DEBUG, \"Decoding MSGID_NEWKEYS\");\n",
"new": " WLOG(WS_LOG_DEBUG, \"Decoding MSGID_DEBUG\");\n ret = DoDebug(ssh, buf + idx, payloadSz, &payloadIdx);\n break;\n\n case MSGID_EXT_INFO:\n WLOG(WS_LOG_DEBUG, \"Decoding MSGID_EXT_INFO\");\n ret = DoExtInfo(ssh, buf + idx, payloadSz, &payloadIdx);\n break;\n\n case MSGID_KEXINIT:\n WLOG(WS_LOG_DEBUG, \"Decoding MSGID_KEXINIT\");\n ret = DoKexInit(ssh, buf + idx, payloadSz, &payloadIdx);\n if ((ret == WS_SUCCESS || ret == WS_WANT_WRITE) &&\n ssh->handshake != NULL && ssh->isKeying &&\n ssh->connectState >= CONNECT_SERVER_CHANNEL_REQUEST_DONE) {\n if (ssh->handshake->kexId == ID_DH_GEX_SHA256) {\n#if !defined(WOLFSSH_NO_DH) && !defined(WOLFSSH_NO_DH_GEX_SHA256)\n ssh->error = SendKexDhGexRequest(ssh);\n#endif\n }\n else\n ssh->error = SendKexDhInit(ssh);\n }\n break;\n\n case MSGID_NEWKEYS:\n WLOG(WS_LOG_DEBUG, \"Decoding MSGID_NEWKEYS\");\n"
},
{
"old": " WLOG(WS_LOG_DEBUG, \"Entering SendKexInit()\");\n\n if (ssh == NULL)\n ret = WS_BAD_ARGUMENT;\n\n if (ret == WS_SUCCESS && ssh->ctx->side == WOLFSSH_ENDPOINT_SERVER &&\n ssh->ctx->privateKeyCount == 0) {\n WLOG(WS_LOG_DEBUG, \"Server needs at least one private key\");\n ret = WS_BAD_ARGUMENT;\n }\n\n if (ret == WS_SUCCESS) {\n ssh->isKeying = 1;\n if (ssh->handshake == NULL) {\n ssh->handshake = HandshakeInfoNew(ssh->ctx->heap);\n if (ssh->handshake == NULL) {\n WLOG(WS_LOG_DEBUG, \"Couldn't allocate handshake info\");\n ret = WS_MEMORY_E;\n }\n }\n }\n\n if (ret == WS_SUCCESS) {\n if (!ssh->algoListKey && ssh->ctx->side == WOLFSSH_ENDPOINT_SERVER) {\n keyAlgoNamesSz = BuildNameList(NULL, 0,\n",
"new": " WLOG(WS_LOG_DEBUG, \"Entering SendKexInit()\");\n\n if (ssh == NULL)\n ret = WS_BAD_ARGUMENT;\n\n if (ret == WS_SUCCESS && ssh->ctx->side == WOLFSSH_ENDPOINT_SERVER &&\n ssh->ctx->privateKeyCount == 0) {\n WLOG(WS_LOG_DEBUG, \"Server needs at least one private key\");\n ret = WS_BAD_ARGUMENT;\n }\n\n if (ret == WS_SUCCESS) {\n /* Set self is keying flag since we started sending the KEX init msg */\n ssh->isKeying |= WOLFSSH_SELF_IS_KEYING;\n if (ssh->handshake == NULL) {\n ssh->handshake = HandshakeInfoNew(ssh->ctx->heap);\n if (ssh->handshake == NULL) {\n WLOG(WS_LOG_DEBUG, \"Couldn't allocate handshake info\");\n ret = WS_MEMORY_E;\n }\n }\n }\n\n if (ret == WS_SUCCESS) {\n if (!ssh->algoListKey && ssh->ctx->side == WOLFSSH_ENDPOINT_SERVER) {\n keyAlgoNamesSz = BuildNameList(NULL, 0,\n"
},
{
"old": " if (ret > 0) {\n keyAlgoNamesSz = (word32)ret;\n ret = WS_SUCCESS;\n }\n }\n else {\n ret = WS_MEMORY_E;\n }\n }\n }\n\n if (ret == WS_SUCCESS) {\n if (ssh->ctx->side == WOLFSSH_ENDPOINT_CLIENT) {\n kexAlgoNamesPlus = \",ext-info-c\";\n kexAlgoNamesPlusSz = (word32)WSTRLEN(kexAlgoNamesPlus);\n }\n\n kexAlgoNamesSz = AlgoListSz(ssh->algoListKex);\n encAlgoNamesSz = AlgoListSz(ssh->algoListCipher);\n if (!keyAlgoNames) {\n keyAlgoNamesSz = AlgoListSz(ssh->algoListKey);\n }\n else {\n keyAlgoNamesSz = AlgoListSz(keyAlgoNames);\n }\n macAlgoNamesSz = AlgoListSz(ssh->algoListMac);\n noneNamesSz = AlgoListSz(cannedNoneNames);\n payloadSz = MSG_ID_SZ + COOKIE_SZ + (LENGTH_SZ * 11) + BOOLEAN_SZ +\n + kexAlgoNamesSz + kexAlgoNamesPlusSz + keyAlgoNamesSz\n",
"new": " if (ret > 0) {\n keyAlgoNamesSz = (word32)ret;\n ret = WS_SUCCESS;\n }\n }\n else {\n ret = WS_MEMORY_E;\n }\n }\n }\n\n if (ret == WS_SUCCESS) {\n kexAlgoNamesSz = AlgoListSz(ssh->algoListKex);\n encAlgoNamesSz = AlgoListSz(ssh->algoListCipher);\n if (!keyAlgoNames) {\n keyAlgoNamesSz = AlgoListSz(ssh->algoListKey);\n }\n else {\n keyAlgoNamesSz = AlgoListSz(keyAlgoNames);\n }\n macAlgoNamesSz = AlgoListSz(ssh->algoListMac);\n noneNamesSz = AlgoListSz(cannedNoneNames);\n payloadSz = MSG_ID_SZ + COOKIE_SZ + (LENGTH_SZ * 11) + BOOLEAN_SZ +\n + kexAlgoNamesSz + kexAlgoNamesPlusSz + keyAlgoNamesSz\n"
},
{
"old": " }\n\n if (keyAlgoNames) {\n WFREE(keyAlgoNames, ssh->ctx->heap, DYNTYPE_STRING);\n }\n\n if (ret == WS_SUCCESS) {\n /* increase amount to be sent only if BundlePacket will be called */\n ssh->outputBuffer.length = idx;\n ret = BundlePacket(ssh);\n }\n\n if (ret == WS_SUCCESS)\n ret = wolfSSH_SendPacket(ssh);\n\n if (ret != WS_WANT_WRITE && ret != WS_SUCCESS)\n PurgePacket(ssh);\n\n WLOG(WS_LOG_DEBUG, \"Leaving SendKexInit(), ret = %d\", ret);\n return ret;\n}\n\n\nstruct wolfSSH_sigKeyBlockFull {\n byte pubKeyId; /* handshake->pubKeyId */\n byte pubKeyFmtId;\n",
"new": " }\n\n if (keyAlgoNames) {\n WFREE(keyAlgoNames, ssh->ctx->heap, DYNTYPE_STRING);\n }\n\n if (ret == WS_SUCCESS) {\n /* increase amount to be sent only if BundlePacket will be called */\n ssh->outputBuffer.length = idx;\n ret = BundlePacket(ssh);\n }\n\n if (ret == WS_SUCCESS) {\n ret = wolfSSH_SendPacket(ssh);\n }\n\n if (ret != WS_WANT_WRITE && ret != WS_SUCCESS)\n PurgePacket(ssh);\n\n WLOG(WS_LOG_DEBUG, \"Leaving SendKexInit(), ret = %d\", ret);\n return ret;\n}\n\n\nstruct wolfSSH_sigKeyBlockFull {\n byte pubKeyId; /* handshake->pubKeyId */\n byte pubKeyFmtId;\n"
},
{
"old": " sigKeyBlock_ptr->pubKeyName, sigKeyBlock_ptr->pubKeyNameSz);\n idx += sigKeyBlock_ptr->pubKeyNameSz;\n c32toa(sigSz, output + idx);\n idx += LENGTH_SZ;\n WMEMCPY(output + idx, sig_ptr, sigSz);\n idx += sigSz;\n\n ssh->outputBuffer.length = idx;\n\n ret = BundlePacket(ssh);\n }\n\n if (ret == WS_SUCCESS)\n ret = SendNewKeys(ssh);\n\n if (ret == WS_SUCCESS && ssh->sendExtInfo) {\n ret = SendExtInfo(ssh);\n }\n\n if (ret != WS_WANT_WRITE && ret != WS_SUCCESS)\n PurgePacket(ssh);\n\n WLOG(WS_LOG_DEBUG, \"Leaving SendKexDhReply(), ret = %d\", ret);\n if (sigKeyBlock_ptr)\n WFREE(sigKeyBlock_ptr, heap, DYNTYPE_PRIVKEY);\n#ifdef WOLFSSH_SMALL_STACK\n if (f_ptr)\n WFREE(f_ptr, heap, DYNTYPE_BUFFER);\n if (sig_ptr)\n",
"new": " sigKeyBlock_ptr->pubKeyName, sigKeyBlock_ptr->pubKeyNameSz);\n idx += sigKeyBlock_ptr->pubKeyNameSz;\n c32toa(sigSz, output + idx);\n idx += LENGTH_SZ;\n WMEMCPY(output + idx, sig_ptr, sigSz);\n idx += sigSz;\n\n ssh->outputBuffer.length = idx;\n\n ret = BundlePacket(ssh);\n }\n\n if (ret == WS_SUCCESS) {\n ssh->handshake->expectMsgId = MSGID_NEWKEYS;\n WLOG_EXPECT_MSGID(ssh->handshake->expectMsgId);\n ret = SendNewKeys(ssh);\n }\n\n if (ret != WS_WANT_WRITE && ret != WS_SUCCESS)\n PurgePacket(ssh);\n\n WLOG(WS_LOG_DEBUG, \"Leaving SendKexDhReply(), ret = %d\", ret);\n if (sigKeyBlock_ptr)\n WFREE(sigKeyBlock_ptr, heap, DYNTYPE_PRIVKEY);\n#ifdef WOLFSSH_SMALL_STACK\n if (f_ptr)\n WFREE(f_ptr, heap, DYNTYPE_BUFFER);\n if (sig_ptr)\n"
},
{
"old": "#endif\n\n default:\n WLOG(WS_LOG_DEBUG, \"SNK: using cipher invalid\");\n ret = WS_INVALID_ALGO_ID;\n }\n }\n\n if (ret == WS_SUCCESS) {\n ssh->txCount = 0;\n }\n\n if (ret == WS_SUCCESS)\n ret = wolfSSH_SendPacket(ssh);\n\n WLOG(WS_LOG_DEBUG, \"Leaving SendNewKeys(), ret = %d\", ret);\n return ret;\n}\n\n\n#ifndef WOLFSSH_NO_DH_GEX_SHA256\nint SendKexDhGexRequest(WOLFSSH* ssh)\n{\n byte* output;\n word32 idx = 0;\n word32 payloadSz;\n",
"new": "#endif\n\n default:\n WLOG(WS_LOG_DEBUG, \"SNK: using cipher invalid\");\n ret = WS_INVALID_ALGO_ID;\n }\n }\n\n if (ret == WS_SUCCESS) {\n ssh->txCount = 0;\n }\n\n if (ret == WS_SUCCESS) {\n ret = wolfSSH_SendPacket(ssh);\n\n /* Queued NEWKEYS is already bundled with the old keys. A partial\n * write is resumed by SendPacket, never by rebuilding NEWKEYS. */\n if (ret == WS_SUCCESS || ret == WS_WANT_WRITE)\n ssh->isKeying &= ~WOLFSSH_SELF_IS_KEYING;\n }\n\n WLOG(WS_LOG_DEBUG, \"Leaving SendNewKeys(), ret = %d\", ret);\n return ret;\n}\n\n\n#ifndef WOLFSSH_NO_DH_GEX_SHA256\nint SendKexDhGexRequest(WOLFSSH* ssh)\n{\n byte* output;\n word32 idx = 0;\n word32 payloadSz;\n"
},
{
"old": " c32toa(ssh->handshake->dhGexMinSz, output + idx);\n idx += UINT32_SZ;\n c32toa(ssh->handshake->dhGexPreferredSz, output + idx);\n idx += UINT32_SZ;\n c32toa(ssh->handshake->dhGexMaxSz, output + idx);\n idx += UINT32_SZ;\n\n ssh->outputBuffer.length = idx;\n\n ret = BundlePacket(ssh);\n }\n\n if (ret == WS_SUCCESS)\n ret = wolfSSH_SendPacket(ssh);\n\n WLOG(WS_LOG_DEBUG, \"Leaving SendKexDhGexRequest(), ret = %d\", ret);\n return ret;\n}\n\n\nint SendKexDhGexGroup(WOLFSSH* ssh)\n{\n byte* output;\n word32 idx = 0;\n word32 payloadSz;\n const byte* primeGroup = dhPrimeGroup14;\n",
"new": " c32toa(ssh->handshake->dhGexMinSz, output + idx);\n idx += UINT32_SZ;\n c32toa(ssh->handshake->dhGexPreferredSz, output + idx);\n idx += UINT32_SZ;\n c32toa(ssh->handshake->dhGexMaxSz, output + idx);\n idx += UINT32_SZ;\n\n ssh->outputBuffer.length = idx;\n\n ret = BundlePacket(ssh);\n }\n\n if (ret == WS_SUCCESS) {\n WLOG_EXPECT_MSGID(MSGID_KEXDH_GEX_GROUP);\n ssh->handshake->expectMsgId = MSGID_KEXDH_GEX_GROUP;\n ret = wolfSSH_SendPacket(ssh);\n }\n\n WLOG(WS_LOG_DEBUG, \"Leaving SendKexDhGexRequest(), ret = %d\", ret);\n return ret;\n}\n\n\nint SendKexDhGexGroup(WOLFSSH* ssh)\n{\n byte* output;\n word32 idx = 0;\n word32 payloadSz;\n const byte* primeGroup = dhPrimeGroup14;\n"
},
{
"old": "{\n byte* output;\n word32 idx = 0;\n word32 payloadSz;\n#ifndef WOLFSSH_NO_DH\n const byte* primeGroup = NULL;\n word32 primeGroupSz = 0;\n const byte* generator = NULL;\n word32 generatorSz = 0;\n#endif\n int ret = WS_SUCCESS;\n byte msgId = MSGID_KEXDH_INIT;\n byte e[MAX_KEX_KEY_SZ+1]; /* plus 1 in case of padding. */\n word32 eSz = (word32)sizeof(e);\n byte ePad = 0;\n\n WLOG(WS_LOG_DEBUG, \"Entering SendKexDhInit()\");\n\n switch (ssh->handshake->kexId) {\n#ifndef WOLFSSH_NO_DH_GROUP1_SHA1\n case ID_DH_GROUP1_SHA1:\n ssh->handshake->useDh = 1;\n primeGroup = dhPrimeGroup1;\n primeGroupSz = dhPrimeGroup1Sz;\n",
"new": "{\n byte* output;\n word32 idx = 0;\n word32 payloadSz;\n#ifndef WOLFSSH_NO_DH\n const byte* primeGroup = NULL;\n word32 primeGroupSz = 0;\n const byte* generator = NULL;\n word32 generatorSz = 0;\n#endif\n int ret = WS_SUCCESS;\n byte msgId = MSGID_KEXDH_INIT;\n byte expectMsgId = MSGID_KEXDH_REPLY;\n byte e[MAX_KEX_KEY_SZ+1]; /* plus 1 in case of padding. */\n word32 eSz = (word32)sizeof(e);\n byte ePad = 0;\n\n WLOG(WS_LOG_DEBUG, \"Entering SendKexDhInit()\");\n\n switch (ssh->handshake->kexId) {\n#ifndef WOLFSSH_NO_DH_GROUP1_SHA1\n case ID_DH_GROUP1_SHA1:\n ssh->handshake->useDh = 1;\n primeGroup = dhPrimeGroup1;\n primeGroupSz = dhPrimeGroup1Sz;\n"
},
{
"old": " generator = dhGenerator;\n generatorSz = dhGeneratorSz;\n break;\n#endif\n#ifndef WOLFSSH_NO_DH_GEX_SHA256\n case ID_DH_GEX_SHA256:\n ssh->handshake->useDh = 1;\n primeGroup = ssh->handshake->primeGroup;\n primeGroupSz = ssh->handshake->primeGroupSz;\n generator = ssh->handshake->generator;\n generatorSz = ssh->handshake->generatorSz;\n msgId = MSGID_KEXDH_GEX_INIT;\n break;\n#endif\n#ifndef WOLFSSH_NO_ECDH_SHA2_NISTP256\n case ID_ECDH_SHA2_NISTP256:\n ssh->handshake->useEcc = 1;\n msgId = MSGID_KEXECDH_INIT;\n break;\n#endif\n#ifndef WOLFSSH_NO_ECDH_SHA2_NISTP384\n case ID_ECDH_SHA2_NISTP384:\n ssh->handshake->useEcc = 1;\n msgId = MSGID_KEXECDH_INIT;\n",
"new": " generator = dhGenerator;\n generatorSz = dhGeneratorSz;\n break;\n#endif\n#ifndef WOLFSSH_NO_DH_GEX_SHA256\n case ID_DH_GEX_SHA256:\n ssh->handshake->useDh = 1;\n primeGroup = ssh->handshake->primeGroup;\n primeGroupSz = ssh->handshake->primeGroupSz;\n generator = ssh->handshake->generator;\n generatorSz = ssh->handshake->generatorSz;\n msgId = MSGID_KEXDH_GEX_INIT;\n expectMsgId = MSGID_KEXDH_GEX_REPLY;\n break;\n#endif\n#ifndef WOLFSSH_NO_ECDH_SHA2_NISTP256\n case ID_ECDH_SHA2_NISTP256:\n ssh->handshake->useEcc = 1;\n msgId = MSGID_KEXECDH_INIT;\n break;\n#endif\n#ifndef WOLFSSH_NO_ECDH_SHA2_NISTP384\n case ID_ECDH_SHA2_NISTP384:\n ssh->handshake->useEcc = 1;\n msgId = MSGID_KEXECDH_INIT;\n"
},
{
"old": " output[idx] = 0;\n idx++;\n }\n\n WMEMCPY(output + idx, e, eSz);\n idx += eSz;\n\n ssh->outputBuffer.length = idx;\n\n ret = BundlePacket(ssh);\n }\n\n if (ret == WS_SUCCESS)\n ret = wolfSSH_SendPacket(ssh);\n\n WLOG(WS_LOG_DEBUG, \"Leaving SendKexDhInit(), ret = %d\", ret);\n return ret;\n}\n\n\nint SendUnimplemented(WOLFSSH* ssh)\n{\n byte* output;\n word32 idx = 0;\n int ret = WS_SUCCESS;\n\n",
"new": " output[idx] = 0;\n idx++;\n }\n\n WMEMCPY(output + idx, e, eSz);\n idx += eSz;\n\n ssh->outputBuffer.length = idx;\n\n ret = BundlePacket(ssh);\n }\n\n if (ret == WS_SUCCESS) {\n WLOG_EXPECT_MSGID(expectMsgId);\n ssh->handshake->expectMsgId = expectMsgId;\n ret = wolfSSH_SendPacket(ssh);\n }\n\n WLOG(WS_LOG_DEBUG, \"Leaving SendKexDhInit(), ret = %d\", ret);\n return ret;\n}\n\n\nint SendUnimplemented(WOLFSSH* ssh)\n{\n byte* output;\n word32 idx = 0;\n int ret = WS_SUCCESS;\n\n"
},
{
"old": " ret = SendUserAuthBanner(ssh);\n\n return ret;\n}\n\n\n#define WS_EXTINFO_EXTENSION_COUNT 1\nstatic const char serverSigAlgsName[] = \"server-sig-algs\";\n\n\nint SendExtInfo(WOLFSSH* ssh)\n{\n byte* output;\n word32 idx;\n word32 keyAlgoNamesSz = 0;\n word32 serverSigAlgsNameSz = 0;\n int ret = WS_SUCCESS;\n\n WLOG(WS_LOG_DEBUG, \"Entering SendExtInfo()\");\n\n if (ssh == NULL) {\n ret = WS_BAD_ARGUMENT;\n }\n\n if (ret == WS_SUCCESS) {\n keyAlgoNamesSz = AlgoListSz(ssh->algoListKeyAccepted);\n serverSigAlgsNameSz = AlgoListSz(serverSigAlgsName);\n ret = PreparePacket(ssh, MSG_ID_SZ + UINT32_SZ + (LENGTH_SZ * 2)\n + serverSigAlgsNameSz + keyAlgoNamesSz);\n }\n\n if (ret == WS_SUCCESS) {\n output = ssh->outputBuffer.buffer;\n idx = ssh->outputBuffer.length;\n\n output[idx++] = MSGID_EXT_INFO;\n c32toa(WS_EXTINFO_EXTENSION_COUNT, output + idx);\n idx += UINT32_SZ;\n\n c32toa(serverSigAlgsNameSz, output + idx);\n idx += LENGTH_SZ;\n WMEMCPY(output + idx, serverSigAlgsName, serverSigAlgsNameSz);\n idx += serverSigAlgsNameSz;\n\n c32toa(keyAlgoNamesSz, output + idx);\n idx += LENGTH_SZ;\n WMEMCPY(output + idx, ssh->algoListKeyAccepted, keyAlgoNamesSz);\n idx += keyAlgoNamesSz;\n\n ssh->outputBuffer.length = idx;\n\n ret = BundlePacket(ssh);\n }\n\n if (ret == WS_SUCCESS) {\n ret = wolfSSH_SendPacket(ssh);\n }\n\n WLOG(WS_LOG_DEBUG, \"Leaving SendExtInfo(), ret = %d\", ret);\n return ret;\n}\n\n\n/* Updates the payload size, and maybe loads keys. */\nstatic int PrepareUserAuthRequestPassword(WOLFSSH* ssh, word32* payloadSz,\n const WS_UserAuthData* authData)\n{\n int ret = WS_SUCCESS;\n\n if (ssh == NULL || payloadSz == NULL || authData == NULL)\n ret = WS_BAD_ARGUMENT;\n\n",
"new": " ret = SendUserAuthBanner(ssh);\n\n return ret;\n}\n\n\n#define WS_EXTINFO_EXTENSION_COUNT 1\nstatic const char serverSigAlgsName[] = \"server-sig-algs\";\n\n\nint SendExtInfo(WOLFSSH* ssh)\n{\n WOLFSSH_UNUSED(ssh);\n return WS_NOT_COMPILED;\n}\n\n\n/* Updates the payload size, and maybe loads keys. */\nstatic int PrepareUserAuthRequestPassword(WOLFSSH* ssh, word32* payloadSz,\n const WS_UserAuthData* authData)\n{\n int ret = WS_SUCCESS;\n\n if (ssh == NULL || payloadSz == NULL || authData == NULL)\n ret = WS_BAD_ARGUMENT;\n\n"
},
{
"old": "int SendChannelEof(WOLFSSH* ssh, word32 peerChannelId)\n{\n byte* output;\n word32 idx;\n int ret = WS_SUCCESS;\n WOLFSSH_CHANNEL* channel = NULL;\n\n WLOG(WS_LOG_DEBUG, \"Entering SendChannelEof()\");\n\n if (ssh == NULL)\n ret = WS_BAD_ARGUMENT;",
"new": "int SendChannelEof(WOLFSSH* ssh, word32 peerChannelId)\n{\n byte* output;\n word32 idx;\n int ret = WS_SUCCESS;\n WOLFSSH_CHANNEL* channel = NULL;\n\n WLOG(WS_LOG_DEBUG, \"Entering SendChannelEof()\");\n\n if (ssh == NULL)\n ret = WS_BAD_ARGUMENT;\n\n if (ret == WS_SUCCESS) {\n if (!IsMessageAllowed(ssh, MSGID_CHANNEL_EOF, WS_MSG_SEND)) {\n ret = WS_MSGID_NOT_ALLOWED_E;\n }\n }"
},
{
"old": " const char* str = \"exit-status\";\n word32 idx;\n word32 strSz = 0;\n int ret = WS_SUCCESS;\n WOLFSSH_CHANNEL* channel = NULL;\n\n WLOG(WS_LOG_DEBUG, \"Entering SendChannelExit(), status = %d\", status);\n\n if (ssh == NULL)\n ret = WS_BAD_ARGUMENT;\n\n if (ret == WS_SUCCESS) {\n channel = ChannelFind(ssh, peerChannelId, WS_CHANNEL_ID_PEER);\n if (channel == NULL)\n ret = WS_INVALID_CHANID;\n }\n\n if (ret == WS_SUCCESS) {\n strSz = (word32)WSTRLEN(str);\n ret = PreparePacket(ssh, MSG_ID_SZ + UINT32_SZ + LENGTH_SZ + strSz +\n BOOLEAN_SZ + UINT32_SZ);\n }\n\n if (ret == WS_SUCCESS) {\n",
"new": " const char* str = \"exit-status\";\n word32 idx;\n word32 strSz = 0;\n int ret = WS_SUCCESS;\n WOLFSSH_CHANNEL* channel = NULL;\n\n WLOG(WS_LOG_DEBUG, \"Entering SendChannelExit(), status = %d\", status);\n\n if (ssh == NULL)\n ret = WS_BAD_ARGUMENT;\n\n if (ret == WS_SUCCESS) {\n if (!IsMessageAllowed(ssh, MSGID_CHANNEL_REQUEST, WS_MSG_SEND)) {\n ret = WS_MSGID_NOT_ALLOWED_E;\n }\n }\n\n if (ret == WS_SUCCESS) {\n channel = ChannelFind(ssh, peerChannelId, WS_CHANNEL_ID_PEER);\n if (channel == NULL)\n ret = WS_INVALID_CHANID;\n }\n\n if (ret == WS_SUCCESS) {\n strSz = (word32)WSTRLEN(str);\n ret = PreparePacket(ssh, MSG_ID_SZ + UINT32_SZ + LENGTH_SZ + strSz +\n BOOLEAN_SZ + UINT32_SZ);\n }\n\n if (ret == WS_SUCCESS) {\n"
},
{
"old": "int SendChannelWindowAdjust(WOLFSSH* ssh, word32 channelId,\n word32 bytesToAdd)\n{\n byte* output;\n word32 idx;\n int ret = WS_SUCCESS;\n WOLFSSH_CHANNEL* channel;\n\n WLOG(WS_LOG_DEBUG, \"Entering SendChannelWindowAdjust()\");\n\n if (ssh == NULL)\n ret = WS_BAD_ARGUMENT;\n\n channel = ChannelFind(ssh, channelId, WS_CHANNEL_ID_SELF);\n if (channel == NULL) {\n WLOG(WS_LOG_DEBUG, \"Invalid channel\");\n ret = WS_INVALID_CHANID;\n }\n if (ret == WS_SUCCESS)\n ret = PreparePacket(ssh, MSG_ID_SZ + (UINT32_SZ * 2));\n\n if (ret == WS_SUCCESS) {\n output = ssh->outputBuffer.buffer;\n idx = ssh->outputBuffer.length;\n",
"new": "int SendChannelWindowAdjust(WOLFSSH* ssh, word32 channelId,\n word32 bytesToAdd)\n{\n byte* output;\n word32 idx;\n int ret = WS_SUCCESS;\n WOLFSSH_CHANNEL* channel;\n\n WLOG(WS_LOG_DEBUG, \"Entering SendChannelWindowAdjust()\");\n\n if (ssh == NULL)\n ret = WS_BAD_ARGUMENT;\n\n if (ret == WS_SUCCESS) {\n if (!IsMessageAllowed(ssh, MSGID_CHANNEL_WINDOW_ADJUST, WS_MSG_SEND)) {\n ret = WS_MSGID_NOT_ALLOWED_E;\n }\n }\n\n channel = ChannelFind(ssh, channelId, WS_CHANNEL_ID_SELF);\n if (channel == NULL) {\n WLOG(WS_LOG_DEBUG, \"Invalid channel\");\n ret = WS_INVALID_CHANID;\n }\n if (ret == WS_SUCCESS)\n ret = PreparePacket(ssh, MSG_ID_SZ + (UINT32_SZ * 2));\n\n if (ret == WS_SUCCESS) {\n output = ssh->outputBuffer.buffer;\n idx = ssh->outputBuffer.length;\n"
},
{
"old": "static const char serverSigAlgsName[] = \"server-sig-algs\";\n",
"new": ""
}
]
},
"src/ssh.c": {
"sha256": "a4f479ff87eea0980ec1ebdf2c7dd090da473780181b695a56799cb9611f4366",
"edits": [
{
"old": " WOLFSSH_BUFFER* inputBuffer;\n\n WLOG(WS_LOG_DEBUG, \"Entering wolfSSH_stream_read()\");\n\n if (ssh == NULL || buf == NULL || bufSz == 0 || ssh->channelList == NULL)\n return WS_BAD_ARGUMENT;\n\n if (ssh->channelList->eofRxd) {\n ssh->error = WS_EOF;\n return WS_ERROR;\n }\n\n inputBuffer = &ssh->channelList->inputBuffer;\n ssh->error = WS_SUCCESS;\n\n if (ret == WS_SUCCESS) {\n WLOG(WS_LOG_DEBUG, \" Stream read index of %u\", inputBuffer->idx);\n WLOG(WS_LOG_DEBUG, \" Stream read ava data %u\", inputBuffer->length);\n while (inputBuffer->length - inputBuffer->idx == 0) {\n WLOG(WS_LOG_DEBUG,\n \"Starting to recieve data at current index of %u\",\n inputBuffer->idx);\n ret = DoReceive(ssh);\n if (ssh->channelList == NULL || ssh->channelList->eofRxd)\n",
"new": " WOLFSSH_BUFFER* inputBuffer;\n\n WLOG(WS_LOG_DEBUG, \"Entering wolfSSH_stream_read()\");\n\n if (ssh == NULL || buf == NULL || bufSz == 0 || ssh->channelList == NULL)\n return WS_BAD_ARGUMENT;\n\n if (ssh->channelList->eofRxd) {\n ssh->error = WS_EOF;\n return WS_ERROR;\n }\n\n if (ssh->isKeying) {\n ssh->error = WS_REKEYING;\n return WS_FATAL_ERROR;\n }\n\n inputBuffer = &ssh->channelList->inputBuffer;\n ssh->error = WS_SUCCESS;\n\n if (ret == WS_SUCCESS) {\n WLOG(WS_LOG_DEBUG, \" Stream read index of %u\", inputBuffer->idx);\n WLOG(WS_LOG_DEBUG, \" Stream read ava data %u\", inputBuffer->length);\n while (inputBuffer->length - inputBuffer->idx == 0) {\n WLOG(WS_LOG_DEBUG,\n \"Starting to recieve data at current index of %u\",\n inputBuffer->idx);\n ret = DoReceive(ssh);\n if (ssh->channelList == NULL || ssh->channelList->eofRxd)\n"
},
{
"old": " if (ssh->lastRxId != ssh->channelList->channel) {\n ret = WS_ERROR;\n break;\n }\n else {\n ret = WS_SUCCESS;\n }\n }\n }\n }\n\n /* update internal input buffer based on data read */\n if (ret == WS_SUCCESS) {\n int n;\n\n n = min(bufSz, inputBuffer->length - inputBuffer->idx);\n if (n <= 0)\n ret = WS_BUFFER_E;\n else {\n WMEMCPY(buf, inputBuffer->buffer + inputBuffer->idx, n);\n ret = _UpdateChannelWindow(ssh->channelList);\n if (ret == WS_SUCCESS) {\n inputBuffer->idx += n;\n ret = n;\n }\n",
"new": " if (ssh->lastRxId != ssh->channelList->channel) {\n ret = WS_ERROR;\n break;\n }\n else {\n ret = WS_SUCCESS;\n }\n }\n }\n }\n\n /* update internal input buffer based on data read */\n if (ret == WS_SUCCESS && !ssh->isKeying) {\n int n;\n\n n = min(bufSz, inputBuffer->length - inputBuffer->idx);\n if (n <= 0)\n ret = WS_BUFFER_E;\n else {\n WMEMCPY(buf, inputBuffer->buffer + inputBuffer->idx, n);\n ret = _UpdateChannelWindow(ssh->channelList);\n if (ret == WS_SUCCESS) {\n inputBuffer->idx += n;\n ret = n;\n }\n"
},
{
"old": "\nint wolfSSH_stream_send(WOLFSSH* ssh, byte* buf, word32 bufSz)\n{\n int bytesTxd = 0;\n\n WLOG(WS_LOG_DEBUG, \"Entering wolfSSH_stream_send()\");\n\n if (ssh == NULL || buf == NULL || ssh->channelList == NULL)\n return WS_BAD_ARGUMENT;\n\n if (ssh->isKeying) {\n ssh->error = WS_REKEYING;\n return WS_REKEYING;\n }\n\n bytesTxd = SendChannelData(ssh, ssh->channelList->channel, buf, bufSz);\n\n WLOG(WS_LOG_DEBUG, \"Leaving wolfSSH_stream_send(), txd = %d\", bytesTxd);\n return bytesTxd;\n}\n\n\nint wolfSSH_ChannelIdSend(WOLFSSH* ssh, word32 channelId,\n byte* buf, word32 bufSz)\n{\n",
"new": "\nint wolfSSH_stream_send(WOLFSSH* ssh, byte* buf, word32 bufSz)\n{\n int bytesTxd = 0;\n\n WLOG(WS_LOG_DEBUG, \"Entering wolfSSH_stream_send()\");\n\n if (ssh == NULL || buf == NULL || ssh->channelList == NULL)\n return WS_BAD_ARGUMENT;\n\n if (ssh->isKeying) {\n ssh->error = WS_REKEYING;\n return WS_FATAL_ERROR;\n }\n\n bytesTxd = SendChannelData(ssh, ssh->channelList->channel, buf, bufSz);\n\n WLOG(WS_LOG_DEBUG, \"Leaving wolfSSH_stream_send(), txd = %d\", bytesTxd);\n return bytesTxd;\n}\n\n\nint wolfSSH_ChannelIdSend(WOLFSSH* ssh, word32 channelId,\n byte* buf, word32 bufSz)\n{\n"
},
{
"old": " return bufSz;\n}\n\n\nint wolfSSH_ChannelRead(WOLFSSH_CHANNEL* channel, byte* buf, word32 bufSz)\n{\n\n WLOG(WS_LOG_DEBUG, \"Entering wolfSSH_ChannelRead()\");\n\n if (channel == NULL || buf == NULL || bufSz == 0)\n return WS_BAD_ARGUMENT;\n\n bufSz = _ChannelRead(channel, buf, bufSz);\n\n WLOG(WS_LOG_DEBUG, \"Leaving wolfSSH_ChannelRead(), bytesRxd = %d\",\n bufSz);\n return bufSz;\n}\n\n\nint wolfSSH_ChannelSend(WOLFSSH_CHANNEL* channel,\n const byte* buf, word32 bufSz)\n{\n int bytesTxd = 0;\n",
"new": " return bufSz;\n}\n\n\nint wolfSSH_ChannelRead(WOLFSSH_CHANNEL* channel, byte* buf, word32 bufSz)\n{\n\n WLOG(WS_LOG_DEBUG, \"Entering wolfSSH_ChannelRead()\");\n\n if (channel == NULL || buf == NULL || bufSz == 0)\n return WS_BAD_ARGUMENT;\n\n if (channel->ssh->isKeying) {\n channel->ssh->error = WS_REKEYING;\n return WS_REKEYING;\n }\n\n bufSz = _ChannelRead(channel, buf, bufSz);\n\n WLOG(WS_LOG_DEBUG, \"Leaving wolfSSH_ChannelRead(), bytesRxd = %d\",\n bufSz);\n return bufSz;\n}\n\n\nint wolfSSH_ChannelSend(WOLFSSH_CHANNEL* channel,\n const byte* buf, word32 bufSz)\n{\n int bytesTxd = 0;\n"
}
]
},
"wolfssh/internal.h": {
"sha256": "8e417149a68f8a6c0506957adf014b3e6c1727a723536826ce5fb0c9e1f1aba3",
"edits": [
{
"old": " #define WOLFSSH_MAX_FILE_SIZE (1024ul * 1024ul * 4)\n#endif\n#ifndef WOLFSSH_MAX_PVT_KEYS\n #define WOLFSSH_MAX_PVT_KEYS 8\n#endif\n#ifndef WOLFSSH_MAX_PUB_KEY_ALGO\n #define WOLFSSH_MAX_PUB_KEY_ALGO (WOLFSSH_MAX_PVT_KEYS + 2)\n#endif\n#ifndef WOLFSSH_KEY_QUANTITY_REQ\n #define WOLFSSH_KEY_QUANTITY_REQ 1\n#endif\n\n\nWOLFSSH_LOCAL byte NameToId(const char* name, word32 nameSz);\nWOLFSSH_LOCAL const char* IdToName(byte id);\nWOLFSSH_LOCAL const char* NameByIndexType(byte type, word32* index);\n\n\n/* For cases when openssl coexist is used */\n#ifdef WC_NO_COMPAT_AES_BLOCK_SIZE\n #define AES_BLOCK_SIZE WC_AES_BLOCK_SIZE\n#endif\n\n#define STATIC_BUFFER_LEN AES_BLOCK_SIZE\n",
"new": " #define WOLFSSH_MAX_FILE_SIZE (1024ul * 1024ul * 4)\n#endif\n#ifndef WOLFSSH_MAX_PVT_KEYS\n #define WOLFSSH_MAX_PVT_KEYS 8\n#endif\n#ifndef WOLFSSH_MAX_PUB_KEY_ALGO\n #define WOLFSSH_MAX_PUB_KEY_ALGO (WOLFSSH_MAX_PVT_KEYS + 2)\n#endif\n#ifndef WOLFSSH_KEY_QUANTITY_REQ\n #define WOLFSSH_KEY_QUANTITY_REQ 1\n#endif\n\n/* Keep track of keying state for both sides of the connection.\n * WOLFSSH_SELF_IS_KEYING gets set on sending KEX init and\n * WOLFSSH_PEER_IS_KEYING gets set on receiving KEX init */\n#define WOLFSSH_PEER_IS_KEYING 0x01\n#define WOLFSSH_SELF_IS_KEYING 0x02\n\nWOLFSSH_LOCAL byte NameToId(const char* name, word32 nameSz);\nWOLFSSH_LOCAL const char* IdToName(byte id);\nWOLFSSH_LOCAL const char* NameByIndexType(byte type, word32* index);\n\n\n/* For cases when openssl coexist is used */\n#ifdef WC_NO_COMPAT_AES_BLOCK_SIZE\n #define AES_BLOCK_SIZE WC_AES_BLOCK_SIZE\n#endif\n\n#define STATIC_BUFFER_LEN AES_BLOCK_SIZE\n"
},
{
"old": "\ntypedef struct Keys {\n byte iv[AES_BLOCK_SIZE];\n byte ivSz;\n byte encKey[AES_256_KEY_SIZE];\n byte encKeySz;\n byte macKey[MAX_HMAC_SZ];\n byte macKeySz;\n} Keys;\n\n\ntypedef struct HandshakeInfo {\n byte kexId;\n byte kexIdGuess;\n byte kexHashId;\n byte pubKeyId;\n byte encryptId;\n byte macId;\n byte kexPacketFollows;\n byte aeadMode;\n\n byte blockSz;\n byte macSz;\n\n",
"new": "\ntypedef struct Keys {\n byte iv[AES_BLOCK_SIZE];\n byte ivSz;\n byte encKey[AES_256_KEY_SIZE];\n byte encKeySz;\n byte macKey[MAX_HMAC_SZ];\n byte macKeySz;\n} Keys;\n\n\ntypedef struct HandshakeInfo {\n byte expectMsgId;\n byte kexId;\n byte kexIdGuess;\n byte kexHashId;\n byte pubKeyId;\n byte encryptId;\n byte macId;\n byte kexPacketFollows;\n byte aeadMode;\n\n byte blockSz;\n byte macSz;\n\n"
},
{
"old": " char* userName;\n word32 userNameSz;\n char* password;\n word32 passwordSz;\n byte* pkBlob;\n word32 pkBlobSz;\n byte* peerProtoId; /* Save for rekey */\n word32 peerProtoIdSz;\n void* publicKeyCheckCtx;\n byte sendTerminalRequest;\n byte userAuthPkDone;\n byte sendExtInfo;\n byte* peerSigId;\n word32 peerSigIdSz;\n\n#ifdef USE_WINDOWS_API\n word32 defaultAttr; /* default windows attributes */\n byte defaultAttrSet;\n byte escBuf[WOLFSSL_MAX_ESCBUF]; /* console codes are about 3 byte and\n * have max arguments of 16 */\n byte escBufSz;\n byte escState; /* current console translation state */\n#endif\n#ifdef WOLFSSH_SFTP\n",
"new": " char* userName;\n word32 userNameSz;\n char* password;\n word32 passwordSz;\n byte* pkBlob;\n word32 pkBlobSz;\n byte* peerProtoId; /* Save for rekey */\n word32 peerProtoIdSz;\n void* publicKeyCheckCtx;\n byte sendTerminalRequest;\n byte userAuthPkDone;\n byte sendExtInfo;\n byte extInfoSent; /* track if the ext info has already been sent */\n byte* peerSigId;\n word32 peerSigIdSz;\n\n#ifdef USE_WINDOWS_API\n word32 defaultAttr; /* default windows attributes */\n byte defaultAttrSet;\n byte escBuf[WOLFSSL_MAX_ESCBUF]; /* console codes are about 3 byte and\n * have max arguments of 16 */\n byte escBufSz;\n byte escState; /* current console translation state */\n#endif\n#ifdef WOLFSSH_SFTP\n"
},
{
"old": "};\n\n\nenum ProcessReplyStates {\n PROCESS_INIT,\n PROCESS_PACKET_LENGTH,\n PROCESS_PACKET_FINISH,\n PROCESS_PACKET\n};\n\n\nenum WS_MessageIds {\n MSGID_DISCONNECT = 1,\n MSGID_IGNORE = 2,\n MSGID_UNIMPLEMENTED = 3,\n MSGID_DEBUG = 4,\n MSGID_SERVICE_REQUEST = 5,\n MSGID_SERVICE_ACCEPT = 6,\n MSGID_EXT_INFO = 7,\n\n MSGID_KEXINIT = 20,\n MSGID_NEWKEYS = 21,\n\n MSGID_KEXDH_INIT = 30,\n",
"new": "};\n\n\nenum ProcessReplyStates {\n PROCESS_INIT,\n PROCESS_PACKET_LENGTH,\n PROCESS_PACKET_FINISH,\n PROCESS_PACKET\n};\n\n\nenum WS_MessageIds {\n MSGID_NONE = 0,\n\n MSGID_DISCONNECT = 1,\n MSGID_IGNORE = 2,\n MSGID_UNIMPLEMENTED = 3,\n MSGID_DEBUG = 4,\n MSGID_SERVICE_REQUEST = 5,\n MSGID_SERVICE_ACCEPT = 6,\n MSGID_EXT_INFO = 7,\n\n MSGID_KEXINIT = 20,\n MSGID_NEWKEYS = 21,\n\n MSGID_KEXDH_INIT = 30,\n"
},
{
"old": " MSGID_CHANNEL_OPEN_FAIL = 92,\n MSGID_CHANNEL_WINDOW_ADJUST = 93,\n MSGID_CHANNEL_DATA = 94,\n MSGID_CHANNEL_EXTENDED_DATA = 95,\n MSGID_CHANNEL_EOF = 96,\n MSGID_CHANNEL_CLOSE = 97,\n MSGID_CHANNEL_REQUEST = 98,\n MSGID_CHANNEL_SUCCESS = 99,\n MSGID_CHANNEL_FAILURE = 100\n};\n\n\n/* Allows the server to receive up to KEXDH GEX Request during KEX. */\n#define MSGID_KEXDH_LIMIT MSGID_KEXDH_GEX_REQUEST\n\n/* The endpoints should not allow message IDs greater than or\n * equal to msgid 80 before user authentication is complete.\n * Per RFC 4252 section 6. */\n#define MSGID_USERAUTH_LIMIT 80\n\n/* The client should only send the user auth request message\n * (50), it should not accept it. The server should only receive\n * the user auth request message, it should not accept the other\n * user auth messages, it sends them. (>50) */\n#define MSGID_USERAUTH_RESTRICT 50\n\n\n#define CHANNEL_EXTENDED_DATA_STDERR WOLFSSH_EXT_DATA_STDERR\n\n\n/* dynamic memory types */\nenum WS_DynamicTypes {\n DYNTYPE_STRING = 500,\n DYNTYPE_CTX,\n DYNTYPE_SSH,\n DYNTYPE_CHANNEL,\n DYNTYPE_BUFFER,\n DYNTYPE_ID,\n DYNTYPE_HS,\n DYNTYPE_CA,\n DYNTYPE_CERT,\n",
"new": " MSGID_CHANNEL_OPEN_FAIL = 92,\n MSGID_CHANNEL_WINDOW_ADJUST = 93,\n MSGID_CHANNEL_DATA = 94,\n MSGID_CHANNEL_EXTENDED_DATA = 95,\n MSGID_CHANNEL_EOF = 96,\n MSGID_CHANNEL_CLOSE = 97,\n MSGID_CHANNEL_REQUEST = 98,\n MSGID_CHANNEL_SUCCESS = 99,\n MSGID_CHANNEL_FAILURE = 100\n};\n\n\n/* The following message ID ranges are described in RFC 5251, section 7. */\nenum WS_MessageIdLimits {\n/* Transport Layer Protocol: */\n MSGIDLIMIT_TRANS_MIN = 1,\n MSGIDLIMIT_TRANS_GEN_MIN = 1,\n MSGIDLIMIT_TRANS_GEN_MAX = 19,\n MSGIDLIMIT_TRANS_ALGO_MIN = 20,\n MSGIDLIMIT_TRANS_ALGO_MAX = 29,\n MSGIDLIMIT_TRANS_KEX_MIN = 30,\n MSGIDLIMIT_TRANS_KEX_MAX = 49,\n MSGIDLIMIT_TRANS_MAX = 49,\n/* User Authentication Protocol: */\n MSGIDLIMIT_AUTH_MIN = 50,\n MSGIDLIMIT_AUTH_GEN_MIN = 50,\n MSGIDLIMIT_AUTH_GEN_MAX = 59,\n MSGIDLIMIT_AUTH_METH_MIN = 60,\n MSGIDLIMIT_AUTH_METH_MAX = 79,\n MSGIDLIMIT_AUTH_MAX = 79,\n/* Connection Protocol: */\n MSGIDLIMIT_CONN_MIN = 80,\n MSGIDLIMIT_CONN_GEN_MIN = 80,\n MSGIDLIMIT_CONN_GEN_MAX = 89,\n MSGIDLIMIT_CONN_CHAN_MIN = 90,\n MSGIDLIMIT_CONN_CHAN_MAX = 127,\n MSGIDLIMIT_CONN_MAX = 127,\n/* Reserved For Client Protocols: */\n MSGIDLIMIT_RESERVED_MIN = 128,\n MSGIDLIMIT_RESERVED_MAX = 191,\n/* Local Extensions: */\n MSGIDLIMIT_EXTENDED_MIN = 192,\n MSGIDLIMIT_EXTENDED_MAX = 255,\n};\n\n/* Message ID bounds checking. */\n#define MSGIDLIMIT_BOUND(x,y,z) ((x) >= (y) && (x) <= (z))\n#define MSGIDLIMIT_COMP(x,name) \\\n MSGIDLIMIT_BOUND((x),MSGIDLIMIT_##name##_MIN,MSGIDLIMIT_##name##_MAX)\n#define MSGIDLIMIT_TRANS(x) MSGIDLIMIT_COMP((x),TRANS)\n#define MSGIDLIMIT_TRANS_GEN(x) MSGIDLIMIT_COMP((x),TRANS_GEN)\n#define MSGIDLIMIT_TRANS_ALGO(x) MSGIDLIMIT_COMP((x),TRANS_ALGO)\n#define MSGIDLIMIT_TRANS_KEX(x) MSGIDLIMIT_COMP((x),TRANS_KEX)\n#define MSGIDLIMIT_AUTH(x) MSGIDLIMIT_COMP((x),AUTH)\n#define MSGIDLIMIT_AUTH_GEN(x) MSGIDLIMIT_COMP((x),AUTH_GEN)\n#define MSGIDLIMIT_AUTH_METH(x) MSGIDLIMIT_COMP((x),AUTH_METH)\n#define MSGIDLIMIT_CONN(x) MSGIDLIMIT_COMP((x),CONN)\n#define MSGIDLIMIT_CONN_GEN(x) MSGIDLIMIT_COMP((x),CONN_GEN)\n#define MSGIDLIMIT_CONN_CHAN(x) MSGIDLIMIT_COMP((x),CONN_CHAN)\n#define MSGIDLIMIT_RESERVED(x) MSGIDLIMIT_COMP((x),RESERVED)\n#define MSGIDLIMIT_EXTENDED(x) MSGIDLIMIT_COMP((x),EXTENDED)\n#define MSGIDLIMIT_POST_USERAUTH(x) ((x) >= MSGIDLIMIT_CONN_MIN)\n\n\n#define CHANNEL_EXTENDED_DATA_STDERR WOLFSSH_EXT_DATA_STDERR\n\n/* Used when checking IsMessageAllowed() to determine if creating and sending\n * the message or receiving the message is allowed */\n#define WS_MSG_SEND 1\n#define WS_MSG_RECV 2\n\n/* dynamic memory types */\nenum WS_DynamicTypes {\n DYNTYPE_STRING = 500,\n DYNTYPE_CTX,\n DYNTYPE_SSH,\n DYNTYPE_CHANNEL,\n DYNTYPE_BUFFER,\n DYNTYPE_ID,\n DYNTYPE_HS,\n DYNTYPE_CA,\n DYNTYPE_CERT,\n"
},
{
"old": "\n\n#define WOLFSSL_V5_0_0 0x05000000\n#define WOLFSSL_V5_7_0 0x05007000\n#define WOLFSSL_V5_7_2 0x05007002\n\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif /* _WOLFSSH_INTERNAL_H_ */\n\n",
"new": "\n\n#define WOLFSSL_V5_0_0 0x05000000\n#define WOLFSSL_V5_7_0 0x05007000\n#define WOLFSSL_V5_7_2 0x05007002\n\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif /* _WOLFSSH_INTERNAL_H_ */\n"
}
]
}
}
+51
View File
@@ -0,0 +1,51 @@
{
"793": {
"url": "https://patch-diff.githubusercontent.com/raw/wolfSSL/wolfssh/pull/793.patch",
"sha256": "66aa999521800371f97b340db2bff162be4e8ffab4b4b953f9d32b8e33f56cea",
"commits": [
"5fa6c0fce30a421879b355a007ef843eb48332d3",
"af45bc3719ddeac112d9d70b2e6a969f1aa3f3e7",
"d74c942c84d44fb46d3a10cb56233b704733e466",
"ff95f3c3029d766b114a91d98b013e0a1636a6c1",
"2a11471bb717a2ee6f06b3e1beab8a3e2b0ef261",
"813ec263cc56e7c9093135d854b3fc887633d368",
"cc17941a6125daefbadb8c236fdeaeb1a21ec786",
"4862400a374253216e596ff5c3b018b857015cbb"
]
},
"819": {
"url": "https://patch-diff.githubusercontent.com/raw/wolfSSL/wolfssh/pull/819.patch",
"sha256": "8e63c2b24679a7d831f7dba12e412d2f8a7fdc391fc4e8fd33f029487110219b",
"commits": [
"201029797b260eee894b12d488bce6022290bf67"
]
},
"840": {
"url": "https://patch-diff.githubusercontent.com/raw/wolfSSL/wolfssh/pull/840.patch",
"sha256": "23e25873cb4dfa36063357111019e0960dfc008a68cc29d6e2d5c37bde47ec94",
"commits": [
"9dc1071da7e560db2ea899fa23aab885a25ea862",
"024b14124aa2434e90468408b94121c897311f37"
]
},
"855": {
"url": "https://patch-diff.githubusercontent.com/raw/wolfSSL/wolfssh/pull/855.patch",
"sha256": "b94393df9528f66f6df1aba94015331fee3110c9ea2007a0eff369d8887b4b29",
"commits": [
"73b165651c80a20047d913d32b0ffac47cb99ef6",
"a87ab400b3900d1e7fdda33c898094d6e3ada21d",
"5ae5c250e2d9b3bfdaea4f9c73cdf4b9f2592daa",
"dee1c59f263220ecd05a88a72da104c22bef0598",
"2e5484f36f279484ca06e02ef34ddd420fc0cf87",
"03ca9221a36a2a7160a99aeee7bc7ea8368013b5",
"2086f34ff37911a1fa388f843ee9d336e740bf44"
]
},
"921": {
"url": "https://patch-diff.githubusercontent.com/raw/wolfSSL/wolfssh/pull/921.patch",
"sha256": "f6c88598d7f3c94d92c31cecc4ef1e6d779b49f9eff6556ac1c57426d272d504",
"commits": [
"e9d288ec603531a1d544e77fb1bbdf634cb2a57f"
]
}
}