1
0
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:
Will Cosgrove
2019-03-14 15:22:13 -07:00
committed by GitHub
parent e1d9bd49e4
commit dc109a7f51
8 changed files with 419 additions and 186 deletions

View File

@@ -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.
*/ */

View File

@@ -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;
@@ -859,6 +872,11 @@ static int channel_setenv(LIBSSH2_CHANNEL *channel,
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) {
LIBSSH2_FREE(session, data); LIBSSH2_FREE(session, data);
@@ -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;

View File

@@ -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;
p_len = _libssh2_ntohu32(s); buf.data = (unsigned char*)hostkey_data;
s += 4; buf.dataptr = buf.data;
p = s; buf.len = hostkey_data_len;
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, if(_libssh2_match_string(&buf, "ssh-dss") != 0)
g, g_len, y, y_len, NULL, 0); return -1;
if(ret) {
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;
if(_libssh2_dsa_new(&dsactx, p, p_len, q, q_len,
g, g_len, y, y_len, NULL, 0)) {
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;
}
buf.data = (unsigned char*)hostkey_data;
buf.dataptr = buf.data;
buf.len = hostkey_data_len;
if(_libssh2_get_c_string(&buf, &type_str) != 19)
return -1; return -1;
s = hostkey_data; if (strncmp((char*) type_str, "ecdsa-sha2-nistp256", 19) == 0 ){
len = _libssh2_ntohu32(s);
s += 4;
if(len != 19)
return -1;
if(strncmp((char *) s, "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;
}
s += 19;
/* Domain length */
n_len = _libssh2_ntohu32(s);
s += 4;
if(n_len != 8)
return -1;
if(type == LIBSSH2_EC_CURVE_NISTP256 && strncmp((char *)s, "nistp256", 8) != 0) {
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; return -1;
} }
s += 8; if(_libssh2_get_c_string(&buf, &domain) != 8)
return -1;
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;
}
/* 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;
s_len = _libssh2_ntohu32(p); if(_libssh2_get_u32(&buf, &len) != 0 || len < 8)
p += 4; return -1;
s = p;
if((r_len = _libssh2_get_c_string(&buf, &r)) <= 0)
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;
} }

154
src/kex.c
View File

@@ -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;
g_len = _libssh2_ntohu32(s); if(key_state->data_len < 9) {
s += 4; ret = _libssh2_error(session, LIBSSH2_ERROR_PROTO,
_libssh2_bn_from_bin(key_state->g, g_len, s); "Unexpected key length");
goto dh_gex_clean_exit;
}
buf.data = key_state->data;
buf.dataptr = buf.data;
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;
g_len = _libssh2_ntohu32(s); if(key_state->data_len < 9) {
s += 4; ret = _libssh2_error(session, LIBSSH2_ERROR_PROTO,
_libssh2_bn_from_bin(key_state->g, g_len, s); "Unexpected key length");
goto dh_gex_clean_exit;
}
buf.data = key_state->data;
buf.dataptr = buf.data;
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);

View File

@@ -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");

View File

@@ -775,6 +775,11 @@ session_startup(LIBSSH2_SESSION *session, libssh2_socket_t sock)
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);

View File

@@ -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];

View File

@@ -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,7 +144,20 @@ static char *userauth_list(LIBSSH2_SESSION *session, const char *username,
return NULL; return NULL;
} }
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); 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,
@@ -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