Merge pull request #44 from ejohnstown/scp-submission

SCP Contribution
pull/47/head
Chris Conlon 2018-03-29 15:11:20 -06:00 committed by GitHub
commit 48590f6896
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 312 additions and 26 deletions

View File

@ -51,6 +51,7 @@
static const char sshProtoIdStr[] = "SSH-2.0-wolfSSHv"
LIBWOLFSSH_VERSION_STRING
"\r\n";
static const char OpenSSH[] = "SSH-2.0-OpenSSH";
#ifndef WOLFSSH_DEFAULT_GEXDH_MIN
#define WOLFSSH_DEFAULT_GEXDH_MIN 1024
#endif
@ -830,6 +831,8 @@ void ChannelDelete(WOLFSSH_CHANNEL* channel, void* heap)
if (channel) {
WFREE(channel->inputBuffer.buffer,
channel->inputBuffer.heap, DYNTYPE_BUFFER);
if (channel->command)
WFREE(channel->command, heap, DYNTYPE_STRING);
WFREE(channel, heap, DYNTYPE_CHANNEL);
}
}
@ -842,7 +845,8 @@ WOLFSSH_CHANNEL* ChannelFind(WOLFSSH* ssh, word32 channel, byte peer)
{
WOLFSSH_CHANNEL* findChannel = NULL;
WLOG(WS_LOG_DEBUG, "Entering ChannelFind()");
WLOG(WS_LOG_DEBUG, "Entering ChannelFind(): %s %u",
peer ? "peer" : "self", channel);
if (ssh == NULL) {
WLOG(WS_LOG_DEBUG, "Null ssh, not looking for channel");
@ -1362,6 +1366,33 @@ static int GetString(char* s, word32* sSz,
}
/* Gets the size of a string, allocates memory to hold it plus a NULL, then
* copies it into the allocated buffer, and terminates it with a NULL. */
static int GetStringAlloc(WOLFSSH* ssh, char** s,
byte* buf, word32 len, word32 *idx)
{
int result;
char* str;
word32 strSz;
result = GetUint32(&strSz, buf, len, idx);
if (result == WS_SUCCESS) {
if (*idx >= len || *idx + strSz > len)
return WS_BUFFER_E;
str = (char*)WMALLOC(strSz + 1, ssh->ctx->heap, DYNTYPE_STRING);
if (str == NULL)
return WS_MEMORY_E;
WMEMCPY(str, buf + *idx, strSz);
*idx += strSz;
str[strSz] = '\0';
*s = str;
}
return result;
}
static int GetNameList(byte* idList, word32* idListSz,
byte* buf, word32 len, word32* idx)
{
@ -3389,7 +3420,7 @@ static int DoChannelOpen(WOLFSSH* ssh,
ssh->defaultPeerChannelId = peerChannelId;
ChannelAppend(ssh, newChannel);
ssh->clientState = CLIENT_DONE;
ssh->clientState = CLIENT_CHANNEL_OPEN_DONE;
}
}
@ -3495,6 +3526,33 @@ static int DoChannelOpenFail(WOLFSSH* ssh,
}
static int DoChannelEof(WOLFSSH* ssh,
byte* buf, word32 len, word32* idx)
{
WOLFSSH_CHANNEL* channel = NULL;
word32 begin = *idx;
word32 channelId;
int ret;
WLOG(WS_LOG_DEBUG, "Entering DoChannelEof()");
ret = GetUint32(&channelId, buf, len, &begin);
if (ret == WS_SUCCESS) {
*idx = begin;
channel = ChannelFind(ssh, channelId, FIND_SELF);
if (channel == NULL)
ret = WS_INVALID_CHANID;
}
channel->receivedEof = 1;
WLOG(WS_LOG_DEBUG, "Leaving DoChannelEof(), ret = %d", ret);
return ret;
}
static int DoChannelClose(WOLFSSH* ssh,
byte* buf, word32 len, word32* idx)
{
@ -3516,7 +3574,7 @@ static int DoChannelClose(WOLFSSH* ssh,
}
if (ret == WS_SUCCESS)
ret = SendChannelClose(ssh, channelId);
ret = SendChannelClose(ssh, channel->peerChannel);
if (ret == WS_SUCCESS)
ret = ChannelRemove(ssh, channelId, FIND_SELF);
@ -3532,6 +3590,7 @@ static int DoChannelClose(WOLFSSH* ssh,
static int DoChannelRequest(WOLFSSH* ssh,
byte* buf, word32 len, word32* idx)
{
WOLFSSH_CHANNEL* channel = NULL;
word32 begin = *idx;
word32 channelId;
word32 typeSz;
@ -3555,6 +3614,12 @@ static int DoChannelRequest(WOLFSSH* ssh,
return ret;
}
if (ret == WS_SUCCESS) {
channel = ChannelFind(ssh, channelId, FIND_SELF);
if (channel == NULL)
ret = WS_INVALID_CHANID;
}
if (ret == WS_SUCCESS) {
WLOG(WS_LOG_DEBUG, " channelId = %u", channelId);
WLOG(WS_LOG_DEBUG, " type = %s", type);
@ -3602,6 +3667,24 @@ static int DoChannelRequest(WOLFSSH* ssh,
WLOG(WS_LOG_DEBUG, " %s = %s", name, value);
}
else if (WSTRNCMP(type, "shell", typeSz) == 0) {
channel->sessionType = WOLFSSH_SESSION_SHELL;
ssh->clientState = CLIENT_DONE;
}
else if (WSTRNCMP(type, "exec", typeSz) == 0) {
ret = GetStringAlloc(ssh, &channel->command, buf, len, &begin);
channel->sessionType = WOLFSSH_SESSION_EXEC;
ssh->clientState = CLIENT_DONE;
WLOG(WS_LOG_DEBUG, " command = %s", channel->command);
}
else if (WSTRNCMP(type, "subsystem", typeSz) == 0) {
ret = GetStringAlloc(ssh, &channel->command, buf, len, &begin);
channel->sessionType = WOLFSSH_SESSION_SUBSYSTEM;
ssh->clientState = CLIENT_DONE;
WLOG(WS_LOG_DEBUG, " subsystem = %s", channel->command);
}
}
if (ret == WS_SUCCESS)
@ -3866,6 +3949,7 @@ static int DoPacket(WOLFSSH* ssh)
case MSGID_CHANNEL_EOF:
WLOG(WS_LOG_DEBUG, "Decoding MSGID_CHANNEL_EOF");
ret = DoChannelEof(ssh, buf + idx, payloadSz, &payloadIdx);
ret = WS_SUCCESS;
break;
@ -4340,6 +4424,10 @@ int DoProtoId(WOLFSSH* ssh)
WLOG(WS_LOG_DEBUG, "SSH version mismatch");
return WS_VERSION_E;
}
if (WSTRNCMP((char*)ssh->inputBuffer.buffer,
OpenSSH, sizeof(OpenSSH)-1) == 0) {
ssh->clientOpenSSH = 1;
}
*eol = 0;
@ -6044,44 +6132,48 @@ int SendUserAuthBanner(WOLFSSH* ssh)
byte* output;
word32 idx;
int ret = WS_SUCCESS;
const char* banner;
const char* banner = NULL;
word32 bannerSz = 0;
WLOG(WS_LOG_DEBUG, "Entering SendUserAuthBanner()");
if (ssh == NULL)
ret = WS_BAD_ARGUMENT;
if (ssh->ctx->banner != NULL && ssh->ctx->bannerSz > 0) {
if (ret == WS_SUCCESS) {
banner = ssh->ctx->banner;
bannerSz = ssh->ctx->bannerSz;
}
if (ret == WS_SUCCESS)
ret = PreparePacket(ssh, MSG_ID_SZ + (LENGTH_SZ * 2) +
bannerSz + cannedLangTagSz);
if (banner != NULL && bannerSz > 0) {
if (ret == WS_SUCCESS)
ret = PreparePacket(ssh, MSG_ID_SZ + (LENGTH_SZ * 2) +
bannerSz + cannedLangTagSz);
if (ret == WS_SUCCESS) {
output = ssh->outputBuffer.buffer;
idx = ssh->outputBuffer.length;
if (ret == WS_SUCCESS) {
output = ssh->outputBuffer.buffer;
idx = ssh->outputBuffer.length;
output[idx++] = MSGID_USERAUTH_BANNER;
c32toa(bannerSz, output + idx);
idx += LENGTH_SZ;
if (bannerSz > 0)
WMEMCPY(output + idx, banner, bannerSz);
idx += bannerSz;
c32toa(cannedLangTagSz, output + idx);
idx += LENGTH_SZ;
WMEMCPY(output + idx, cannedLangTag, cannedLangTagSz);
idx += cannedLangTagSz;
output[idx++] = MSGID_USERAUTH_BANNER;
c32toa(bannerSz, output + idx);
idx += LENGTH_SZ;
if (bannerSz > 0)
WMEMCPY(output + idx, banner, bannerSz);
idx += bannerSz;
c32toa(cannedLangTagSz, output + idx);
idx += LENGTH_SZ;
WMEMCPY(output + idx, cannedLangTag, cannedLangTagSz);
idx += cannedLangTagSz;
ssh->outputBuffer.length = idx;
ssh->outputBuffer.length = idx;
ret = BundlePacket(ssh);
ret = BundlePacket(ssh);
}
}
if (ret == WS_SUCCESS)
ret = SendBuffered(ssh);
WLOG(WS_LOG_DEBUG, "Leaving SendUserAuthBanner()");
return ret;
}
@ -6273,6 +6365,111 @@ int SendChannelEof(WOLFSSH* ssh, word32 peerChannelId)
}
int SendChannelEow(WOLFSSH* ssh, word32 peerChannelId)
{
byte* output;
word32 idx;
word32 strSz = sizeof("eow@openssh.com");
int ret = WS_SUCCESS;
WOLFSSH_CHANNEL* channel;
WLOG(WS_LOG_DEBUG, "Entering SendChannelEow()");
if (ssh == NULL)
ret = WS_BAD_ARGUMENT;
if (!ssh->clientOpenSSH) {
WLOG(WS_LOG_DEBUG, "Leaving SendChannelEow(), not OpenSSH");
return ret;
}
if (ret == WS_SUCCESS) {
channel = ChannelFind(ssh, peerChannelId, FIND_PEER);
if (channel == NULL)
ret = WS_INVALID_CHANID;
}
if (ret == WS_SUCCESS)
ret = PreparePacket(ssh, MSG_ID_SZ + UINT32_SZ + LENGTH_SZ + strSz +
BOOLEAN_SZ);
if (ret == WS_SUCCESS) {
output = ssh->outputBuffer.buffer;
idx = ssh->outputBuffer.length;
output[idx++] = MSGID_CHANNEL_REQUEST;
c32toa(channel->peerChannel, output + idx);
idx += UINT32_SZ;
c32toa(strSz, output + idx);
idx += LENGTH_SZ;
WMEMCPY(output + idx, "eow@openssh.com", strSz);
idx += strSz;
output[idx++] = 0; // false
ssh->outputBuffer.length = idx;
ret = BundlePacket(ssh);
}
if (ret == WS_SUCCESS)
ret = SendBuffered(ssh);
WLOG(WS_LOG_DEBUG, "Leaving SendChannelEow(), ret = %d", ret);
return ret;
}
int SendChannelExit(WOLFSSH* ssh, word32 peerChannelId, int status)
{
byte* output;
word32 idx;
word32 strSz = sizeof("exit-status");
int ret = WS_SUCCESS;
WOLFSSH_CHANNEL* channel;
WLOG(WS_LOG_DEBUG, "Entering SendChannelExit(), status = %d", status);
if (ssh == NULL)
ret = WS_BAD_ARGUMENT;
if (ret == WS_SUCCESS) {
channel = ChannelFind(ssh, peerChannelId, FIND_PEER);
if (channel == NULL)
ret = WS_INVALID_CHANID;
}
if (ret == WS_SUCCESS)
ret = PreparePacket(ssh, MSG_ID_SZ + UINT32_SZ + LENGTH_SZ + strSz +
BOOLEAN_SZ + UINT32_SZ);
if (ret == WS_SUCCESS) {
output = ssh->outputBuffer.buffer;
idx = ssh->outputBuffer.length;
output[idx++] = MSGID_CHANNEL_REQUEST;
c32toa(channel->peerChannel, output + idx);
idx += UINT32_SZ;
c32toa(strSz, output + idx);
idx += LENGTH_SZ;
WMEMCPY(output + idx, "exit-status", strSz);
idx += strSz;
output[idx++] = 0; // false
c32toa(status, output + idx);
idx += UINT32_SZ;
ssh->outputBuffer.length = idx;
ret = BundlePacket(ssh);
}
if (ret == WS_SUCCESS)
ret = SendBuffered(ssh);
WLOG(WS_LOG_DEBUG, "Leaving SendChannelExit(), ret = %d", ret);
return ret;
}
int SendChannelClose(WOLFSSH* ssh, word32 peerChannelId)
{
byte* output;
@ -6289,6 +6486,10 @@ int SendChannelClose(WOLFSSH* ssh, word32 peerChannelId)
channel = ChannelFind(ssh, peerChannelId, FIND_PEER);
if (channel == NULL)
ret = WS_INVALID_CHANID;
else if (channel->closeSent) {
WLOG(WS_LOG_DEBUG, "Leaving SendChannelClose(), already sent");
return ret;
}
}
if (ret == WS_SUCCESS)
@ -6307,8 +6508,10 @@ int SendChannelClose(WOLFSSH* ssh, word32 peerChannelId)
ret = BundlePacket(ssh);
}
if (ret == WS_SUCCESS)
if (ret == WS_SUCCESS) {
ret = SendBuffered(ssh);
channel->closeSent = 1;
}
WLOG(WS_LOG_DEBUG, "Leaving SendChannelClose(), ret = %d", ret);
return ret;

View File

@ -346,7 +346,7 @@ int wolfSSH_accept(WOLFSSH* ssh)
FALL_THROUGH;
case ACCEPT_SERVER_USERAUTH_SENT:
while (ssh->clientState < CLIENT_DONE) {
while (ssh->clientState < CLIENT_CHANNEL_OPEN_DONE) {
if ( (ssh->error = DoReceive(ssh)) < 0) {
WLOG(WS_LOG_DEBUG, acceptError,
"SERVER_USERAUTH_SENT", ssh->error);
@ -365,6 +365,18 @@ int wolfSSH_accept(WOLFSSH* ssh)
}
ssh->acceptState = ACCEPT_SERVER_CHANNEL_ACCEPT_SENT;
WLOG(WS_LOG_DEBUG, acceptState, "SERVER_CHANNEL_ACCEPT_SENT");
case ACCEPT_SERVER_CHANNEL_ACCEPT_SENT:
while (ssh->clientState < CLIENT_DONE) {
if ( (ssh->error = DoReceive(ssh)) < 0) {
WLOG(WS_LOG_DEBUG, acceptError,
"SERVER_CHANNEL_ACCEPT_SENT", ssh->error);
return WS_FATAL_ERROR;
}
}
ssh->acceptState = ACCEPT_CLIENT_SESSION_ESTABLISHED;
WLOG(WS_LOG_DEBUG, acceptState, "CLIENT_SESSION_ESTABLISHED");
}
return WS_SUCCESS;
@ -604,6 +616,8 @@ int wolfSSH_stream_read(WOLFSSH* ssh, byte* buf, word32 bufSz)
while (inputBuffer->length - inputBuffer->idx == 0) {
int ret = DoReceive(ssh);
if (ssh->channelList == NULL || ssh->channelList->receivedEof)
ret = WS_EOF;
if (ret < 0) {
WLOG(WS_LOG_DEBUG, "Leaving wolfSSH_stream_read(), ret = %d", ret);
return ret;
@ -663,6 +677,32 @@ int wolfSSH_stream_send(WOLFSSH* ssh, byte* buf, word32 bufSz)
}
int wolfSSH_stream_exit(WOLFSSH* ssh, int status)
{
int ret = WS_SUCCESS;
WLOG(WS_LOG_DEBUG, "Entering wolfSSH_stream_exit(), status = %d", status);
if (ssh == NULL || ssh->channelList == NULL)
ret = WS_BAD_ARGUMENT;
if (ret == WS_SUCCESS)
ret = SendChannelExit(ssh, ssh->channelList->peerChannel, status);
if (ret == WS_SUCCESS)
ret = SendChannelEow(ssh, ssh->channelList->peerChannel);
if (ret == WS_SUCCESS)
ret = SendChannelEof(ssh, ssh->channelList->peerChannel);
if (ret == WS_SUCCESS)
ret = SendChannelClose(ssh, ssh->channelList->peerChannel);
WLOG(WS_LOG_DEBUG, "Leaving wolfSSH_stream_exit()");
return ret;
}
void wolfSSH_SetUserAuth(WOLFSSH_CTX* ctx, WS_CallbackUserAuth cb)
{
if (ctx != NULL) {
@ -790,3 +830,24 @@ int wolfSSH_KDF(byte hashId, byte keyId,
sessionId, sessionIdSz);
}
WS_SessionType wolfSSH_GetSessionType(const WOLFSSH* ssh)
{
WLOG(WS_LOG_DEBUG, "Entering wolfSSH_GetSessionCommand()");
if (ssh && ssh->channelList)
return ssh->channelList->sessionType;
return WOLFSSH_SESSION_UNKNOWN;
}
const char* wolfSSH_GetSessionCommand(const WOLFSSH* ssh)
{
WLOG(WS_LOG_DEBUG, "Entering wolfSSH_GetSessionCommand()");
if (ssh && ssh->channelList)
return ssh->channelList->command;
return NULL;
}

View File

@ -68,6 +68,7 @@ enum WS_ErrorCodes {
WS_INVALID_USERNAME = -28,
WS_CRYPTO_FAILED = -29, /* crypto action failed */
WS_INVALID_STATE_E = -30,
WS_EOF = -31,
WS_INVALID_PRIME_CURVE = -32,
WS_ECC_E = -33,
WS_CHANOPEN_FAILED = -34,

View File

@ -258,6 +258,7 @@ struct WOLFSSH {
byte connReset;
byte isClosed;
byte clientOpenSSH;
byte blockSz;
byte encryptId;
@ -307,6 +308,9 @@ struct WOLFSSH {
struct WOLFSSH_CHANNEL {
byte channelType;
byte sessionType;
byte closeSent;
byte receivedEof;
word32 channel;
word32 windowSz;
word32 maxPacketSz;
@ -314,6 +318,7 @@ struct WOLFSSH_CHANNEL {
word32 peerWindowSz;
word32 peerMaxPacketSz;
Buffer inputBuffer;
char* command;
struct WOLFSSH* ssh;
struct WOLFSSH_CHANNEL* next;
};
@ -369,7 +374,9 @@ WOLFSSH_LOCAL int SendRequestSuccess(WOLFSSH*, int);
WOLFSSH_LOCAL int SendChannelOpenSession(WOLFSSH*, word32, word32);
WOLFSSH_LOCAL int SendChannelOpenConf(WOLFSSH*);
WOLFSSH_LOCAL int SendChannelEof(WOLFSSH*, word32);
WOLFSSH_LOCAL int SendChannelEow(WOLFSSH*, word32);
WOLFSSH_LOCAL int SendChannelClose(WOLFSSH*, word32);
WOLFSSH_LOCAL int SendChannelExit(WOLFSSH*, word32, int);
WOLFSSH_LOCAL int SendChannelData(WOLFSSH*, word32, byte*, word32);
WOLFSSH_LOCAL int SendChannelWindowAdjust(WOLFSSH*, word32, word32);
WOLFSSH_LOCAL int SendChannelRequestShell(WOLFSSH*);
@ -389,7 +396,8 @@ enum AcceptStates {
ACCEPT_CLIENT_USERAUTH_DONE,
ACCEPT_SERVER_USERAUTH_SENT,
ACCEPT_CLIENT_CHANNEL_REQUEST_DONE,
ACCEPT_SERVER_CHANNEL_ACCEPT_SENT
ACCEPT_SERVER_CHANNEL_ACCEPT_SENT,
ACCEPT_CLIENT_SESSION_ESTABLISHED
};
@ -419,6 +427,7 @@ enum ClientStates {
CLIENT_KEXDH_INIT_DONE,
CLIENT_USERAUTH_REQUEST_DONE,
CLIENT_USERAUTH_DONE,
CLIENT_CHANNEL_OPEN_DONE,
CLIENT_DONE
};

View File

@ -136,6 +136,7 @@ WOLFSSH_API int wolfSSH_connect(WOLFSSH*);
WOLFSSH_API int wolfSSH_shutdown(WOLFSSH*);
WOLFSSH_API int wolfSSH_stream_read(WOLFSSH*, byte*, word32);
WOLFSSH_API int wolfSSH_stream_send(WOLFSSH*, byte*, word32);
WOLFSSH_API int wolfSSH_stream_exit(WOLFSSH*, int);
WOLFSSH_API int wolfSSH_TriggerKeyExchange(WOLFSSH*);
WOLFSSH_API void wolfSSH_GetStats(WOLFSSH*,
@ -145,6 +146,17 @@ WOLFSSH_API int wolfSSH_KDF(byte, byte, byte*, word32, const byte*, word32,
const byte*, word32, const byte*, word32);
typedef enum {
WOLFSSH_SESSION_UNKNOWN = 0,
WOLFSSH_SESSION_SHELL,
WOLFSSH_SESSION_EXEC,
WOLFSSH_SESSION_SUBSYSTEM,
} WS_SessionType;
WOLFSSH_API WS_SessionType wolfSSH_GetSessionType(const WOLFSSH*);
WOLFSSH_API const char* wolfSSH_GetSessionCommand(const WOLFSSH*);
enum WS_HighwaterSide {
WOLFSSH_HWSIDE_TRANSMIT,
WOLFSSH_HWSIDE_RECEIVE