Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
d840f84
F-4582 - Use WOLFSSH_ prefix for default logging callback opt-out
aidangarske Jul 10, 2026
7600be0
F-6268 - Fix Windows SFTP GET resume check to test gOfst elements
aidangarske Jul 10, 2026
5c46814
F-4592 - Bound agent FindKeyId keyBlob compare by stored length
aidangarske Jul 10, 2026
ecebe61
F-6693 - Reject zero-length agent message payload in DoMessage
aidangarske Jul 10, 2026
818d119
F-2082 - Zeroize agent private key buffer with ForceZero before free
aidangarske Jul 10, 2026
48cd39e
F-6694 - Return error instead of hanging in AGENT_worker on NULL ssh
aidangarske Jul 10, 2026
9896f5d
F-3881 - Reserve separator and NUL in RealPath segment bound check
aidangarske Jul 10, 2026
d52f978
F-5852 - Only treat /.. as parent traversal in CleanPath
aidangarske Jul 10, 2026
8960fe2
F-4795 - Guard ClientPublicKeyCheck against short public key blob
aidangarske Jul 10, 2026
c6df30e
F-3210 - Null-check command allocation in client argument parsing
aidangarske Jul 10, 2026
d91c3aa
F-4583 - Remove vestigial zero-length read in echoserver global_req
aidangarske Jul 10, 2026
f595a1e
F-3446 - Bound default password copy to userPassword buffer size
aidangarske Jul 10, 2026
3900ae6
F-1278 - Zeroize ML-KEM client private key after decapsulation
aidangarske Jul 10, 2026
14d86c2
F-3453 - Free and zeroize host key DER on key-count error path
aidangarske Jul 10, 2026
4304fee
F-6277 - Zeroize SFTP GET and PUT file buffers before freeing state
aidangarske Jul 10, 2026
218030e
F-4794 - Bound CSI control sequence read and reset escape state
aidangarske Jul 10, 2026
6dbe879
F-4106 - Write only the newline byte to console, not the NUL
aidangarske Jul 10, 2026
77f9314
F-4105 - Write only bytes read to Windows stdout handle
aidangarske Jul 10, 2026
7628e84
F-4108 - Build full path and check lstat return in QNX Include scan
aidangarske Jul 10, 2026
edb1bf7
F-5900 - Require SHA-256+ signature algorithm in FPKI CheckProfile
aidangarske Jul 10, 2026
5c11893
F-6698 - Bound SFTP handle length against received packet size
aidangarske Jul 10, 2026
fc89265
F-6703 - Add AES-GCM tamper rejection test for DoReceive
aidangarske Jul 10, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 8 additions & 3 deletions apps/wolfssh/common.c
Original file line number Diff line number Diff line change
Expand Up @@ -392,11 +392,16 @@ int ClientPublicKeyCheck(const byte* pubKey, word32 pubKeySz, void* ctx)
fp[0] = 0;

/* Get the key type out of the key. */
ato32(pubKey, &sz);
if ((sz > pubKeySz - sizeof(word32))
|| (sz > WOLFSSH_CLIENT_PUBKEYTYPE_SIZE_ESTIMATE - 1)) {
if (pubKeySz < sizeof(word32)) {
ret = -1;
}
else {
ato32(pubKey, &sz);
if ((sz > pubKeySz - sizeof(word32))
|| (sz > WOLFSSH_CLIENT_PUBKEYTYPE_SIZE_ESTIMATE - 1)) {
ret = -1;
}
}
}

if (ret == 0) {
Expand Down
6 changes: 5 additions & 1 deletion apps/wolfssh/wolfssh.c
Original file line number Diff line number Diff line change
Expand Up @@ -563,7 +563,7 @@ static THREAD_RET readPeer(void* in)
buf[bufSz - 1] = '\0';

#ifdef USE_WINDOWS_API
if (WriteFile(stdoutHandle, buf, bufSz, &writtn, NULL) == FALSE) {
if (WriteFile(stdoutHandle, buf, (DWORD)ret, &writtn, NULL) == FALSE) {
err_sys("Failed to write to stdout handle");
}
#else
Expand Down Expand Up @@ -857,6 +857,10 @@ static int config_parse_command_line(struct config* config,
}

command = (char*)WMALLOC(commandSz, NULL, 0);
if (command == NULL) {
fprintf(stderr, "Couldn't capture the command.\n");
exit(EXIT_FAILURE);
}
config->command = command;
cursor = command;

Expand Down
16 changes: 12 additions & 4 deletions apps/wolfsshd/configuration.c
Original file line number Diff line number Diff line change
Expand Up @@ -787,9 +787,13 @@ static int HandleInclude(WOLFSSHD_CONFIG *conf, const char *value, int depth)
/* Skip sub-directories */
#if defined(__QNX__) || defined(__QNXNTO__)
struct stat s;
int pathLen;

lstat(dir->d_name, &s);
if (!S_ISDIR(s.st_mode))
pathLen = WSNPRINTF(filepath, PATH_MAX, "%s/%s",
path, dir->d_name);
if (pathLen > 0 && pathLen < PATH_MAX &&
lstat(filepath, &s) == 0 &&
!S_ISDIR(s.st_mode))
#else
if (dir->d_type != DT_DIR)
#endif
Expand Down Expand Up @@ -819,9 +823,13 @@ static int HandleInclude(WOLFSSHD_CONFIG *conf, const char *value, int depth)
/* Skip sub-directories */
#if defined(__QNX__) || defined(__QNXNTO__)
struct stat s;
int pathLen;

lstat(dir->d_name, &s);
if (!S_ISDIR(s.st_mode))
pathLen = WSNPRINTF(filepath, PATH_MAX, "%s/%s",
path, dir->d_name);
if (pathLen > 0 && pathLen < PATH_MAX &&
lstat(filepath, &s) == 0 &&
!S_ISDIR(s.st_mode))
#else
if (dir->d_type != DT_DIR)
#endif
Expand Down
2 changes: 1 addition & 1 deletion examples/client/client.c
Original file line number Diff line number Diff line change
Expand Up @@ -546,7 +546,7 @@ static THREAD_RET readPeer(void* in)
buf[bufSz - 1] = '\0';

#ifdef USE_WINDOWS_API
if (WriteFile(stdoutHandle, buf, bufSz, &writtn, NULL) == FALSE) {
if (WriteFile(stdoutHandle, buf, (DWORD)ret, &writtn, NULL) == FALSE) {
err_sys("Failed to write to stdout handle");
}
#else
Expand Down
2 changes: 2 additions & 0 deletions examples/client/common.c
Original file line number Diff line number Diff line change
Expand Up @@ -519,6 +519,8 @@ int ClientUserAuth(byte authType,
else if (authType == WOLFSSH_USERAUTH_PASSWORD) {
if (defaultPassword != NULL) {
passwordSz = (word32)strlen(defaultPassword);
if (passwordSz > (word32)sizeof(userPassword))
passwordSz = (word32)sizeof(userPassword);
memcpy(userPassword, defaultPassword, passwordSz);
}
#ifdef WOLFSSH_TERM
Expand Down
9 changes: 0 additions & 9 deletions examples/echoserver/echoserver.c
Original file line number Diff line number Diff line change
Expand Up @@ -299,7 +299,6 @@ static void *global_req(void *ctx)
int ret;
const char str[] = "SampleRequest";
thread_ctx_t *threadCtx = (thread_ctx_t *)ctx;
byte buf[0];

wolfSSH_SetReqSuccess(threadCtx->ctx, callbackReqSuccess);
wolfSSH_SetReqSuccessCtx(threadCtx->ssh, &threadCtx->ssh); /* dummy ctx */
Expand All @@ -318,14 +317,6 @@ static void *global_req(void *ctx)
wolfSSH_shutdown(threadCtx->ssh);
return NULL;
}

wolfSSH_stream_read(threadCtx->ssh, buf, 0);
if (ret != WS_SUCCESS)
{
printf("wolfSSH_stream_read Failed.\n");
wolfSSH_shutdown(threadCtx->ssh);
return NULL;
}
}
return NULL;
}
Expand Down
2 changes: 2 additions & 0 deletions examples/portfwd/portfwd.c
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,8 @@ static int wsUserAuth(byte authType,
(void)authType;
if (defaultPassword != NULL) {
passwordSz = (word32)strlen(defaultPassword);
if (passwordSz > (word32)sizeof(userPassword))
passwordSz = (word32)sizeof(userPassword);
memcpy(userPassword, defaultPassword, passwordSz);
}
else {
Expand Down
18 changes: 8 additions & 10 deletions src/agent.c
Original file line number Diff line number Diff line change
Expand Up @@ -687,6 +687,7 @@ static WOLFSSH_AGENT_ID* FindKeyId(WOLFSSH_AGENT_ID* id,
wc_Sha256Free(&sha);

if (ret == WS_SUCCESS) {
/* only compare equal-length blobs to avoid an over-read */
while (id != NULL &&
WMEMCMP(digest, id->id, WC_SHA256_DIGEST_SIZE) != 0 &&
(id->keyBlobSz != keyBlobSz ||
Expand Down Expand Up @@ -1406,7 +1407,8 @@ static int DoMessage(WOLFSSH_AGENT_CTX* agent,
ato32(buf + begin, &payloadSz);
WLOG(WS_LOG_AGENT, "payloadSz = %u", payloadSz);
begin += LENGTH_SZ;
if (payloadSz > len - begin) {
/* reject 0: payloadSz - 1 is used as a length below */
if (payloadSz == 0 || payloadSz > len - begin) {
ret = WS_OVERFLOW_E;
}
}
Expand Down Expand Up @@ -1602,7 +1604,7 @@ void wolfSSH_AGENT_ID_free(WOLFSSH_AGENT_ID* id, void* heap)

if (id != NULL) {
if (id->keyBuffer != NULL) {
WMEMSET(id->keyBuffer, 0, id->keyBufferSz);
WS_FORCEZERO(id->keyBuffer, id->keyBufferSz);
WFREE(id->keyBuffer, heap, DYNTYPE_STRING);
}
WMEMSET(id, 0, sizeof(WOLFSSH_AGENT_ID));
Expand Down Expand Up @@ -1702,14 +1704,10 @@ int wolfSSH_AGENT_worker(WOLFSSH* ssh)
if (ssh == NULL)
ret = WS_SSH_NULL_E;

while (1) {
if (ret == WS_SUCCESS) {

SendSuccess(NULL);
DoMessage(NULL, NULL, 0, NULL);
ssh->agent->state = AGENT_STATE_DONE;
break;
}
if (ret == WS_SUCCESS) {
SendSuccess(NULL);
DoMessage(NULL, NULL, 0, NULL);
ssh->agent->state = AGENT_STATE_DONE;
}

WLOG_LEAVE(ret);
Expand Down
12 changes: 12 additions & 0 deletions src/certman.c
Original file line number Diff line number Diff line change
Expand Up @@ -562,6 +562,18 @@ static int CheckProfile(DecodedCert* cert, int profile)
}
}

if (valid) {
valid =
cert->signatureOID == CTC_SHA256wRSA ||
cert->signatureOID == CTC_SHA384wRSA ||
cert->signatureOID == CTC_SHA512wRSA ||
cert->signatureOID == CTC_SHA256wECDSA ||
cert->signatureOID == CTC_SHA384wECDSA ||
cert->signatureOID == CTC_SHA512wECDSA;
if (valid != 1)
WLOG(WS_LOG_CERTMAN, "cert signature algorithm not FPKI approved");
}

#ifdef DEBUG_WOLFSSH
switch (profile) {
case PROFILE_FPKI_WORKSHEET_6:
Expand Down
10 changes: 8 additions & 2 deletions src/internal.c
Original file line number Diff line number Diff line change
Expand Up @@ -2794,6 +2794,9 @@ static int SetHostPrivateKey(WOLFSSH_CTX* ctx,
}

if (destIdx >= WOLFSSH_MAX_PVT_KEYS) {
/* der not taken on this path; free it to avoid a leak */
WS_FORCEZERO(der, derSz);
WFREE(der, ctx->heap, dynamicType);
ret = WS_CTX_KEY_COUNT_E;
}
else {
Expand Down Expand Up @@ -6678,6 +6681,8 @@ static int KeyAgreeEcdhMlKem_client(WOLFSSH* ssh, byte hashId,

wc_MlKemKey_Free(&kem);

WS_FORCEZERO(ssh->handshake->x, ssh->handshake->xSz);

/* Replace the concatenated shared secrets with the hash. That
* will become the new shared secret. */
if (ret == 0) {
Expand Down Expand Up @@ -19885,8 +19890,9 @@ int wolfSSH_CleanPath(WOLFSSH* ssh, char* in, int inSz)
if (path[i] == WS_DELIM) {
int z;

/* if next two chars are .. then delete */
if (path[i+1] == '.' && path[i+2] == '.') {
/* delete only a real ".." segment, not "..name" */
if (path[i+1] == '.' && path[i+2] == '.' &&
(path[i+3] == WS_DELIM || path[i+3] == '\0')) {
enIdx = i + 3;

/* start at one char before / and retrace path */
Expand Down
2 changes: 1 addition & 1 deletion src/log.c
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@
#endif


#ifndef WOLFSSL_NO_DEFAULT_LOGGING_CB
#ifndef WOLFSSH_NO_DEFAULT_LOGGING_CB
static void DefaultLoggingCb(enum wolfSSH_LogLevel level,
const char *const msgStr);
static wolfSSH_LoggingCb logFunction = DefaultLoggingCb;
Expand Down
10 changes: 8 additions & 2 deletions src/wolfsftp.c
Original file line number Diff line number Diff line change
Expand Up @@ -850,6 +850,7 @@ static void wolfSSH_SFTP_ClearState(WOLFSSH* ssh, enum WS_SFTP_STATE_ID state)

if (state & STATE_ID_GET) {
if (ssh->getState) {
WS_FORCEZERO(ssh->getState->r, WOLFSSH_MAX_SFTP_RW);
WFREE(ssh->getState, ssh->ctx->heap, DYNTYPE_SFTP_STATE);
ssh->getState = NULL;
}
Expand Down Expand Up @@ -928,6 +929,7 @@ static void wolfSSH_SFTP_ClearState(WOLFSSH* ssh, enum WS_SFTP_STATE_ID state)

if (state & STATE_ID_PUT) {
if (ssh->putState) {
WS_FORCEZERO(ssh->putState->r, WOLFSSH_MAX_SFTP_RW);
WFREE(ssh->putState, ssh->ctx->heap, DYNTYPE_SFTP_STATE);
ssh->putState = NULL;
}
Expand Down Expand Up @@ -7278,7 +7280,9 @@ static int wolfSSH_SFTP_GetHandle(WOLFSSH* ssh, byte* handle, word32* handleSz)
* max size */
wolfSSH_SFTP_buffer_rewind(&state->buffer);
if (wolfSSH_SFTP_buffer_ato32(&state->buffer, &sz) != WS_SUCCESS
|| sz > WOLFSSH_MAX_HANDLE || *handleSz < sz) {
|| sz > WOLFSSH_MAX_HANDLE || *handleSz < sz
|| UINT32_SZ + sz
> wolfSSH_SFTP_buffer_size(&state->buffer)) {
WLOG(WS_LOG_SFTP, "Handle size found was too big");
WLOG(WS_LOG_SFTP, "Check size set in input handleSz");
ssh->error = WS_BUFFER_E;
Expand Down Expand Up @@ -9654,7 +9658,7 @@ int wolfSSH_SFTP_Get(WOLFSSH* ssh, char* from,
#elif defined(USE_WINDOWS_API)
{
DWORD desiredAccess = GENERIC_WRITE;
if (state->gOfst > 0)
if (state->gOfst[0] > 0 || state->gOfst[1] > 0)
desiredAccess |= FILE_APPEND_DATA;
state->fileHandle = WS_CreateFileA(to, desiredAccess,
(FILE_SHARE_DELETE | FILE_SHARE_READ |
Expand Down Expand Up @@ -9777,6 +9781,7 @@ int wolfSSH_SFTP_Get(WOLFSSH* ssh, char* from,
case STATE_GET_CLEANUP:
WLOG(WS_LOG_SFTP, "SFTP GET STATE: CLEANUP");
if (ssh->getState != NULL) {
WS_FORCEZERO(ssh->getState->r, WOLFSSH_MAX_SFTP_RW);
WFREE(ssh->getState, ssh->ctx->heap, DYNTYPE_SFTP_STATE);
ssh->getState = NULL;
}
Expand Down Expand Up @@ -10000,6 +10005,7 @@ int wolfSSH_SFTP_Put(WOLFSSH* ssh, char* from, char* to, byte resume,
case STATE_PUT_CLEANUP:
WLOG(WS_LOG_SFTP, "SFTP PUT STATE: CLEANUP");
if (ssh->putState != NULL) {
WS_FORCEZERO(ssh->putState->r, WOLFSSH_MAX_SFTP_RW);
WFREE(ssh->putState, ssh->ctx->heap, DYNTYPE_SFTP_STATE);
ssh->putState = NULL;
}
Expand Down
14 changes: 12 additions & 2 deletions src/wolfterm.c
Original file line number Diff line number Diff line change
Expand Up @@ -473,6 +473,15 @@ static int wolfSSH_DoControlSeq(WOLFSSH* ssh, WOLFSSH_HANDLE handle, byte* buf,
}
else {
numArgs = getArgs(buf, bufSz, &i, args);
if (i >= bufSz) {
/* save left overs for next call */
if (bufSz - *idx > WOLFSSL_MAX_ESCBUF) {
return WS_FATAL_ERROR;
}
WMEMCPY(ssh->escBuf, buf + *idx, bufSz - *idx);
ssh->escBufSz = bufSz - *idx;
return WS_WANT_READ;
}
c = buf[i]; i++;
}
}
Expand Down Expand Up @@ -669,6 +678,7 @@ int wolfSSH_ConvertConsole(WOLFSSH* ssh, WOLFSSH_HANDLE handle, byte* buf,
if (ret == WS_WANT_READ) {
return ret;
}
ssh->escState = WC_ESC_NONE;
ssh->escBufSz = 0;
break;

Expand Down Expand Up @@ -737,15 +747,15 @@ int wolfSSH_ConvertConsole(WOLFSSH* ssh, WOLFSSH_HANDLE handle, byte* buf,

case 'D':
/* linefeed */
if (WS_WRITECONSOLE(handle, "\n", sizeof("\n"), &wrt, NULL)
if (WS_WRITECONSOLE(handle, "\n", 1, &wrt, NULL)
== 0) {
WLOG(WS_LOG_DEBUG, "Error writing newline to handle");
return WS_FATAL_ERROR;
}
break;

case 'E': /* newline */
if (WS_WRITECONSOLE(handle, "\n", sizeof("\n"), &wrt, NULL)
if (WS_WRITECONSOLE(handle, "\n", 1, &wrt, NULL)
== 0) {
WLOG(WS_LOG_DEBUG, "Error writing newline to handle");
return WS_FATAL_ERROR;
Expand Down
2 changes: 2 additions & 0 deletions tests/api.c
Original file line number Diff line number Diff line change
Expand Up @@ -3390,6 +3390,8 @@ struct RealPathTestFailCase realPathFail[] = {
{ "12345678", "12345678", 8, WS_INVALID_PATH_E },
/* Copy segment will not fit in output. */
{ "1234567", "12345678", 8, WS_INVALID_PATH_E },
/* Separator plus segment must leave room for the NUL. */
{ NULL, "aaa/bbb", 8, WS_INVALID_PATH_E },
};

static void DoRealPathTestFailCase(struct RealPathTestFailCase* tc)
Expand Down
Loading
Loading