From b548720a9ab05435c203b563fece5fc25c10ea23 Mon Sep 17 00:00:00 2001 From: John Safranek Date: Wed, 7 Jan 2015 13:49:01 -0800 Subject: [PATCH] 1. added in the stream send function 2. example uses the new send function 3. added in window size update receipt 4. tweaked the accept state machine to actually finish --- examples/server/server.c | 8 +-- src/internal.c | 150 ++++++++++++++++++++++++++++++++------- src/log.c | 2 +- src/ssh.c | 36 +++++++--- wolfssh/error.h | 24 ++++--- wolfssh/internal.h | 15 ++-- wolfssh/ssh.h | 4 +- 7 files changed, 183 insertions(+), 56 deletions(-) diff --git a/examples/server/server.c b/examples/server/server.c index 289b7148..c9c3d635 100644 --- a/examples/server/server.c +++ b/examples/server/server.c @@ -245,13 +245,13 @@ static THREAD_RETURN CYASSL_THREAD server_worker(void* vArgs) { WOLFSSH* ssh = (WOLFSSH*)vArgs; SOCKET_T clientFd = wolfSSH_get_fd(ssh); - const char* msgA = "Who's there?!\n"; - const char* msgB = "Go away!\n"; + const char* msgA = "Who's there?!\r\n"; + const char* msgB = "Go away!\r\n"; if (wolfSSH_accept(ssh) == WS_SUCCESS) { - send(clientFd, msgA, strlen(msgA), 0); + wolfSSH_stream_send(ssh, (uint8_t*)msgA, (uint32_t)strlen(msgA)); sleep(1); - send(clientFd, msgB, strlen(msgB), 0); + wolfSSH_stream_send(ssh, (uint8_t*)msgB, (uint32_t)strlen(msgB)); } close(clientFd); wolfSSH_free(ssh); diff --git a/src/internal.c b/src/internal.c index 9ef8f791..e74709c1 100644 --- a/src/internal.c +++ b/src/internal.c @@ -136,6 +136,9 @@ const char* GetErrorString(int err) case WS_CREATE_MAC_E: return "verify mac error"; + case WS_RESOURCE_E: + return "insufficient resources for new channel"; + default: return "Unknown error code"; } @@ -169,7 +172,10 @@ static const NameIdPair NameIdMap[] = { { ID_SSH_RSA, "ssh-rsa" }, /* UserAuth IDs */ - { ID_USERAUTH_PASSWORD, "password" } + { ID_USERAUTH_PASSWORD, "password" }, + + /* Channel Type IDs */ + { ID_CHANTYPE_SESSION, "session" } }; @@ -207,6 +213,33 @@ const char* IdToName(uint8_t id) } +static Channel* ChannelNew(WOLFSSH* ssh, uint8_t channelType, + uint32_t peerChannel, + uint32_t peerInitialWindowSz, + uint32_t peerMaxPacketSz) +{ + Channel *newChannel = NULL; + + WLOG(WS_LOG_DEBUG, "Entering ChannelNew()"); + + if (!ssh->channel.inUse) { + newChannel = &ssh->channel; + newChannel->inUse = 1; + newChannel->channelType = channelType; + newChannel->channel = ssh->nextChannel++; + newChannel->windowSz = DEFAULT_WINDOW_SZ; + newChannel->maxPacketSz = DEFAULT_MAX_PACKET_SZ; + newChannel->peerChannel = peerChannel; + newChannel->peerWindowSz = peerInitialWindowSz; + newChannel->peerMaxPacketSz = peerMaxPacketSz; + } + + WLOG(WS_LOG_INFO, "Leaving ChannelNew(), ret = %p", newChannel); + + return newChannel; +} + + int BufferInit(Buffer* buffer, uint32_t size, void* heap) { if (buffer == NULL) @@ -1273,40 +1306,51 @@ static int DoChannelOpen(WOLFSSH* ssh, uint32_t begin = *idx; uint32_t typeSz; char type[32]; - uint32_t channel; - uint32_t initialWindowSz; - uint32_t maxPacketSz; + uint8_t typeId; + uint32_t peerChannel; + uint32_t peerInitialWindowSz; + uint32_t peerMaxPacketSz; int ret; + Channel* newChannel; WLOG(WS_LOG_DEBUG, "Entering DoChannelOpen()"); - (void)ssh; - (void)len; - ret = GetString(type, &typeSz, buf, len, &begin); if (ret == WS_SUCCESS) - ret = GetUint32(&channel, buf, len, &begin); + ret = GetUint32(&peerChannel, buf, len, &begin); if (ret == WS_SUCCESS) - ret = GetUint32(&initialWindowSz, buf, len, &begin); + ret = GetUint32(&peerInitialWindowSz, buf, len, &begin); if (ret == WS_SUCCESS) - ret = GetUint32(&maxPacketSz, buf, len, &begin); + ret = GetUint32(&peerMaxPacketSz, buf, len, &begin); if (ret != WS_SUCCESS) { WLOG(WS_LOG_DEBUG, "Leaving DoChannelOpen(), ret = %d", ret); return ret; } - WLOG(WS_LOG_DEBUG, " type = %s", type); - WLOG(WS_LOG_DEBUG, " channel = %u", channel); - WLOG(WS_LOG_DEBUG, " initialWindowSz = %u", initialWindowSz); - WLOG(WS_LOG_DEBUG, " maxPacketSz = %u", maxPacketSz); + WLOG(WS_LOG_INFO, " type = %s", type); + WLOG(WS_LOG_INFO, " peerChannel = %u", peerChannel); + WLOG(WS_LOG_INFO, " peerInitialWindowSz = %u", peerInitialWindowSz); + WLOG(WS_LOG_INFO, " peerMaxPacketSz = %u", peerMaxPacketSz); *idx = begin; - ssh->clientState = CLIENT_CHANNEL_REQUEST_DONE; + typeId = NameToId(type, typeSz); + if (typeId != ID_CHANTYPE_SESSION) + return WS_INVALID_CHANTYPE; + + newChannel = ChannelNew(ssh, typeId, + peerChannel, peerInitialWindowSz, peerMaxPacketSz); + if (newChannel == NULL) + return WS_RESOURCE_E; + + ssh->clientState = CLIENT_DONE; + newChannel->peerChannel = peerChannel; + newChannel->peerWindowSz = peerInitialWindowSz; + newChannel->peerMaxPacketSz = peerMaxPacketSz; return WS_SUCCESS; } @@ -1398,6 +1442,36 @@ static int DoChannelRequest(WOLFSSH* ssh, } +static int DoChannelWindowAdjust(WOLFSSH* ssh, + uint8_t* buf, uint32_t len, uint32_t* idx) +{ + uint32_t begin = *idx; + uint32_t channel, bytesToAdd; + int ret; + + WLOG(WS_LOG_DEBUG, "Entering DoChannelWindowAdjust()"); + + ret = GetUint32(&channel, buf, len, &begin); + if (ret == WS_SUCCESS) + ret = GetUint32(&bytesToAdd, buf, len, &begin); + + if (ret != WS_SUCCESS) { + WLOG(WS_LOG_DEBUG, "Leaving DoChannelWindowAdjust(), ret = %d", ret); + return ret; + } + + WLOG(WS_LOG_INFO, " channel = %u", channel); + WLOG(WS_LOG_INFO, " bytesToAdd = %u", bytesToAdd); + WLOG(WS_LOG_INFO, " peerWindowSz = %u", ssh->channel.peerWindowSz); + + ssh->channel.peerWindowSz += bytesToAdd; + WLOG(WS_LOG_INFO, " update peerWindowSz = %u", ssh->channel.peerWindowSz); + + WLOG(WS_LOG_DEBUG, "Leaving DoChannelWindowAdjust()"); + return WS_SUCCESS; +} + + static int DoChannelData(WOLFSSH* ssh, uint8_t* buf, uint32_t len, uint32_t* idx) { @@ -1416,7 +1490,7 @@ static int DoChannelData(WOLFSSH* ssh, return ret; } - SendChannelData(ssh, channel, buf + begin, dataSz); + SendChannelData(ssh, ssh->channel.peerChannel, buf + begin, dataSz); *idx = begin + dataSz; @@ -1505,6 +1579,12 @@ static int DoPacket(WOLFSSH* ssh) idx += payloadIdx; break; + case MSGID_CHANNEL_WINDOW_ADJUST: + WLOG(WS_LOG_DEBUG, "Decoding MSGID_CHANNEL_WINDOW_ADJUST"); + DoChannelWindowAdjust(ssh, buf + idx, payloadSz, &payloadIdx); + idx += payloadIdx; + break; + case MSGID_CHANNEL_DATA: WLOG(WS_LOG_DEBUG, "Decoding MSGID_CHANNEL_DATA"); DoChannelData(ssh, buf + idx, payloadSz, &payloadIdx); @@ -2197,7 +2277,7 @@ int SendNewKeys(WOLFSSH* ssh) idx = ssh->outputBuffer.length; output[idx++] = MSGID_NEWKEYS; - + ssh->outputBuffer.length = idx; BundlePacket(ssh); @@ -2470,11 +2550,17 @@ int SendChannelOpenConf(WOLFSSH* ssh) { uint8_t* output; uint32_t idx; + Channel* channel; WLOG(WS_LOG_DEBUG, "Entering SendChannelOpenConf()"); - if (ssh == NULL) + if (ssh == NULL) { + WLOG(WS_LOG_DEBUG, "Leaving SendChannelOpenConf(), ret = %d", + WS_BAD_ARGUMENT); return WS_BAD_ARGUMENT; + } + + channel = &ssh->channel; PreparePacket(ssh, MSG_ID_SZ + (UINT32_SZ * 4)); @@ -2482,13 +2568,13 @@ int SendChannelOpenConf(WOLFSSH* ssh) idx = ssh->outputBuffer.length; output[idx++] = MSGID_CHANNEL_OPEN_CONF; - c32toa(0, output + idx); /* recipient channel */ + c32toa(channel->peerChannel, output + idx); idx += UINT32_SZ; - c32toa(0, output + idx); /* sender channel */ + c32toa(channel->channel, output + idx); idx += UINT32_SZ; - c32toa(DEFAULT_WINDOW_SZ, output + idx); + c32toa(channel->windowSz, output + idx); idx += UINT32_SZ; - c32toa(DEFAULT_MAX_PACKET_SZ, output + idx); + c32toa(channel->maxPacketSz, output + idx); idx += UINT32_SZ; ssh->outputBuffer.length = idx; @@ -2496,20 +2582,31 @@ int SendChannelOpenConf(WOLFSSH* ssh) BundlePacket(ssh); SendBuffered(ssh); + WLOG(WS_LOG_DEBUG, "Leaving SendChannelOpenConf()"); return WS_SUCCESS; } -int SendChannelData(WOLFSSH* ssh, uint32_t channel, +int SendChannelData(WOLFSSH* ssh, uint32_t peerChannel, uint8_t* data, uint32_t dataSz) { uint8_t* output; uint32_t idx; + Channel* channel; WLOG(WS_LOG_DEBUG, "Entering SendChannelData()"); if (ssh == NULL) return WS_BAD_ARGUMENT; + channel = &ssh->channel; + + if (channel->peerChannel != peerChannel) { + WLOG(WS_LOG_DEBUG, "Invalid peer channel"); + } + + if (channel->peerWindowSz < dataSz) { + WLOG(WS_LOG_DEBUG, "Peer window too small"); + } PreparePacket(ssh, MSG_ID_SZ + UINT32_SZ + LENGTH_SZ + dataSz); @@ -2517,7 +2614,7 @@ int SendChannelData(WOLFSSH* ssh, uint32_t channel, idx = ssh->outputBuffer.length; output[idx++] = MSGID_CHANNEL_DATA; - c32toa(channel, output + idx); + c32toa(channel->peerChannel, output + idx); idx += UINT32_SZ; c32toa(dataSz, output + idx); idx += LENGTH_SZ; @@ -2529,6 +2626,11 @@ int SendChannelData(WOLFSSH* ssh, uint32_t channel, BundlePacket(ssh); SendBuffered(ssh); + WLOG(WS_LOG_INFO, " dataSz = %u", dataSz); + WLOG(WS_LOG_INFO, " peerWindowSz = %u", channel->peerWindowSz); + channel->peerWindowSz -= dataSz; + WLOG(WS_LOG_INFO, " update peerWindowSz = %u", channel->peerWindowSz); + WLOG(WS_LOG_DEBUG, "Leaving SendChannelData()"); return WS_SUCCESS; } diff --git a/src/log.c b/src/log.c index 1d963652..6308ff62 100644 --- a/src/log.c +++ b/src/log.c @@ -158,7 +158,7 @@ void WLOG(enum wolfSSH_LogLevel level, const char *const fmt, ...) if (logFunction) logFunction(level, msgStr); else - fprintf(stderr, "%s: [%s] %s\n", timeStr, GetLogStr(level), msgStr); + fprintf(stdout, "%s: [%s] %s\n", timeStr, GetLogStr(level), msgStr); } #endif /* DEBUG_WOLFSSH */ diff --git a/src/ssh.c b/src/ssh.c index 13c2aa4f..e3eff8a7 100644 --- a/src/ssh.c +++ b/src/ssh.c @@ -151,6 +151,7 @@ static WOLFSSH* SshInit(WOLFSSH* ssh, WOLFSSH_CTX* ctx) ssh->ioWriteCtx = &ssh->wfd; /* set */ ssh->acceptState = ACCEPT_BEGIN; ssh->clientState = CLIENT_BEGIN; + ssh->nextChannel = DEFAULT_NEXT_CHANNEL; ssh->blockSz = MIN_BLOCK_SZ; ssh->encryptId = ID_NONE; ssh->macId = ID_NONE; @@ -401,7 +402,7 @@ int wolfSSH_accept(WOLFSSH* ssh) WLOG(WS_LOG_DEBUG, acceptState, "SERVER_USERAUTH_SENT"); case ACCEPT_SERVER_USERAUTH_SENT: - while (ssh->clientState < CLIENT_CHANNEL_REQUEST_DONE) { + while (ssh->clientState < CLIENT_DONE) { if ( (ssh->error = ProcessReply(ssh)) < 0) { WLOG(WS_LOG_DEBUG, acceptError, "SERVER_USERAUTH_SENT", ssh->error); @@ -419,18 +420,31 @@ 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 = ProcessReply(ssh)) < 0) { - WLOG(WS_LOG_DEBUG, acceptError, - "SERVER_CHANNEL_ACCEPT_SENT", ssh->error); - return WS_FATAL_ERROR; - } - } } - return WS_FATAL_ERROR; + return WS_SUCCESS; +} + + +int wolfSSH_stream_read(WOLFSSH* ssh, uint8_t* buf, uint32_t bufSz) +{ + int bytesRxd = 0; + + (void)ssh; + (void)buf; + (void)bufSz; + + return bytesRxd; +} + + +int wolfSSH_stream_send(WOLFSSH* ssh, uint8_t* buf, uint32_t bufSz) +{ + int bytesTxd = 0; + + bytesTxd = SendChannelData(ssh, ssh->channel.peerChannel, buf, bufSz); + + return bytesTxd; } diff --git a/wolfssh/error.h b/wolfssh/error.h index c2ebf213..11c3ceb2 100644 --- a/wolfssh/error.h +++ b/wolfssh/error.h @@ -39,20 +39,20 @@ extern "C" { /* main public return values */ enum WS_ErrorCodes { - WS_SUCCESS = 0, /* function success */ - WS_FATAL_ERROR = -1, /* general function failure */ - WS_BAD_ARGUMENT = -2, /* bad function argument */ - WS_MEMORY_E = -3, /* memory allocation failure */ - WS_BUFFER_E = -4, /* input/output buffer size error */ - WS_PARSE_E = -5, /* general parsing error */ - WS_NOT_COMPILED = -6, /* feature not compiled in */ - WS_OVERFLOW_E = -7, /* would overflow if continued */ - WS_BAD_USAGE = -8, /* bad example usage */ + WS_SUCCESS = 0, /* function success */ + WS_FATAL_ERROR = -1, /* general function failure */ + WS_BAD_ARGUMENT = -2, /* bad function argument */ + WS_MEMORY_E = -3, /* memory allocation failure */ + WS_BUFFER_E = -4, /* input/output buffer size error */ + WS_PARSE_E = -5, /* general parsing error */ + WS_NOT_COMPILED = -6, /* feature not compiled in */ + WS_OVERFLOW_E = -7, /* would overflow if continued */ + WS_BAD_USAGE = -8, /* bad example usage */ WS_SOCKET_ERROR_E = -9, WS_WANT_READ = -10, WS_WANT_WRITE = -11, WS_RECV_OVERFLOW_E = -12, - WS_VERSION_E = -13, /* Peer using wrong version of SSH */ + WS_VERSION_E = -13, /* Peer using wrong version of SSH */ WS_SEND_OOB_READ_E = -14, WS_INPUT_CASE_E = -15, WS_BAD_FILETYPE_E = -16, @@ -63,7 +63,9 @@ enum WS_ErrorCodes { WS_DECRYPT_E = -21, WS_ENCRYPT_E = -22, WS_VERIFY_MAC_E = -23, - WS_CREATE_MAC_E = -24 + WS_CREATE_MAC_E = -24, + WS_RESOURCE_E = -25, /* insufficient resources for new channel */ + WS_INVALID_CHANTYPE = -26, /* invalid channel type */ }; diff --git a/wolfssh/internal.h b/wolfssh/internal.h index 9f6e73ae..c05cb5c2 100644 --- a/wolfssh/internal.h +++ b/wolfssh/internal.h @@ -81,6 +81,9 @@ enum { /* UserAuth IDs */ ID_USERAUTH_PASSWORD, + /* Channel Type IDs */ + ID_CHANTYPE_SESSION, + ID_UNKNOWN }; @@ -99,6 +102,7 @@ enum { #define UINT32_SZ 4 #define DEFAULT_WINDOW_SZ (1024 * 1024) #define DEFAULT_MAX_PACKET_SZ (16 * 1024) +#define DEFAULT_NEXT_CHANNEL 13013 WOLFSSH_LOCAL uint8_t NameToId(const char*, uint32_t); @@ -163,13 +167,14 @@ typedef struct HandshakeInfo { typedef struct Channel { + uint8_t inUse; uint8_t channelType; + uint32_t channel; uint32_t windowSz; uint32_t maxPacketSz; + uint32_t peerChannel; uint32_t peerWindowSz; uint32_t peerMaxPacketSz; - uint32_t channel; - uint32_t peerChannel; } Channel; @@ -210,6 +215,9 @@ struct WOLFSSH { Ciphers encryptCipher; Ciphers decryptCipher; + uint32_t nextChannel; + Channel channel; + Buffer inputBuffer; Buffer outputBuffer; RNG* rng; @@ -291,8 +299,6 @@ enum ClientStates { CLIENT_USING_KEYS, CLIENT_USERAUTH_REQUEST_DONE, CLIENT_USERAUTH_DONE, - CLIENT_CHANNEL_REQUEST_DONE, - CLIENT_CHANNEL_PTY_OPEN, CLIENT_DONE }; @@ -326,6 +332,7 @@ enum WS_MessageIds { MSGID_CHANNEL_OPEN = 90, MSGID_CHANNEL_OPEN_CONF = 91, + MSGID_CHANNEL_WINDOW_ADJUST = 93, MSGID_CHANNEL_DATA = 94, MSGID_CHANNEL_REQUEST = 98 }; diff --git a/wolfssh/ssh.h b/wolfssh/ssh.h index 85687832..058e26dd 100644 --- a/wolfssh/ssh.h +++ b/wolfssh/ssh.h @@ -83,7 +83,9 @@ WOLFSSH_API int wolfSSH_CTX_UseCert_buffer(WOLFSSH_CTX*, WOLFSSH_API int wolfSSH_CTX_UseCaCert_buffer(WOLFSSH_CTX*, const uint8_t*, uint32_t, int); -WOLFSSH_API int wolfSSH_accept(WOLFSSH* ssh); +WOLFSSH_API int wolfSSH_accept(WOLFSSH*); +WOLFSSH_API int wolfSSH_stream_read(WOLFSSH*, uint8_t*, uint32_t); +WOLFSSH_API int wolfSSH_stream_send(WOLFSSH*, uint8_t*, uint32_t); enum WS_EndpointTypes {