diff --git a/src/internal.c b/src/internal.c index 2355c7b..35d67ad 100644 --- a/src/internal.c +++ b/src/internal.c @@ -6780,6 +6780,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 +6811,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; diff --git a/src/ssh.c b/src/ssh.c index e857266..e9d4471 100644 --- a/src/ssh.c +++ b/src/ssh.c @@ -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; } diff --git a/src/wolfscp.c b/src/wolfscp.c index d022230..01d6fd5 100644 --- a/src/wolfscp.c +++ b/src/wolfscp.c @@ -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; diff --git a/src/wolfsftp.c b/src/wolfsftp.c index 99e4a6c..f78e7ce 100644 --- a/src/wolfsftp.c +++ b/src/wolfsftp.c @@ -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; } @@ -1235,7 +1235,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; @@ -1436,6 +1436,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; @@ -4911,7 +4912,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 && @@ -6382,7 +6383,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 */