mirror of
https://github.com/libssh2/libssh2.git
synced 2025-12-03 13:31:12 +03:00
Security fixes (#315)
* Bounds checks Fixes for CVEs https://www.libssh2.org/CVE-2019-3863.html https://www.libssh2.org/CVE-2019-3856.html * Packet length bounds check CVE https://www.libssh2.org/CVE-2019-3855.html * Response length check CVE https://www.libssh2.org/CVE-2019-3859.html * Bounds check CVE https://www.libssh2.org/CVE-2019-3857.html * Bounds checking CVE https://www.libssh2.org/CVE-2019-3859.html and additional data validation * Check bounds before reading into buffers * Bounds checking CVE https://www.libssh2.org/CVE-2019-3859.html * declare SIZE_MAX and UINT_MAX if needed
This commit is contained in:
@@ -154,6 +154,18 @@ typedef int libssh2_socket_t;
|
|||||||
#define LIBSSH2_INVALID_SOCKET -1
|
#define LIBSSH2_INVALID_SOCKET -1
|
||||||
#endif /* WIN32 */
|
#endif /* WIN32 */
|
||||||
|
|
||||||
|
#ifndef SIZE_MAX
|
||||||
|
#if _WIN64
|
||||||
|
#define SIZE_MAX 0xFFFFFFFFFFFFFFFF
|
||||||
|
#else
|
||||||
|
#define SIZE_MAX 0xFFFFFFFF
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef UINT_MAX
|
||||||
|
#define UINT_MAX 0xFFFFFFFF
|
||||||
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Determine whether there is small or large file support on windows.
|
* Determine whether there is small or large file support on windows.
|
||||||
*/
|
*/
|
||||||
|
|||||||
129
src/channel.c
129
src/channel.c
@@ -239,7 +239,20 @@ _libssh2_channel_open(LIBSSH2_SESSION * session, const char *channel_type,
|
|||||||
goto channel_error;
|
goto channel_error;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(session->open_data_len < 1) {
|
||||||
|
_libssh2_error(session, LIBSSH2_ERROR_PROTO,
|
||||||
|
"Unexpected packet size");
|
||||||
|
goto channel_error;
|
||||||
|
}
|
||||||
|
|
||||||
if(session->open_data[0] == SSH_MSG_CHANNEL_OPEN_CONFIRMATION) {
|
if(session->open_data[0] == SSH_MSG_CHANNEL_OPEN_CONFIRMATION) {
|
||||||
|
|
||||||
|
if(session->open_data_len < 17) {
|
||||||
|
_libssh2_error(session, LIBSSH2_ERROR_PROTO,
|
||||||
|
"Unexpected packet size");
|
||||||
|
goto channel_error;
|
||||||
|
}
|
||||||
|
|
||||||
session->open_channel->remote.id =
|
session->open_channel->remote.id =
|
||||||
_libssh2_ntohu32(session->open_data + 5);
|
_libssh2_ntohu32(session->open_data + 5);
|
||||||
session->open_channel->local.window_size =
|
session->open_channel->local.window_size =
|
||||||
@@ -520,7 +533,7 @@ channel_forward_listen(LIBSSH2_SESSION * session, const char *host,
|
|||||||
_libssh2_error(session, LIBSSH2_ERROR_EAGAIN, "Would block");
|
_libssh2_error(session, LIBSSH2_ERROR_EAGAIN, "Would block");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
else if(rc) {
|
else if(rc || (data_len < 1)) {
|
||||||
_libssh2_error(session, LIBSSH2_ERROR_PROTO, "Unknown");
|
_libssh2_error(session, LIBSSH2_ERROR_PROTO, "Unknown");
|
||||||
session->fwdLstn_state = libssh2_NB_state_idle;
|
session->fwdLstn_state = libssh2_NB_state_idle;
|
||||||
return NULL;
|
return NULL;
|
||||||
@@ -858,6 +871,11 @@ static int channel_setenv(LIBSSH2_CHANNEL *channel,
|
|||||||
if(rc) {
|
if(rc) {
|
||||||
channel->setenv_state = libssh2_NB_state_idle;
|
channel->setenv_state = libssh2_NB_state_idle;
|
||||||
return rc;
|
return rc;
|
||||||
|
}
|
||||||
|
else if(data_len < 1) {
|
||||||
|
channel->setenv_state = libssh2_NB_state_idle;
|
||||||
|
return _libssh2_error(session, LIBSSH2_ERROR_PROTO,
|
||||||
|
"Unexpected packet size");
|
||||||
}
|
}
|
||||||
|
|
||||||
if(data[0] == SSH_MSG_CHANNEL_SUCCESS) {
|
if(data[0] == SSH_MSG_CHANNEL_SUCCESS) {
|
||||||
@@ -977,7 +995,7 @@ static int channel_request_pty(LIBSSH2_CHANNEL *channel,
|
|||||||
if(rc == LIBSSH2_ERROR_EAGAIN) {
|
if(rc == LIBSSH2_ERROR_EAGAIN) {
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
else if(rc) {
|
else if(rc || data_len < 1) {
|
||||||
channel->reqPTY_state = libssh2_NB_state_idle;
|
channel->reqPTY_state = libssh2_NB_state_idle;
|
||||||
return _libssh2_error(session, LIBSSH2_ERROR_PROTO,
|
return _libssh2_error(session, LIBSSH2_ERROR_PROTO,
|
||||||
"Failed to require the PTY package");
|
"Failed to require the PTY package");
|
||||||
@@ -1206,7 +1224,7 @@ channel_x11_req(LIBSSH2_CHANNEL *channel, int single_connection,
|
|||||||
if(rc == LIBSSH2_ERROR_EAGAIN) {
|
if(rc == LIBSSH2_ERROR_EAGAIN) {
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
else if(rc) {
|
else if(rc || data_len < 1) {
|
||||||
channel->reqX11_state = libssh2_NB_state_idle;
|
channel->reqX11_state = libssh2_NB_state_idle;
|
||||||
return _libssh2_error(session, rc,
|
return _libssh2_error(session, rc,
|
||||||
"waiting for x11-req response packet");
|
"waiting for x11-req response packet");
|
||||||
@@ -1334,7 +1352,7 @@ _libssh2_channel_process_startup(LIBSSH2_CHANNEL *channel,
|
|||||||
if(rc == LIBSSH2_ERROR_EAGAIN) {
|
if(rc == LIBSSH2_ERROR_EAGAIN) {
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
else if(rc) {
|
else if(rc || data_len < 1) {
|
||||||
channel->process_state = libssh2_NB_state_end;
|
channel->process_state = libssh2_NB_state_end;
|
||||||
return _libssh2_error(session, rc,
|
return _libssh2_error(session, rc,
|
||||||
"Failed waiting for channel success");
|
"Failed waiting for channel success");
|
||||||
@@ -1404,23 +1422,45 @@ _libssh2_channel_flush(LIBSSH2_CHANNEL *channel, int streamid)
|
|||||||
channel->flush_flush_bytes = 0;
|
channel->flush_flush_bytes = 0;
|
||||||
|
|
||||||
while(packet) {
|
while(packet) {
|
||||||
|
unsigned char packet_type;
|
||||||
LIBSSH2_PACKET *next = _libssh2_list_next(&packet->node);
|
LIBSSH2_PACKET *next = _libssh2_list_next(&packet->node);
|
||||||
unsigned char packet_type = packet->data[0];
|
|
||||||
|
if(packet->data_len < 1) {
|
||||||
|
packet = next;
|
||||||
|
_libssh2_debug(channel->session, LIBSSH2_TRACE_ERROR,
|
||||||
|
"Unexpected packet length");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
packet_type = packet->data[0];
|
||||||
|
|
||||||
if(((packet_type == SSH_MSG_CHANNEL_DATA)
|
if(((packet_type == SSH_MSG_CHANNEL_DATA)
|
||||||
|| (packet_type == SSH_MSG_CHANNEL_EXTENDED_DATA))
|
|| (packet_type == SSH_MSG_CHANNEL_EXTENDED_DATA))
|
||||||
&& (_libssh2_ntohu32(packet->data + 1) == channel->local.id)) {
|
&& ((packet->data_len >= 5)
|
||||||
|
&& (_libssh2_ntohu32(packet->data + 1) == channel->local.id))) {
|
||||||
/* It's our channel at least */
|
/* It's our channel at least */
|
||||||
long packet_stream_id =
|
unsigned int packet_stream_id;
|
||||||
(packet_type == SSH_MSG_CHANNEL_DATA) ? 0 :
|
|
||||||
_libssh2_ntohu32(packet->data + 5);
|
if(packet_type == SSH_MSG_CHANNEL_DATA) {
|
||||||
|
packet_stream_id = 0;
|
||||||
|
}
|
||||||
|
else if(packet->data_len >= 9) {
|
||||||
|
packet_stream_id = _libssh2_ntohu32(packet->data + 5);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
channel->flush_state = libssh2_NB_state_idle;
|
||||||
|
return _libssh2_error(channel->session,
|
||||||
|
LIBSSH2_ERROR_PROTO,
|
||||||
|
"Unexpected packet length");
|
||||||
|
}
|
||||||
|
|
||||||
if((streamid == LIBSSH2_CHANNEL_FLUSH_ALL)
|
if((streamid == LIBSSH2_CHANNEL_FLUSH_ALL)
|
||||||
|| ((packet_type == SSH_MSG_CHANNEL_EXTENDED_DATA)
|
|| ((packet_type == SSH_MSG_CHANNEL_EXTENDED_DATA)
|
||||||
&& ((streamid == LIBSSH2_CHANNEL_FLUSH_EXTENDED_DATA)
|
&& ((streamid == LIBSSH2_CHANNEL_FLUSH_EXTENDED_DATA)
|
||||||
|| (streamid == packet_stream_id)))
|
|| (streamid == packet_stream_id)))
|
||||||
|| ((packet_type == SSH_MSG_CHANNEL_DATA)
|
|| ((packet_type == SSH_MSG_CHANNEL_DATA)
|
||||||
&& (streamid == 0))) {
|
&& (streamid == 0))) {
|
||||||
int bytes_to_flush = packet->data_len - packet->data_head;
|
size_t bytes_to_flush = packet->data_len - packet->data_head;
|
||||||
|
|
||||||
_libssh2_debug(channel->session, LIBSSH2_TRACE_CONN,
|
_libssh2_debug(channel->session, LIBSSH2_TRACE_CONN,
|
||||||
"Flushing %d bytes of data from stream "
|
"Flushing %d bytes of data from stream "
|
||||||
@@ -1777,8 +1817,8 @@ ssize_t _libssh2_channel_read(LIBSSH2_CHANNEL *channel, int stream_id,
|
|||||||
{
|
{
|
||||||
LIBSSH2_SESSION *session = channel->session;
|
LIBSSH2_SESSION *session = channel->session;
|
||||||
int rc;
|
int rc;
|
||||||
int bytes_read = 0;
|
size_t bytes_read = 0;
|
||||||
int bytes_want;
|
size_t bytes_want;
|
||||||
int unlink_packet;
|
int unlink_packet;
|
||||||
LIBSSH2_PACKET *read_packet;
|
LIBSSH2_PACKET *read_packet;
|
||||||
LIBSSH2_PACKET *read_next;
|
LIBSSH2_PACKET *read_next;
|
||||||
@@ -1818,7 +1858,7 @@ ssize_t _libssh2_channel_read(LIBSSH2_CHANNEL *channel, int stream_id,
|
|||||||
return _libssh2_error(session, rc, "transport read");
|
return _libssh2_error(session, rc, "transport read");
|
||||||
|
|
||||||
read_packet = _libssh2_list_first(&session->packets);
|
read_packet = _libssh2_list_first(&session->packets);
|
||||||
while(read_packet && (bytes_read < (int) buflen)) {
|
while(read_packet && (bytes_read < buflen)) {
|
||||||
/* previously this loop condition also checked for
|
/* previously this loop condition also checked for
|
||||||
!channel->remote.close but we cannot let it do this:
|
!channel->remote.close but we cannot let it do this:
|
||||||
|
|
||||||
@@ -1832,6 +1872,13 @@ ssize_t _libssh2_channel_read(LIBSSH2_CHANNEL *channel, int stream_id,
|
|||||||
/* In case packet gets destroyed during this iteration */
|
/* In case packet gets destroyed during this iteration */
|
||||||
read_next = _libssh2_list_next(&readpkt->node);
|
read_next = _libssh2_list_next(&readpkt->node);
|
||||||
|
|
||||||
|
if(readpkt->data_len < 5) {
|
||||||
|
read_packet = read_next;
|
||||||
|
_libssh2_debug(channel->session, LIBSSH2_TRACE_ERROR,
|
||||||
|
"Unexpected packet length");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
channel->read_local_id =
|
channel->read_local_id =
|
||||||
_libssh2_ntohu32(readpkt->data + 1);
|
_libssh2_ntohu32(readpkt->data + 1);
|
||||||
|
|
||||||
@@ -1845,6 +1892,7 @@ ssize_t _libssh2_channel_read(LIBSSH2_CHANNEL *channel, int stream_id,
|
|||||||
if((stream_id
|
if((stream_id
|
||||||
&& (readpkt->data[0] == SSH_MSG_CHANNEL_EXTENDED_DATA)
|
&& (readpkt->data[0] == SSH_MSG_CHANNEL_EXTENDED_DATA)
|
||||||
&& (channel->local.id == channel->read_local_id)
|
&& (channel->local.id == channel->read_local_id)
|
||||||
|
&& (readpkt->data_len >= 9)
|
||||||
&& (stream_id == (int) _libssh2_ntohu32(readpkt->data + 5)))
|
&& (stream_id == (int) _libssh2_ntohu32(readpkt->data + 5)))
|
||||||
|| (!stream_id && (readpkt->data[0] == SSH_MSG_CHANNEL_DATA)
|
|| (!stream_id && (readpkt->data[0] == SSH_MSG_CHANNEL_DATA)
|
||||||
&& (channel->local.id == channel->read_local_id))
|
&& (channel->local.id == channel->read_local_id))
|
||||||
@@ -1858,7 +1906,7 @@ ssize_t _libssh2_channel_read(LIBSSH2_CHANNEL *channel, int stream_id,
|
|||||||
bytes_want = buflen - bytes_read;
|
bytes_want = buflen - bytes_read;
|
||||||
unlink_packet = FALSE;
|
unlink_packet = FALSE;
|
||||||
|
|
||||||
if(bytes_want >= (int) (readpkt->data_len - readpkt->data_head)) {
|
if(bytes_want >= (readpkt->data_len - readpkt->data_head)) {
|
||||||
/* we want more than this node keeps, so adjust the number and
|
/* we want more than this node keeps, so adjust the number and
|
||||||
delete this node after the copy */
|
delete this node after the copy */
|
||||||
bytes_want = readpkt->data_len - readpkt->data_head;
|
bytes_want = readpkt->data_len - readpkt->data_head;
|
||||||
@@ -1961,6 +2009,7 @@ _libssh2_channel_packet_data_len(LIBSSH2_CHANNEL * channel, int stream_id)
|
|||||||
{
|
{
|
||||||
LIBSSH2_SESSION *session = channel->session;
|
LIBSSH2_SESSION *session = channel->session;
|
||||||
LIBSSH2_PACKET *read_packet;
|
LIBSSH2_PACKET *read_packet;
|
||||||
|
LIBSSH2_PACKET *next_packet;
|
||||||
uint32_t read_local_id;
|
uint32_t read_local_id;
|
||||||
|
|
||||||
read_packet = _libssh2_list_first(&session->packets);
|
read_packet = _libssh2_list_first(&session->packets);
|
||||||
@@ -1968,6 +2017,16 @@ _libssh2_channel_packet_data_len(LIBSSH2_CHANNEL * channel, int stream_id)
|
|||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
while(read_packet) {
|
while(read_packet) {
|
||||||
|
|
||||||
|
next_packet = _libssh2_list_next(&read_packet->node);
|
||||||
|
|
||||||
|
if(read_packet->data_len < 5) {
|
||||||
|
read_packet = next_packet;
|
||||||
|
_libssh2_debug(channel->session, LIBSSH2_TRACE_ERROR,
|
||||||
|
"Unexpected packet length");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
read_local_id = _libssh2_ntohu32(read_packet->data + 1);
|
read_local_id = _libssh2_ntohu32(read_packet->data + 1);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -1980,6 +2039,7 @@ _libssh2_channel_packet_data_len(LIBSSH2_CHANNEL * channel, int stream_id)
|
|||||||
if((stream_id
|
if((stream_id
|
||||||
&& (read_packet->data[0] == SSH_MSG_CHANNEL_EXTENDED_DATA)
|
&& (read_packet->data[0] == SSH_MSG_CHANNEL_EXTENDED_DATA)
|
||||||
&& (channel->local.id == read_local_id)
|
&& (channel->local.id == read_local_id)
|
||||||
|
&& (read_packet->data_len >= 9)
|
||||||
&& (stream_id == (int) _libssh2_ntohu32(read_packet->data + 5)))
|
&& (stream_id == (int) _libssh2_ntohu32(read_packet->data + 5)))
|
||||||
||
|
||
|
||||||
(!stream_id
|
(!stream_id
|
||||||
@@ -1993,7 +2053,8 @@ _libssh2_channel_packet_data_len(LIBSSH2_CHANNEL * channel, int stream_id)
|
|||||||
== LIBSSH2_CHANNEL_EXTENDED_DATA_MERGE))) {
|
== LIBSSH2_CHANNEL_EXTENDED_DATA_MERGE))) {
|
||||||
return (read_packet->data_len - read_packet->data_head);
|
return (read_packet->data_len - read_packet->data_head);
|
||||||
}
|
}
|
||||||
read_packet = _libssh2_list_next(&read_packet->node);
|
|
||||||
|
read_packet = next_packet;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
@@ -2220,6 +2281,7 @@ libssh2_channel_eof(LIBSSH2_CHANNEL * channel)
|
|||||||
{
|
{
|
||||||
LIBSSH2_SESSION *session;
|
LIBSSH2_SESSION *session;
|
||||||
LIBSSH2_PACKET *packet;
|
LIBSSH2_PACKET *packet;
|
||||||
|
LIBSSH2_PACKET *next_packet;
|
||||||
|
|
||||||
if(!channel)
|
if(!channel)
|
||||||
return LIBSSH2_ERROR_BAD_USE;
|
return LIBSSH2_ERROR_BAD_USE;
|
||||||
@@ -2228,13 +2290,24 @@ libssh2_channel_eof(LIBSSH2_CHANNEL * channel)
|
|||||||
packet = _libssh2_list_first(&session->packets);
|
packet = _libssh2_list_first(&session->packets);
|
||||||
|
|
||||||
while(packet) {
|
while(packet) {
|
||||||
|
|
||||||
|
next_packet = _libssh2_list_next(&packet->node);
|
||||||
|
|
||||||
|
if(packet->data_len < 1) {
|
||||||
|
packet = next_packet;
|
||||||
|
_libssh2_debug(channel->session, LIBSSH2_TRACE_ERROR,
|
||||||
|
"Unexpected packet length");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
if(((packet->data[0] == SSH_MSG_CHANNEL_DATA)
|
if(((packet->data[0] == SSH_MSG_CHANNEL_DATA)
|
||||||
|| (packet->data[0] == SSH_MSG_CHANNEL_EXTENDED_DATA))
|
|| (packet->data[0] == SSH_MSG_CHANNEL_EXTENDED_DATA))
|
||||||
&& (channel->local.id == _libssh2_ntohu32(packet->data + 1))) {
|
&& ((packet->data_len >= 5)
|
||||||
|
&& (channel->local.id == _libssh2_ntohu32(packet->data + 1)))) {
|
||||||
/* There's data waiting to be read yet, mask the EOF status */
|
/* There's data waiting to be read yet, mask the EOF status */
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
packet = _libssh2_list_next(&packet->node);
|
packet = next_packet;
|
||||||
}
|
}
|
||||||
|
|
||||||
return channel->remote.eof;
|
return channel->remote.eof;
|
||||||
@@ -2594,19 +2667,31 @@ libssh2_channel_window_read_ex(LIBSSH2_CHANNEL *channel,
|
|||||||
|
|
||||||
if(read_avail) {
|
if(read_avail) {
|
||||||
size_t bytes_queued = 0;
|
size_t bytes_queued = 0;
|
||||||
|
LIBSSH2_PACKET *next_packet;
|
||||||
LIBSSH2_PACKET *packet =
|
LIBSSH2_PACKET *packet =
|
||||||
_libssh2_list_first(&channel->session->packets);
|
_libssh2_list_first(&channel->session->packets);
|
||||||
|
|
||||||
while(packet) {
|
while(packet) {
|
||||||
unsigned char packet_type = packet->data[0];
|
unsigned char packet_type;
|
||||||
|
next_packet = _libssh2_list_next(&packet->node);
|
||||||
|
|
||||||
|
if(packet->data_len < 1) {
|
||||||
|
packet = next_packet;
|
||||||
|
_libssh2_debug(channel->session, LIBSSH2_TRACE_ERROR,
|
||||||
|
"Unexpected packet length");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
packet_type = packet->data[0];
|
||||||
|
|
||||||
if(((packet_type == SSH_MSG_CHANNEL_DATA)
|
if(((packet_type == SSH_MSG_CHANNEL_DATA)
|
||||||
|| (packet_type == SSH_MSG_CHANNEL_EXTENDED_DATA))
|
|| (packet_type == SSH_MSG_CHANNEL_EXTENDED_DATA))
|
||||||
&& (_libssh2_ntohu32(packet->data + 1) == channel->local.id)) {
|
&& ((packet->data_len >= 5)
|
||||||
|
&& (_libssh2_ntohu32(packet->data + 1) == channel->local.id))) {
|
||||||
bytes_queued += packet->data_len - packet->data_head;
|
bytes_queued += packet->data_len - packet->data_head;
|
||||||
}
|
}
|
||||||
|
|
||||||
packet = _libssh2_list_next(&packet->node);
|
packet = next_packet;
|
||||||
}
|
}
|
||||||
|
|
||||||
*read_avail = bytes_queued;
|
*read_avail = bytes_queued;
|
||||||
|
|||||||
211
src/hostkey.c
211
src/hostkey.c
@@ -64,38 +64,36 @@ hostkey_method_ssh_rsa_init(LIBSSH2_SESSION * session,
|
|||||||
void **abstract)
|
void **abstract)
|
||||||
{
|
{
|
||||||
libssh2_rsa_ctx *rsactx;
|
libssh2_rsa_ctx *rsactx;
|
||||||
const unsigned char *s, *e, *n;
|
unsigned char *e, *n;
|
||||||
unsigned long len, e_len, n_len;
|
unsigned int e_len, n_len;
|
||||||
int ret;
|
struct string_buf buf = { .len = 0, .offset = 0 };
|
||||||
|
|
||||||
(void) hostkey_data_len;
|
|
||||||
|
|
||||||
if(*abstract) {
|
if(*abstract) {
|
||||||
hostkey_method_ssh_rsa_dtor(session, abstract);
|
hostkey_method_ssh_rsa_dtor(session, abstract);
|
||||||
*abstract = NULL;
|
*abstract = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
s = hostkey_data;
|
if(hostkey_data_len < 19) {
|
||||||
len = _libssh2_ntohu32(s);
|
_libssh2_debug(session, LIBSSH2_TRACE_ERROR,
|
||||||
s += 4;
|
"host key length too short");
|
||||||
|
|
||||||
if(len != 7 || strncmp((char *) s, "ssh-rsa", 7) != 0) {
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
s += 7;
|
|
||||||
|
|
||||||
e_len = _libssh2_ntohu32(s);
|
buf.data = (unsigned char*)hostkey_data;
|
||||||
s += 4;
|
buf.dataptr = buf.data;
|
||||||
|
buf.len = hostkey_data_len;
|
||||||
|
|
||||||
e = s;
|
if(_libssh2_match_string(&buf, "ssh-rsa") != 0)
|
||||||
s += e_len;
|
return -1;
|
||||||
n_len = _libssh2_ntohu32(s);
|
|
||||||
s += 4;
|
|
||||||
n = s;
|
|
||||||
|
|
||||||
ret = _libssh2_rsa_new(&rsactx, e, e_len, n, n_len, NULL, 0,
|
if((e_len = _libssh2_get_c_string(&buf, &e)) <= 0)
|
||||||
NULL, 0, NULL, 0, NULL, 0, NULL, 0, NULL, 0);
|
return -1;
|
||||||
if(ret) {
|
|
||||||
|
if((n_len = _libssh2_get_c_string(&buf, &n)) <= 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if(_libssh2_rsa_new(&rsactx, e, e_len, n, n_len, NULL, 0,
|
||||||
|
NULL, 0, NULL, 0, NULL, 0, NULL, 0, NULL, 0)) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -181,6 +179,9 @@ hostkey_method_ssh_rsa_sig_verify(LIBSSH2_SESSION * session,
|
|||||||
(void) session;
|
(void) session;
|
||||||
|
|
||||||
/* Skip past keyname_len(4) + keyname(7){"ssh-rsa"} + signature_len(4) */
|
/* Skip past keyname_len(4) + keyname(7){"ssh-rsa"} + signature_len(4) */
|
||||||
|
if(sig_len < 15)
|
||||||
|
return -1;
|
||||||
|
|
||||||
sig += 15;
|
sig += 15;
|
||||||
sig_len -= 15;
|
sig_len -= 15;
|
||||||
return _libssh2_rsa_sha1_verify(rsactx, sig, sig_len, m, m_len);
|
return _libssh2_rsa_sha1_verify(rsactx, sig, sig_len, m, m_len);
|
||||||
@@ -281,45 +282,42 @@ hostkey_method_ssh_dss_init(LIBSSH2_SESSION * session,
|
|||||||
void **abstract)
|
void **abstract)
|
||||||
{
|
{
|
||||||
libssh2_dsa_ctx *dsactx;
|
libssh2_dsa_ctx *dsactx;
|
||||||
const unsigned char *p, *q, *g, *y, *s;
|
unsigned char *p, *q, *g, *y;
|
||||||
unsigned long p_len, q_len, g_len, y_len, len;
|
unsigned long p_len, q_len, g_len, y_len;
|
||||||
int ret;
|
struct string_buf buf = { .len = 0, .offset = 0 };
|
||||||
|
|
||||||
(void) hostkey_data_len;
|
|
||||||
|
|
||||||
if(*abstract) {
|
if(*abstract) {
|
||||||
hostkey_method_ssh_dss_dtor(session, abstract);
|
hostkey_method_ssh_dss_dtor(session, abstract);
|
||||||
*abstract = NULL;
|
*abstract = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
s = hostkey_data;
|
if(hostkey_data_len < 27) {
|
||||||
len = _libssh2_ntohu32(s);
|
_libssh2_debug(session, LIBSSH2_TRACE_ERROR,
|
||||||
s += 4;
|
"host key length too short");
|
||||||
if(len != 7 || strncmp((char *) s, "ssh-dss", 7) != 0) {
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
s += 7;
|
|
||||||
|
buf.data = (unsigned char*)hostkey_data;
|
||||||
|
buf.dataptr = buf.data;
|
||||||
|
buf.len = hostkey_data_len;
|
||||||
|
|
||||||
|
if(_libssh2_match_string(&buf, "ssh-dss") != 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if((p_len = _libssh2_get_c_string(&buf, &p)) < 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if((q_len = _libssh2_get_c_string(&buf, &q)) < 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if((g_len = _libssh2_get_c_string(&buf, &g)) < 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if((y_len = _libssh2_get_c_string(&buf, &y)) < 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
p_len = _libssh2_ntohu32(s);
|
if(_libssh2_dsa_new(&dsactx, p, p_len, q, q_len,
|
||||||
s += 4;
|
g, g_len, y, y_len, NULL, 0)) {
|
||||||
p = s;
|
|
||||||
s += p_len;
|
|
||||||
q_len = _libssh2_ntohu32(s);
|
|
||||||
s += 4;
|
|
||||||
q = s;
|
|
||||||
s += q_len;
|
|
||||||
g_len = _libssh2_ntohu32(s);
|
|
||||||
s += 4;
|
|
||||||
g = s;
|
|
||||||
s += g_len;
|
|
||||||
y_len = _libssh2_ntohu32(s);
|
|
||||||
s += 4;
|
|
||||||
y = s;
|
|
||||||
/* s += y_len; */
|
|
||||||
|
|
||||||
ret = _libssh2_dsa_new(&dsactx, p, p_len, q, q_len,
|
|
||||||
g, g_len, y, y_len, NULL, 0);
|
|
||||||
if(ret) {
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -404,12 +402,14 @@ hostkey_method_ssh_dss_sig_verify(LIBSSH2_SESSION * session,
|
|||||||
libssh2_dsa_ctx *dsactx = (libssh2_dsa_ctx *) (*abstract);
|
libssh2_dsa_ctx *dsactx = (libssh2_dsa_ctx *) (*abstract);
|
||||||
|
|
||||||
/* Skip past keyname_len(4) + keyname(7){"ssh-dss"} + signature_len(4) */
|
/* Skip past keyname_len(4) + keyname(7){"ssh-dss"} + signature_len(4) */
|
||||||
sig += 15;
|
if(sig_len != 55) {
|
||||||
sig_len -= 15;
|
|
||||||
if(sig_len != 40) {
|
|
||||||
return _libssh2_error(session, LIBSSH2_ERROR_PROTO,
|
return _libssh2_error(session, LIBSSH2_ERROR_PROTO,
|
||||||
"Invalid DSS signature length");
|
"Invalid DSS signature length");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sig += 15;
|
||||||
|
sig_len -= 15;
|
||||||
|
|
||||||
return _libssh2_dsa_sha1_verify(dsactx, sig, m, m_len);
|
return _libssh2_dsa_sha1_verify(dsactx, sig, m, m_len);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -505,65 +505,55 @@ hostkey_method_ssh_ecdsa_init(LIBSSH2_SESSION * session,
|
|||||||
void **abstract)
|
void **abstract)
|
||||||
{
|
{
|
||||||
libssh2_ecdsa_ctx *ecdsactx = NULL;
|
libssh2_ecdsa_ctx *ecdsactx = NULL;
|
||||||
const unsigned char *s, *k;
|
unsigned char *type_str, *domain, *public_key;
|
||||||
size_t len, key_len, n_len;
|
unsigned int key_len;
|
||||||
libssh2_curve_type type;
|
libssh2_curve_type type;
|
||||||
|
struct string_buf buf = { .len = 0, .offset = 0 };
|
||||||
|
|
||||||
if(abstract != NULL && *abstract) {
|
if(abstract != NULL && *abstract) {
|
||||||
hostkey_method_ssh_ecdsa_dtor(session, abstract);
|
hostkey_method_ssh_ecdsa_dtor(session, abstract);
|
||||||
*abstract = NULL;
|
*abstract = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(hostkey_data_len < 23)
|
if(hostkey_data_len < 39) {
|
||||||
|
_libssh2_debug(session, LIBSSH2_TRACE_ERROR,
|
||||||
|
"host key length too short");
|
||||||
return -1;
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
s = hostkey_data;
|
buf.data = (unsigned char*)hostkey_data;
|
||||||
len = _libssh2_ntohu32(s);
|
buf.dataptr = buf.data;
|
||||||
s += 4;
|
buf.len = hostkey_data_len;
|
||||||
|
|
||||||
if(len != 19)
|
if(_libssh2_get_c_string(&buf, &type_str) != 19)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
if(strncmp((char *) s, "ecdsa-sha2-nistp256", 19) == 0) {
|
if (strncmp((char*) type_str, "ecdsa-sha2-nistp256", 19) == 0 ){
|
||||||
type = LIBSSH2_EC_CURVE_NISTP256;
|
type = LIBSSH2_EC_CURVE_NISTP256;
|
||||||
}
|
}else if(strncmp((char*) type_str, "ecdsa-sha2-nistp384", 19) == 0 ){
|
||||||
else if(strncmp((char *) s, "ecdsa-sha2-nistp384", 19) == 0) {
|
|
||||||
type = LIBSSH2_EC_CURVE_NISTP384;
|
type = LIBSSH2_EC_CURVE_NISTP384;
|
||||||
}
|
}else if(strncmp((char*) type_str, "ecdsa-sha2-nistp521", 19) == 0 ){
|
||||||
else if(strncmp((char *) s, "ecdsa-sha2-nistp521", 19) == 0) {
|
|
||||||
type = LIBSSH2_EC_CURVE_NISTP521;
|
type = LIBSSH2_EC_CURVE_NISTP521;
|
||||||
}
|
}else{
|
||||||
else {
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
s += 19;
|
|
||||||
|
if(_libssh2_get_c_string(&buf, &domain) != 8)
|
||||||
/* Domain length */
|
|
||||||
n_len = _libssh2_ntohu32(s);
|
|
||||||
s += 4;
|
|
||||||
|
|
||||||
if(n_len != 8)
|
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
if(type == LIBSSH2_EC_CURVE_NISTP256 && strncmp((char *)s, "nistp256", 8) != 0) {
|
if ( type == LIBSSH2_EC_CURVE_NISTP256 && strncmp((char*)domain, "nistp256", 8) != 0){
|
||||||
|
return -1;
|
||||||
|
}else if ( type == LIBSSH2_EC_CURVE_NISTP384 && strncmp((char*)domain, "nistp384", 8) != 0){
|
||||||
|
return -1;
|
||||||
|
}else if ( type == LIBSSH2_EC_CURVE_NISTP521 && strncmp((char*)domain, "nistp521", 8) != 0){
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
else if(type == LIBSSH2_EC_CURVE_NISTP384 && strncmp((char *)s, "nistp384", 8) != 0) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
else if(type == LIBSSH2_EC_CURVE_NISTP521 && strncmp((char *)s, "nistp521", 8) != 0) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
s += 8;
|
|
||||||
|
|
||||||
/* public key */
|
/* public key */
|
||||||
key_len = _libssh2_ntohu32(s);
|
if((key_len = _libssh2_get_c_string(&buf, &public_key)) <= 0)
|
||||||
s += 4;
|
return -1;
|
||||||
|
|
||||||
k = s;
|
if(_libssh2_ecdsa_curve_name_with_octal_new(&ecdsactx, public_key, key_len, type) )
|
||||||
|
|
||||||
if(_libssh2_ecdsa_curve_name_with_octal_new(&ecdsactx, k, key_len, type) )
|
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
if(abstract != NULL)
|
if(abstract != NULL)
|
||||||
@@ -644,8 +634,9 @@ hostkey_method_ssh_ecdsa_sig_verify(LIBSSH2_SESSION * session,
|
|||||||
const unsigned char *m,
|
const unsigned char *m,
|
||||||
size_t m_len, void **abstract)
|
size_t m_len, void **abstract)
|
||||||
{
|
{
|
||||||
const unsigned char *r, *s, *p;
|
unsigned char *r, *s, *name;
|
||||||
size_t r_len, s_len;
|
unsigned int r_len, s_len, len;
|
||||||
|
struct string_buf buf = { .len = 0, .offset = 0 };
|
||||||
libssh2_ecdsa_ctx *ctx = (libssh2_ecdsa_ctx *) (*abstract);
|
libssh2_ecdsa_ctx *ctx = (libssh2_ecdsa_ctx *) (*abstract);
|
||||||
|
|
||||||
(void) session;
|
(void) session;
|
||||||
@@ -653,18 +644,22 @@ hostkey_method_ssh_ecdsa_sig_verify(LIBSSH2_SESSION * session,
|
|||||||
if(sig_len < 35)
|
if(sig_len < 35)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
/* Skip past keyname_len(4) + keyname(19){"ecdsa-sha2-nistp256"} + signature_len(4) */
|
/* keyname_len(4) + keyname(19){"ecdsa-sha2-nistp256"} + signature_len(4) */
|
||||||
p = sig;
|
buf.data = (unsigned char*)sig;
|
||||||
p += 27;
|
buf.dataptr = buf.data;
|
||||||
|
buf.len = sig_len;
|
||||||
|
|
||||||
r_len = _libssh2_ntohu32(p);
|
if(_libssh2_get_c_string(&buf, &name) != 19)
|
||||||
p += 4;
|
return -1;
|
||||||
r = p;
|
|
||||||
p += r_len;
|
if(_libssh2_get_u32(&buf, &len) != 0 || len < 8)
|
||||||
|
return -1;
|
||||||
s_len = _libssh2_ntohu32(p);
|
|
||||||
p += 4;
|
if((r_len = _libssh2_get_c_string(&buf, &r)) <= 0)
|
||||||
s = p;
|
return -1;
|
||||||
|
|
||||||
|
if((s_len = _libssh2_get_c_string(&buf, &s)) <= 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
return _libssh2_ecdsa_verify(ctx, r, r_len, s, s_len, m, m_len);
|
return _libssh2_ecdsa_verify(ctx, r, r_len, s, s_len, m, m_len);
|
||||||
}
|
}
|
||||||
@@ -804,7 +799,9 @@ hostkey_method_ssh_ed25519_init(LIBSSH2_SESSION * session,
|
|||||||
*abstract = NULL;
|
*abstract = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(hostkey_data_len < 15) {
|
if(hostkey_data_len < 19) {
|
||||||
|
_libssh2_debug(session, LIBSSH2_TRACE_ERROR,
|
||||||
|
"host key length too short");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
156
src/kex.c
156
src/kex.c
@@ -247,11 +247,23 @@ static int diffie_hellman_sha1(LIBSSH2_SESSION *session,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Parse KEXDH_REPLY */
|
/* Parse KEXDH_REPLY */
|
||||||
|
if(exchange_state->s_packet_len < 5) {
|
||||||
|
ret = _libssh2_error(session, LIBSSH2_ERROR_PROTO,
|
||||||
|
"Unexpected packet length");
|
||||||
|
goto clean_exit;
|
||||||
|
}
|
||||||
|
|
||||||
exchange_state->s = exchange_state->s_packet + 1;
|
exchange_state->s = exchange_state->s_packet + 1;
|
||||||
|
|
||||||
session->server_hostkey_len = _libssh2_ntohu32(exchange_state->s);
|
session->server_hostkey_len = _libssh2_ntohu32(exchange_state->s);
|
||||||
exchange_state->s += 4;
|
exchange_state->s += 4;
|
||||||
|
|
||||||
|
if(session->server_hostkey_len > exchange_state->s_packet_len - 5) {
|
||||||
|
ret = _libssh2_error(session, LIBSSH2_ERROR_OUT_OF_BOUNDARY,
|
||||||
|
"Host key length out of bounds");
|
||||||
|
goto clean_exit;
|
||||||
|
}
|
||||||
|
|
||||||
if(session->server_hostkey)
|
if(session->server_hostkey)
|
||||||
LIBSSH2_FREE(session, session->server_hostkey);
|
LIBSSH2_FREE(session, session->server_hostkey);
|
||||||
|
|
||||||
@@ -908,11 +920,23 @@ static int diffie_hellman_sha256(LIBSSH2_SESSION *session,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Parse KEXDH_REPLY */
|
/* Parse KEXDH_REPLY */
|
||||||
|
if(exchange_state->s_packet_len < 5) {
|
||||||
|
ret = _libssh2_error(session, LIBSSH2_ERROR_PROTO,
|
||||||
|
"Unexpected packet length");
|
||||||
|
goto clean_exit;
|
||||||
|
}
|
||||||
|
|
||||||
exchange_state->s = exchange_state->s_packet + 1;
|
exchange_state->s = exchange_state->s_packet + 1;
|
||||||
|
|
||||||
session->server_hostkey_len = _libssh2_ntohu32(exchange_state->s);
|
session->server_hostkey_len = _libssh2_ntohu32(exchange_state->s);
|
||||||
exchange_state->s += 4;
|
exchange_state->s += 4;
|
||||||
|
|
||||||
|
if(session->server_hostkey_len > exchange_state->s_packet_len - 5) {
|
||||||
|
ret = _libssh2_error(session, LIBSSH2_ERROR_OUT_OF_BOUNDARY,
|
||||||
|
"Host key length out of bounds");
|
||||||
|
goto clean_exit;
|
||||||
|
}
|
||||||
|
|
||||||
if(session->server_hostkey)
|
if(session->server_hostkey)
|
||||||
LIBSSH2_FREE(session, session->server_hostkey);
|
LIBSSH2_FREE(session, session->server_hostkey);
|
||||||
|
|
||||||
@@ -1583,7 +1607,6 @@ static int
|
|||||||
kex_method_diffie_hellman_group_exchange_sha1_key_exchange
|
kex_method_diffie_hellman_group_exchange_sha1_key_exchange
|
||||||
(LIBSSH2_SESSION * session, key_exchange_state_low_t * key_state)
|
(LIBSSH2_SESSION * session, key_exchange_state_low_t * key_state)
|
||||||
{
|
{
|
||||||
unsigned long p_len, g_len;
|
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
@@ -1642,15 +1665,36 @@ kex_method_diffie_hellman_group_exchange_sha1_key_exchange
|
|||||||
}
|
}
|
||||||
|
|
||||||
if(key_state->state == libssh2_NB_state_sent1) {
|
if(key_state->state == libssh2_NB_state_sent1) {
|
||||||
unsigned char *s = key_state->data + 1;
|
unsigned int p_len, g_len;
|
||||||
p_len = _libssh2_ntohu32(s);
|
unsigned char *p, *g;
|
||||||
s += 4;
|
struct string_buf buf = { .len = 0, .offset = 0 };
|
||||||
_libssh2_bn_from_bin(key_state->p, p_len, s);
|
|
||||||
s += p_len;
|
if(key_state->data_len < 9) {
|
||||||
|
ret = _libssh2_error(session, LIBSSH2_ERROR_PROTO,
|
||||||
|
"Unexpected key length");
|
||||||
|
goto dh_gex_clean_exit;
|
||||||
|
}
|
||||||
|
|
||||||
g_len = _libssh2_ntohu32(s);
|
buf.data = key_state->data;
|
||||||
s += 4;
|
buf.dataptr = buf.data;
|
||||||
_libssh2_bn_from_bin(key_state->g, g_len, s);
|
buf.len = key_state->data_len;
|
||||||
|
|
||||||
|
buf.dataptr++; /* increment to big num */
|
||||||
|
|
||||||
|
if((p_len = _libssh2_get_bignum_bytes(&buf, &p)) <= 0) {
|
||||||
|
ret = _libssh2_error(session, LIBSSH2_ERROR_PROTO,
|
||||||
|
"Unexpected value");
|
||||||
|
goto dh_gex_clean_exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
if((g_len = _libssh2_get_bignum_bytes(&buf, &g)) <= 0) {
|
||||||
|
ret = _libssh2_error(session, LIBSSH2_ERROR_PROTO,
|
||||||
|
"Unexpected value");
|
||||||
|
goto dh_gex_clean_exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
_libssh2_bn_from_bin(key_state->p, p_len, p);
|
||||||
|
_libssh2_bn_from_bin(key_state->g, g_len, g);
|
||||||
|
|
||||||
ret = diffie_hellman_sha1(session, key_state->g, key_state->p, p_len,
|
ret = diffie_hellman_sha1(session, key_state->g, key_state->p, p_len,
|
||||||
SSH_MSG_KEX_DH_GEX_INIT,
|
SSH_MSG_KEX_DH_GEX_INIT,
|
||||||
@@ -1685,7 +1729,6 @@ static int
|
|||||||
kex_method_diffie_hellman_group_exchange_sha256_key_exchange
|
kex_method_diffie_hellman_group_exchange_sha256_key_exchange
|
||||||
(LIBSSH2_SESSION * session, key_exchange_state_low_t * key_state)
|
(LIBSSH2_SESSION * session, key_exchange_state_low_t * key_state)
|
||||||
{
|
{
|
||||||
unsigned long p_len, g_len;
|
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
@@ -1744,15 +1787,36 @@ kex_method_diffie_hellman_group_exchange_sha256_key_exchange
|
|||||||
}
|
}
|
||||||
|
|
||||||
if(key_state->state == libssh2_NB_state_sent1) {
|
if(key_state->state == libssh2_NB_state_sent1) {
|
||||||
unsigned char *s = key_state->data + 1;
|
unsigned char *p, *g;
|
||||||
p_len = _libssh2_ntohu32(s);
|
unsigned long p_len, g_len;
|
||||||
s += 4;
|
struct string_buf buf = { .len = 0, .offset = 0 };
|
||||||
_libssh2_bn_from_bin(key_state->p, p_len, s);
|
|
||||||
s += p_len;
|
if(key_state->data_len < 9) {
|
||||||
|
ret = _libssh2_error(session, LIBSSH2_ERROR_PROTO,
|
||||||
|
"Unexpected key length");
|
||||||
|
goto dh_gex_clean_exit;
|
||||||
|
}
|
||||||
|
|
||||||
g_len = _libssh2_ntohu32(s);
|
buf.data = key_state->data;
|
||||||
s += 4;
|
buf.dataptr = buf.data;
|
||||||
_libssh2_bn_from_bin(key_state->g, g_len, s);
|
buf.len = key_state->data_len;
|
||||||
|
|
||||||
|
buf.dataptr++; /* increment to big num */
|
||||||
|
|
||||||
|
if((p_len = _libssh2_get_bignum_bytes(&buf, &p)) <= 0) {
|
||||||
|
ret = _libssh2_error(session, LIBSSH2_ERROR_PROTO,
|
||||||
|
"Unexpected value");
|
||||||
|
goto dh_gex_clean_exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
if((g_len = _libssh2_get_bignum_bytes(&buf, &g)) <= 0) {
|
||||||
|
ret = _libssh2_error(session, LIBSSH2_ERROR_PROTO,
|
||||||
|
"Unexpected value");
|
||||||
|
goto dh_gex_clean_exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
_libssh2_bn_from_bin(key_state->p, p_len, p);
|
||||||
|
_libssh2_bn_from_bin(key_state->g, g_len, g);
|
||||||
|
|
||||||
ret = diffie_hellman_sha256(session, key_state->g, key_state->p, p_len,
|
ret = diffie_hellman_sha256(session, key_state->g, key_state->p, p_len,
|
||||||
SSH_MSG_KEX_DH_GEX_INIT,
|
SSH_MSG_KEX_DH_GEX_INIT,
|
||||||
@@ -2534,28 +2598,38 @@ static int curve25519_sha256(LIBSSH2_SESSION *session, unsigned char *data,
|
|||||||
exchange_state->state = libssh2_NB_state_created;
|
exchange_state->state = libssh2_NB_state_created;
|
||||||
}
|
}
|
||||||
|
|
||||||
if( exchange_state->state == libssh2_NB_state_created) {
|
if(exchange_state->state == libssh2_NB_state_created) {
|
||||||
/* parse INIT reply data */
|
/* parse INIT reply data */
|
||||||
|
unsigned char *server_public_key, *server_host_key;
|
||||||
|
unsigned int server_public_key_len;
|
||||||
|
struct string_buf buf = { .len = 0, .offset = 0 };
|
||||||
|
|
||||||
/*host key K_S*/
|
if(data_len < 5) {
|
||||||
unsigned char *s = data + 1; //advance past packet type
|
ret = _libssh2_error(session, LIBSSH2_ERROR_PROTO,
|
||||||
unsigned char *server_public_key;
|
"Unexpected key length");
|
||||||
size_t server_public_key_len;
|
goto clean_exit;
|
||||||
size_t host_sig_len;
|
}
|
||||||
|
|
||||||
session->server_hostkey_len = _libssh2_ntohu32((const unsigned char*)s);
|
buf.data = data;
|
||||||
s += 4;
|
buf.len = data_len;
|
||||||
|
buf.dataptr = buf.data;
|
||||||
|
buf.dataptr++; /* advance past packet type */
|
||||||
|
|
||||||
|
if((session->server_hostkey_len = _libssh2_get_c_string(&buf, &server_host_key)) <= 0) {
|
||||||
|
ret = _libssh2_error(session, LIBSSH2_ERROR_PROTO,
|
||||||
|
"Unexpected key length");
|
||||||
|
goto clean_exit;
|
||||||
|
}
|
||||||
|
|
||||||
session->server_hostkey = LIBSSH2_ALLOC(session, session->server_hostkey_len);
|
session->server_hostkey = LIBSSH2_ALLOC(session, session->server_hostkey_len);
|
||||||
if(!session->server_hostkey) {
|
if (!session->server_hostkey) {
|
||||||
ret = _libssh2_error(session, LIBSSH2_ERROR_ALLOC,
|
ret = _libssh2_error(session, LIBSSH2_ERROR_ALLOC,
|
||||||
"Unable to allocate memory for a copy "
|
"Unable to allocate memory for a copy "
|
||||||
"of the host key");
|
"of the host key");
|
||||||
goto clean_exit;
|
goto clean_exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
memcpy(session->server_hostkey, s, session->server_hostkey_len);
|
memcpy(session->server_hostkey, server_host_key, session->server_hostkey_len);
|
||||||
s += session->server_hostkey_len;
|
|
||||||
|
|
||||||
#if LIBSSH2_MD5
|
#if LIBSSH2_MD5
|
||||||
{
|
{
|
||||||
@@ -2647,8 +2721,12 @@ static int curve25519_sha256(LIBSSH2_SESSION *session, unsigned char *data,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* server public key Q_S */
|
/* server public key Q_S */
|
||||||
server_public_key_len = _libssh2_ntohu32((const unsigned char*)s);
|
if((server_public_key_len =
|
||||||
s += 4;
|
_libssh2_get_c_string(&buf, &server_public_key)) <= 0) {
|
||||||
|
ret = _libssh2_error(session, LIBSSH2_ERROR_PROTO,
|
||||||
|
"Unexpected key length");
|
||||||
|
goto clean_exit;
|
||||||
|
}
|
||||||
|
|
||||||
if( server_public_key_len != LIBSSH2_ED25519_KEY_LEN) {
|
if( server_public_key_len != LIBSSH2_ED25519_KEY_LEN) {
|
||||||
ret = _libssh2_error(session, LIBSSH2_ERROR_HOSTKEY_INIT,
|
ret = _libssh2_error(session, LIBSSH2_ERROR_HOSTKEY_INIT,
|
||||||
@@ -2656,16 +2734,14 @@ static int curve25519_sha256(LIBSSH2_SESSION *session, unsigned char *data,
|
|||||||
goto clean_exit;
|
goto clean_exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
server_public_key = s;
|
|
||||||
s += server_public_key_len;
|
|
||||||
|
|
||||||
/* server signature */
|
/* server signature */
|
||||||
host_sig_len = _libssh2_ntohu32((const unsigned char*)s);
|
if((exchange_state->h_sig_len =
|
||||||
s += 4;
|
_libssh2_get_c_string(&buf, &exchange_state->h_sig)) <= 0) {
|
||||||
|
ret = _libssh2_error(session, LIBSSH2_ERROR_HOSTKEY_INIT,
|
||||||
|
"Unexpected curve25519 server sig length");
|
||||||
|
goto clean_exit;
|
||||||
|
|
||||||
exchange_state->h_sig = s;
|
}
|
||||||
exchange_state->h_sig_len = host_sig_len;
|
|
||||||
s += host_sig_len;
|
|
||||||
|
|
||||||
// Compute the shared secret K
|
// Compute the shared secret K
|
||||||
rc = _libssh2_curve25519_gen_k(&exchange_state->k, private_key, server_public_key);
|
rc = _libssh2_curve25519_gen_k(&exchange_state->k, private_key, server_public_key);
|
||||||
|
|||||||
11
src/packet.c
11
src/packet.c
@@ -819,8 +819,15 @@ _libssh2_packet_add(LIBSSH2_SESSION * session, unsigned char *data,
|
|||||||
/* set signal name (without SIG prefix) */
|
/* set signal name (without SIG prefix) */
|
||||||
uint32_t namelen =
|
uint32_t namelen =
|
||||||
_libssh2_ntohu32(data + 9 + sizeof("exit-signal"));
|
_libssh2_ntohu32(data + 9 + sizeof("exit-signal"));
|
||||||
channelp->exit_signal =
|
|
||||||
LIBSSH2_ALLOC(session, namelen + 1);
|
if(namelen <= UINT_MAX - 1) {
|
||||||
|
channelp->exit_signal =
|
||||||
|
LIBSSH2_ALLOC(session, namelen + 1);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
channelp->exit_signal = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
if(!channelp->exit_signal)
|
if(!channelp->exit_signal)
|
||||||
rc = _libssh2_error(session, LIBSSH2_ERROR_ALLOC,
|
rc = _libssh2_error(session, LIBSSH2_ERROR_ALLOC,
|
||||||
"memory for signal name");
|
"memory for signal name");
|
||||||
|
|||||||
@@ -774,6 +774,11 @@ session_startup(LIBSSH2_SESSION *session, libssh2_socket_t sock)
|
|||||||
&session->startup_req_state);
|
&session->startup_req_state);
|
||||||
if(rc)
|
if(rc)
|
||||||
return rc;
|
return rc;
|
||||||
|
|
||||||
|
if(session->startup_data_len < 5) {
|
||||||
|
return _libssh2_error(session, LIBSSH2_ERROR_PROTO,
|
||||||
|
"Unexpected packet length");
|
||||||
|
}
|
||||||
|
|
||||||
session->startup_service_length =
|
session->startup_service_length =
|
||||||
_libssh2_ntohu32(session->startup_data + 1);
|
_libssh2_ntohu32(session->startup_data + 1);
|
||||||
|
|||||||
@@ -437,8 +437,12 @@ int _libssh2_transport_read(LIBSSH2_SESSION * session)
|
|||||||
* and we can extract packet and padding length from it
|
* and we can extract packet and padding length from it
|
||||||
*/
|
*/
|
||||||
p->packet_length = _libssh2_ntohu32(block);
|
p->packet_length = _libssh2_ntohu32(block);
|
||||||
if(p->packet_length < 1)
|
if(p->packet_length < 1) {
|
||||||
return LIBSSH2_ERROR_DECRYPT;
|
return LIBSSH2_ERROR_DECRYPT;
|
||||||
|
}
|
||||||
|
else if(p->packet_length > LIBSSH2_PACKET_MAXPAYLOAD) {
|
||||||
|
return LIBSSH2_ERROR_OUT_OF_BOUNDARY;
|
||||||
|
}
|
||||||
|
|
||||||
p->padding_length = block[4];
|
p->padding_length = block[4];
|
||||||
|
|
||||||
|
|||||||
@@ -128,7 +128,7 @@ static char *userauth_list(LIBSSH2_SESSION *session, const char *username,
|
|||||||
"Would block requesting userauth list");
|
"Would block requesting userauth list");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
else if(rc) {
|
else if(rc || (session->userauth_list_data_len < 1)) {
|
||||||
_libssh2_error(session, rc, "Failed getting response");
|
_libssh2_error(session, rc, "Failed getting response");
|
||||||
session->userauth_list_state = libssh2_NB_state_idle;
|
session->userauth_list_state = libssh2_NB_state_idle;
|
||||||
return NULL;
|
return NULL;
|
||||||
@@ -144,8 +144,21 @@ static char *userauth_list(LIBSSH2_SESSION *session, const char *username,
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
methods_len = _libssh2_ntohu32(session->userauth_list_data + 1);
|
if(session->userauth_list_data_len < 5) {
|
||||||
|
LIBSSH2_FREE(session, session->userauth_list_data);
|
||||||
|
session->userauth_list_data = NULL;
|
||||||
|
_libssh2_error(session, LIBSSH2_ERROR_PROTO,
|
||||||
|
"Unexpected packet size");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
methods_len = _libssh2_ntohu32(session->userauth_list_data + 1);
|
||||||
|
if(methods_len >= session->userauth_list_data_len - 5) {
|
||||||
|
_libssh2_error(session, LIBSSH2_ERROR_OUT_OF_BOUNDARY,
|
||||||
|
"Unexpected userauth list size");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
/* Do note that the memory areas overlap! */
|
/* Do note that the memory areas overlap! */
|
||||||
memmove(session->userauth_list_data, session->userauth_list_data + 5,
|
memmove(session->userauth_list_data, session->userauth_list_data + 5,
|
||||||
methods_len);
|
methods_len);
|
||||||
@@ -286,6 +299,11 @@ userauth_password(LIBSSH2_SESSION *session,
|
|||||||
return _libssh2_error(session, rc,
|
return _libssh2_error(session, rc,
|
||||||
"Waiting for password response");
|
"Waiting for password response");
|
||||||
}
|
}
|
||||||
|
else if(session->userauth_pswd_data_len < 1) {
|
||||||
|
session->userauth_pswd_state = libssh2_NB_state_idle;
|
||||||
|
return _libssh2_error(session, LIBSSH2_ERROR_PROTO,
|
||||||
|
"Unexpected packet size");
|
||||||
|
}
|
||||||
|
|
||||||
if(session->userauth_pswd_data[0] == SSH_MSG_USERAUTH_SUCCESS) {
|
if(session->userauth_pswd_data[0] == SSH_MSG_USERAUTH_SUCCESS) {
|
||||||
_libssh2_debug(session, LIBSSH2_TRACE_AUTH,
|
_libssh2_debug(session, LIBSSH2_TRACE_AUTH,
|
||||||
@@ -314,6 +332,12 @@ userauth_password(LIBSSH2_SESSION *session,
|
|||||||
session->userauth_pswd_state = libssh2_NB_state_sent1;
|
session->userauth_pswd_state = libssh2_NB_state_sent1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(session->userauth_pswd_data_len < 1) {
|
||||||
|
session->userauth_pswd_state = libssh2_NB_state_idle;
|
||||||
|
return _libssh2_error(session, LIBSSH2_ERROR_PROTO,
|
||||||
|
"Unexpected packet size");
|
||||||
|
}
|
||||||
|
|
||||||
if((session->userauth_pswd_data[0] ==
|
if((session->userauth_pswd_data[0] ==
|
||||||
SSH_MSG_USERAUTH_PASSWD_CHANGEREQ)
|
SSH_MSG_USERAUTH_PASSWD_CHANGEREQ)
|
||||||
|| (session->userauth_pswd_data0 ==
|
|| (session->userauth_pswd_data0 ==
|
||||||
@@ -342,12 +366,18 @@ userauth_password(LIBSSH2_SESSION *session,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* basic data_len + newpw_len(4) */
|
/* basic data_len + newpw_len(4) */
|
||||||
session->userauth_pswd_data_len =
|
if(username_len + password_len + 44 <= UINT_MAX) {
|
||||||
username_len + password_len + 44;
|
session->userauth_pswd_data_len =
|
||||||
|
username_len + password_len + 44;
|
||||||
|
s = session->userauth_pswd_data =
|
||||||
|
LIBSSH2_ALLOC(session,
|
||||||
|
session->userauth_pswd_data_len);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
s = session->userauth_pswd_data = NULL;
|
||||||
|
session->userauth_pswd_data_len = 0;
|
||||||
|
}
|
||||||
|
|
||||||
s = session->userauth_pswd_data =
|
|
||||||
LIBSSH2_ALLOC(session,
|
|
||||||
session->userauth_pswd_data_len);
|
|
||||||
if(!session->userauth_pswd_data) {
|
if(!session->userauth_pswd_data) {
|
||||||
LIBSSH2_FREE(session,
|
LIBSSH2_FREE(session,
|
||||||
session->userauth_pswd_newpw);
|
session->userauth_pswd_newpw);
|
||||||
@@ -988,7 +1018,7 @@ userauth_hostbased_fromfile(LIBSSH2_SESSION *session,
|
|||||||
}
|
}
|
||||||
|
|
||||||
session->userauth_host_state = libssh2_NB_state_idle;
|
session->userauth_host_state = libssh2_NB_state_idle;
|
||||||
if(rc) {
|
if(rc || data_len < 1) {
|
||||||
return _libssh2_error(session, LIBSSH2_ERROR_PUBLICKEY_UNVERIFIED,
|
return _libssh2_error(session, LIBSSH2_ERROR_PUBLICKEY_UNVERIFIED,
|
||||||
"Auth failed");
|
"Auth failed");
|
||||||
}
|
}
|
||||||
@@ -1077,7 +1107,7 @@ _libssh2_userauth_publickey(LIBSSH2_SESSION *session,
|
|||||||
if(!session->userauth_pblc_method) {
|
if(!session->userauth_pblc_method) {
|
||||||
session->userauth_pblc_method_len = _libssh2_ntohu32(pubkeydata);
|
session->userauth_pblc_method_len = _libssh2_ntohu32(pubkeydata);
|
||||||
|
|
||||||
if(session->userauth_pblc_method_len > pubkeydata_len)
|
if(session->userauth_pblc_method_len > pubkeydata_len - 4)
|
||||||
/* the method length simply cannot be longer than the entire
|
/* the method length simply cannot be longer than the entire
|
||||||
passed in data, so we use this to detect crazy input
|
passed in data, so we use this to detect crazy input
|
||||||
data */
|
data */
|
||||||
@@ -1184,7 +1214,7 @@ _libssh2_userauth_publickey(LIBSSH2_SESSION *session,
|
|||||||
if(rc == LIBSSH2_ERROR_EAGAIN) {
|
if(rc == LIBSSH2_ERROR_EAGAIN) {
|
||||||
return _libssh2_error(session, LIBSSH2_ERROR_EAGAIN, "Would block");
|
return _libssh2_error(session, LIBSSH2_ERROR_EAGAIN, "Would block");
|
||||||
}
|
}
|
||||||
else if(rc) {
|
else if(rc || (session->userauth_pblc_data_len < 1)) {
|
||||||
LIBSSH2_FREE(session, session->userauth_pblc_packet);
|
LIBSSH2_FREE(session, session->userauth_pblc_packet);
|
||||||
session->userauth_pblc_packet = NULL;
|
session->userauth_pblc_packet = NULL;
|
||||||
LIBSSH2_FREE(session, session->userauth_pblc_method);
|
LIBSSH2_FREE(session, session->userauth_pblc_method);
|
||||||
@@ -1347,7 +1377,7 @@ _libssh2_userauth_publickey(LIBSSH2_SESSION *session,
|
|||||||
return _libssh2_error(session, LIBSSH2_ERROR_EAGAIN,
|
return _libssh2_error(session, LIBSSH2_ERROR_EAGAIN,
|
||||||
"Would block requesting userauth list");
|
"Would block requesting userauth list");
|
||||||
}
|
}
|
||||||
else if(rc) {
|
else if(rc || session->userauth_pblc_data_len < 1) {
|
||||||
session->userauth_pblc_state = libssh2_NB_state_idle;
|
session->userauth_pblc_state = libssh2_NB_state_idle;
|
||||||
return _libssh2_error(session, LIBSSH2_ERROR_PUBLICKEY_UNVERIFIED,
|
return _libssh2_error(session, LIBSSH2_ERROR_PUBLICKEY_UNVERIFIED,
|
||||||
"Waiting for publickey USERAUTH response");
|
"Waiting for publickey USERAUTH response");
|
||||||
@@ -1681,7 +1711,7 @@ userauth_keyboard_interactive(LIBSSH2_SESSION * session,
|
|||||||
return _libssh2_error(session, LIBSSH2_ERROR_EAGAIN,
|
return _libssh2_error(session, LIBSSH2_ERROR_EAGAIN,
|
||||||
"Would block");
|
"Would block");
|
||||||
}
|
}
|
||||||
else if(rc) {
|
else if(rc || session->userauth_kybd_data_len < 1) {
|
||||||
session->userauth_kybd_state = libssh2_NB_state_idle;
|
session->userauth_kybd_state = libssh2_NB_state_idle;
|
||||||
return _libssh2_error(session,
|
return _libssh2_error(session,
|
||||||
LIBSSH2_ERROR_AUTHENTICATION_FAILED,
|
LIBSSH2_ERROR_AUTHENTICATION_FAILED,
|
||||||
@@ -1762,6 +1792,14 @@ userauth_keyboard_interactive(LIBSSH2_SESSION * session,
|
|||||||
session->userauth_kybd_num_prompts = _libssh2_ntohu32(s);
|
session->userauth_kybd_num_prompts = _libssh2_ntohu32(s);
|
||||||
s += 4;
|
s += 4;
|
||||||
|
|
||||||
|
if(session->userauth_kybd_num_prompts &&
|
||||||
|
session->userauth_kybd_num_prompts > 100) {
|
||||||
|
_libssh2_error(session, LIBSSH2_ERROR_OUT_OF_BOUNDARY,
|
||||||
|
"Too many replies for "
|
||||||
|
"keyboard-interactive prompts");
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
if(session->userauth_kybd_num_prompts) {
|
if(session->userauth_kybd_num_prompts) {
|
||||||
session->userauth_kybd_prompts =
|
session->userauth_kybd_prompts =
|
||||||
LIBSSH2_CALLOC(session,
|
LIBSSH2_CALLOC(session,
|
||||||
@@ -1828,8 +1866,17 @@ userauth_keyboard_interactive(LIBSSH2_SESSION * session,
|
|||||||
|
|
||||||
for(i = 0; i < session->userauth_kybd_num_prompts; i++) {
|
for(i = 0; i < session->userauth_kybd_num_prompts; i++) {
|
||||||
/* string response[1] (ISO-10646 UTF-8) */
|
/* string response[1] (ISO-10646 UTF-8) */
|
||||||
session->userauth_kybd_packet_len +=
|
if(session->userauth_kybd_responses[i].length <=
|
||||||
4 + session->userauth_kybd_responses[i].length;
|
(SIZE_MAX - 4 - session->userauth_kybd_packet_len) ) {
|
||||||
|
session->userauth_kybd_packet_len +=
|
||||||
|
4 + session->userauth_kybd_responses[i].length;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
_libssh2_error(session, LIBSSH2_ERROR_ALLOC,
|
||||||
|
"Unable to allocate memory for keyboard-"
|
||||||
|
"interactive response packet");
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* A new userauth_kybd_data area is to be allocated, free the
|
/* A new userauth_kybd_data area is to be allocated, free the
|
||||||
|
|||||||
Reference in New Issue
Block a user