Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
10 changes: 10 additions & 0 deletions src/internal.c
Original file line number Diff line number Diff line change
Expand Up @@ -9652,6 +9652,10 @@ static int DoChannelRequest(WOLFSSH* ssh,
WLOG(WS_LOG_AGENT, "Agent callback not set, not using.");
}
#endif /* WOLFSSH_AGENT */
else {
WLOG(WS_LOG_DEBUG, " unknown channel request type, rejecting.");
rej = 1;
}
Comment thread
yosuke-wolfssl marked this conversation as resolved.
}

if (ret == WS_SUCCESS) {
Expand Down Expand Up @@ -10708,6 +10712,12 @@ int wolfSSH_TestDoUserAuthBanner(WOLFSSH* ssh, byte* buf, word32 len,
{
return DoUserAuthBanner(ssh, buf, len, idx);
}

int wolfSSH_TestDoChannelRequest(WOLFSSH* ssh, byte* buf, word32 len,
word32* idx)
{
return DoChannelRequest(ssh, buf, len, idx);
}
#endif


Expand Down
135 changes: 135 additions & 0 deletions tests/unit.c
Original file line number Diff line number Diff line change
Expand Up @@ -714,6 +714,137 @@ static int test_DoUserAuthBanner(void)
return result;
}


/* Verify DoChannelRequest sends CHANNEL_SUCCESS for known types and
* CHANNEL_FAILURE for unrecognized ones (RFC 4254 Section 5.4).
*
* A custom IoSend callback captures the outgoing packet in plaintext
* (no cipher negotiated on a fresh session). The SSH packet layout is:
* [4-byte packet_length][1-byte padding_length][1-byte msg_id]...
* so the message ID lives at byte offset 5. */
static byte s_chanReqCapture[256];
static word32 s_chanReqCaptureSz = 0;

static int CaptureIoSendChanReq(WOLFSSH* ssh, void* buf, word32 sz, void* ctx)
{
(void)ssh; (void)ctx;
s_chanReqCaptureSz = (sz < (word32)sizeof(s_chanReqCapture))
? sz : (word32)sizeof(s_chanReqCapture);
WMEMCPY(s_chanReqCapture, buf, s_chanReqCaptureSz);
return (int)sz;
}

static int test_DoChannelRequest(void)
{
WOLFSSH_CTX* ctx = NULL;
WOLFSSH* ssh = NULL;
WOLFSSH_CHANNEL* ch = NULL;
int result = 0;
int i;

/* Payloads: [uint32 channelId=0][string type][byte wantReply=1][extra] */
static const byte payShell[] = {
0x00,0x00,0x00,0x00, /* channelId = 0 */
0x00,0x00,0x00,0x05, /* typeSz = 5 */
0x73,0x68,0x65,0x6C,0x6C, /* "shell" */
0x01 /* wantReply = 1 */
};
static const byte payExec[] = {
0x00,0x00,0x00,0x00, /* channelId = 0 */
0x00,0x00,0x00,0x04, /* typeSz = 4 */
0x65,0x78,0x65,0x63, /* "exec" */
0x01, /* wantReply = 1 */
0x00,0x00,0x00,0x02, /* cmdSz = 2 */
0x6C,0x73 /* "ls" */
};
static const byte payUnknown[] = {
0x00,0x00,0x00,0x00, /* channelId = 0 */
0x00,0x00,0x00,0x0C, /* typeSz = 12 */
0x75,0x6E,0x6B,0x6E,0x6F,0x77,
0x6E,0x2D,0x74,0x79,0x70,0x65, /* "unknown-type" */
0x01 /* wantReply = 1 */
};

struct {
const char* label;
const byte* payload;
word32 payloadSz;
int expectRet;
byte expectMsgId;
} cases[] = {
{ "shell",
payShell, (word32)sizeof(payShell),
WS_SUCCESS, MSGID_CHANNEL_SUCCESS },
{ "exec",
payExec, (word32)sizeof(payExec),
WS_SUCCESS, MSGID_CHANNEL_SUCCESS },
{ "unknown-type",
payUnknown, (word32)sizeof(payUnknown),
WS_SUCCESS, MSGID_CHANNEL_FAILURE },
};

ctx = wolfSSH_CTX_new(WOLFSSH_ENDPOINT_SERVER, NULL);
if (ctx == NULL)
return -400;
wolfSSH_SetIOSend(ctx, CaptureIoSendChanReq);

ssh = wolfSSH_new(ctx);
if (ssh == NULL) {
result = -401;
goto done;
}

ch = ChannelNew(ssh, ID_CHANTYPE_SESSION,
DEFAULT_WINDOW_SZ, DEFAULT_MAX_PACKET_SZ);
if (ch == NULL) {
result = -402;
goto done;
}
if (ChannelAppend(ssh, ch) != WS_SUCCESS) {
ChannelDelete(ch, ssh->ctx->heap);
result = -403;
goto done;
}

for (i = 0; i < (int)(sizeof(cases) / sizeof(cases[0])); i++) {
word32 idx = 0;
int ret;

s_chanReqCaptureSz = 0;
WMEMSET(s_chanReqCapture, 0, sizeof(s_chanReqCapture));

ret = wolfSSH_TestDoChannelRequest(ssh,
(byte*)cases[i].payload, cases[i].payloadSz, &idx);

if (ret != cases[i].expectRet) {
printf("DoChannelRequest[%s]: ret=%d, expected=%d\n",
cases[i].label, ret, cases[i].expectRet);
result = -404 - i;
goto done;
}

if (s_chanReqCaptureSz <= 5) {
printf("DoChannelRequest[%s]: captured packet too short (%u)\n",
cases[i].label, s_chanReqCaptureSz);
result = -410 - i;
goto done;
}

if (s_chanReqCapture[5] != cases[i].expectMsgId) {
printf("DoChannelRequest[%s]: msg_id=0x%02x, expected=0x%02x\n",
cases[i].label,
s_chanReqCapture[5], cases[i].expectMsgId);
result = -420 - i;
goto done;
}
}

done:
wolfSSH_free(ssh);
wolfSSH_CTX_free(ctx);
return result;
}

#endif /* WOLFSSH_TEST_INTERNAL */


Expand Down Expand Up @@ -809,6 +940,10 @@ int wolfSSH_UnitTest(int argc, char** argv)
unitResult = test_DoUserAuthBanner();
printf("DoUserAuthBanner: %s\n", (unitResult == 0 ? "SUCCESS" : "FAILED"));
testResult = testResult || unitResult;

unitResult = test_DoChannelRequest();
printf("DoChannelRequest: %s\n", (unitResult == 0 ? "SUCCESS" : "FAILED"));
testResult = testResult || unitResult;
#endif

#ifdef WOLFSSH_KEYGEN
Expand Down
2 changes: 2 additions & 0 deletions wolfssh/internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -1329,6 +1329,8 @@ enum WS_MessageIdLimits {
WOLFSSH_API int wolfSSH_TestDoReceive(WOLFSSH* ssh);
WOLFSSH_API int wolfSSH_TestDoUserAuthBanner(WOLFSSH* ssh, byte* buf,
word32 len, word32* idx);
WOLFSSH_API int wolfSSH_TestDoChannelRequest(WOLFSSH* ssh, byte* buf,
word32 len, word32* idx);
#ifndef WOLFSSH_NO_DH_GEX_SHA256
WOLFSSH_API int wolfSSH_TestValidateKexDhGexGroup(const byte* primeGroup,
word32 primeGroupSz, const byte* generator, word32 generatorSz,
Expand Down
Loading