Skip to content

Commit cd7a7f4

Browse files
yosuke-wolfsslejohnstown
authored andcommitted
Fix DoChannelRequest and Add unit test for DoChannelRequest
1 parent 0d283d2 commit cd7a7f4

3 files changed

Lines changed: 147 additions & 0 deletions

File tree

src/internal.c

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9659,6 +9659,10 @@ static int DoChannelRequest(WOLFSSH* ssh,
96599659
WLOG(WS_LOG_AGENT, "Agent callback not set, not using.");
96609660
}
96619661
#endif /* WOLFSSH_AGENT */
9662+
else {
9663+
WLOG(WS_LOG_DEBUG, " unknown channel request type, rejecting.");
9664+
rej = 1;
9665+
}
96629666
}
96639667

96649668
if (ret == WS_SUCCESS) {
@@ -10715,6 +10719,12 @@ int wolfSSH_TestDoUserAuthBanner(WOLFSSH* ssh, byte* buf, word32 len,
1071510719
{
1071610720
return DoUserAuthBanner(ssh, buf, len, idx);
1071710721
}
10722+
10723+
int wolfSSH_TestDoChannelRequest(WOLFSSH* ssh, byte* buf, word32 len,
10724+
word32* idx)
10725+
{
10726+
return DoChannelRequest(ssh, buf, len, idx);
10727+
}
1071810728
#endif
1071910729

1072010730

tests/unit.c

Lines changed: 135 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -714,6 +714,137 @@ static int test_DoUserAuthBanner(void)
714714
return result;
715715
}
716716

717+
718+
/* Verify DoChannelRequest sends CHANNEL_SUCCESS for known types and
719+
* CHANNEL_FAILURE for unrecognized ones (RFC 4254 Section 5.4).
720+
*
721+
* A custom IoSend callback captures the outgoing packet in plaintext
722+
* (no cipher negotiated on a fresh session). The SSH packet layout is:
723+
* [4-byte packet_length][1-byte padding_length][1-byte msg_id]...
724+
* so the message ID lives at byte offset 5. */
725+
static byte s_chanReqCapture[256];
726+
static word32 s_chanReqCaptureSz = 0;
727+
728+
static int CaptureIoSendChanReq(WOLFSSH* ssh, void* buf, word32 sz, void* ctx)
729+
{
730+
(void)ssh; (void)ctx;
731+
s_chanReqCaptureSz = (sz < (word32)sizeof(s_chanReqCapture))
732+
? sz : (word32)sizeof(s_chanReqCapture);
733+
WMEMCPY(s_chanReqCapture, buf, s_chanReqCaptureSz);
734+
return (int)sz;
735+
}
736+
737+
static int test_DoChannelRequest(void)
738+
{
739+
WOLFSSH_CTX* ctx = NULL;
740+
WOLFSSH* ssh = NULL;
741+
WOLFSSH_CHANNEL* ch = NULL;
742+
int result = 0;
743+
int i;
744+
745+
/* Payloads: [uint32 channelId=0][string type][byte wantReply=1][extra] */
746+
static const byte payShell[] = {
747+
0x00,0x00,0x00,0x00, /* channelId = 0 */
748+
0x00,0x00,0x00,0x05, /* typeSz = 5 */
749+
0x73,0x68,0x65,0x6C,0x6C, /* "shell" */
750+
0x01 /* wantReply = 1 */
751+
};
752+
static const byte payExec[] = {
753+
0x00,0x00,0x00,0x00, /* channelId = 0 */
754+
0x00,0x00,0x00,0x04, /* typeSz = 4 */
755+
0x65,0x78,0x65,0x63, /* "exec" */
756+
0x01, /* wantReply = 1 */
757+
0x00,0x00,0x00,0x02, /* cmdSz = 2 */
758+
0x6C,0x73 /* "ls" */
759+
};
760+
static const byte payUnknown[] = {
761+
0x00,0x00,0x00,0x00, /* channelId = 0 */
762+
0x00,0x00,0x00,0x0C, /* typeSz = 12 */
763+
0x75,0x6E,0x6B,0x6E,0x6F,0x77,
764+
0x6E,0x2D,0x74,0x79,0x70,0x65, /* "unknown-type" */
765+
0x01 /* wantReply = 1 */
766+
};
767+
768+
struct {
769+
const char* label;
770+
const byte* payload;
771+
word32 payloadSz;
772+
int expectRet;
773+
byte expectMsgId;
774+
} cases[] = {
775+
{ "shell",
776+
payShell, (word32)sizeof(payShell),
777+
WS_SUCCESS, MSGID_CHANNEL_SUCCESS },
778+
{ "exec",
779+
payExec, (word32)sizeof(payExec),
780+
WS_SUCCESS, MSGID_CHANNEL_SUCCESS },
781+
{ "unknown-type",
782+
payUnknown, (word32)sizeof(payUnknown),
783+
WS_SUCCESS, MSGID_CHANNEL_FAILURE },
784+
};
785+
786+
ctx = wolfSSH_CTX_new(WOLFSSH_ENDPOINT_SERVER, NULL);
787+
if (ctx == NULL)
788+
return -400;
789+
wolfSSH_SetIOSend(ctx, CaptureIoSendChanReq);
790+
791+
ssh = wolfSSH_new(ctx);
792+
if (ssh == NULL) {
793+
result = -401;
794+
goto done;
795+
}
796+
797+
ch = ChannelNew(ssh, ID_CHANTYPE_SESSION,
798+
DEFAULT_WINDOW_SZ, DEFAULT_MAX_PACKET_SZ);
799+
if (ch == NULL) {
800+
result = -402;
801+
goto done;
802+
}
803+
if (ChannelAppend(ssh, ch) != WS_SUCCESS) {
804+
ChannelDelete(ch, ssh->ctx->heap);
805+
result = -403;
806+
goto done;
807+
}
808+
809+
for (i = 0; i < (int)(sizeof(cases) / sizeof(cases[0])); i++) {
810+
word32 idx = 0;
811+
int ret;
812+
813+
s_chanReqCaptureSz = 0;
814+
WMEMSET(s_chanReqCapture, 0, sizeof(s_chanReqCapture));
815+
816+
ret = wolfSSH_TestDoChannelRequest(ssh,
817+
(byte*)cases[i].payload, cases[i].payloadSz, &idx);
818+
819+
if (ret != cases[i].expectRet) {
820+
printf("DoChannelRequest[%s]: ret=%d, expected=%d\n",
821+
cases[i].label, ret, cases[i].expectRet);
822+
result = -404 - i;
823+
goto done;
824+
}
825+
826+
if (s_chanReqCaptureSz <= 5) {
827+
printf("DoChannelRequest[%s]: captured packet too short (%u)\n",
828+
cases[i].label, s_chanReqCaptureSz);
829+
result = -410 - i;
830+
goto done;
831+
}
832+
833+
if (s_chanReqCapture[5] != cases[i].expectMsgId) {
834+
printf("DoChannelRequest[%s]: msg_id=0x%02x, expected=0x%02x\n",
835+
cases[i].label,
836+
s_chanReqCapture[5], cases[i].expectMsgId);
837+
result = -420 - i;
838+
goto done;
839+
}
840+
}
841+
842+
done:
843+
wolfSSH_free(ssh);
844+
wolfSSH_CTX_free(ctx);
845+
return result;
846+
}
847+
717848
#endif /* WOLFSSH_TEST_INTERNAL */
718849

719850

@@ -809,6 +940,10 @@ int wolfSSH_UnitTest(int argc, char** argv)
809940
unitResult = test_DoUserAuthBanner();
810941
printf("DoUserAuthBanner: %s\n", (unitResult == 0 ? "SUCCESS" : "FAILED"));
811942
testResult = testResult || unitResult;
943+
944+
unitResult = test_DoChannelRequest();
945+
printf("DoChannelRequest: %s\n", (unitResult == 0 ? "SUCCESS" : "FAILED"));
946+
testResult = testResult || unitResult;
812947
#endif
813948

814949
#ifdef WOLFSSH_KEYGEN

wolfssh/internal.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1332,6 +1332,8 @@ enum WS_MessageIdLimits {
13321332
WOLFSSH_API int wolfSSH_TestDoReceive(WOLFSSH* ssh);
13331333
WOLFSSH_API int wolfSSH_TestDoUserAuthBanner(WOLFSSH* ssh, byte* buf,
13341334
word32 len, word32* idx);
1335+
WOLFSSH_API int wolfSSH_TestDoChannelRequest(WOLFSSH* ssh, byte* buf,
1336+
word32 len, word32* idx);
13351337
#ifndef WOLFSSH_NO_DH_GEX_SHA256
13361338
WOLFSSH_API int wolfSSH_TestValidateKexDhGexGroup(const byte* primeGroup,
13371339
word32 primeGroupSz, const byte* generator, word32 generatorSz,

0 commit comments

Comments
 (0)