1
0
mirror of https://github.com/libssh2/libssh2.git synced 2025-12-24 19:37:49 +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
#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.
*/

View File

@@ -239,7 +239,20 @@ _libssh2_channel_open(LIBSSH2_SESSION * session, const char *channel_type,
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_len < 17) {
_libssh2_error(session, LIBSSH2_ERROR_PROTO,
"Unexpected packet size");
goto channel_error;
}
session->open_channel->remote.id =
_libssh2_ntohu32(session->open_data + 5);
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");
return NULL;
}
else if(rc) {
else if(rc || (data_len < 1)) {
_libssh2_error(session, LIBSSH2_ERROR_PROTO, "Unknown");
session->fwdLstn_state = libssh2_NB_state_idle;
return NULL;
@@ -858,6 +871,11 @@ static int channel_setenv(LIBSSH2_CHANNEL *channel,
if(rc) {
channel->setenv_state = libssh2_NB_state_idle;
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) {
@@ -977,7 +995,7 @@ static int channel_request_pty(LIBSSH2_CHANNEL *channel,
if(rc == LIBSSH2_ERROR_EAGAIN) {
return rc;
}
else if(rc) {
else if(rc || data_len < 1) {
channel->reqPTY_state = libssh2_NB_state_idle;
return _libssh2_error(session, LIBSSH2_ERROR_PROTO,
"Failed to require the PTY package");
@@ -1206,7 +1224,7 @@ channel_x11_req(LIBSSH2_CHANNEL *channel, int single_connection,
if(rc == LIBSSH2_ERROR_EAGAIN) {
return rc;
}
else if(rc) {
else if(rc || data_len < 1) {
channel->reqX11_state = libssh2_NB_state_idle;
return _libssh2_error(session, rc,
"waiting for x11-req response packet");
@@ -1334,7 +1352,7 @@ _libssh2_channel_process_startup(LIBSSH2_CHANNEL *channel,
if(rc == LIBSSH2_ERROR_EAGAIN) {
return rc;
}
else if(rc) {
else if(rc || data_len < 1) {
channel->process_state = libssh2_NB_state_end;
return _libssh2_error(session, rc,
"Failed waiting for channel success");
@@ -1404,23 +1422,45 @@ _libssh2_channel_flush(LIBSSH2_CHANNEL *channel, int streamid)
channel->flush_flush_bytes = 0;
while(packet) {
unsigned char packet_type;
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)
|| (packet_type == SSH_MSG_CHANNEL_EXTENDED_DATA))
&& (_libssh2_ntohu32(packet->data + 1) == channel->local.id)) {
|| (packet_type == SSH_MSG_CHANNEL_EXTENDED_DATA))
&& ((packet->data_len >= 5)
&& (_libssh2_ntohu32(packet->data + 1) == channel->local.id))) {
/* It's our channel at least */
long packet_stream_id =
(packet_type == SSH_MSG_CHANNEL_DATA) ? 0 :
_libssh2_ntohu32(packet->data + 5);
unsigned int packet_stream_id;
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)
|| ((packet_type == SSH_MSG_CHANNEL_EXTENDED_DATA)
&& ((streamid == LIBSSH2_CHANNEL_FLUSH_EXTENDED_DATA)
|| (streamid == packet_stream_id)))
|| ((packet_type == SSH_MSG_CHANNEL_DATA)
&& (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,
"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;
int rc;
int bytes_read = 0;
int bytes_want;
size_t bytes_read = 0;
size_t bytes_want;
int unlink_packet;
LIBSSH2_PACKET *read_packet;
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");
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
!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 */
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 =
_libssh2_ntohu32(readpkt->data + 1);
@@ -1845,6 +1892,7 @@ ssize_t _libssh2_channel_read(LIBSSH2_CHANNEL *channel, int stream_id,
if((stream_id
&& (readpkt->data[0] == SSH_MSG_CHANNEL_EXTENDED_DATA)
&& (channel->local.id == channel->read_local_id)
&& (readpkt->data_len >= 9)
&& (stream_id == (int) _libssh2_ntohu32(readpkt->data + 5)))
|| (!stream_id && (readpkt->data[0] == SSH_MSG_CHANNEL_DATA)
&& (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;
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
delete this node after the copy */
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_PACKET *read_packet;
LIBSSH2_PACKET *next_packet;
uint32_t read_local_id;
read_packet = _libssh2_list_first(&session->packets);
@@ -1968,6 +2017,16 @@ _libssh2_channel_packet_data_len(LIBSSH2_CHANNEL * channel, int stream_id)
return 0;
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);
/*
@@ -1980,6 +2039,7 @@ _libssh2_channel_packet_data_len(LIBSSH2_CHANNEL * channel, int stream_id)
if((stream_id
&& (read_packet->data[0] == SSH_MSG_CHANNEL_EXTENDED_DATA)
&& (channel->local.id == read_local_id)
&& (read_packet->data_len >= 9)
&& (stream_id == (int) _libssh2_ntohu32(read_packet->data + 5)))
||
(!stream_id
@@ -1993,7 +2053,8 @@ _libssh2_channel_packet_data_len(LIBSSH2_CHANNEL * channel, int stream_id)
== LIBSSH2_CHANNEL_EXTENDED_DATA_MERGE))) {
return (read_packet->data_len - read_packet->data_head);
}
read_packet = _libssh2_list_next(&read_packet->node);
read_packet = next_packet;
}
return 0;
@@ -2220,6 +2281,7 @@ libssh2_channel_eof(LIBSSH2_CHANNEL * channel)
{
LIBSSH2_SESSION *session;
LIBSSH2_PACKET *packet;
LIBSSH2_PACKET *next_packet;
if(!channel)
return LIBSSH2_ERROR_BAD_USE;
@@ -2228,13 +2290,24 @@ libssh2_channel_eof(LIBSSH2_CHANNEL * channel)
packet = _libssh2_list_first(&session->packets);
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)
|| (packet->data[0] == SSH_MSG_CHANNEL_EXTENDED_DATA))
&& (channel->local.id == _libssh2_ntohu32(packet->data + 1))) {
|| (packet->data[0] == SSH_MSG_CHANNEL_EXTENDED_DATA))
&& ((packet->data_len >= 5)
&& (channel->local.id == _libssh2_ntohu32(packet->data + 1)))) {
/* There's data waiting to be read yet, mask the EOF status */
return 0;
}
packet = _libssh2_list_next(&packet->node);
packet = next_packet;
}
return channel->remote.eof;
@@ -2594,19 +2667,31 @@ libssh2_channel_window_read_ex(LIBSSH2_CHANNEL *channel,
if(read_avail) {
size_t bytes_queued = 0;
LIBSSH2_PACKET *next_packet;
LIBSSH2_PACKET *packet =
_libssh2_list_first(&channel->session->packets);
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)
|| (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;
}
packet = _libssh2_list_next(&packet->node);
packet = next_packet;
}
*read_avail = bytes_queued;

View File

@@ -64,38 +64,36 @@ hostkey_method_ssh_rsa_init(LIBSSH2_SESSION * session,
void **abstract)
{
libssh2_rsa_ctx *rsactx;
const unsigned char *s, *e, *n;
unsigned long len, e_len, n_len;
int ret;
(void) hostkey_data_len;
unsigned char *e, *n;
unsigned int e_len, n_len;
struct string_buf buf = { .len = 0, .offset = 0 };
if(*abstract) {
hostkey_method_ssh_rsa_dtor(session, abstract);
*abstract = NULL;
}
s = hostkey_data;
len = _libssh2_ntohu32(s);
s += 4;
if(len != 7 || strncmp((char *) s, "ssh-rsa", 7) != 0) {
if(hostkey_data_len < 19) {
_libssh2_debug(session, LIBSSH2_TRACE_ERROR,
"host key length too short");
return -1;
}
s += 7;
e_len = _libssh2_ntohu32(s);
s += 4;
buf.data = (unsigned char*)hostkey_data;
buf.dataptr = buf.data;
buf.len = hostkey_data_len;
e = s;
s += e_len;
n_len = _libssh2_ntohu32(s);
s += 4;
n = s;
if(_libssh2_match_string(&buf, "ssh-rsa") != 0)
return -1;
ret = _libssh2_rsa_new(&rsactx, e, e_len, n, n_len, NULL, 0,
NULL, 0, NULL, 0, NULL, 0, NULL, 0, NULL, 0);
if(ret) {
if((e_len = _libssh2_get_c_string(&buf, &e)) <= 0)
return -1;
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;
}
@@ -181,6 +179,9 @@ hostkey_method_ssh_rsa_sig_verify(LIBSSH2_SESSION * session,
(void) session;
/* Skip past keyname_len(4) + keyname(7){"ssh-rsa"} + signature_len(4) */
if(sig_len < 15)
return -1;
sig += 15;
sig_len -= 15;
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)
{
libssh2_dsa_ctx *dsactx;
const unsigned char *p, *q, *g, *y, *s;
unsigned long p_len, q_len, g_len, y_len, len;
int ret;
(void) hostkey_data_len;
unsigned char *p, *q, *g, *y;
unsigned long p_len, q_len, g_len, y_len;
struct string_buf buf = { .len = 0, .offset = 0 };
if(*abstract) {
hostkey_method_ssh_dss_dtor(session, abstract);
*abstract = NULL;
}
s = hostkey_data;
len = _libssh2_ntohu32(s);
s += 4;
if(len != 7 || strncmp((char *) s, "ssh-dss", 7) != 0) {
if(hostkey_data_len < 27) {
_libssh2_debug(session, LIBSSH2_TRACE_ERROR,
"host key length too short");
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);
s += 4;
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) {
if(_libssh2_dsa_new(&dsactx, p, p_len, q, q_len,
g, g_len, y, y_len, NULL, 0)) {
return -1;
}
@@ -404,12 +402,14 @@ hostkey_method_ssh_dss_sig_verify(LIBSSH2_SESSION * session,
libssh2_dsa_ctx *dsactx = (libssh2_dsa_ctx *) (*abstract);
/* Skip past keyname_len(4) + keyname(7){"ssh-dss"} + signature_len(4) */
sig += 15;
sig_len -= 15;
if(sig_len != 40) {
if(sig_len != 55) {
return _libssh2_error(session, LIBSSH2_ERROR_PROTO,
"Invalid DSS signature length");
}
sig += 15;
sig_len -= 15;
return _libssh2_dsa_sha1_verify(dsactx, sig, m, m_len);
}
@@ -505,65 +505,55 @@ hostkey_method_ssh_ecdsa_init(LIBSSH2_SESSION * session,
void **abstract)
{
libssh2_ecdsa_ctx *ecdsactx = NULL;
const unsigned char *s, *k;
size_t len, key_len, n_len;
unsigned char *type_str, *domain, *public_key;
unsigned int key_len;
libssh2_curve_type type;
struct string_buf buf = { .len = 0, .offset = 0 };
if(abstract != NULL && *abstract) {
hostkey_method_ssh_ecdsa_dtor(session, abstract);
*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;
}
s = hostkey_data;
len = _libssh2_ntohu32(s);
s += 4;
buf.data = (unsigned char*)hostkey_data;
buf.dataptr = buf.data;
buf.len = hostkey_data_len;
if(len != 19)
if(_libssh2_get_c_string(&buf, &type_str) != 19)
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;
}
else if(strncmp((char *) s, "ecdsa-sha2-nistp384", 19) == 0) {
}else if(strncmp((char*) type_str, "ecdsa-sha2-nistp384", 19) == 0 ){
type = LIBSSH2_EC_CURVE_NISTP384;
}
else if(strncmp((char *) s, "ecdsa-sha2-nistp521", 19) == 0) {
}else if(strncmp((char*) type_str, "ecdsa-sha2-nistp521", 19) == 0 ){
type = LIBSSH2_EC_CURVE_NISTP521;
}
else {
}else{
return -1;
}
s += 19;
/* Domain length */
n_len = _libssh2_ntohu32(s);
s += 4;
if(n_len != 8)
if(_libssh2_get_c_string(&buf, &domain) != 8)
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;
}
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 */
key_len = _libssh2_ntohu32(s);
s += 4;
if((key_len = _libssh2_get_c_string(&buf, &public_key)) <= 0)
return -1;
k = s;
if(_libssh2_ecdsa_curve_name_with_octal_new(&ecdsactx, k, key_len, type) )
if(_libssh2_ecdsa_curve_name_with_octal_new(&ecdsactx, public_key, key_len, type) )
return -1;
if(abstract != NULL)
@@ -644,8 +634,9 @@ hostkey_method_ssh_ecdsa_sig_verify(LIBSSH2_SESSION * session,
const unsigned char *m,
size_t m_len, void **abstract)
{
const unsigned char *r, *s, *p;
size_t r_len, s_len;
unsigned char *r, *s, *name;
unsigned int r_len, s_len, len;
struct string_buf buf = { .len = 0, .offset = 0 };
libssh2_ecdsa_ctx *ctx = (libssh2_ecdsa_ctx *) (*abstract);
(void) session;
@@ -653,18 +644,22 @@ hostkey_method_ssh_ecdsa_sig_verify(LIBSSH2_SESSION * session,
if(sig_len < 35)
return -1;
/* Skip past keyname_len(4) + keyname(19){"ecdsa-sha2-nistp256"} + signature_len(4) */
p = sig;
p += 27;
/* keyname_len(4) + keyname(19){"ecdsa-sha2-nistp256"} + signature_len(4) */
buf.data = (unsigned char*)sig;
buf.dataptr = buf.data;
buf.len = sig_len;
r_len = _libssh2_ntohu32(p);
p += 4;
r = p;
p += r_len;
s_len = _libssh2_ntohu32(p);
p += 4;
s = p;
if(_libssh2_get_c_string(&buf, &name) != 19)
return -1;
if(_libssh2_get_u32(&buf, &len) != 0 || len < 8)
return -1;
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);
}
@@ -804,7 +799,9 @@ hostkey_method_ssh_ed25519_init(LIBSSH2_SESSION * session,
*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;
}

156
src/kex.c
View File

@@ -247,11 +247,23 @@ static int diffie_hellman_sha1(LIBSSH2_SESSION *session,
}
/* 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;
session->server_hostkey_len = _libssh2_ntohu32(exchange_state->s);
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)
LIBSSH2_FREE(session, session->server_hostkey);
@@ -908,11 +920,23 @@ static int diffie_hellman_sha256(LIBSSH2_SESSION *session,
}
/* 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;
session->server_hostkey_len = _libssh2_ntohu32(exchange_state->s);
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)
LIBSSH2_FREE(session, session->server_hostkey);
@@ -1583,7 +1607,6 @@ static int
kex_method_diffie_hellman_group_exchange_sha1_key_exchange
(LIBSSH2_SESSION * session, key_exchange_state_low_t * key_state)
{
unsigned long p_len, g_len;
int ret = 0;
int rc;
@@ -1642,15 +1665,36 @@ kex_method_diffie_hellman_group_exchange_sha1_key_exchange
}
if(key_state->state == libssh2_NB_state_sent1) {
unsigned char *s = key_state->data + 1;
p_len = _libssh2_ntohu32(s);
s += 4;
_libssh2_bn_from_bin(key_state->p, p_len, s);
s += p_len;
unsigned int p_len, g_len;
unsigned char *p, *g;
struct string_buf buf = { .len = 0, .offset = 0 };
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);
s += 4;
_libssh2_bn_from_bin(key_state->g, g_len, s);
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,
SSH_MSG_KEX_DH_GEX_INIT,
@@ -1685,7 +1729,6 @@ static int
kex_method_diffie_hellman_group_exchange_sha256_key_exchange
(LIBSSH2_SESSION * session, key_exchange_state_low_t * key_state)
{
unsigned long p_len, g_len;
int ret = 0;
int rc;
@@ -1744,15 +1787,36 @@ kex_method_diffie_hellman_group_exchange_sha256_key_exchange
}
if(key_state->state == libssh2_NB_state_sent1) {
unsigned char *s = key_state->data + 1;
p_len = _libssh2_ntohu32(s);
s += 4;
_libssh2_bn_from_bin(key_state->p, p_len, s);
s += p_len;
unsigned char *p, *g;
unsigned long p_len, g_len;
struct string_buf buf = { .len = 0, .offset = 0 };
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);
s += 4;
_libssh2_bn_from_bin(key_state->g, g_len, s);
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,
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;
}
if( exchange_state->state == libssh2_NB_state_created) {
if(exchange_state->state == libssh2_NB_state_created) {
/* 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*/
unsigned char *s = data + 1; //advance past packet type
unsigned char *server_public_key;
size_t server_public_key_len;
size_t host_sig_len;
session->server_hostkey_len = _libssh2_ntohu32((const unsigned char*)s);
s += 4;
if(data_len < 5) {
ret = _libssh2_error(session, LIBSSH2_ERROR_PROTO,
"Unexpected key length");
goto clean_exit;
}
buf.data = data;
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);
if(!session->server_hostkey) {
if (!session->server_hostkey) {
ret = _libssh2_error(session, LIBSSH2_ERROR_ALLOC,
"Unable to allocate memory for a copy "
"of the host key");
goto clean_exit;
}
memcpy(session->server_hostkey, s, session->server_hostkey_len);
s += session->server_hostkey_len;
memcpy(session->server_hostkey, server_host_key, session->server_hostkey_len);
#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_len = _libssh2_ntohu32((const unsigned char*)s);
s += 4;
if((server_public_key_len =
_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) {
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;
}
server_public_key = s;
s += server_public_key_len;
/* server signature */
host_sig_len = _libssh2_ntohu32((const unsigned char*)s);
s += 4;
if((exchange_state->h_sig_len =
_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
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) */
uint32_t namelen =
_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)
rc = _libssh2_error(session, LIBSSH2_ERROR_ALLOC,
"memory for signal name");

View File

@@ -774,6 +774,11 @@ session_startup(LIBSSH2_SESSION *session, libssh2_socket_t sock)
&session->startup_req_state);
if(rc)
return rc;
if(session->startup_data_len < 5) {
return _libssh2_error(session, LIBSSH2_ERROR_PROTO,
"Unexpected packet length");
}
session->startup_service_length =
_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
*/
p->packet_length = _libssh2_ntohu32(block);
if(p->packet_length < 1)
if(p->packet_length < 1) {
return LIBSSH2_ERROR_DECRYPT;
}
else if(p->packet_length > LIBSSH2_PACKET_MAXPAYLOAD) {
return LIBSSH2_ERROR_OUT_OF_BOUNDARY;
}
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");
return NULL;
}
else if(rc) {
else if(rc || (session->userauth_list_data_len < 1)) {
_libssh2_error(session, rc, "Failed getting response");
session->userauth_list_state = libssh2_NB_state_idle;
return NULL;
@@ -144,8 +144,21 @@ static char *userauth_list(LIBSSH2_SESSION *session, const char *username,
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! */
memmove(session->userauth_list_data, session->userauth_list_data + 5,
methods_len);
@@ -286,6 +299,11 @@ userauth_password(LIBSSH2_SESSION *session,
return _libssh2_error(session, rc,
"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) {
_libssh2_debug(session, LIBSSH2_TRACE_AUTH,
@@ -314,6 +332,12 @@ userauth_password(LIBSSH2_SESSION *session,
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] ==
SSH_MSG_USERAUTH_PASSWD_CHANGEREQ)
|| (session->userauth_pswd_data0 ==
@@ -342,12 +366,18 @@ userauth_password(LIBSSH2_SESSION *session,
}
/* basic data_len + newpw_len(4) */
session->userauth_pswd_data_len =
username_len + password_len + 44;
if(username_len + password_len + 44 <= UINT_MAX) {
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) {
LIBSSH2_FREE(session,
session->userauth_pswd_newpw);
@@ -988,7 +1018,7 @@ userauth_hostbased_fromfile(LIBSSH2_SESSION *session,
}
session->userauth_host_state = libssh2_NB_state_idle;
if(rc) {
if(rc || data_len < 1) {
return _libssh2_error(session, LIBSSH2_ERROR_PUBLICKEY_UNVERIFIED,
"Auth failed");
}
@@ -1077,7 +1107,7 @@ _libssh2_userauth_publickey(LIBSSH2_SESSION *session,
if(!session->userauth_pblc_method) {
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
passed in data, so we use this to detect crazy input
data */
@@ -1184,7 +1214,7 @@ _libssh2_userauth_publickey(LIBSSH2_SESSION *session,
if(rc == LIBSSH2_ERROR_EAGAIN) {
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);
session->userauth_pblc_packet = NULL;
LIBSSH2_FREE(session, session->userauth_pblc_method);
@@ -1347,7 +1377,7 @@ _libssh2_userauth_publickey(LIBSSH2_SESSION *session,
return _libssh2_error(session, LIBSSH2_ERROR_EAGAIN,
"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;
return _libssh2_error(session, LIBSSH2_ERROR_PUBLICKEY_UNVERIFIED,
"Waiting for publickey USERAUTH response");
@@ -1681,7 +1711,7 @@ userauth_keyboard_interactive(LIBSSH2_SESSION * session,
return _libssh2_error(session, LIBSSH2_ERROR_EAGAIN,
"Would block");
}
else if(rc) {
else if(rc || session->userauth_kybd_data_len < 1) {
session->userauth_kybd_state = libssh2_NB_state_idle;
return _libssh2_error(session,
LIBSSH2_ERROR_AUTHENTICATION_FAILED,
@@ -1762,6 +1792,14 @@ userauth_keyboard_interactive(LIBSSH2_SESSION * session,
session->userauth_kybd_num_prompts = _libssh2_ntohu32(s);
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) {
session->userauth_kybd_prompts =
LIBSSH2_CALLOC(session,
@@ -1828,8 +1866,17 @@ userauth_keyboard_interactive(LIBSSH2_SESSION * session,
for(i = 0; i < session->userauth_kybd_num_prompts; i++) {
/* string response[1] (ISO-10646 UTF-8) */
session->userauth_kybd_packet_len +=
4 + session->userauth_kybd_responses[i].length;
if(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