mirror of https://github.com/wolfSSL/wolfssh.git
fixed buffer issue on receive
parent
1d2e1af069
commit
b331ff9cba
|
@ -48,12 +48,11 @@ static const NameIdPair NameIdMap[] = {
|
|||
};
|
||||
|
||||
|
||||
uint8_t NameToId(const char* name)
|
||||
uint8_t NameToId(const char* name, uint32_t nameSz)
|
||||
{
|
||||
uint8_t id = ID_UNKNOWN;
|
||||
size_t nameSz = WSTRLEN(name);
|
||||
uint32_t i;
|
||||
|
||||
(void)nameSz;
|
||||
for (i = 0; i < (sizeof(NameIdMap)/sizeof(NameIdPair)); i++) {
|
||||
if (nameSz == WSTRLEN(NameIdMap[i].name) &&
|
||||
WSTRNCMP(name, NameIdMap[i].name, nameSz) == 0) {
|
||||
|
@ -123,17 +122,29 @@ void BufferFree(Buffer* buf)
|
|||
}
|
||||
|
||||
|
||||
int GrowBuffer(Buffer* buf, uint32_t newSize)
|
||||
int GrowBuffer(Buffer* buf, uint32_t sz, uint32_t usedSz)
|
||||
{
|
||||
WLOG(WS_LOG_DEBUG, "GB: buf = %p", buf);
|
||||
WLOG(WS_LOG_DEBUG, "GB: sz = %d", sz);
|
||||
WLOG(WS_LOG_DEBUG, "GB: usedSz = %d", usedSz);
|
||||
/* New buffer will end up being sz+usedSz long
|
||||
* empty space at the head of the buffer will be compressed */
|
||||
if (buf != NULL) {
|
||||
if (newSize > buf->bufferSz) {
|
||||
uint8_t* newBuffer = (uint8_t*)WMALLOC(newSize,
|
||||
uint32_t newSz = sz + usedSz;
|
||||
WLOG(WS_LOG_DEBUG, "GB: newSz = %d", newSz);
|
||||
|
||||
if (newSz > buf->bufferSz) {
|
||||
uint8_t* newBuffer = (uint8_t*)WMALLOC(newSz,
|
||||
buf->heap, WOLFSSH_TYPE_BUFFER);
|
||||
|
||||
WLOG(WS_LOG_DEBUG, "Growing buffer");
|
||||
|
||||
if (newBuffer == NULL)
|
||||
return WS_MEMORY_E;
|
||||
|
||||
WLOG(WS_LOG_DEBUG, "GB: resizing buffer");
|
||||
if (buf->length > 0)
|
||||
WMEMCPY(newBuffer, buf->buffer, buf->length);
|
||||
WMEMCPY(newBuffer, buf->buffer + buf->idx, buf->length);
|
||||
|
||||
if (!buf->dynamicFlag)
|
||||
buf->dynamicFlag = 1;
|
||||
|
@ -141,7 +152,9 @@ int GrowBuffer(Buffer* buf, uint32_t newSize)
|
|||
WFREE(buf->buffer, buf->heap, WOLFSSH_TYPE_BUFFER);
|
||||
|
||||
buf->buffer = newBuffer;
|
||||
buf->bufferSz = newSize;
|
||||
buf->bufferSz = newSz;
|
||||
buf->length = usedSz;
|
||||
buf->idx = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -149,15 +162,26 @@ int GrowBuffer(Buffer* buf, uint32_t newSize)
|
|||
}
|
||||
|
||||
|
||||
int ShrinkBuffer(Buffer* buf)
|
||||
void ShrinkBuffer(Buffer* buf)
|
||||
{
|
||||
if (buf != NULL && buf->dynamicFlag) {
|
||||
WFREE(buf->buffer, buf->heap, WOLFSSH_TYPE_BUFFER);
|
||||
buf->buffer = NULL;
|
||||
buf->bufferSz = STATIC_BUFFER_LEN;
|
||||
}
|
||||
if (buf != NULL) {
|
||||
uint32_t usedSz = buf->length - buf->idx;
|
||||
|
||||
return WS_SUCCESS;
|
||||
if (usedSz > STATIC_BUFFER_LEN)
|
||||
return;
|
||||
|
||||
WLOG(WS_LOG_DEBUG, "Shrinking buffer");
|
||||
|
||||
if (usedSz)
|
||||
WMEMCPY(buf->staticBuffer, buf->buffer + buf->idx, usedSz);
|
||||
|
||||
WFREE(buf->buffer, buf->heap, WOLFSSH_TYPE_BUFFER);
|
||||
buf->dynamicFlag = 0;
|
||||
buf->buffer = buf->staticBuffer;
|
||||
buf->bufferSz = STATIC_BUFFER_LEN;
|
||||
buf->length = usedSz;
|
||||
buf->idx = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
172
src/ssh.c
172
src/ssh.c
|
@ -283,6 +283,7 @@ static int Receive(WOLFSSH* ssh, uint8_t* buf, uint32_t sz)
|
|||
|
||||
retry:
|
||||
recvd = ssh->ctx->ioRecvCb(ssh, buf, sz, ssh->ioReadCtx);
|
||||
WLOG(WS_LOG_DEBUG, "Receive: recvd = %d", recvd);
|
||||
if (recvd < 0)
|
||||
switch (recvd) {
|
||||
case WS_CBIO_ERR_GENERAL: /* general/unknown error */
|
||||
|
@ -319,7 +320,7 @@ static int GetInputText(WOLFSSH* ssh)
|
|||
int inSz = 255;
|
||||
int in;
|
||||
|
||||
if (GrowBuffer(ssh->inputBuffer, inSz) < 0)
|
||||
if (GrowBuffer(ssh->inputBuffer, inSz, 0) < 0)
|
||||
return WS_MEMORY_E;
|
||||
|
||||
do {
|
||||
|
@ -385,7 +386,7 @@ static int SendBuffer(WOLFSSH* ssh)
|
|||
|
||||
static int SendText(WOLFSSH* ssh, const char* text, uint32_t textLen)
|
||||
{
|
||||
GrowBuffer(ssh->outputBuffer, textLen);
|
||||
GrowBuffer(ssh->outputBuffer, textLen, 0);
|
||||
WMEMCPY(ssh->outputBuffer->buffer, text, textLen);
|
||||
ssh->outputBuffer->length = textLen;
|
||||
|
||||
|
@ -406,14 +407,38 @@ static int GetInputData(WOLFSSH* ssh, uint32_t size)
|
|||
maxLength = ssh->inputBuffer->bufferSz - usedLength;
|
||||
inSz = (int)(size - usedLength); /* from last partial read */
|
||||
|
||||
WLOG(WS_LOG_DEBUG, "GID: size = %d", size);
|
||||
WLOG(WS_LOG_DEBUG, "GID: usedLength = %d", usedLength);
|
||||
WLOG(WS_LOG_DEBUG, "GID: maxLength = %d", maxLength);
|
||||
WLOG(WS_LOG_DEBUG, "GID: inSz = %d", inSz);
|
||||
|
||||
/*
|
||||
* usedLength - how much untouched data is in the buffer
|
||||
* maxLength - how much empty space is in the buffer
|
||||
* inSz - difference between requested data and empty space in the buffer
|
||||
* how much more we need to allocate
|
||||
*/
|
||||
|
||||
if (inSz <= 0)
|
||||
return WS_BUFFER_E;
|
||||
|
||||
/*
|
||||
* If we need more space than there is left in the buffer grow buffer.
|
||||
* Growing the buffer also compresses empty space at the head of the
|
||||
* buffer and resets idx to 0.
|
||||
*/
|
||||
if (inSz > maxLength) {
|
||||
if (GrowBuffer(ssh->inputBuffer, size, usedLength) < 0)
|
||||
return WS_MEMORY_E;
|
||||
}
|
||||
|
||||
/* Put buffer data at start if not there */
|
||||
if (usedLength > 0 && ssh->inputBuffer->idx != 0)
|
||||
/* Compress the buffer if needed, i.e. buffer idx is non-zero */
|
||||
if (usedLength > 0 && ssh->inputBuffer->idx != 0) {
|
||||
WMEMMOVE(ssh->inputBuffer->buffer,
|
||||
ssh->inputBuffer->buffer + ssh->inputBuffer->idx,
|
||||
usedLength);
|
||||
}
|
||||
|
||||
/* remove processed data */
|
||||
ssh->inputBuffer->idx = 0;
|
||||
|
@ -441,8 +466,124 @@ static int GetInputData(WOLFSSH* ssh, uint32_t size)
|
|||
}
|
||||
|
||||
|
||||
static int DoKexInit(uint8_t* buf, uint32_t len, uint32_t* idx)
|
||||
static int DoNameList(uint8_t* list, uint8_t* listSz,
|
||||
uint8_t* buf, uint32_t len, uint32_t* idx)
|
||||
{
|
||||
uint8_t i = 0;
|
||||
uint32_t nameListSz;
|
||||
uint32_t begin = *idx;
|
||||
(void)list;
|
||||
|
||||
if (begin >= len || begin + 4 >= len)
|
||||
return -1;
|
||||
|
||||
ato32(buf + begin, &nameListSz);
|
||||
begin += 4;
|
||||
if (begin + nameListSz > len)
|
||||
return -1;
|
||||
|
||||
begin += nameListSz;
|
||||
/* list[0] = NameToId(nextName, 0); */
|
||||
|
||||
*listSz = i;
|
||||
*idx = begin;
|
||||
|
||||
return WS_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
static int DoKexInit(WOLFSSH* ssh, uint8_t* buf, uint32_t len, uint32_t* idx)
|
||||
{
|
||||
uint8_t list[3];
|
||||
uint8_t listSz;
|
||||
uint32_t skipSz;
|
||||
uint32_t begin = *idx;
|
||||
|
||||
/*
|
||||
* I don't need to save what the client sends here. I should decode
|
||||
* each list into a local array of IDs, and pick the one the peer is
|
||||
* using that's on my known list, or verify that the one the peer can
|
||||
* support the other direction is on my known list. All I need to do
|
||||
* is save the actual values.
|
||||
*
|
||||
* Save the cookie for now. Maybe that is used in KEX.
|
||||
*
|
||||
* byte[16] cookie
|
||||
* name-list kex_algorithms (2)
|
||||
* name-list server_host_key_algorithms (1)
|
||||
* name-list encryption_algorithms_client_to_server (3)
|
||||
* name-list encryption_algorithms_server_to_client (3)
|
||||
* name-list mac_algorithms_client_to_server (2)
|
||||
* name-list mac_algorithms_server_to_client (2)
|
||||
* name-list compression_algorithms_client_to_server (1)
|
||||
* name-list compression_algorithms_server_to_client (1)
|
||||
* name-list languages_client_to_server (0, skip)
|
||||
* name-list languages_server_to_client (0, skip)
|
||||
* boolean first_kex_packet_follows
|
||||
* uint32 0 (reserved for future extension)
|
||||
*/
|
||||
|
||||
/* Save the peer's cookie. */
|
||||
if (begin + COOKIE_SZ > len) {
|
||||
/* error, out of bounds */
|
||||
return -1;
|
||||
}
|
||||
WMEMCPY(ssh->peerCookie, buf + begin, COOKIE_SZ);
|
||||
begin += COOKIE_SZ;
|
||||
|
||||
/* KEX Algorithms */
|
||||
listSz = 2;
|
||||
DoNameList(list, &listSz, buf, len, &begin);
|
||||
|
||||
/* Server Host Key Algorithms */
|
||||
listSz = 1;
|
||||
DoNameList(list, &listSz, buf, len, &begin);
|
||||
|
||||
/* Enc Algorithms - Client to Server */
|
||||
listSz = 3;
|
||||
DoNameList(list, &listSz, buf, len, &begin);
|
||||
|
||||
/* Enc Algorithms - Server to Client */
|
||||
listSz = 3;
|
||||
DoNameList(list, &listSz, buf, len, &begin);
|
||||
|
||||
/* MAC Algorithms - Client to Server */
|
||||
listSz = 2;
|
||||
DoNameList(list, &listSz, buf, len, &begin);
|
||||
|
||||
/* MAC Algorithms - Server to Client */
|
||||
listSz = 2;
|
||||
DoNameList(list, &listSz, buf, len, &begin);
|
||||
|
||||
/* Compression Algorithms - Client to Server */
|
||||
listSz = 1;
|
||||
DoNameList(list, &listSz, buf, len, &begin);
|
||||
/* verify the list contains "none" */
|
||||
|
||||
/* Compression Algorithms - Server to Client */
|
||||
listSz = 1;
|
||||
DoNameList(list, &listSz, buf, len, &begin);
|
||||
/* verify the list contains "none" */
|
||||
|
||||
/* Languages - Client to Server, skip */
|
||||
ato32(buf + begin, &skipSz);
|
||||
begin += 4 + skipSz;
|
||||
|
||||
/* Languages - Server to Client, skip */
|
||||
ato32(buf + begin, &skipSz);
|
||||
begin += 4 + skipSz;
|
||||
|
||||
/* First KEX Packet Follows */
|
||||
ssh->kexPacketFollows = buf[begin];
|
||||
begin += 1;
|
||||
|
||||
/* Skip the "for future use" length. */
|
||||
ato32(buf + begin, &skipSz);
|
||||
begin += 4 + skipSz;
|
||||
|
||||
*idx = begin;
|
||||
|
||||
return WS_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
|
@ -452,23 +593,28 @@ static int DoPacket(WOLFSSH* ssh)
|
|||
uint32_t idx = ssh->inputBuffer->idx;
|
||||
uint32_t len = ssh->inputBuffer->length;
|
||||
uint8_t msg;
|
||||
uint8_t padSz;
|
||||
|
||||
/* Advance past packet size and padding size */
|
||||
idx += 5;
|
||||
padSz = buf[idx++];
|
||||
|
||||
msg = buf[idx++];
|
||||
switch (msg) {
|
||||
|
||||
case SSH_MSG_KEXINIT:
|
||||
WLOG(WS_LOG_DEBUG, "Decoding SSH_MSG_KEXINIT (%d)", len);
|
||||
DoKexInit(buf, len, &idx);
|
||||
WLOG(WS_LOG_DEBUG, "Decoding SSH_MSG_KEXINIT (len = %d)", len);
|
||||
DoKexInit(ssh, buf, len, &idx);
|
||||
break;
|
||||
|
||||
default:
|
||||
WLOG(WS_LOG_DEBUG, "Unsupported message ID");
|
||||
WLOG(WS_LOG_DEBUG, "Unsupported message ID (%d)", msg);
|
||||
break;
|
||||
}
|
||||
|
||||
if (idx + padSz > len) {
|
||||
return -1;
|
||||
}
|
||||
idx += padSz;
|
||||
|
||||
ssh->inputBuffer->idx = idx;
|
||||
return WS_SUCCESS;
|
||||
}
|
||||
|
@ -484,6 +630,7 @@ int ProcessReply(WOLFSSH* ssh)
|
|||
switch (ssh->processReplyState) {
|
||||
case PROCESS_INIT:
|
||||
readSz = ssh->blockSz;
|
||||
WLOG(WS_LOG_DEBUG, "PR1: size = %d", readSz);
|
||||
if ((ret = GetInputData(ssh, readSz)) < 0) {
|
||||
return ret;
|
||||
}
|
||||
|
@ -493,9 +640,11 @@ int ProcessReply(WOLFSSH* ssh)
|
|||
|
||||
case PROCESS_PACKET_LENGTH:
|
||||
ato32(ssh->inputBuffer->buffer + ssh->inputBuffer->idx, &ssh->curSz);
|
||||
ssh->inputBuffer->idx += LENGTH_SZ;
|
||||
ssh->processReplyState = PROCESS_PACKET_FINISH;
|
||||
|
||||
case PROCESS_PACKET_FINISH:
|
||||
WLOG(WS_LOG_DEBUG, "PR2: size = %d", ssh->curSz);
|
||||
if ((ret = GetInputData(ssh, ssh->curSz)) < 0) {
|
||||
|
||||
return ret;
|
||||
|
@ -542,7 +691,10 @@ int wolfSSH_accept(WOLFSSH* ssh)
|
|||
|
||||
case SERVER_VERSION_SENT:
|
||||
while (ssh->clientState < CLIENT_ALGO_DONE) {
|
||||
ProcessReply(ssh);
|
||||
if ( (ssh->error = ProcessReply(ssh)) < 0) {
|
||||
WLOG(WS_LOG_DEBUG, "accept reply error: %d", ssh->error);
|
||||
return WS_FATAL_ERROR;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -71,9 +71,12 @@ enum {
|
|||
#define MAX_INTEGRITY 2
|
||||
#define MAX_KEY_EXCHANGE 2
|
||||
#define MAX_PUBLIC_KEY 1
|
||||
#define COOKIE_SZ 16
|
||||
#define LENGTH_SZ 4
|
||||
#define PAD_LENGTH_SZ 1
|
||||
|
||||
|
||||
WOLFSSH_LOCAL uint8_t NameToId(const char*);
|
||||
WOLFSSH_LOCAL uint8_t NameToId(const char*, uint32_t);
|
||||
WOLFSSH_LOCAL const char* IdToName(uint8_t);
|
||||
|
||||
|
||||
|
@ -104,22 +107,16 @@ struct WOLFSSH {
|
|||
uint8_t connReset;
|
||||
uint8_t isClosed;
|
||||
|
||||
uint8_t encryptionId;
|
||||
uint8_t integrityId;
|
||||
uint8_t keyExchangeId;
|
||||
uint8_t publicKeyId;
|
||||
uint8_t encryptionId;
|
||||
uint8_t integrityId;
|
||||
uint8_t kexPacketFollows;
|
||||
|
||||
char* peerId;
|
||||
/* The lengths of the lists are contrained to how many of choices
|
||||
* we actually support. */
|
||||
uint8_t peerEncryptionList[MAX_ENCRYPTION];
|
||||
uint8_t peerEncryptionListSz;
|
||||
uint8_t peerIntegrityList[MAX_INTEGRITY];
|
||||
uint8_t peerIntegrityListSz;
|
||||
uint8_t peerKeyExchangeList[MAX_KEY_EXCHANGE];
|
||||
uint8_t peerKeyExchangeListSz;
|
||||
uint8_t peerPublicKeyList[MAX_PUBLIC_KEY];
|
||||
uint8_t peerPublicKeyListSz;
|
||||
|
||||
uint8_t peerCookie[COOKIE_SZ];
|
||||
uint8_t myCookie[COOKIE_SZ];
|
||||
|
||||
struct Buffer* inputBuffer;
|
||||
struct Buffer* outputBuffer;
|
||||
|
@ -198,8 +195,8 @@ typedef struct Buffer {
|
|||
|
||||
WOLFSSH_LOCAL Buffer* BufferNew(uint32_t, void*);
|
||||
WOLFSSH_LOCAL void BufferFree(Buffer*);
|
||||
WOLFSSH_LOCAL int GrowBuffer(Buffer*, uint32_t);
|
||||
WOLFSSH_LOCAL int ShrinkBuffer(Buffer* buf);
|
||||
WOLFSSH_LOCAL int GrowBuffer(Buffer*, uint32_t, uint32_t);
|
||||
WOLFSSH_LOCAL void ShrinkBuffer(Buffer* buf);
|
||||
|
||||
|
||||
WOLFSSH_LOCAL int ProcessClientVersion(WOLFSSH*);
|
||||
|
|
Loading…
Reference in New Issue