sftp: reply OP_UNSUPPORTED to unknown requests

wolfSSH_SFTP_read() answers a request type it has no handler for,
SSH_FXP_EXTENDED among them, with SSH_FX_OP_UNSUPPORTED rather than
the generic SSH_FX_FAILURE (draft-ietf-secsh-filexfer-02 Section 7).

Issue: F-8840
pull/1352/head
John Safranek 2026-10-20 10:46:01 -07:00 committed by philljj
parent d2530b33aa
commit a602fc41b7
2 changed files with 100 additions and 2 deletions

View File

@ -1856,7 +1856,7 @@ int wolfSSH_SFTP_read(WOLFSSH* ssh)
default:
WLOG(WS_LOG_SFTP, "Unknown packet type [%d] received",
state->type);
if (wolfSSH_SFTP_CreateStatus(ssh, WOLFSSH_FTP_FAILURE,
if (wolfSSH_SFTP_CreateStatus(ssh, WOLFSSH_FTP_UNSUPPORTED,
state->reqId,
"Unknown/Unsupported packet type",
"English", NULL, (word32*)&maxSz)
@ -1875,7 +1875,7 @@ int wolfSSH_SFTP_read(WOLFSSH* ssh)
}
maxSz = (int)wolfSSH_SFTP_buffer_size(&state->buffer);
ret = wolfSSH_SFTP_CreateStatus(ssh, WOLFSSH_FTP_FAILURE,
ret = wolfSSH_SFTP_CreateStatus(ssh, WOLFSSH_FTP_UNSUPPORTED,
state->reqId,
"Unknown/Unsupported packet type", "English",
wolfSSH_SFTP_buffer_data(&state->buffer),

View File

@ -23723,6 +23723,99 @@ static int test_SftpRecvSizeBoundAccept(void)
return 0;
}
static byte s_sftpSent[512];
static word32 s_sftpSentSz = 0;
static int SftpCaptureIoSend(WOLFSSH* ssh, void* buf, word32 sz, void* ctx)
{
WOLFSSH_UNUSED(ssh);
WOLFSSH_UNUSED(ctx);
if (s_sftpSentSz + sz > (word32)sizeof(s_sftpSent))
return WS_CBIO_ERR_GENERAL;
WMEMCPY(s_sftpSent + s_sftpSentSz, buf, sz);
s_sftpSentSz += sz;
return (int)sz;
}
/* An SSH_FXP_EXTENDED request the server does not implement is answered
* with SSH_FX_OP_UNSUPPORTED (draft-ietf-secsh-filexfer-02 Section 8),
* not the generic SSH_FX_FAILURE. */
static int test_SftpExtendedUnsupported(void)
{
static const char extName[] = "unknown@example.com";
WOLFSSH_CTX* ctx = NULL;
WOLFSSH* ssh = NULL;
WOLFSSH_CHANNEL* ch = NULL;
int result = 0;
word32 extSz = (word32)(sizeof(extName) - 1);
word32 sz = 0;
word32 i;
byte pkt[WOLFSSH_SFTP_HEADER + UINT32_SZ + sizeof(extName)];
/* STATUS header for request id 7, as it appears on the wire */
static const byte status[] = { WOLFSSH_FTP_STATUS, 0, 0, 0, 7 };
PutU32BE(pkt, MSG_ID_SZ + UINT32_SZ + UINT32_SZ + extSz);
pkt[LENGTH_SZ] = WOLFSSH_FTP_EXTENDED;
PutU32BE(pkt + LENGTH_SZ + MSG_ID_SZ, 7);
sz = WOLFSSH_SFTP_HEADER;
PutU32BE(pkt + sz, extSz);
sz += UINT32_SZ;
WMEMCPY(pkt + sz, extName, extSz);
sz += extSz;
s_sftpSentSz = 0;
ctx = wolfSSH_CTX_new(WOLFSSH_ENDPOINT_SERVER, NULL);
if (ctx == NULL)
return -960;
wolfSSH_SetIOSend(ctx, SftpCaptureIoSend);
wolfSSH_SetIORecv(ctx, RecvAlwaysWantRead);
ssh = wolfSSH_new(ctx);
if (ssh == NULL) { result = -961; goto done; }
ssh->acceptState = ACCEPT_SERVER_USERAUTH_SENT;
ch = ChannelNew(ssh, ID_CHANTYPE_SESSION, 1024, 1024);
if (ch == NULL) { result = -962; goto done; }
if (ChannelAppend(ssh, ch) != WS_SUCCESS) {
ChannelDelete(ch, ssh->ctx->heap);
result = -963;
goto done;
}
ch->openConfirmed = 1;
ch->peerWindowSz = 1024;
ch->peerMaxPacketSz = 1024;
if (wolfSSH_TestChannelPutData(ch, pkt, sz) != WS_SUCCESS) {
result = -964;
goto done;
}
if (wolfSSH_SFTP_read(ssh) != WS_SUCCESS) {
result = -965;
goto done;
}
/* no keys yet, so the reply crosses the transport in the clear */
for (i = 0; i + sizeof(status) + UINT32_SZ <= s_sftpSentSz; i++) {
if (WMEMCMP(s_sftpSent + i, status, sizeof(status)) == 0)
break;
}
if (i + sizeof(status) + UINT32_SZ > s_sftpSentSz) {
result = -966;
goto done;
}
i += (word32)sizeof(status);
sz = ((word32)s_sftpSent[i] << 24) | ((word32)s_sftpSent[i + 1] << 16)
| ((word32)s_sftpSent[i + 2] << 8) | (word32)s_sftpSent[i + 3];
if (sz != WOLFSSH_FTP_UNSUPPORTED)
result = -967;
done:
wolfSSH_free(ssh);
wolfSSH_CTX_free(ctx);
return result;
}
#endif /* NO_WOLFSSH_SERVER */
#ifndef NO_WOLFSSH_CLIENT
@ -26736,6 +26829,11 @@ int wolfSSH_UnitTest(int argc, char** argv)
printf("SftpRecvSizeBoundAccept: %s\n",
(unitResult == 0 ? "SUCCESS" : "FAILED"));
testResult = testResult || unitResult;
unitResult = test_SftpExtendedUnsupported();
printf("SftpExtendedUnsupported: %s\n",
(unitResult == 0 ? "SUCCESS" : "FAILED"));
testResult = testResult || unitResult;
#endif /* NO_WOLFSSH_SERVER */
#ifndef NO_WOLFSSH_CLIENT