Skip to content

Commit 6622473

Browse files
committed
Add agent sign request regression tests
Exercise agent write failures, non-signature responses, oversized signatures, and the happy path to cover the recent wolfSSH_AGENT_SignRequest hardening.
1 parent ab17b01 commit 6622473

1 file changed

Lines changed: 213 additions & 0 deletions

File tree

tests/api.c

Lines changed: 213 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,11 +31,15 @@
3131
#include <wolfssh/port.h>
3232

3333
#include <stdio.h>
34+
#include <string.h>
3435
#include <wolfssh/ssh.h>
3536
#include <wolfssh/internal.h>
3637
#ifdef WOLFSSH_SCP
3738
#include <wolfssh/wolfscp.h>
3839
#endif
40+
#ifdef WOLFSSH_AGENT
41+
#include <wolfssh/agent.h>
42+
#endif
3943

4044
#ifdef WOLFSSH_SFTP
4145
#define WOLFSSH_TEST_LOCKING
@@ -873,6 +877,209 @@ static void test_wolfSSH_SCP_CB(void)
873877
static void test_wolfSSH_SCP_CB(void) { ; }
874878
#endif /* WOLFSSH_SCP */
875879

880+
#ifdef WOLFSSH_AGENT
881+
typedef struct AgentTestCtx {
882+
int partialWrite;
883+
byte response[128];
884+
word32 responseSz;
885+
int writeCalls;
886+
int readCalls;
887+
} AgentTestCtx;
888+
889+
static int test_agent_cb(WS_AgentCbAction action, void* ctx)
890+
{
891+
(void)ctx;
892+
893+
if (action == WOLFSSH_AGENT_LOCAL_SETUP ||
894+
action == WOLFSSH_AGENT_LOCAL_CLEANUP) {
895+
return WS_AGENT_SUCCESS;
896+
}
897+
898+
return WS_AGENT_INVALID_ACTION;
899+
}
900+
901+
static void put_uint32(byte* dst, word32 value)
902+
{
903+
dst[0] = (byte)((value >> 24) & 0xff);
904+
dst[1] = (byte)((value >> 16) & 0xff);
905+
dst[2] = (byte)((value >> 8) & 0xff);
906+
dst[3] = (byte)(value & 0xff);
907+
}
908+
909+
static void build_agent_message(byte* out, word32* outSz, byte id,
910+
const byte* body, word32 bodySz)
911+
{
912+
word32 payloadSz = 1 + bodySz;
913+
914+
put_uint32(out, payloadSz);
915+
out[4] = id;
916+
if (bodySz > 0)
917+
memcpy(out + 5, body, bodySz);
918+
*outSz = payloadSz + LENGTH_SZ;
919+
}
920+
921+
static void build_sign_response(AgentTestCtx* ctx, const byte* sig,
922+
word32 sigSz)
923+
{
924+
byte body[4 + 64];
925+
926+
AssertTrue(sigSz <= 64);
927+
put_uint32(body, sigSz);
928+
if (sigSz > 0)
929+
memcpy(body + LENGTH_SZ, sig, sigSz);
930+
build_agent_message(ctx->response, &ctx->responseSz,
931+
MSGID_AGENT_SIGN_RESPONSE, body, LENGTH_SZ + sigSz);
932+
}
933+
934+
static void build_simple_response(AgentTestCtx* ctx, byte id)
935+
{
936+
build_agent_message(ctx->response, &ctx->responseSz, id, NULL, 0);
937+
}
938+
939+
static int test_agent_io_cb(WS_AgentIoCbAction action, void* buf, word32 bufSz,
940+
void* ctx)
941+
{
942+
AgentTestCtx* io = (AgentTestCtx*)ctx;
943+
944+
if (action == WOLFSSH_AGENT_IO_WRITE) {
945+
io->writeCalls++;
946+
if (io->partialWrite && bufSz > 0) {
947+
io->partialWrite = 0;
948+
return (int)(bufSz - 1);
949+
}
950+
return (int)bufSz;
951+
}
952+
953+
io->readCalls++;
954+
if (io->responseSz == 0 || bufSz < io->responseSz)
955+
return 0;
956+
memcpy(buf, io->response, io->responseSz);
957+
return (int)io->responseSz;
958+
}
959+
960+
static void setup_agent_test(WOLFSSH_CTX** ctx, WOLFSSH** ssh, AgentTestCtx* io)
961+
{
962+
AssertNotNull(*ctx = wolfSSH_CTX_new(WOLFSSH_ENDPOINT_CLIENT, NULL));
963+
AssertIntEQ(wolfSSH_CTX_AGENT_enable(*ctx, 1), WS_SUCCESS);
964+
AssertIntEQ(wolfSSH_CTX_set_agent_cb(*ctx, test_agent_cb,
965+
test_agent_io_cb), WS_SUCCESS);
966+
AssertNotNull(*ssh = wolfSSH_new(*ctx));
967+
AssertIntEQ(wolfSSH_set_agent_cb_ctx(*ssh, io), WS_SUCCESS);
968+
AssertIntEQ(wolfSSH_AGENT_enable(*ssh, 1), WS_SUCCESS);
969+
}
970+
971+
static void cleanup_agent_test(WOLFSSH_CTX* ctx, WOLFSSH* ssh)
972+
{
973+
wolfSSH_free(ssh);
974+
wolfSSH_CTX_free(ctx);
975+
}
976+
977+
static void test_wolfSSH_agent_signrequest_partial_write(void)
978+
{
979+
WOLFSSH_CTX* ctx;
980+
WOLFSSH* ssh;
981+
AgentTestCtx io;
982+
byte digest[16] = {0};
983+
byte keyBlob[8] = {0};
984+
byte sig[8];
985+
word32 sigSz = sizeof(sig);
986+
int ret;
987+
988+
memset(&io, 0, sizeof(io));
989+
io.partialWrite = 1;
990+
setup_agent_test(&ctx, &ssh, &io);
991+
992+
ret = wolfSSH_AGENT_SignRequest(ssh, digest, sizeof(digest),
993+
sig, &sigSz, keyBlob, sizeof(keyBlob), 0);
994+
AssertIntEQ(ret, WS_AGENT_CXN_FAIL);
995+
AssertIntEQ(sigSz, 0);
996+
AssertIntEQ(io.writeCalls, 1);
997+
AssertIntEQ(io.readCalls, 0);
998+
999+
cleanup_agent_test(ctx, ssh);
1000+
}
1001+
1002+
static void test_wolfSSH_agent_signrequest_wrong_message(void)
1003+
{
1004+
WOLFSSH_CTX* ctx;
1005+
WOLFSSH* ssh;
1006+
AgentTestCtx io;
1007+
byte digest[16] = {0};
1008+
byte keyBlob[8] = {0};
1009+
byte sig[16];
1010+
word32 sigSz = sizeof(sig);
1011+
int ret;
1012+
1013+
memset(&io, 0, sizeof(io));
1014+
build_simple_response(&io, MSGID_AGENT_SUCCESS);
1015+
setup_agent_test(&ctx, &ssh, &io);
1016+
1017+
ret = wolfSSH_AGENT_SignRequest(ssh, digest, sizeof(digest),
1018+
sig, &sigSz, keyBlob, sizeof(keyBlob), 0);
1019+
AssertIntEQ(ret, WS_AGENT_NO_KEY_E);
1020+
AssertIntEQ(sigSz, 0);
1021+
AssertIntEQ(io.writeCalls, 1);
1022+
AssertIntEQ(io.readCalls, 1);
1023+
1024+
cleanup_agent_test(ctx, ssh);
1025+
}
1026+
1027+
static void test_wolfSSH_agent_signrequest_signature_too_large(void)
1028+
{
1029+
WOLFSSH_CTX* ctx;
1030+
WOLFSSH* ssh;
1031+
AgentTestCtx io;
1032+
byte digest[16] = {0};
1033+
byte keyBlob[8] = {0};
1034+
byte signatureData[12];
1035+
byte sig[8];
1036+
word32 sigSz = sizeof(sig);
1037+
int ret;
1038+
1039+
memset(signatureData, 0x5a, sizeof(signatureData));
1040+
memset(&io, 0, sizeof(io));
1041+
build_sign_response(&io, signatureData, sizeof(signatureData));
1042+
setup_agent_test(&ctx, &ssh, &io);
1043+
1044+
ret = wolfSSH_AGENT_SignRequest(ssh, digest, sizeof(digest),
1045+
sig, &sigSz, keyBlob, sizeof(keyBlob), 0);
1046+
AssertIntEQ(ret, WS_BUFFER_E);
1047+
AssertIntEQ(sigSz, 0);
1048+
AssertIntEQ(io.writeCalls, 1);
1049+
AssertIntEQ(io.readCalls, 1);
1050+
1051+
cleanup_agent_test(ctx, ssh);
1052+
}
1053+
1054+
static void test_wolfSSH_agent_signrequest_success(void)
1055+
{
1056+
WOLFSSH_CTX* ctx;
1057+
WOLFSSH* ssh;
1058+
AgentTestCtx io;
1059+
byte digest[16] = {0};
1060+
byte keyBlob[8] = {0};
1061+
byte signatureData[8];
1062+
byte sig[16];
1063+
word32 sigSz = sizeof(sig);
1064+
int ret;
1065+
1066+
memset(signatureData, 0xa5, sizeof(signatureData));
1067+
memset(&io, 0, sizeof(io));
1068+
build_sign_response(&io, signatureData, sizeof(signatureData));
1069+
setup_agent_test(&ctx, &ssh, &io);
1070+
1071+
ret = wolfSSH_AGENT_SignRequest(ssh, digest, sizeof(digest),
1072+
sig, &sigSz, keyBlob, sizeof(keyBlob), 0);
1073+
AssertIntEQ(ret, WS_SUCCESS);
1074+
AssertIntEQ(sigSz, sizeof(signatureData));
1075+
AssertTrue(memcmp(sig, signatureData, sizeof(signatureData)) == 0);
1076+
AssertIntEQ(io.writeCalls, 1);
1077+
AssertIntEQ(io.readCalls, 1);
1078+
1079+
cleanup_agent_test(ctx, ssh);
1080+
}
1081+
#endif /* WOLFSSH_AGENT */
1082+
8761083

8771084
#if defined(WOLFSSH_SFTP) && !defined(NO_WOLFSSH_CLIENT) && \
8781085
!defined(SINGLE_THREADED)
@@ -1779,6 +1986,12 @@ int wolfSSH_ApiTest(int argc, char** argv)
17791986
test_wolfSSH_ReadKey();
17801987
test_wolfSSH_QueryAlgoList();
17811988
test_wolfSSH_SetAlgoList();
1989+
#ifdef WOLFSSH_AGENT
1990+
test_wolfSSH_agent_signrequest_partial_write();
1991+
test_wolfSSH_agent_signrequest_wrong_message();
1992+
test_wolfSSH_agent_signrequest_signature_too_large();
1993+
test_wolfSSH_agent_signrequest_success();
1994+
#endif
17821995
#ifdef WOLFSSH_KEYBOARD_INTERACTIVE
17831996
test_wolfSSH_KeyboardInteractive();
17841997
#endif

0 commit comments

Comments
 (0)