mirror of https://github.com/wolfSSL/wolfssh.git
commit
2d2c1f5ac5
58
src/agent.c
58
src/agent.c
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
||||
|
|
|
|||
214
tests/api.c
214
tests/api.c
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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_ */
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue