kex: Added diffie-hellman-group-exchange-sha256 support
... and fixed HMAC_Init depricated usage Closes #48
Этот коммит содержится в:
родитель
92fff06e27
Коммит
fc4a969a05
806
src/kex.c
806
src/kex.c
@ -70,6 +70,35 @@
|
|||||||
} \
|
} \
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Helper macro called from kex_method_diffie_hellman_group1_sha256_key_exchange */
|
||||||
|
#define LIBSSH2_KEX_METHOD_DIFFIE_HELLMAN_SHA256_HASH(value, reqlen, version) \
|
||||||
|
{ \
|
||||||
|
libssh2_sha256_ctx hash; \
|
||||||
|
unsigned long len = 0; \
|
||||||
|
if (!(value)) { \
|
||||||
|
value = LIBSSH2_ALLOC(session, reqlen + SHA256_DIGEST_LENGTH); \
|
||||||
|
} \
|
||||||
|
if (value) \
|
||||||
|
while (len < (unsigned long)reqlen) { \
|
||||||
|
libssh2_sha256_init(&hash); \
|
||||||
|
libssh2_sha256_update(hash, exchange_state->k_value, \
|
||||||
|
exchange_state->k_value_len); \
|
||||||
|
libssh2_sha256_update(hash, exchange_state->h_sig_comp, \
|
||||||
|
SHA256_DIGEST_LENGTH); \
|
||||||
|
if (len > 0) { \
|
||||||
|
libssh2_sha256_update(hash, value, len); \
|
||||||
|
} else { \
|
||||||
|
libssh2_sha256_update(hash, (version), 1); \
|
||||||
|
libssh2_sha256_update(hash, session->session_id, \
|
||||||
|
session->session_id_len); \
|
||||||
|
} \
|
||||||
|
libssh2_sha256_final(hash, (value) + len); \
|
||||||
|
len += SHA256_DIGEST_LENGTH; \
|
||||||
|
} \
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* diffie_hellman_sha1
|
* diffie_hellman_sha1
|
||||||
*
|
*
|
||||||
@ -83,10 +112,11 @@ static int diffie_hellman_sha1(LIBSSH2_SESSION *session,
|
|||||||
unsigned char packet_type_reply,
|
unsigned char packet_type_reply,
|
||||||
unsigned char *midhash,
|
unsigned char *midhash,
|
||||||
unsigned long midhash_len,
|
unsigned long midhash_len,
|
||||||
kmdhgGPsha1kex_state_t *exchange_state)
|
kmdhgGPshakex_state_t *exchange_state)
|
||||||
{
|
{
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
int rc;
|
int rc;
|
||||||
|
libssh2_sha1_ctx exchange_hash_ctx;
|
||||||
|
|
||||||
if (exchange_state->state == libssh2_NB_state_idle) {
|
if (exchange_state->state == libssh2_NB_state_idle) {
|
||||||
/* Setup initial values */
|
/* Setup initial values */
|
||||||
@ -318,54 +348,56 @@ static int diffie_hellman_sha1(LIBSSH2_SESSION *session,
|
|||||||
_libssh2_bn_to_bin(exchange_state->k, exchange_state->k_value + 5);
|
_libssh2_bn_to_bin(exchange_state->k, exchange_state->k_value + 5);
|
||||||
}
|
}
|
||||||
|
|
||||||
libssh2_sha1_init(&exchange_state->exchange_hash);
|
exchange_state->exchange_hash = (void*)&exchange_hash_ctx;
|
||||||
|
libssh2_sha1_init(&exchange_hash_ctx);
|
||||||
|
|
||||||
if (session->local.banner) {
|
if (session->local.banner) {
|
||||||
_libssh2_htonu32(exchange_state->h_sig_comp,
|
_libssh2_htonu32(exchange_state->h_sig_comp,
|
||||||
strlen((char *) session->local.banner) - 2);
|
strlen((char *) session->local.banner) - 2);
|
||||||
libssh2_sha1_update(exchange_state->exchange_hash,
|
libssh2_sha1_update(exchange_hash_ctx,
|
||||||
exchange_state->h_sig_comp, 4);
|
exchange_state->h_sig_comp, 4);
|
||||||
libssh2_sha1_update(exchange_state->exchange_hash,
|
libssh2_sha1_update(exchange_hash_ctx,
|
||||||
(char *) session->local.banner,
|
(char *) session->local.banner,
|
||||||
strlen((char *) session->local.banner) - 2);
|
strlen((char *) session->local.banner) - 2);
|
||||||
} else {
|
} else {
|
||||||
_libssh2_htonu32(exchange_state->h_sig_comp,
|
_libssh2_htonu32(exchange_state->h_sig_comp,
|
||||||
sizeof(LIBSSH2_SSH_DEFAULT_BANNER) - 1);
|
sizeof(LIBSSH2_SSH_DEFAULT_BANNER) - 1);
|
||||||
libssh2_sha1_update(exchange_state->exchange_hash,
|
libssh2_sha1_update(exchange_hash_ctx,
|
||||||
exchange_state->h_sig_comp, 4);
|
exchange_state->h_sig_comp, 4);
|
||||||
libssh2_sha1_update(exchange_state->exchange_hash,
|
libssh2_sha1_update(exchange_hash_ctx,
|
||||||
LIBSSH2_SSH_DEFAULT_BANNER,
|
LIBSSH2_SSH_DEFAULT_BANNER,
|
||||||
sizeof(LIBSSH2_SSH_DEFAULT_BANNER) - 1);
|
sizeof(LIBSSH2_SSH_DEFAULT_BANNER) - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
_libssh2_htonu32(exchange_state->h_sig_comp,
|
_libssh2_htonu32(exchange_state->h_sig_comp,
|
||||||
strlen((char *) session->remote.banner));
|
strlen((char *) session->remote.banner));
|
||||||
libssh2_sha1_update(exchange_state->exchange_hash,
|
libssh2_sha1_update(exchange_hash_ctx,
|
||||||
exchange_state->h_sig_comp, 4);
|
exchange_state->h_sig_comp, 4);
|
||||||
libssh2_sha1_update(exchange_state->exchange_hash,
|
libssh2_sha1_update(exchange_hash_ctx,
|
||||||
session->remote.banner,
|
session->remote.banner,
|
||||||
strlen((char *) session->remote.banner));
|
strlen((char *) session->remote.banner));
|
||||||
|
|
||||||
_libssh2_htonu32(exchange_state->h_sig_comp,
|
_libssh2_htonu32(exchange_state->h_sig_comp,
|
||||||
session->local.kexinit_len);
|
session->local.kexinit_len);
|
||||||
libssh2_sha1_update(exchange_state->exchange_hash,
|
libssh2_sha1_update(exchange_hash_ctx,
|
||||||
exchange_state->h_sig_comp, 4);
|
exchange_state->h_sig_comp, 4);
|
||||||
libssh2_sha1_update(exchange_state->exchange_hash,
|
libssh2_sha1_update(exchange_hash_ctx,
|
||||||
session->local.kexinit,
|
session->local.kexinit,
|
||||||
session->local.kexinit_len);
|
session->local.kexinit_len);
|
||||||
|
|
||||||
_libssh2_htonu32(exchange_state->h_sig_comp,
|
_libssh2_htonu32(exchange_state->h_sig_comp,
|
||||||
session->remote.kexinit_len);
|
session->remote.kexinit_len);
|
||||||
libssh2_sha1_update(exchange_state->exchange_hash,
|
libssh2_sha1_update(exchange_hash_ctx,
|
||||||
exchange_state->h_sig_comp, 4);
|
exchange_state->h_sig_comp, 4);
|
||||||
libssh2_sha1_update(exchange_state->exchange_hash,
|
libssh2_sha1_update(exchange_hash_ctx,
|
||||||
session->remote.kexinit,
|
session->remote.kexinit,
|
||||||
session->remote.kexinit_len);
|
session->remote.kexinit_len);
|
||||||
|
|
||||||
_libssh2_htonu32(exchange_state->h_sig_comp,
|
_libssh2_htonu32(exchange_state->h_sig_comp,
|
||||||
session->server_hostkey_len);
|
session->server_hostkey_len);
|
||||||
libssh2_sha1_update(exchange_state->exchange_hash,
|
libssh2_sha1_update(exchange_hash_ctx,
|
||||||
exchange_state->h_sig_comp, 4);
|
exchange_state->h_sig_comp, 4);
|
||||||
libssh2_sha1_update(exchange_state->exchange_hash,
|
libssh2_sha1_update(exchange_hash_ctx,
|
||||||
session->server_hostkey,
|
session->server_hostkey,
|
||||||
session->server_hostkey_len);
|
session->server_hostkey_len);
|
||||||
|
|
||||||
@ -378,38 +410,38 @@ static int diffie_hellman_sha1(LIBSSH2_SESSION *session,
|
|||||||
LIBSSH2_DH_GEX_OPTGROUP);
|
LIBSSH2_DH_GEX_OPTGROUP);
|
||||||
_libssh2_htonu32(exchange_state->h_sig_comp + 8,
|
_libssh2_htonu32(exchange_state->h_sig_comp + 8,
|
||||||
LIBSSH2_DH_GEX_MAXGROUP);
|
LIBSSH2_DH_GEX_MAXGROUP);
|
||||||
libssh2_sha1_update(exchange_state->exchange_hash,
|
libssh2_sha1_update(exchange_hash_ctx,
|
||||||
exchange_state->h_sig_comp, 12);
|
exchange_state->h_sig_comp, 12);
|
||||||
#else
|
#else
|
||||||
_libssh2_htonu32(exchange_state->h_sig_comp,
|
_libssh2_htonu32(exchange_state->h_sig_comp,
|
||||||
LIBSSH2_DH_GEX_OPTGROUP);
|
LIBSSH2_DH_GEX_OPTGROUP);
|
||||||
libssh2_sha1_update(exchange_state->exchange_hash,
|
libssh2_sha1_update(exchange_hash_ctx,
|
||||||
exchange_state->h_sig_comp, 4);
|
exchange_state->h_sig_comp, 4);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
if (midhash) {
|
if (midhash) {
|
||||||
libssh2_sha1_update(exchange_state->exchange_hash, midhash,
|
libssh2_sha1_update(exchange_hash_ctx, midhash,
|
||||||
midhash_len);
|
midhash_len);
|
||||||
}
|
}
|
||||||
|
|
||||||
libssh2_sha1_update(exchange_state->exchange_hash,
|
libssh2_sha1_update(exchange_hash_ctx,
|
||||||
exchange_state->e_packet + 1,
|
exchange_state->e_packet + 1,
|
||||||
exchange_state->e_packet_len - 1);
|
exchange_state->e_packet_len - 1);
|
||||||
|
|
||||||
_libssh2_htonu32(exchange_state->h_sig_comp,
|
_libssh2_htonu32(exchange_state->h_sig_comp,
|
||||||
exchange_state->f_value_len);
|
exchange_state->f_value_len);
|
||||||
libssh2_sha1_update(exchange_state->exchange_hash,
|
libssh2_sha1_update(exchange_hash_ctx,
|
||||||
exchange_state->h_sig_comp, 4);
|
exchange_state->h_sig_comp, 4);
|
||||||
libssh2_sha1_update(exchange_state->exchange_hash,
|
libssh2_sha1_update(exchange_hash_ctx,
|
||||||
exchange_state->f_value,
|
exchange_state->f_value,
|
||||||
exchange_state->f_value_len);
|
exchange_state->f_value_len);
|
||||||
|
|
||||||
libssh2_sha1_update(exchange_state->exchange_hash,
|
libssh2_sha1_update(exchange_hash_ctx,
|
||||||
exchange_state->k_value,
|
exchange_state->k_value,
|
||||||
exchange_state->k_value_len);
|
exchange_state->k_value_len);
|
||||||
|
|
||||||
libssh2_sha1_final(exchange_state->exchange_hash,
|
libssh2_sha1_final(exchange_hash_ctx,
|
||||||
exchange_state->h_sig_comp);
|
exchange_state->h_sig_comp);
|
||||||
|
|
||||||
if (session->hostkey->
|
if (session->hostkey->
|
||||||
@ -687,6 +719,628 @@ static int diffie_hellman_sha1(LIBSSH2_SESSION *session,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* diffie_hellman_sha256
|
||||||
|
*
|
||||||
|
* Diffie Hellman Key Exchange, Group Agnostic
|
||||||
|
*/
|
||||||
|
static int diffie_hellman_sha256(LIBSSH2_SESSION *session,
|
||||||
|
_libssh2_bn *g,
|
||||||
|
_libssh2_bn *p,
|
||||||
|
int group_order,
|
||||||
|
unsigned char packet_type_init,
|
||||||
|
unsigned char packet_type_reply,
|
||||||
|
unsigned char *midhash,
|
||||||
|
unsigned long midhash_len,
|
||||||
|
kmdhgGPshakex_state_t *exchange_state)
|
||||||
|
{
|
||||||
|
int ret = 0;
|
||||||
|
int rc;
|
||||||
|
libssh2_sha256_ctx exchange_hash_ctx;
|
||||||
|
|
||||||
|
if (exchange_state->state == libssh2_NB_state_idle) {
|
||||||
|
/* Setup initial values */
|
||||||
|
exchange_state->e_packet = NULL;
|
||||||
|
exchange_state->s_packet = NULL;
|
||||||
|
exchange_state->k_value = NULL;
|
||||||
|
exchange_state->ctx = _libssh2_bn_ctx_new();
|
||||||
|
exchange_state->x = _libssh2_bn_init(); /* Random from client */
|
||||||
|
exchange_state->e = _libssh2_bn_init(); /* g^x mod p */
|
||||||
|
exchange_state->f = _libssh2_bn_init_from_bin(); /* g^(Random from server) mod p */
|
||||||
|
exchange_state->k = _libssh2_bn_init(); /* The shared secret: f^x mod p */
|
||||||
|
|
||||||
|
/* Zero the whole thing out */
|
||||||
|
memset(&exchange_state->req_state, 0, sizeof(packet_require_state_t));
|
||||||
|
|
||||||
|
/* Generate x and e */
|
||||||
|
_libssh2_bn_rand(exchange_state->x, group_order, 0, -1);
|
||||||
|
_libssh2_bn_mod_exp(exchange_state->e, g, exchange_state->x, p,
|
||||||
|
exchange_state->ctx);
|
||||||
|
|
||||||
|
/* Send KEX init */
|
||||||
|
/* packet_type(1) + String Length(4) + leading 0(1) */
|
||||||
|
exchange_state->e_packet_len =
|
||||||
|
_libssh2_bn_bytes(exchange_state->e) + 6;
|
||||||
|
if (_libssh2_bn_bits(exchange_state->e) % 8) {
|
||||||
|
/* Leading 00 not needed */
|
||||||
|
exchange_state->e_packet_len--;
|
||||||
|
}
|
||||||
|
|
||||||
|
exchange_state->e_packet =
|
||||||
|
LIBSSH2_ALLOC(session, exchange_state->e_packet_len);
|
||||||
|
if (!exchange_state->e_packet) {
|
||||||
|
ret = _libssh2_error(session, LIBSSH2_ERROR_ALLOC,
|
||||||
|
"Out of memory error");
|
||||||
|
goto clean_exit;
|
||||||
|
}
|
||||||
|
exchange_state->e_packet[0] = packet_type_init;
|
||||||
|
_libssh2_htonu32(exchange_state->e_packet + 1,
|
||||||
|
exchange_state->e_packet_len - 5);
|
||||||
|
if (_libssh2_bn_bits(exchange_state->e) % 8) {
|
||||||
|
_libssh2_bn_to_bin(exchange_state->e,
|
||||||
|
exchange_state->e_packet + 5);
|
||||||
|
} else {
|
||||||
|
exchange_state->e_packet[5] = 0;
|
||||||
|
_libssh2_bn_to_bin(exchange_state->e,
|
||||||
|
exchange_state->e_packet + 6);
|
||||||
|
}
|
||||||
|
|
||||||
|
_libssh2_debug(session, LIBSSH2_TRACE_KEX, "Sending KEX packet %d",
|
||||||
|
(int) packet_type_init);
|
||||||
|
exchange_state->state = libssh2_NB_state_created;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (exchange_state->state == libssh2_NB_state_created) {
|
||||||
|
rc = _libssh2_transport_send(session, exchange_state->e_packet,
|
||||||
|
exchange_state->e_packet_len,
|
||||||
|
NULL, 0);
|
||||||
|
if (rc == LIBSSH2_ERROR_EAGAIN) {
|
||||||
|
return rc;
|
||||||
|
} else if (rc) {
|
||||||
|
ret = _libssh2_error(session, rc,
|
||||||
|
"Unable to send KEX init message");
|
||||||
|
goto clean_exit;
|
||||||
|
}
|
||||||
|
exchange_state->state = libssh2_NB_state_sent;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (exchange_state->state == libssh2_NB_state_sent) {
|
||||||
|
if (session->burn_optimistic_kexinit) {
|
||||||
|
/* The first KEX packet to come along will be the guess initially
|
||||||
|
* sent by the server. That guess turned out to be wrong so we
|
||||||
|
* need to silently ignore it */
|
||||||
|
int burn_type;
|
||||||
|
|
||||||
|
_libssh2_debug(session, LIBSSH2_TRACE_KEX,
|
||||||
|
"Waiting for badly guessed KEX packet (to be ignored)");
|
||||||
|
burn_type =
|
||||||
|
_libssh2_packet_burn(session, &exchange_state->burn_state);
|
||||||
|
if (burn_type == LIBSSH2_ERROR_EAGAIN) {
|
||||||
|
return burn_type;
|
||||||
|
} else if (burn_type <= 0) {
|
||||||
|
/* Failed to receive a packet */
|
||||||
|
ret = burn_type;
|
||||||
|
goto clean_exit;
|
||||||
|
}
|
||||||
|
session->burn_optimistic_kexinit = 0;
|
||||||
|
|
||||||
|
_libssh2_debug(session, LIBSSH2_TRACE_KEX,
|
||||||
|
"Burnt packet of type: %02x",
|
||||||
|
(unsigned int) burn_type);
|
||||||
|
}
|
||||||
|
|
||||||
|
exchange_state->state = libssh2_NB_state_sent1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (exchange_state->state == libssh2_NB_state_sent1) {
|
||||||
|
/* Wait for KEX reply */
|
||||||
|
rc = _libssh2_packet_require(session, packet_type_reply,
|
||||||
|
&exchange_state->s_packet,
|
||||||
|
&exchange_state->s_packet_len, 0, NULL,
|
||||||
|
0, &exchange_state->req_state);
|
||||||
|
if (rc == LIBSSH2_ERROR_EAGAIN) {
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
if (rc) {
|
||||||
|
ret = _libssh2_error(session, LIBSSH2_ERROR_TIMEOUT,
|
||||||
|
"Timed out waiting for KEX reply");
|
||||||
|
goto clean_exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Parse KEXDH_REPLY */
|
||||||
|
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)
|
||||||
|
LIBSSH2_FREE(session, session->server_hostkey);
|
||||||
|
|
||||||
|
session->server_hostkey =
|
||||||
|
LIBSSH2_ALLOC(session, session->server_hostkey_len);
|
||||||
|
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, exchange_state->s,
|
||||||
|
session->server_hostkey_len);
|
||||||
|
exchange_state->s += session->server_hostkey_len;
|
||||||
|
|
||||||
|
#if LIBSSH2_MD5
|
||||||
|
{
|
||||||
|
libssh2_md5_ctx fingerprint_ctx;
|
||||||
|
|
||||||
|
if (libssh2_md5_init(&fingerprint_ctx)) {
|
||||||
|
libssh2_md5_update(fingerprint_ctx, session->server_hostkey,
|
||||||
|
session->server_hostkey_len);
|
||||||
|
libssh2_md5_final(fingerprint_ctx,
|
||||||
|
session->server_hostkey_md5);
|
||||||
|
session->server_hostkey_md5_valid = TRUE;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
session->server_hostkey_md5_valid = FALSE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#ifdef LIBSSH2DEBUG
|
||||||
|
{
|
||||||
|
char fingerprint[50], *fprint = fingerprint;
|
||||||
|
int i;
|
||||||
|
for(i = 0; i < 16; i++, fprint += 3) {
|
||||||
|
snprintf(fprint, 4, "%02x:", session->server_hostkey_md5[i]);
|
||||||
|
}
|
||||||
|
*(--fprint) = '\0';
|
||||||
|
_libssh2_debug(session, LIBSSH2_TRACE_KEX,
|
||||||
|
"Server's MD5 Fingerprint: %s", fingerprint);
|
||||||
|
}
|
||||||
|
#endif /* LIBSSH2DEBUG */
|
||||||
|
#endif /* ! LIBSSH2_MD5 */
|
||||||
|
|
||||||
|
{
|
||||||
|
libssh2_sha1_ctx fingerprint_ctx;
|
||||||
|
|
||||||
|
if (libssh2_sha1_init(&fingerprint_ctx)) {
|
||||||
|
libssh2_sha1_update(fingerprint_ctx, session->server_hostkey,
|
||||||
|
session->server_hostkey_len);
|
||||||
|
libssh2_sha1_final(fingerprint_ctx,
|
||||||
|
session->server_hostkey_sha1);
|
||||||
|
session->server_hostkey_sha1_valid = TRUE;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
session->server_hostkey_sha1_valid = FALSE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#ifdef LIBSSH2DEBUG
|
||||||
|
{
|
||||||
|
char fingerprint[64], *fprint = fingerprint;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for(i = 0; i < 20; i++, fprint += 3) {
|
||||||
|
snprintf(fprint, 4, "%02x:", session->server_hostkey_sha1[i]);
|
||||||
|
}
|
||||||
|
*(--fprint) = '\0';
|
||||||
|
_libssh2_debug(session, LIBSSH2_TRACE_KEX,
|
||||||
|
"Server's SHA1 Fingerprint: %s", fingerprint);
|
||||||
|
}
|
||||||
|
#endif /* LIBSSH2DEBUG */
|
||||||
|
|
||||||
|
if (session->hostkey->init(session, session->server_hostkey,
|
||||||
|
session->server_hostkey_len,
|
||||||
|
&session->server_hostkey_abstract)) {
|
||||||
|
ret = _libssh2_error(session, LIBSSH2_ERROR_HOSTKEY_INIT,
|
||||||
|
"Unable to initialize hostkey importer");
|
||||||
|
goto clean_exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
exchange_state->f_value_len = _libssh2_ntohu32(exchange_state->s);
|
||||||
|
exchange_state->s += 4;
|
||||||
|
exchange_state->f_value = exchange_state->s;
|
||||||
|
exchange_state->s += exchange_state->f_value_len;
|
||||||
|
_libssh2_bn_from_bin(exchange_state->f, exchange_state->f_value_len,
|
||||||
|
exchange_state->f_value);
|
||||||
|
|
||||||
|
exchange_state->h_sig_len = _libssh2_ntohu32(exchange_state->s);
|
||||||
|
exchange_state->s += 4;
|
||||||
|
exchange_state->h_sig = exchange_state->s;
|
||||||
|
|
||||||
|
/* Compute the shared secret */
|
||||||
|
_libssh2_bn_mod_exp(exchange_state->k, exchange_state->f,
|
||||||
|
exchange_state->x, p, exchange_state->ctx);
|
||||||
|
exchange_state->k_value_len = _libssh2_bn_bytes(exchange_state->k) + 5;
|
||||||
|
if (_libssh2_bn_bits(exchange_state->k) % 8) {
|
||||||
|
/* don't need leading 00 */
|
||||||
|
exchange_state->k_value_len--;
|
||||||
|
}
|
||||||
|
exchange_state->k_value =
|
||||||
|
LIBSSH2_ALLOC(session, exchange_state->k_value_len);
|
||||||
|
if (!exchange_state->k_value) {
|
||||||
|
ret = _libssh2_error(session, LIBSSH2_ERROR_ALLOC,
|
||||||
|
"Unable to allocate buffer for K");
|
||||||
|
goto clean_exit;
|
||||||
|
}
|
||||||
|
_libssh2_htonu32(exchange_state->k_value,
|
||||||
|
exchange_state->k_value_len - 4);
|
||||||
|
if (_libssh2_bn_bits(exchange_state->k) % 8) {
|
||||||
|
_libssh2_bn_to_bin(exchange_state->k, exchange_state->k_value + 4);
|
||||||
|
} else {
|
||||||
|
exchange_state->k_value[4] = 0;
|
||||||
|
_libssh2_bn_to_bin(exchange_state->k, exchange_state->k_value + 5);
|
||||||
|
}
|
||||||
|
|
||||||
|
exchange_state->exchange_hash = (void*)&exchange_hash_ctx;
|
||||||
|
libssh2_sha256_init(&exchange_hash_ctx);
|
||||||
|
|
||||||
|
if (session->local.banner) {
|
||||||
|
_libssh2_htonu32(exchange_state->h_sig_comp,
|
||||||
|
strlen((char *) session->local.banner) - 2);
|
||||||
|
libssh2_sha256_update(exchange_hash_ctx,
|
||||||
|
exchange_state->h_sig_comp, 4);
|
||||||
|
libssh2_sha256_update(exchange_hash_ctx,
|
||||||
|
(char *) session->local.banner,
|
||||||
|
strlen((char *) session->local.banner) - 2);
|
||||||
|
} else {
|
||||||
|
_libssh2_htonu32(exchange_state->h_sig_comp,
|
||||||
|
sizeof(LIBSSH2_SSH_DEFAULT_BANNER) - 1);
|
||||||
|
libssh2_sha256_update(exchange_hash_ctx,
|
||||||
|
exchange_state->h_sig_comp, 4);
|
||||||
|
libssh2_sha256_update(exchange_hash_ctx,
|
||||||
|
LIBSSH2_SSH_DEFAULT_BANNER,
|
||||||
|
sizeof(LIBSSH2_SSH_DEFAULT_BANNER) - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
_libssh2_htonu32(exchange_state->h_sig_comp,
|
||||||
|
strlen((char *) session->remote.banner));
|
||||||
|
libssh2_sha256_update(exchange_hash_ctx,
|
||||||
|
exchange_state->h_sig_comp, 4);
|
||||||
|
libssh2_sha256_update(exchange_hash_ctx,
|
||||||
|
session->remote.banner,
|
||||||
|
strlen((char *) session->remote.banner));
|
||||||
|
|
||||||
|
_libssh2_htonu32(exchange_state->h_sig_comp,
|
||||||
|
session->local.kexinit_len);
|
||||||
|
libssh2_sha256_update(exchange_hash_ctx,
|
||||||
|
exchange_state->h_sig_comp, 4);
|
||||||
|
libssh2_sha256_update(exchange_hash_ctx,
|
||||||
|
session->local.kexinit,
|
||||||
|
session->local.kexinit_len);
|
||||||
|
|
||||||
|
_libssh2_htonu32(exchange_state->h_sig_comp,
|
||||||
|
session->remote.kexinit_len);
|
||||||
|
libssh2_sha256_update(exchange_hash_ctx,
|
||||||
|
exchange_state->h_sig_comp, 4);
|
||||||
|
libssh2_sha256_update(exchange_hash_ctx,
|
||||||
|
session->remote.kexinit,
|
||||||
|
session->remote.kexinit_len);
|
||||||
|
|
||||||
|
_libssh2_htonu32(exchange_state->h_sig_comp,
|
||||||
|
session->server_hostkey_len);
|
||||||
|
libssh2_sha256_update(exchange_hash_ctx,
|
||||||
|
exchange_state->h_sig_comp, 4);
|
||||||
|
libssh2_sha256_update(exchange_hash_ctx,
|
||||||
|
session->server_hostkey,
|
||||||
|
session->server_hostkey_len);
|
||||||
|
|
||||||
|
if (packet_type_init == SSH_MSG_KEX_DH_GEX_INIT) {
|
||||||
|
/* diffie-hellman-group-exchange hashes additional fields */
|
||||||
|
#ifdef LIBSSH2_DH_GEX_NEW
|
||||||
|
_libssh2_htonu32(exchange_state->h_sig_comp,
|
||||||
|
LIBSSH2_DH_GEX_MINGROUP);
|
||||||
|
_libssh2_htonu32(exchange_state->h_sig_comp + 4,
|
||||||
|
LIBSSH2_DH_GEX_OPTGROUP);
|
||||||
|
_libssh2_htonu32(exchange_state->h_sig_comp + 8,
|
||||||
|
LIBSSH2_DH_GEX_MAXGROUP);
|
||||||
|
libssh2_sha256_update(exchange_hash_ctx,
|
||||||
|
exchange_state->h_sig_comp, 12);
|
||||||
|
#else
|
||||||
|
_libssh2_htonu32(exchange_state->h_sig_comp,
|
||||||
|
LIBSSH2_DH_GEX_OPTGROUP);
|
||||||
|
libssh2_sha256_update(exchange_hash_ctx,
|
||||||
|
exchange_state->h_sig_comp, 4);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
if (midhash) {
|
||||||
|
libssh2_sha256_update(exchange_hash_ctx, midhash,
|
||||||
|
midhash_len);
|
||||||
|
}
|
||||||
|
|
||||||
|
libssh2_sha256_update(exchange_hash_ctx,
|
||||||
|
exchange_state->e_packet + 1,
|
||||||
|
exchange_state->e_packet_len - 1);
|
||||||
|
|
||||||
|
_libssh2_htonu32(exchange_state->h_sig_comp,
|
||||||
|
exchange_state->f_value_len);
|
||||||
|
libssh2_sha256_update(exchange_hash_ctx,
|
||||||
|
exchange_state->h_sig_comp, 4);
|
||||||
|
libssh2_sha256_update(exchange_hash_ctx,
|
||||||
|
exchange_state->f_value,
|
||||||
|
exchange_state->f_value_len);
|
||||||
|
|
||||||
|
libssh2_sha256_update(exchange_hash_ctx,
|
||||||
|
exchange_state->k_value,
|
||||||
|
exchange_state->k_value_len);
|
||||||
|
|
||||||
|
libssh2_sha256_final(exchange_hash_ctx,
|
||||||
|
exchange_state->h_sig_comp);
|
||||||
|
|
||||||
|
if (session->hostkey->
|
||||||
|
sig_verify(session, exchange_state->h_sig,
|
||||||
|
exchange_state->h_sig_len, exchange_state->h_sig_comp,
|
||||||
|
SHA256_DIGEST_LENGTH, &session->server_hostkey_abstract)) {
|
||||||
|
ret = _libssh2_error(session, LIBSSH2_ERROR_HOSTKEY_SIGN,
|
||||||
|
"Unable to verify hostkey signature");
|
||||||
|
goto clean_exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
_libssh2_debug(session, LIBSSH2_TRACE_KEX, "Sending NEWKEYS message");
|
||||||
|
exchange_state->c = SSH_MSG_NEWKEYS;
|
||||||
|
|
||||||
|
exchange_state->state = libssh2_NB_state_sent2;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (exchange_state->state == libssh2_NB_state_sent2) {
|
||||||
|
rc = _libssh2_transport_send(session, &exchange_state->c, 1, NULL, 0);
|
||||||
|
if (rc == LIBSSH2_ERROR_EAGAIN) {
|
||||||
|
return rc;
|
||||||
|
} else if (rc) {
|
||||||
|
ret = _libssh2_error(session, rc, "Unable to send NEWKEYS message");
|
||||||
|
goto clean_exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
exchange_state->state = libssh2_NB_state_sent3;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (exchange_state->state == libssh2_NB_state_sent3) {
|
||||||
|
rc = _libssh2_packet_require(session, SSH_MSG_NEWKEYS,
|
||||||
|
&exchange_state->tmp,
|
||||||
|
&exchange_state->tmp_len, 0, NULL, 0,
|
||||||
|
&exchange_state->req_state);
|
||||||
|
if (rc == LIBSSH2_ERROR_EAGAIN) {
|
||||||
|
return rc;
|
||||||
|
} else if (rc) {
|
||||||
|
ret = _libssh2_error(session, rc, "Timed out waiting for NEWKEYS");
|
||||||
|
goto clean_exit;
|
||||||
|
}
|
||||||
|
/* The first key exchange has been performed,
|
||||||
|
switch to active crypt/comp/mac mode */
|
||||||
|
session->state |= LIBSSH2_STATE_NEWKEYS;
|
||||||
|
_libssh2_debug(session, LIBSSH2_TRACE_KEX, "Received NEWKEYS message");
|
||||||
|
|
||||||
|
/* This will actually end up being just packet_type(1)
|
||||||
|
for this packet type anyway */
|
||||||
|
LIBSSH2_FREE(session, exchange_state->tmp);
|
||||||
|
|
||||||
|
if (!session->session_id) {
|
||||||
|
session->session_id = LIBSSH2_ALLOC(session, SHA256_DIGEST_LENGTH);
|
||||||
|
if (!session->session_id) {
|
||||||
|
ret = _libssh2_error(session, LIBSSH2_ERROR_ALLOC,
|
||||||
|
"Unable to allocate buffer for SHA digest");
|
||||||
|
goto clean_exit;
|
||||||
|
}
|
||||||
|
memcpy(session->session_id, exchange_state->h_sig_comp,
|
||||||
|
SHA256_DIGEST_LENGTH);
|
||||||
|
session->session_id_len = SHA256_DIGEST_LENGTH;
|
||||||
|
_libssh2_debug(session, LIBSSH2_TRACE_KEX, "session_id calculated");
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Cleanup any existing cipher */
|
||||||
|
if (session->local.crypt->dtor) {
|
||||||
|
session->local.crypt->dtor(session,
|
||||||
|
&session->local.crypt_abstract);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Calculate IV/Secret/Key for each direction */
|
||||||
|
if (session->local.crypt->init) {
|
||||||
|
unsigned char *iv = NULL, *secret = NULL;
|
||||||
|
int free_iv = 0, free_secret = 0;
|
||||||
|
|
||||||
|
LIBSSH2_KEX_METHOD_DIFFIE_HELLMAN_SHA256_HASH(iv,
|
||||||
|
session->local.crypt->
|
||||||
|
iv_len, "A");
|
||||||
|
if (!iv) {
|
||||||
|
ret = -1;
|
||||||
|
goto clean_exit;
|
||||||
|
}
|
||||||
|
LIBSSH2_KEX_METHOD_DIFFIE_HELLMAN_SHA256_HASH(secret,
|
||||||
|
session->local.crypt->
|
||||||
|
secret_len, "C");
|
||||||
|
if (!secret) {
|
||||||
|
LIBSSH2_FREE(session, iv);
|
||||||
|
ret = LIBSSH2_ERROR_KEX_FAILURE;
|
||||||
|
goto clean_exit;
|
||||||
|
}
|
||||||
|
if (session->local.crypt->
|
||||||
|
init(session, session->local.crypt, iv, &free_iv, secret,
|
||||||
|
&free_secret, 1, &session->local.crypt_abstract)) {
|
||||||
|
LIBSSH2_FREE(session, iv);
|
||||||
|
LIBSSH2_FREE(session, secret);
|
||||||
|
ret = LIBSSH2_ERROR_KEX_FAILURE;
|
||||||
|
goto clean_exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (free_iv) {
|
||||||
|
memset(iv, 0, session->local.crypt->iv_len);
|
||||||
|
LIBSSH2_FREE(session, iv);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (free_secret) {
|
||||||
|
memset(secret, 0, session->local.crypt->secret_len);
|
||||||
|
LIBSSH2_FREE(session, secret);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_libssh2_debug(session, LIBSSH2_TRACE_KEX,
|
||||||
|
"Client to Server IV and Key calculated");
|
||||||
|
|
||||||
|
if (session->remote.crypt->dtor) {
|
||||||
|
/* Cleanup any existing cipher */
|
||||||
|
session->remote.crypt->dtor(session,
|
||||||
|
&session->remote.crypt_abstract);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (session->remote.crypt->init) {
|
||||||
|
unsigned char *iv = NULL, *secret = NULL;
|
||||||
|
int free_iv = 0, free_secret = 0;
|
||||||
|
|
||||||
|
LIBSSH2_KEX_METHOD_DIFFIE_HELLMAN_SHA256_HASH(iv,
|
||||||
|
session->remote.crypt->
|
||||||
|
iv_len, "B");
|
||||||
|
if (!iv) {
|
||||||
|
ret = LIBSSH2_ERROR_KEX_FAILURE;
|
||||||
|
goto clean_exit;
|
||||||
|
}
|
||||||
|
LIBSSH2_KEX_METHOD_DIFFIE_HELLMAN_SHA256_HASH(secret,
|
||||||
|
session->remote.crypt->
|
||||||
|
secret_len, "D");
|
||||||
|
if (!secret) {
|
||||||
|
LIBSSH2_FREE(session, iv);
|
||||||
|
ret = LIBSSH2_ERROR_KEX_FAILURE;
|
||||||
|
goto clean_exit;
|
||||||
|
}
|
||||||
|
if (session->remote.crypt->
|
||||||
|
init(session, session->remote.crypt, iv, &free_iv, secret,
|
||||||
|
&free_secret, 0, &session->remote.crypt_abstract)) {
|
||||||
|
LIBSSH2_FREE(session, iv);
|
||||||
|
LIBSSH2_FREE(session, secret);
|
||||||
|
ret = LIBSSH2_ERROR_KEX_FAILURE;
|
||||||
|
goto clean_exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (free_iv) {
|
||||||
|
memset(iv, 0, session->remote.crypt->iv_len);
|
||||||
|
LIBSSH2_FREE(session, iv);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (free_secret) {
|
||||||
|
memset(secret, 0, session->remote.crypt->secret_len);
|
||||||
|
LIBSSH2_FREE(session, secret);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_libssh2_debug(session, LIBSSH2_TRACE_KEX,
|
||||||
|
"Server to Client IV and Key calculated");
|
||||||
|
|
||||||
|
if (session->local.mac->dtor) {
|
||||||
|
session->local.mac->dtor(session, &session->local.mac_abstract);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (session->local.mac->init) {
|
||||||
|
unsigned char *key = NULL;
|
||||||
|
int free_key = 0;
|
||||||
|
|
||||||
|
LIBSSH2_KEX_METHOD_DIFFIE_HELLMAN_SHA256_HASH(key,
|
||||||
|
session->local.mac->
|
||||||
|
key_len, "E");
|
||||||
|
if (!key) {
|
||||||
|
ret = LIBSSH2_ERROR_KEX_FAILURE;
|
||||||
|
goto clean_exit;
|
||||||
|
}
|
||||||
|
session->local.mac->init(session, key, &free_key,
|
||||||
|
&session->local.mac_abstract);
|
||||||
|
|
||||||
|
if (free_key) {
|
||||||
|
memset(key, 0, session->local.mac->key_len);
|
||||||
|
LIBSSH2_FREE(session, key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_libssh2_debug(session, LIBSSH2_TRACE_KEX,
|
||||||
|
"Client to Server HMAC Key calculated");
|
||||||
|
|
||||||
|
if (session->remote.mac->dtor) {
|
||||||
|
session->remote.mac->dtor(session, &session->remote.mac_abstract);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (session->remote.mac->init) {
|
||||||
|
unsigned char *key = NULL;
|
||||||
|
int free_key = 0;
|
||||||
|
|
||||||
|
LIBSSH2_KEX_METHOD_DIFFIE_HELLMAN_SHA256_HASH(key,
|
||||||
|
session->remote.mac->
|
||||||
|
key_len, "F");
|
||||||
|
if (!key) {
|
||||||
|
ret = LIBSSH2_ERROR_KEX_FAILURE;
|
||||||
|
goto clean_exit;
|
||||||
|
}
|
||||||
|
session->remote.mac->init(session, key, &free_key,
|
||||||
|
&session->remote.mac_abstract);
|
||||||
|
|
||||||
|
if (free_key) {
|
||||||
|
memset(key, 0, session->remote.mac->key_len);
|
||||||
|
LIBSSH2_FREE(session, key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_libssh2_debug(session, LIBSSH2_TRACE_KEX,
|
||||||
|
"Server to Client HMAC Key calculated");
|
||||||
|
|
||||||
|
/* Initialize compression for each direction */
|
||||||
|
|
||||||
|
/* Cleanup any existing compression */
|
||||||
|
if (session->local.comp && session->local.comp->dtor) {
|
||||||
|
session->local.comp->dtor(session, 1,
|
||||||
|
&session->local.comp_abstract);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (session->local.comp && session->local.comp->init) {
|
||||||
|
if (session->local.comp->init(session, 1,
|
||||||
|
&session->local.comp_abstract)) {
|
||||||
|
ret = LIBSSH2_ERROR_KEX_FAILURE;
|
||||||
|
goto clean_exit;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_libssh2_debug(session, LIBSSH2_TRACE_KEX,
|
||||||
|
"Client to Server compression initialized");
|
||||||
|
|
||||||
|
if (session->remote.comp && session->remote.comp->dtor) {
|
||||||
|
session->remote.comp->dtor(session, 0,
|
||||||
|
&session->remote.comp_abstract);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (session->remote.comp && session->remote.comp->init) {
|
||||||
|
if (session->remote.comp->init(session, 0,
|
||||||
|
&session->remote.comp_abstract)) {
|
||||||
|
ret = LIBSSH2_ERROR_KEX_FAILURE;
|
||||||
|
goto clean_exit;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_libssh2_debug(session, LIBSSH2_TRACE_KEX,
|
||||||
|
"Server to Client compression initialized");
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
clean_exit:
|
||||||
|
_libssh2_bn_free(exchange_state->x);
|
||||||
|
exchange_state->x = NULL;
|
||||||
|
_libssh2_bn_free(exchange_state->e);
|
||||||
|
exchange_state->e = NULL;
|
||||||
|
_libssh2_bn_free(exchange_state->f);
|
||||||
|
exchange_state->f = NULL;
|
||||||
|
_libssh2_bn_free(exchange_state->k);
|
||||||
|
exchange_state->k = NULL;
|
||||||
|
_libssh2_bn_ctx_free(exchange_state->ctx);
|
||||||
|
exchange_state->ctx = NULL;
|
||||||
|
|
||||||
|
if (exchange_state->e_packet) {
|
||||||
|
LIBSSH2_FREE(session, exchange_state->e_packet);
|
||||||
|
exchange_state->e_packet = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (exchange_state->s_packet) {
|
||||||
|
LIBSSH2_FREE(session, exchange_state->s_packet);
|
||||||
|
exchange_state->s_packet = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (exchange_state->k_value) {
|
||||||
|
LIBSSH2_FREE(session, exchange_state->k_value);
|
||||||
|
exchange_state->k_value = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
exchange_state->state = libssh2_NB_state_idle;
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* kex_method_diffie_hellman_group1_sha1_key_exchange
|
/* kex_method_diffie_hellman_group1_sha1_key_exchange
|
||||||
* Diffie-Hellman Group1 (Actually Group2) Key Exchange using SHA1
|
* Diffie-Hellman Group1 (Actually Group2) Key Exchange using SHA1
|
||||||
@ -925,6 +1579,105 @@ kex_method_diffie_hellman_group_exchange_sha1_key_exchange
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* kex_method_diffie_hellman_group_exchange_sha256_key_exchange
|
||||||
|
* Diffie-Hellman Group Exchange Key Exchange using SHA256
|
||||||
|
* Negotiates random(ish) group for secret derivation
|
||||||
|
*/
|
||||||
|
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;
|
||||||
|
|
||||||
|
if (key_state->state == libssh2_NB_state_idle) {
|
||||||
|
key_state->p = _libssh2_bn_init();
|
||||||
|
key_state->g = _libssh2_bn_init();
|
||||||
|
/* Ask for a P and G pair */
|
||||||
|
#ifdef LIBSSH2_DH_GEX_NEW
|
||||||
|
key_state->request[0] = SSH_MSG_KEX_DH_GEX_REQUEST;
|
||||||
|
_libssh2_htonu32(key_state->request + 1, LIBSSH2_DH_GEX_MINGROUP);
|
||||||
|
_libssh2_htonu32(key_state->request + 5, LIBSSH2_DH_GEX_OPTGROUP);
|
||||||
|
_libssh2_htonu32(key_state->request + 9, LIBSSH2_DH_GEX_MAXGROUP);
|
||||||
|
key_state->request_len = 13;
|
||||||
|
_libssh2_debug(session, LIBSSH2_TRACE_KEX,
|
||||||
|
"Initiating Diffie-Hellman Group-Exchange (New Method SHA256)");
|
||||||
|
#else
|
||||||
|
key_state->request[0] = SSH_MSG_KEX_DH_GEX_REQUEST_OLD;
|
||||||
|
_libssh2_htonu32(key_state->request + 1, LIBSSH2_DH_GEX_OPTGROUP);
|
||||||
|
key_state->request_len = 5;
|
||||||
|
_libssh2_debug(session, LIBSSH2_TRACE_KEX,
|
||||||
|
"Initiating Diffie-Hellman Group-Exchange (Old Method SHA256)");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
key_state->state = libssh2_NB_state_created;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (key_state->state == libssh2_NB_state_created) {
|
||||||
|
rc = _libssh2_transport_send(session, key_state->request,
|
||||||
|
key_state->request_len, NULL, 0);
|
||||||
|
if (rc == LIBSSH2_ERROR_EAGAIN) {
|
||||||
|
return rc;
|
||||||
|
} else if (rc) {
|
||||||
|
ret = _libssh2_error(session, rc,
|
||||||
|
"Unable to send Group Exchange Request SHA256");
|
||||||
|
goto dh_gex_clean_exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
key_state->state = libssh2_NB_state_sent;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (key_state->state == libssh2_NB_state_sent) {
|
||||||
|
rc = _libssh2_packet_require(session, SSH_MSG_KEX_DH_GEX_GROUP,
|
||||||
|
&key_state->data, &key_state->data_len,
|
||||||
|
0, NULL, 0, &key_state->req_state);
|
||||||
|
if (rc == LIBSSH2_ERROR_EAGAIN) {
|
||||||
|
return rc;
|
||||||
|
} else if (rc) {
|
||||||
|
ret = _libssh2_error(session, rc,
|
||||||
|
"Timeout waiting for GEX_GROUP reply SHA256");
|
||||||
|
goto dh_gex_clean_exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
key_state->state = libssh2_NB_state_sent1;
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
g_len = _libssh2_ntohu32(s);
|
||||||
|
s += 4;
|
||||||
|
_libssh2_bn_from_bin(key_state->g, g_len, s);
|
||||||
|
|
||||||
|
ret = diffie_hellman_sha256(session, key_state->g, key_state->p, p_len,
|
||||||
|
SSH_MSG_KEX_DH_GEX_INIT,
|
||||||
|
SSH_MSG_KEX_DH_GEX_REPLY,
|
||||||
|
key_state->data + 1,
|
||||||
|
key_state->data_len - 1,
|
||||||
|
&key_state->exchange_state);
|
||||||
|
if (ret == LIBSSH2_ERROR_EAGAIN) {
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
LIBSSH2_FREE(session, key_state->data);
|
||||||
|
}
|
||||||
|
|
||||||
|
dh_gex_clean_exit:
|
||||||
|
key_state->state = libssh2_NB_state_idle;
|
||||||
|
_libssh2_bn_free(key_state->g);
|
||||||
|
key_state->g = NULL;
|
||||||
|
_libssh2_bn_free(key_state->p);
|
||||||
|
key_state->p = NULL;
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
#define LIBSSH2_KEX_METHOD_FLAG_REQ_ENC_HOSTKEY 0x0001
|
#define LIBSSH2_KEX_METHOD_FLAG_REQ_ENC_HOSTKEY 0x0001
|
||||||
#define LIBSSH2_KEX_METHOD_FLAG_REQ_SIGN_HOSTKEY 0x0002
|
#define LIBSSH2_KEX_METHOD_FLAG_REQ_SIGN_HOSTKEY 0x0002
|
||||||
|
|
||||||
@ -947,7 +1700,16 @@ kex_method_diffie_helman_group_exchange_sha1 = {
|
|||||||
LIBSSH2_KEX_METHOD_FLAG_REQ_SIGN_HOSTKEY,
|
LIBSSH2_KEX_METHOD_FLAG_REQ_SIGN_HOSTKEY,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static const LIBSSH2_KEX_METHOD
|
||||||
|
kex_method_diffie_helman_group_exchange_sha256 = {
|
||||||
|
"diffie-hellman-group-exchange-sha256",
|
||||||
|
kex_method_diffie_hellman_group_exchange_sha256_key_exchange,
|
||||||
|
LIBSSH2_KEX_METHOD_FLAG_REQ_SIGN_HOSTKEY,
|
||||||
|
};
|
||||||
|
|
||||||
static const LIBSSH2_KEX_METHOD *libssh2_kex_methods[] = {
|
static const LIBSSH2_KEX_METHOD *libssh2_kex_methods[] = {
|
||||||
|
&kex_method_diffie_helman_group_exchange_sha256,
|
||||||
|
&kex_method_diffie_helman_group_exchange_sha1,
|
||||||
&kex_method_diffie_helman_group14_sha1,
|
&kex_method_diffie_helman_group14_sha1,
|
||||||
&kex_method_diffie_helman_group_exchange_sha1,
|
&kex_method_diffie_helman_group_exchange_sha1,
|
||||||
&kex_method_diffie_helman_group1_sha1,
|
&kex_method_diffie_helman_group1_sha1,
|
||||||
|
@ -57,6 +57,7 @@
|
|||||||
|
|
||||||
#define MD5_DIGEST_LENGTH 16
|
#define MD5_DIGEST_LENGTH 16
|
||||||
#define SHA_DIGEST_LENGTH 20
|
#define SHA_DIGEST_LENGTH 20
|
||||||
|
#define SHA256_DIGEST_LENGTH 32
|
||||||
|
|
||||||
#define _libssh2_random(buf, len) \
|
#define _libssh2_random(buf, len) \
|
||||||
(gcry_randomize ((buf), (len), GCRY_STRONG_RANDOM), 1)
|
(gcry_randomize ((buf), (len), GCRY_STRONG_RANDOM), 1)
|
||||||
@ -73,6 +74,15 @@
|
|||||||
#define libssh2_sha1(message, len, out) \
|
#define libssh2_sha1(message, len, out) \
|
||||||
gcry_md_hash_buffer (GCRY_MD_SHA1, out, message, len)
|
gcry_md_hash_buffer (GCRY_MD_SHA1, out, message, len)
|
||||||
|
|
||||||
|
#define libssh2_sha256_init(ctx) \
|
||||||
|
(GPG_ERR_NO_ERROR == gcry_md_open (ctx, GCRY_MD_SHA256, 0))
|
||||||
|
#define libssh2_sha256_update(ctx, data, len) \
|
||||||
|
gcry_md_write (ctx, (unsigned char *) data, len)
|
||||||
|
#define libssh2_sha256_final(ctx, out) \
|
||||||
|
memcpy (out, gcry_md_read (ctx, 0), SHA256_DIGEST_LENGTH), gcry_md_close (ctx)
|
||||||
|
#define libssh2_sha256(message, len, out) \
|
||||||
|
gcry_md_hash_buffer (GCRY_MD_SHA256, out, message, len)
|
||||||
|
|
||||||
#define libssh2_md5_ctx gcry_md_hd_t
|
#define libssh2_md5_ctx gcry_md_hd_t
|
||||||
|
|
||||||
/* returns 0 in case of failure */
|
/* returns 0 in case of failure */
|
||||||
|
@ -149,6 +149,7 @@ static inline int writev(int sock, struct iovec *iov, int nvecs)
|
|||||||
* padding length, payload, padding, and MAC.)."
|
* padding length, payload, padding, and MAC.)."
|
||||||
*/
|
*/
|
||||||
#define MAX_SSH_PACKET_LEN 35000
|
#define MAX_SSH_PACKET_LEN 35000
|
||||||
|
#define MAX_SHA_DIGEST_LEN SHA256_DIGEST_LENGTH
|
||||||
|
|
||||||
#define LIBSSH2_ALLOC(session, count) \
|
#define LIBSSH2_ALLOC(session, count) \
|
||||||
session->alloc((count), &(session)->abstract)
|
session->alloc((count), &(session)->abstract)
|
||||||
@ -229,13 +230,13 @@ typedef struct packet_requirev_state_t
|
|||||||
time_t start;
|
time_t start;
|
||||||
} packet_requirev_state_t;
|
} packet_requirev_state_t;
|
||||||
|
|
||||||
typedef struct kmdhgGPsha1kex_state_t
|
typedef struct kmdhgGPshakex_state_t
|
||||||
{
|
{
|
||||||
libssh2_nonblocking_states state;
|
libssh2_nonblocking_states state;
|
||||||
unsigned char *e_packet;
|
unsigned char *e_packet;
|
||||||
unsigned char *s_packet;
|
unsigned char *s_packet;
|
||||||
unsigned char *tmp;
|
unsigned char *tmp;
|
||||||
unsigned char h_sig_comp[SHA_DIGEST_LENGTH];
|
unsigned char h_sig_comp[MAX_SHA_DIGEST_LEN];
|
||||||
unsigned char c;
|
unsigned char c;
|
||||||
size_t e_packet_len;
|
size_t e_packet_len;
|
||||||
size_t s_packet_len;
|
size_t s_packet_len;
|
||||||
@ -252,16 +253,16 @@ typedef struct kmdhgGPsha1kex_state_t
|
|||||||
size_t f_value_len;
|
size_t f_value_len;
|
||||||
size_t k_value_len;
|
size_t k_value_len;
|
||||||
size_t h_sig_len;
|
size_t h_sig_len;
|
||||||
libssh2_sha1_ctx exchange_hash;
|
void *exchange_hash;
|
||||||
packet_require_state_t req_state;
|
packet_require_state_t req_state;
|
||||||
libssh2_nonblocking_states burn_state;
|
libssh2_nonblocking_states burn_state;
|
||||||
} kmdhgGPsha1kex_state_t;
|
} kmdhgGPshakex_state_t;
|
||||||
|
|
||||||
typedef struct key_exchange_state_low_t
|
typedef struct key_exchange_state_low_t
|
||||||
{
|
{
|
||||||
libssh2_nonblocking_states state;
|
libssh2_nonblocking_states state;
|
||||||
packet_require_state_t req_state;
|
packet_require_state_t req_state;
|
||||||
kmdhgGPsha1kex_state_t exchange_state;
|
kmdhgGPshakex_state_t exchange_state;
|
||||||
_libssh2_bn *p; /* SSH2 defined value (p_value) */
|
_libssh2_bn *p; /* SSH2 defined value (p_value) */
|
||||||
_libssh2_bn *g; /* SSH2 defined value (2) */
|
_libssh2_bn *g; /* SSH2 defined value (2) */
|
||||||
unsigned char request[13];
|
unsigned char request[13];
|
||||||
@ -964,7 +965,7 @@ _libssh2_debug(LIBSSH2_SESSION * session, int context, const char *format, ...)
|
|||||||
#define SSH_MSG_KEXDH_INIT 30
|
#define SSH_MSG_KEXDH_INIT 30
|
||||||
#define SSH_MSG_KEXDH_REPLY 31
|
#define SSH_MSG_KEXDH_REPLY 31
|
||||||
|
|
||||||
/* diffie-hellman-group-exchange-sha1 */
|
/* diffie-hellman-group-exchange-sha1 and diffie-hellman-group-exchange-sha256 */
|
||||||
#define SSH_MSG_KEX_DH_GEX_REQUEST_OLD 30
|
#define SSH_MSG_KEX_DH_GEX_REQUEST_OLD 30
|
||||||
#define SSH_MSG_KEX_DH_GEX_REQUEST 34
|
#define SSH_MSG_KEX_DH_GEX_REQUEST 34
|
||||||
#define SSH_MSG_KEX_DH_GEX_GROUP 31
|
#define SSH_MSG_KEX_DH_GEX_GROUP 31
|
||||||
|
@ -434,7 +434,7 @@ read_private_key_from_file(void ** key_ctx,
|
|||||||
return (*key_ctx) ? 0 : -1;
|
return (*key_ctx) ? 0 : -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
_libssh2_rsa_new_private_frommemory(libssh2_rsa_ctx ** rsa,
|
_libssh2_rsa_new_private_frommemory(libssh2_rsa_ctx ** rsa,
|
||||||
LIBSSH2_SESSION * session,
|
LIBSSH2_SESSION * session,
|
||||||
const char *filedata, size_t filedata_len,
|
const char *filedata, size_t filedata_len,
|
||||||
@ -588,6 +588,28 @@ _libssh2_sha1(const unsigned char *message, unsigned long len,
|
|||||||
return 1; /* error */
|
return 1; /* error */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
_libssh2_sha256_init(libssh2_sha256_ctx *ctx)
|
||||||
|
{
|
||||||
|
EVP_MD_CTX_init(ctx);
|
||||||
|
return EVP_DigestInit(ctx, EVP_get_digestbyname("sha256"));
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
_libssh2_sha256(const unsigned char *message, unsigned long len,
|
||||||
|
unsigned char *out)
|
||||||
|
{
|
||||||
|
EVP_MD_CTX ctx;
|
||||||
|
|
||||||
|
EVP_MD_CTX_init(&ctx);
|
||||||
|
if(EVP_DigestInit(&ctx, EVP_get_digestbyname("sha256"))) {
|
||||||
|
EVP_DigestUpdate(&ctx, message, len);
|
||||||
|
EVP_DigestFinal(&ctx, out, NULL);
|
||||||
|
return 0; /* success */
|
||||||
|
}
|
||||||
|
return 1; /* error */
|
||||||
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
_libssh2_md5_init(libssh2_md5_ctx *ctx)
|
_libssh2_md5_init(libssh2_md5_ctx *ctx)
|
||||||
{
|
{
|
||||||
|
@ -124,6 +124,17 @@ int _libssh2_sha1(const unsigned char *message, unsigned long len,
|
|||||||
unsigned char *out);
|
unsigned char *out);
|
||||||
#define libssh2_sha1(x,y,z) _libssh2_sha1(x,y,z)
|
#define libssh2_sha1(x,y,z) _libssh2_sha1(x,y,z)
|
||||||
|
|
||||||
|
#define libssh2_sha256_ctx EVP_MD_CTX
|
||||||
|
|
||||||
|
/* returns 0 in case of failure */
|
||||||
|
int _libssh2_sha256_init(libssh2_sha256_ctx *ctx);
|
||||||
|
#define libssh2_sha256_init(x) _libssh2_sha256_init(x)
|
||||||
|
#define libssh2_sha256_update(ctx, data, len) EVP_DigestUpdate(&(ctx), data, len)
|
||||||
|
#define libssh2_sha256_final(ctx, out) EVP_DigestFinal(&(ctx), out, NULL)
|
||||||
|
int _libssh2_sha256(const unsigned char *message, unsigned long len,
|
||||||
|
unsigned char *out);
|
||||||
|
#define libssh2_sha256(x,y,z) _libssh2_sha256(x,y,z)
|
||||||
|
|
||||||
#define libssh2_md5_ctx EVP_MD_CTX
|
#define libssh2_md5_ctx EVP_MD_CTX
|
||||||
|
|
||||||
/* returns 0 in case of failure */
|
/* returns 0 in case of failure */
|
||||||
@ -136,21 +147,26 @@ int _libssh2_md5_init(libssh2_md5_ctx *);
|
|||||||
#define libssh2_hmac_ctx_init(ctx) \
|
#define libssh2_hmac_ctx_init(ctx) \
|
||||||
HMAC_CTX_init(&ctx)
|
HMAC_CTX_init(&ctx)
|
||||||
#define libssh2_hmac_sha1_init(ctx, key, keylen) \
|
#define libssh2_hmac_sha1_init(ctx, key, keylen) \
|
||||||
HMAC_Init(ctx, key, keylen, EVP_sha1())
|
HMAC_Init_ex(ctx, key, keylen, EVP_sha1(), NULL)
|
||||||
#define libssh2_hmac_md5_init(ctx, key, keylen) \
|
#define libssh2_hmac_md5_init(ctx, key, keylen) \
|
||||||
HMAC_Init(ctx, key, keylen, EVP_md5())
|
HMAC_Init_ex(ctx, key, keylen, EVP_md5(), NULL)
|
||||||
#define libssh2_hmac_ripemd160_init(ctx, key, keylen) \
|
#define libssh2_hmac_ripemd160_init(ctx, key, keylen) \
|
||||||
HMAC_Init(ctx, key, keylen, EVP_ripemd160())
|
HMAC_Init_ex(ctx, key, keylen, EVP_ripemd160(), NULL)
|
||||||
#define libssh2_hmac_sha256_init(ctx, key, keylen) \
|
#define libssh2_hmac_sha256_init(ctx, key, keylen) \
|
||||||
HMAC_Init(ctx, key, keylen, EVP_sha256())
|
HMAC_Init_ex(ctx, key, keylen, EVP_sha256(), NULL)
|
||||||
#define libssh2_hmac_sha512_init(ctx, key, keylen) \
|
#define libssh2_hmac_sha512_init(ctx, key, keylen) \
|
||||||
HMAC_Init(ctx, key, keylen, EVP_sha512())
|
HMAC_Init_ex(ctx, key, keylen, EVP_sha512(), NULL)
|
||||||
|
|
||||||
#define libssh2_hmac_update(ctx, data, datalen) \
|
#define libssh2_hmac_update(ctx, data, datalen) \
|
||||||
HMAC_Update(&(ctx), data, datalen)
|
HMAC_Update(&(ctx), data, datalen)
|
||||||
#define libssh2_hmac_final(ctx, data) HMAC_Final(&(ctx), data, NULL)
|
#define libssh2_hmac_final(ctx, data) HMAC_Final(&(ctx), data, NULL)
|
||||||
#define libssh2_hmac_cleanup(ctx) HMAC_cleanup(ctx)
|
#define libssh2_hmac_cleanup(ctx) HMAC_cleanup(ctx)
|
||||||
|
|
||||||
#define libssh2_crypto_init() OpenSSL_add_all_algorithms()
|
#define libssh2_crypto_init() \
|
||||||
|
OpenSSL_add_all_algorithms(); \
|
||||||
|
ENGINE_load_builtin_engines(); \
|
||||||
|
ENGINE_register_all_complete()
|
||||||
|
|
||||||
#define libssh2_crypto_exit()
|
#define libssh2_crypto_exit()
|
||||||
|
|
||||||
#define libssh2_rsa_ctx RSA
|
#define libssh2_rsa_ctx RSA
|
||||||
|
Загрузка…
x
Ссылка в новой задаче
Block a user