Merge pull request #325 from JacobBarthelmeh/sftp

fix for handling rekey
pull/329/head
John Safranek 2021-03-11 08:21:10 -08:00 committed by GitHub
commit 3b61ea2ab8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 104 additions and 49 deletions

View File

@ -5246,6 +5246,16 @@ static int DoPacket(WOLFSSH* ssh)
case MSGID_KEXINIT:
WLOG(WS_LOG_DEBUG, "Decoding MSGID_KEXINIT");
ret = DoKexInit(ssh, buf + idx, payloadSz, &payloadIdx);
if (ssh->isKeying == 1 &&
ssh->connectState == CONNECT_SERVER_CHANNEL_REQUEST_DONE) {
if (ssh->handshake->kexId == ID_DH_GEX_SHA256) {
#ifndef WOLFSSH_NO_DH
ssh->error = SendKexDhGexRequest(ssh);
#endif
}
else
ssh->error = SendKexDhInit(ssh);
}
break;
case MSGID_NEWKEYS:
@ -6780,6 +6790,11 @@ int SendKexDhReply(WOLFSSH* ssh)
ret = wc_HashUpdate(&ssh->handshake->hash, enmhashId,
ssh->handshake->e, ssh->handshake->eSz);
/* reset size here because a previous shared secret could potentially be
* smaller by a byte than usual and cause buffer issues with re-key */
if (ret == 0)
ssh->kSz = MAX_KEX_KEY_SZ;
/* Make the server's DH f-value and the shared secret K. */
/* Or make the server's ECDH private value, and the shared secret K. */
if (ret == 0) {
@ -6806,8 +6821,9 @@ int SendKexDhReply(WOLFSSH* ssh)
else {
ecc_key pubKey;
ecc_key privKey;
int primeId = wcPrimeForId(ssh->handshake->kexId);
int primeId;
primeId = wcPrimeForId(ssh->handshake->kexId);
if (primeId == ECC_CURVE_INVALID)
ret = WS_INVALID_PRIME_CURVE;

119
src/ssh.c
View File

@ -968,8 +968,56 @@ int wolfSSH_stream_peek(WOLFSSH* ssh, byte* buf, word32 bufSz)
}
/* moves the window for more room
* returns WS_SUCCESS on success */
static int wolfSSH_stream_adjust_window(WOLFSSH* ssh)
{
word32 usedSz;
word32 bytesToAdd;
int ret;
Buffer* inputBuffer;
inputBuffer = &ssh->channelList->inputBuffer;
usedSz = inputBuffer->length - inputBuffer->idx;
bytesToAdd = inputBuffer->idx;
WLOG(WS_LOG_DEBUG, "Making more room: %u", usedSz);
if (usedSz) {
WLOG(WS_LOG_DEBUG, " ...moving data down");
WMEMMOVE(inputBuffer->buffer, inputBuffer->buffer + bytesToAdd, usedSz);
}
ret = SendChannelWindowAdjust(ssh, ssh->channelList->channel,
bytesToAdd);
if (ret != WS_SUCCESS) {
WLOG(WS_LOG_ERROR, "Error adjusting window");
}
else {
WLOG(WS_LOG_INFO, " bytesToAdd = %u", bytesToAdd);
WLOG(WS_LOG_INFO, " windowSz = %u", ssh->channelList->windowSz);
ssh->channelList->windowSz += bytesToAdd;
WLOG(WS_LOG_INFO, " update windowSz = %u", ssh->channelList->windowSz);
inputBuffer->length = usedSz;
inputBuffer->idx = 0;
}
return ret;
}
/* Wrapper function for ease of use to get data after it has been decrypted from
* the SSH connection. This function handles low level operations in addition to
* the read, such as window adjustment and high water checking.
*
* In non blocking mode use the function wolfSSH_get_error(ssh) to check for
* WS_WANT_READ / WS_WANT_WRITE after a fail case was hit with
* wolfSSH_stream_read().
*
* Returns the number of bytes read on success, negative values on fail
*/
int wolfSSH_stream_read(WOLFSSH* ssh, byte* buf, word32 bufSz)
{
int ret = WS_SUCCESS;
Buffer* inputBuffer;
WLOG(WS_LOG_DEBUG, "Entering wolfSSH_stream_read()");
@ -979,52 +1027,41 @@ int wolfSSH_stream_read(WOLFSSH* ssh, byte* buf, word32 bufSz)
inputBuffer = &ssh->channelList->inputBuffer;
while (inputBuffer->length - inputBuffer->idx == 0) {
int ret = DoReceive(ssh);
if (ssh->channelList == NULL || ssh->channelList->receivedEof)
ret = WS_EOF;
if (ret < 0 && ret != WS_CHAN_RXD) {
WLOG(WS_LOG_DEBUG, "Leaving wolfSSH_stream_read(), ret = %d", ret);
return ret;
}
if (ssh->error == WS_CHAN_RXD &&
ssh->lastRxId != ssh->channelList->channel) {
return WS_ERROR;
/* check if the window needs updated before attempting to read */
if ((ssh->channelList->windowSz == 0) || (!ssh->isKeying &&
(inputBuffer->length > inputBuffer->bufferSz / 2)))
ret = wolfSSH_stream_adjust_window(ssh);
if (ret == WS_SUCCESS) {
while (inputBuffer->length - inputBuffer->idx == 0) {
ret = DoReceive(ssh);
if (ssh->channelList == NULL || ssh->channelList->receivedEof)
ret = WS_EOF;
if (ret < 0 && ret != WS_CHAN_RXD) {
break;
}
if (ssh->error == WS_CHAN_RXD &&
ssh->lastRxId != ssh->channelList->channel) {
ret = WS_ERROR;
break;
}
}
}
bufSz = min(bufSz, inputBuffer->length - inputBuffer->idx);
WMEMCPY(buf, inputBuffer->buffer + inputBuffer->idx, bufSz);
inputBuffer->idx += bufSz;
if (!ssh->isKeying && (inputBuffer->length > inputBuffer->bufferSz / 2)) {
word32 usedSz = inputBuffer->length - inputBuffer->idx;
word32 bytesToAdd = inputBuffer->idx;
int sendResult;
WLOG(WS_LOG_DEBUG, "Making more room: %u", usedSz);
if (usedSz) {
WLOG(WS_LOG_DEBUG, " ...moving data down");
WMEMMOVE(inputBuffer->buffer,
inputBuffer->buffer + bytesToAdd, usedSz);
/* update internal input buffer based on data read */
if (ret == WS_SUCCESS) {
ret = min(bufSz, inputBuffer->length - inputBuffer->idx);
if (ret <= 0)
ret = WS_BUFFER_E;
else {
WMEMCPY(buf, inputBuffer->buffer + inputBuffer->idx, ret);
inputBuffer->idx += ret;
}
sendResult = SendChannelWindowAdjust(ssh, ssh->channelList->channel,
bytesToAdd);
if (sendResult != WS_SUCCESS)
bufSz = sendResult;
WLOG(WS_LOG_INFO, " bytesToAdd = %u", bytesToAdd);
WLOG(WS_LOG_INFO, " windowSz = %u", ssh->channelList->windowSz);
ssh->channelList->windowSz += bytesToAdd;
WLOG(WS_LOG_INFO, " update windowSz = %u", ssh->channelList->windowSz);
inputBuffer->length = usedSz;
inputBuffer->idx = 0;
}
WLOG(WS_LOG_DEBUG, "Leaving wolfSSH_stream_read(), rxd = %d", bufSz);
return bufSz;
WLOG(WS_LOG_DEBUG, "Leaving wolfSSH_stream_read(), rxd = %d", ret);
return ret;
}

View File

@ -572,7 +572,7 @@ int DoScpSource(WOLFSSH* ssh)
ret = wolfSSH_stream_send(ssh, ssh->scpFileBuffer,
ssh->scpBufferedSz);
if (ret == WS_WINDOW_FULL) {
if (ret == WS_WINDOW_FULL || ret == WS_REKEYING) {
ret = wolfSSH_worker(ssh, NULL);
if (ret == WS_SUCCESS)
continue;

View File

@ -504,7 +504,7 @@ static int wolfSSH_SFTP_buffer_send(WOLFSSH* ssh, WS_SFTP_BUFFER* buffer)
do {
ret = wolfSSH_stream_send(ssh, buffer->data + buffer->idx,
buffer->sz - buffer->idx);
if (ret == WS_WINDOW_FULL) {
if (ret == WS_WINDOW_FULL || ret == WS_REKEYING) {
ret = wolfSSH_worker(ssh, NULL);
if (ret == WS_SUCCESS)
continue; /* skip past increment and send more */
@ -786,8 +786,8 @@ static int SFTP_GetHeader(WOLFSSH* ssh, word32* reqId, byte* type,
ato32(buffer->data + UINT32_SZ + MSG_ID_SZ, reqId);
wolfSSH_SFTP_buffer_free(ssh, buffer);
WLOG(WS_LOG_SFTP, "Leaving SFTP_GetHeader(), %d",
len - UINT32_SZ - MSG_ID_SZ);
WLOG(WS_LOG_SFTP, "Leaving SFTP_GetHeader(), packet length = %d id = %d"
" type = %d", len - UINT32_SZ - MSG_ID_SZ, *reqId, *type);
return len - UINT32_SZ - MSG_ID_SZ;
}
@ -1258,7 +1258,7 @@ int wolfSSH_SFTP_read(WOLFSSH* ssh)
int maxSz, ret = WS_SUCCESS;
WS_SFTP_RECV_STATE* state = NULL;
WLOG(WS_LOG_DEBUG, "Entering wolfSSH_SFTP_read()");
WLOG(WS_LOG_SFTP, "Entering wolfSSH_SFTP_read()");
if (ssh == NULL)
return WS_BAD_ARGUMENT;
@ -1459,6 +1459,7 @@ int wolfSSH_SFTP_read(WOLFSSH* ssh)
if (ret < 0) {
if (ssh->error != WS_WANT_READ &&
ssh->error != WS_WANT_WRITE &&
ssh->error != WS_REKEYING &&
ssh->error != WS_WINDOW_FULL)
wolfSSH_SFTP_ClearState(ssh, STATE_ID_RECV);
return WS_FATAL_ERROR;
@ -4935,7 +4936,7 @@ int SendPacketType(WOLFSSH* ssh, byte type, byte* buf, word32 bufSz)
/* check for adjust window packet */
err = wolfSSH_get_error(ssh);
if (err == WS_WINDOW_FULL)
if (err == WS_WINDOW_FULL || err == WS_REKEYING)
ret = wolfSSH_worker(ssh, NULL);
ssh->error = err; /* don't save potential want read here */
} while (ret > 0 &&
@ -6406,7 +6407,8 @@ int wolfSSH_SFTP_SendWritePacket(WOLFSSH* ssh, byte* handle, word32 handleSz,
case STATE_SEND_WRITE_SEND_BODY:
WLOG(WS_LOG_SFTP, "SFTP SEND_WRITE STATE: SEND_BODY");
state->sentSz = wolfSSH_stream_send(ssh, in, inSz);
if (state->sentSz == WS_WINDOW_FULL) {
if (state->sentSz == WS_WINDOW_FULL ||
state->sentSz == WS_REKEYING) {
ret = wolfSSH_worker(ssh, NULL);
if (ret == WS_SUCCESS)
continue; /* skip past rest and send more */