Merge pull request #845 from LinuxJedi/zp-fixes

Fix issues found using ZeroPath
pull/848/head
JacobBarthelmeh 2025-10-23 09:56:32 -06:00 committed by GitHub
commit 2d2c1f5ac5
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 294 additions and 17 deletions

View File

@ -1340,6 +1340,8 @@ static int DoMessage(WOLFSSH_AGENT_CTX* agent,
if (agent == NULL)
ret = WS_SSH_NULL_E; /* WS_AGENT_NULL_E */
else
agent->lastMsgId = 0;
if (ret == WS_SUCCESS) {
if (buf == NULL || idx == NULL || len == 0)
@ -1371,6 +1373,7 @@ static int DoMessage(WOLFSSH_AGENT_CTX* agent,
if (ret == WS_SUCCESS) {
msg = buf[begin++];
agent->lastMsgId = msg;
payloadIdx = 0;
switch (msg) {
case MSGID_AGENT_FAILURE:
@ -1793,6 +1796,11 @@ int wolfSSH_AGENT_SignRequest(WOLFSSH* ssh,
if (ret == WS_SUCCESS) {
agent = ssh->agent;
agent->requestFailure = 0;
agent->requestSuccess = 0;
agent->msg = NULL;
agent->msgSz = 0;
agent->lastMsgId = 0;
if (ssh->ctx->agentCb)
ret = ssh->ctx->agentCb(WOLFSSH_AGENT_LOCAL_SETUP, ssh->agentCbCtx);
}
@ -1801,11 +1809,16 @@ int wolfSSH_AGENT_SignRequest(WOLFSSH* ssh,
ret = SendSignRequest(agent, digest, digestSz,
keyBlob, keyBlobSz, flags);
if (ret == WS_SUCCESS)
ret = ssh->ctx->agentIoCb(WOLFSSH_AGENT_IO_WRITE,
agent->msg, agent->msgSz, ssh->agentCbCtx);
if (ret == WS_SUCCESS) {
int wrote;
if (ret > 0) ret = WS_SUCCESS;
wrote = ssh->ctx->agentIoCb(WOLFSSH_AGENT_IO_WRITE,
agent->msg, agent->msgSz, ssh->agentCbCtx);
if (wrote != (int)agent->msgSz) {
WLOG(WS_LOG_AGENT, "agent write incomplete");
ret = WS_AGENT_CXN_FAIL;
}
}
if (agent != NULL && agent->msg != NULL) {
WFREE(ssh->agent->msg, ssh->agent->heap, DYNTYPE_AGENT_BUFFER);
@ -1818,18 +1831,41 @@ int wolfSSH_AGENT_SignRequest(WOLFSSH* ssh,
rxBuf, sizeof(rxBuf), ssh->agentCbCtx);
if (rxSz > 0) {
ret = DoMessage(ssh->agent, rxBuf, rxSz, &idx);
if (ssh->agent->requestFailure) {
ssh->agent->requestFailure = 0;
ret = WS_AGENT_NO_KEY_E;
}
else {
WMEMCPY(sig, ssh->agent->msg, ssh->agent->msgSz);
*sigSz = ssh->agent->msgSz;
if (ret == WS_SUCCESS) {
if (ssh->agent->lastMsgId != MSGID_AGENT_SIGN_RESPONSE) {
WLOG(WS_LOG_AGENT,
"agent response was not a signature message");
ret = WS_AGENT_NO_KEY_E;
}
else {
if (ssh->agent->requestFailure ||
ssh->agent->msg == NULL ||
ssh->agent->msgSz == 0) {
ssh->agent->requestFailure = 0;
ret = WS_AGENT_NO_KEY_E;
}
else {
word32 maxSigSz = *sigSz;
if (ssh->agent->msgSz > maxSigSz) {
WLOG(WS_LOG_AGENT,
"agent signature too large for caller buffer");
ret = WS_BUFFER_E;
}
else {
WMEMCPY(sig, ssh->agent->msg, ssh->agent->msgSz);
*sigSz = ssh->agent->msgSz;
}
}
}
}
}
else ret = WS_AGENT_NO_KEY_E;
}
if (ret != WS_SUCCESS && sigSz != NULL)
*sigSz = 0;
if (agent != NULL) {
agent->msg = NULL;
agent->msgSz = 0;

View File

@ -966,6 +966,7 @@ static int GetScpFileName(WOLFSSH* ssh, byte* buf, word32 bufSz,
{
int ret = WS_SUCCESS;
word32 idx, len;
const char* fileName;
if (ssh == NULL || buf == NULL || inOutIdx == NULL)
return WS_BAD_ARGUMENT;
@ -977,6 +978,31 @@ static int GetScpFileName(WOLFSSH* ssh, byte* buf, word32 bufSz,
ret = WS_SCP_CMD_E;
if (ret == WS_SUCCESS) {
word32 i;
fileName = (const char*)(buf + idx);
if (len == 0 ||
(len == 1 && fileName[0] == '.') ||
(len == 2 && fileName[0] == '.' && fileName[1] == '.')) {
WLOG(WS_LOG_ERROR, "scp: invalid file name component received");
wolfSSH_SetScpErrorMsg(ssh, "invalid file name");
return WS_SCP_BAD_MSG_E;
}
for (i = 0; i < len; i++) {
char c = fileName[i];
if (c == '/' || c == '\\'
#if defined(USE_WINDOWS_API) || defined(WOLFSSL_NUCLEUS)
|| c == ':'
#endif
) {
WLOG(WS_LOG_ERROR, "scp: invalid file name component received");
wolfSSH_SetScpErrorMsg(ssh, "invalid file name");
return WS_SCP_BAD_MSG_E;
}
}
if (ssh->scpFileName != NULL) {
WFREE(ssh->scpFileName, ssh->ctx->heap, DYNTYPE_STRING);
@ -1277,11 +1303,13 @@ int ParseScpCommand(WOLFSSH* ssh)
ssh->scpBasePath = ssh->scpBasePathDynamic;
WMEMCPY(ssh->scpBasePathDynamic, cmd + idx,
cmdSz - idx);
ret = ParseBasePathHelper(ssh, cmdSz);
if (ret == WS_SUCCESS &&
wolfSSH_CleanPath(ssh,
ssh->scpBasePathDynamic) < 0)
if (wolfSSH_CleanPath(ssh,
ssh->scpBasePathDynamic) < 0) {
ret = WS_FATAL_ERROR;
}
else {
ret = ParseBasePathHelper(ssh, cmdSz);
}
}
break;
@ -3090,4 +3118,3 @@ int wsScpSendCallback(WOLFSSH* ssh, int state, const char* peerRequest,
#endif /* WOLFSSH_SCP_USER_CALLBACKS */
#endif /* WOLFSSH_SCP */

View File

@ -31,11 +31,15 @@
#include <wolfssh/port.h>
#include <stdio.h>
#include <string.h>
#include <wolfssh/ssh.h>
#include <wolfssh/internal.h>
#ifdef WOLFSSH_SCP
#include <wolfssh/wolfscp.h>
#endif
#ifdef WOLFSSH_AGENT
#include <wolfssh/agent.h>
#endif
#ifdef WOLFSSH_SFTP
#define WOLFSSH_TEST_LOCKING
@ -873,6 +877,210 @@ static void test_wolfSSH_SCP_CB(void)
static void test_wolfSSH_SCP_CB(void) { ; }
#endif /* WOLFSSH_SCP */
#ifdef WOLFSSH_AGENT
typedef struct AgentTestCtx {
int partialWrite;
byte response[128];
word32 responseSz;
int writeCalls;
int readCalls;
} AgentTestCtx;
static int test_agent_cb(WS_AgentCbAction action, void* ctx)
{
(void)ctx;
if (action == WOLFSSH_AGENT_LOCAL_SETUP ||
action == WOLFSSH_AGENT_LOCAL_CLEANUP) {
return WS_AGENT_SUCCESS;
}
return WS_AGENT_INVALID_ACTION;
}
static void put_uint32(byte* dst, word32 value)
{
dst[0] = (byte)((value >> 24) & 0xff);
dst[1] = (byte)((value >> 16) & 0xff);
dst[2] = (byte)((value >> 8) & 0xff);
dst[3] = (byte)(value & 0xff);
}
static void build_agent_message(byte* out, word32* outSz, byte id,
const byte* body, word32 bodySz)
{
word32 payloadSz = 1 + bodySz;
put_uint32(out, payloadSz);
out[4] = id;
if (bodySz > 0)
memcpy(out + 5, body, bodySz);
*outSz = payloadSz + LENGTH_SZ;
}
static void build_sign_response(AgentTestCtx* ctx, const byte* sig,
word32 sigSz)
{
byte body[4 + 64];
AssertTrue(sigSz <= 64);
put_uint32(body, sigSz);
if (sigSz > 0)
memcpy(body + LENGTH_SZ, sig, sigSz);
build_agent_message(ctx->response, &ctx->responseSz,
MSGID_AGENT_SIGN_RESPONSE, body, LENGTH_SZ + sigSz);
}
static void build_simple_response(AgentTestCtx* ctx, byte id)
{
build_agent_message(ctx->response, &ctx->responseSz, id, NULL, 0);
}
static int test_agent_io_cb(WS_AgentIoCbAction action, void* buf, word32 bufSz,
void* ctx)
{
AgentTestCtx* io = (AgentTestCtx*)ctx;
if (action == WOLFSSH_AGENT_IO_WRITE) {
io->writeCalls++;
if (io->partialWrite && bufSz > 0) {
io->partialWrite = 0;
return (int)(bufSz - 1);
}
return (int)bufSz;
}
io->readCalls++;
if (io->responseSz == 0 || bufSz < io->responseSz)
return 0;
memcpy(buf, io->response, io->responseSz);
return (int)io->responseSz;
}
static void setup_agent_test(WOLFSSH_CTX** ctx, WOLFSSH** ssh, AgentTestCtx* io)
{
AssertNotNull(*ctx = wolfSSH_CTX_new(WOLFSSH_ENDPOINT_CLIENT, NULL));
AssertIntEQ(wolfSSH_CTX_AGENT_enable(*ctx, 1), WS_SUCCESS);
AssertIntEQ(wolfSSH_CTX_set_agent_cb(*ctx, test_agent_cb,
test_agent_io_cb), WS_SUCCESS);
AssertNotNull(*ssh = wolfSSH_new(*ctx));
AssertNotNull((*ssh)->agent = wolfSSH_AGENT_new((*ctx)->heap));
AssertIntEQ(wolfSSH_set_agent_cb_ctx(*ssh, io), WS_SUCCESS);
AssertIntEQ(wolfSSH_AGENT_enable(*ssh, 1), WS_SUCCESS);
}
static void cleanup_agent_test(WOLFSSH_CTX* ctx, WOLFSSH* ssh)
{
wolfSSH_free(ssh);
wolfSSH_CTX_free(ctx);
}
static void test_wolfSSH_agent_signrequest_partial_write(void)
{
WOLFSSH_CTX* ctx;
WOLFSSH* ssh;
AgentTestCtx io;
byte digest[16] = {0};
byte keyBlob[8] = {0};
byte sig[8];
word32 sigSz = sizeof(sig);
int ret;
memset(&io, 0, sizeof(io));
io.partialWrite = 1;
setup_agent_test(&ctx, &ssh, &io);
ret = wolfSSH_AGENT_SignRequest(ssh, digest, sizeof(digest),
sig, &sigSz, keyBlob, sizeof(keyBlob), 0);
AssertIntEQ(ret, WS_AGENT_CXN_FAIL);
AssertIntEQ(sigSz, 0);
AssertIntEQ(io.writeCalls, 1);
AssertIntEQ(io.readCalls, 0);
cleanup_agent_test(ctx, ssh);
}
static void test_wolfSSH_agent_signrequest_wrong_message(void)
{
WOLFSSH_CTX* ctx;
WOLFSSH* ssh;
AgentTestCtx io;
byte digest[16] = {0};
byte keyBlob[8] = {0};
byte sig[16];
word32 sigSz = sizeof(sig);
int ret;
memset(&io, 0, sizeof(io));
build_simple_response(&io, MSGID_AGENT_SUCCESS);
setup_agent_test(&ctx, &ssh, &io);
ret = wolfSSH_AGENT_SignRequest(ssh, digest, sizeof(digest),
sig, &sigSz, keyBlob, sizeof(keyBlob), 0);
AssertIntEQ(ret, WS_AGENT_NO_KEY_E);
AssertIntEQ(sigSz, 0);
AssertIntEQ(io.writeCalls, 1);
AssertIntEQ(io.readCalls, 1);
cleanup_agent_test(ctx, ssh);
}
static void test_wolfSSH_agent_signrequest_signature_too_large(void)
{
WOLFSSH_CTX* ctx;
WOLFSSH* ssh;
AgentTestCtx io;
byte digest[16] = {0};
byte keyBlob[8] = {0};
byte signatureData[12];
byte sig[8];
word32 sigSz = sizeof(sig);
int ret;
memset(signatureData, 0x5a, sizeof(signatureData));
memset(&io, 0, sizeof(io));
build_sign_response(&io, signatureData, sizeof(signatureData));
setup_agent_test(&ctx, &ssh, &io);
ret = wolfSSH_AGENT_SignRequest(ssh, digest, sizeof(digest),
sig, &sigSz, keyBlob, sizeof(keyBlob), 0);
AssertIntEQ(ret, WS_BUFFER_E);
AssertIntEQ(sigSz, 0);
AssertIntEQ(io.writeCalls, 1);
AssertIntEQ(io.readCalls, 1);
cleanup_agent_test(ctx, ssh);
}
static void test_wolfSSH_agent_signrequest_success(void)
{
WOLFSSH_CTX* ctx;
WOLFSSH* ssh;
AgentTestCtx io;
byte digest[16] = {0};
byte keyBlob[8] = {0};
byte signatureData[8];
byte sig[16];
word32 sigSz = sizeof(sig);
int ret;
memset(signatureData, 0xa5, sizeof(signatureData));
memset(&io, 0, sizeof(io));
build_sign_response(&io, signatureData, sizeof(signatureData));
setup_agent_test(&ctx, &ssh, &io);
ret = wolfSSH_AGENT_SignRequest(ssh, digest, sizeof(digest),
sig, &sigSz, keyBlob, sizeof(keyBlob), 0);
AssertIntEQ(ret, WS_SUCCESS);
AssertIntEQ(sigSz, sizeof(signatureData));
AssertTrue(memcmp(sig, signatureData, sizeof(signatureData)) == 0);
AssertIntEQ(io.writeCalls, 1);
AssertIntEQ(io.readCalls, 1);
cleanup_agent_test(ctx, ssh);
}
#endif /* WOLFSSH_AGENT */
#if defined(WOLFSSH_SFTP) && !defined(NO_WOLFSSH_CLIENT) && \
!defined(SINGLE_THREADED)
@ -1779,6 +1987,12 @@ int wolfSSH_ApiTest(int argc, char** argv)
test_wolfSSH_ReadKey();
test_wolfSSH_QueryAlgoList();
test_wolfSSH_SetAlgoList();
#ifdef WOLFSSH_AGENT
test_wolfSSH_agent_signrequest_partial_write();
test_wolfSSH_agent_signrequest_wrong_message();
test_wolfSSH_agent_signrequest_signature_too_large();
test_wolfSSH_agent_signrequest_success();
#endif
#ifdef WOLFSSH_KEYBOARD_INTERACTIVE
test_wolfSSH_KeyboardInteractive();
#endif

View File

@ -140,6 +140,7 @@ struct WOLFSSH_AGENT_CTX {
enum AgentStates state;
int requestSuccess;
int requestFailure;
byte lastMsgId;
};
typedef struct WOLFSSH_AGENT_CTX WOLFSSH_AGENT_CTX;
@ -190,4 +191,3 @@ WOLFSSH_API int wolfSSH_AGENT_SignRequest(WOLFSSH*, const byte*, word32,
#endif
#endif /* _WOLFSSH_AGENT_H_ */