Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
cba26eb
F-4582 - Use WOLFSSH_ prefix for default logging callback opt-out
aidangarske Jul 10, 2026
d0c911d
F-2869 - Raise default DH-GEX client minimum to 2048 bits
aidangarske Jul 10, 2026
927760b
F-6268 - Fix Windows SFTP GET resume check to test gOfst elements
aidangarske Jul 10, 2026
fbe0cd9
F-4592 - Bound agent FindKeyId keyBlob compare by stored length
aidangarske Jul 10, 2026
078f0af
F-6693 - Reject zero-length agent message payload in DoMessage
aidangarske Jul 10, 2026
b93fc3d
F-1684 - Do not log agent passphrase and zeroize it after use
aidangarske Jul 10, 2026
43d5853
F-2082 - Zeroize agent private key buffer with ForceZero before free
aidangarske Jul 10, 2026
7f065e2
F-6694 - Return error instead of hanging in AGENT_worker on NULL ssh
aidangarske Jul 10, 2026
5b0a8f6
F-3881 - Reserve separator and NUL in RealPath segment bound check
aidangarske Jul 10, 2026
6c4a0e1
F-5852 - Only treat /.. as parent traversal in CleanPath
aidangarske Jul 10, 2026
1cfa165
F-4795 - Guard ClientPublicKeyCheck against short public key blob
aidangarske Jul 10, 2026
32ac265
F-3210 - Null-check command allocation in client argument parsing
aidangarske Jul 10, 2026
9dfe1dc
F-4583 - Remove vestigial zero-length read in echoserver global_req
aidangarske Jul 10, 2026
80d90e7
F-3446 - Bound default password copy to userPassword buffer size
aidangarske Jul 10, 2026
40e5365
F-1278 - Zeroize ML-KEM client private key after decapsulation
aidangarske Jul 10, 2026
92bfa1f
F-3453 - Free and zeroize host key DER on key-count error path
aidangarske Jul 10, 2026
c22e219
F-6277 - Zeroize SFTP GET and PUT file buffers before freeing state
aidangarske Jul 10, 2026
b57aac8
F-4794 - Bound CSI control sequence read and reset escape state
aidangarske Jul 10, 2026
9a162b9
F-4106 - Write only the newline byte to console, not the NUL
aidangarske Jul 10, 2026
5be8990
F-4105 - Write only bytes read to Windows stdout handle
aidangarske Jul 10, 2026
8c411f4
F-4108 - Build full path and check lstat return in QNX Include scan
aidangarske Jul 10, 2026
1ea8ed2
F-5900 - Require SHA-256+ signature algorithm in FPKI CheckProfile
aidangarske Jul 10, 2026
790dfb4
F-6698 - Bound SFTP handle length against received packet size
aidangarske Jul 10, 2026
b99e75c
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
27 changes: 14 additions & 13 deletions src/agent.c
Original file line number Diff line number Diff line change
Expand Up @@ -383,7 +383,8 @@ static int PostLock(WOLFSSH_AGENT_CTX* agent,

WMEMCPY(pp, passphrase, ppSz);
pp[ppSz] = 0;
WLOG(WS_LOG_AGENT, "Locking with passphrase '%s'", pp);
WLOG(WS_LOG_AGENT, "Locking with passphrase");
ForceZero(pp, sizeof(pp));

return WS_SUCCESS;
}
Expand All @@ -406,7 +407,8 @@ static int PostUnlock(WOLFSSH_AGENT_CTX* agent,

WMEMCPY(pp, passphrase, ppSz);
pp[ppSz] = 0;
WLOG(WS_LOG_AGENT, "Unlocking with passphrase '%s'", pp);
WLOG(WS_LOG_AGENT, "Unlocking with passphrase");
ForceZero(pp, sizeof(pp));

return WS_SUCCESS;
}
Expand Down Expand Up @@ -670,9 +672,11 @@ 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 &&
WMEMCMP(keyBlob, id->keyBlob, keyBlobSz)) {
(keyBlobSz != id->keyBlobSz ||
WMEMCMP(keyBlob, id->keyBlob, keyBlobSz) != 0)) {
id = id->next;
}
}
Expand Down Expand Up @@ -1386,7 +1390,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 @@ -1582,7 +1587,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);
ForceZero(id->keyBuffer, id->keyBufferSz);
WFREE(id->keyBuffer, heap, DYNTYPE_STRING);
}
WMEMSET(id, 0, sizeof(WOLFSSH_AGENT_ID));
Expand Down Expand Up @@ -1682,14 +1687,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 @@ -560,6 +560,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 */
ForceZero(der, derSz);
WFREE(der, ctx->heap, dynamicType);
ret = WS_CTX_KEY_COUNT_E;
}
else {
Expand Down Expand Up @@ -6666,6 +6669,8 @@ static int KeyAgreeEcdhMlKem_client(WOLFSSH* ssh, byte hashId,

wc_MlKemKey_Free(&kem);

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 @@ -19705,8 +19710,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
13 changes: 7 additions & 6 deletions src/ssh.c
Original file line number Diff line number Diff line change
Expand Up @@ -3835,15 +3835,16 @@ int wolfSSH_RealPath(const char* defaultPath, char* in,
}
/* Everything else is copied */
else {
if (curSz >= outSz - segSz) {
return WS_INVALID_PATH_E;
}

/* WSTRNCAT size arg is the whole buffer; NULL if seg won't fit */
if (curSz != 1) {
WSTRNCAT(out, "/", outSz - curSz);
if (WSTRNCAT(out, "/", outSz) == NULL) {
return WS_INVALID_PATH_E;
}
curSz++;
}
WSTRNCAT(out, seg, outSz - curSz);
if (WSTRNCAT(out, seg, outSz) == NULL) {
return WS_INVALID_PATH_E;
}
curSz += segSz;
}
}
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) {
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) {
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 @@ -9652,7 +9656,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 @@ -9775,6 +9779,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) {
ForceZero(ssh->getState->r, WOLFSSH_MAX_SFTP_RW);
WFREE(ssh->getState, ssh->ctx->heap, DYNTYPE_SFTP_STATE);
ssh->getState = NULL;
}
Expand Down Expand Up @@ -9998,6 +10003,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) {
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 @@ -3336,6 +3336,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