File 0001-kex-Added-diffie-hellman-group-exchange-sha256-suppo.patch of Package libssh2_org.30348
From fc4a969a0512e226de9b821496d20b9ddf53b741 Mon Sep 17 00:00:00 2001
From: Will Cosgrove <will@panic.com>
Date: Wed, 23 Sep 2015 12:12:00 -0700
Subject: [PATCH] kex: Added diffie-hellman-group-exchange-sha256 support
... and fixed HMAC_Init depricated usage
Closes #48
---
src/kex.c | 944 +++++++++++++++++++++++++++++++++++++++++++++++------
src/libgcrypt.h | 10 +
src/libssh2_priv.h | 13 +-
src/openssl.c | 26 +-
src/openssl.h | 28 +-
5 files changed, 916 insertions(+), 105 deletions(-)
Index: libssh2-1.4.3/src/kex.c
===================================================================
--- libssh2-1.4.3.orig/src/kex.c 2016-02-23 15:28:39.264493076 +0100
+++ libssh2-1.4.3/src/kex.c 2016-02-23 15:29:40.190481788 +0100
@@ -70,23 +70,673 @@
} \
}
+
+/* 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 Key Exchange, Group Agnostic
+ */
+static int diffie_hellman_sha1(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_sha1_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(); /* 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 * 8 - 1, 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_sha1_init(&exchange_hash_ctx);
+
+ if (session->local.banner) {
+ _libssh2_htonu32(exchange_state->h_sig_comp,
+ strlen((char *) session->local.banner) - 2);
+ libssh2_sha1_update(exchange_hash_ctx,
+ exchange_state->h_sig_comp, 4);
+ libssh2_sha1_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_sha1_update(exchange_hash_ctx,
+ exchange_state->h_sig_comp, 4);
+ libssh2_sha1_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_sha1_update(exchange_hash_ctx,
+ exchange_state->h_sig_comp, 4);
+ libssh2_sha1_update(exchange_hash_ctx,
+ session->remote.banner,
+ strlen((char *) session->remote.banner));
+
+ _libssh2_htonu32(exchange_state->h_sig_comp,
+ session->local.kexinit_len);
+ libssh2_sha1_update(exchange_hash_ctx,
+ exchange_state->h_sig_comp, 4);
+ libssh2_sha1_update(exchange_hash_ctx,
+ session->local.kexinit,
+ session->local.kexinit_len);
+
+ _libssh2_htonu32(exchange_state->h_sig_comp,
+ session->remote.kexinit_len);
+ libssh2_sha1_update(exchange_hash_ctx,
+ exchange_state->h_sig_comp, 4);
+ libssh2_sha1_update(exchange_hash_ctx,
+ session->remote.kexinit,
+ session->remote.kexinit_len);
+
+ _libssh2_htonu32(exchange_state->h_sig_comp,
+ session->server_hostkey_len);
+ libssh2_sha1_update(exchange_hash_ctx,
+ exchange_state->h_sig_comp, 4);
+ libssh2_sha1_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_sha1_update(exchange_hash_ctx,
+ exchange_state->h_sig_comp, 12);
+#else
+ _libssh2_htonu32(exchange_state->h_sig_comp,
+ LIBSSH2_DH_GEX_OPTGROUP);
+ libssh2_sha1_update(exchange_hash_ctx,
+ exchange_state->h_sig_comp, 4);
+#endif
+ }
+
+ if (midhash) {
+ libssh2_sha1_update(exchange_hash_ctx, midhash,
+ midhash_len);
+ }
+
+ libssh2_sha1_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_sha1_update(exchange_hash_ctx,
+ exchange_state->h_sig_comp, 4);
+ libssh2_sha1_update(exchange_hash_ctx,
+ exchange_state->f_value,
+ exchange_state->f_value_len);
+
+ libssh2_sha1_update(exchange_hash_ctx,
+ exchange_state->k_value,
+ exchange_state->k_value_len);
+
+ libssh2_sha1_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,
+ 20, &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, SHA_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,
+ SHA_DIGEST_LENGTH);
+ session->session_id_len = SHA_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_SHA1_HASH(iv,
+ session->local.crypt->
+ iv_len, "A");
+ if (!iv) {
+ ret = -1;
+ goto clean_exit;
+ }
+ LIBSSH2_KEX_METHOD_DIFFIE_HELLMAN_SHA1_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_SHA1_HASH(iv,
+ session->remote.crypt->
+ iv_len, "B");
+ if (!iv) {
+ ret = LIBSSH2_ERROR_KEX_FAILURE;
+ goto clean_exit;
+ }
+ LIBSSH2_KEX_METHOD_DIFFIE_HELLMAN_SHA1_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_SHA1_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_SHA1_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;
+}
+
+
/*
- * diffie_hellman_sha1
+ * diffie_hellman_sha256
*
* Diffie Hellman Key Exchange, Group Agnostic
*/
-static int diffie_hellman_sha1(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,
- kmdhgGPsha1kex_state_t *exchange_state)
+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 */
@@ -307,56 +957,58 @@ static int diffie_hellman_sha1(LIBSSH2_S
_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_sha256_init(&exchange_hash_ctx);
+
if (session->local.banner) {
_libssh2_htonu32(exchange_state->h_sig_comp,
strlen((char *) session->local.banner) - 2);
- libssh2_sha1_update(exchange_state->exchange_hash,
- exchange_state->h_sig_comp, 4);
- libssh2_sha1_update(exchange_state->exchange_hash,
- (char *) session->local.banner,
- 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_sha1_update(exchange_state->exchange_hash,
- exchange_state->h_sig_comp, 4);
- libssh2_sha1_update(exchange_state->exchange_hash,
- LIBSSH2_SSH_DEFAULT_BANNER,
- 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_sha1_update(exchange_state->exchange_hash,
- exchange_state->h_sig_comp, 4);
- libssh2_sha1_update(exchange_state->exchange_hash,
- session->remote.banner,
- 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_sha1_update(exchange_state->exchange_hash,
- exchange_state->h_sig_comp, 4);
- libssh2_sha1_update(exchange_state->exchange_hash,
- session->local.kexinit,
- 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_sha1_update(exchange_state->exchange_hash,
- exchange_state->h_sig_comp, 4);
- libssh2_sha1_update(exchange_state->exchange_hash,
- session->remote.kexinit,
- 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_sha1_update(exchange_state->exchange_hash,
- exchange_state->h_sig_comp, 4);
- libssh2_sha1_update(exchange_state->exchange_hash,
- session->server_hostkey,
- 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 */
@@ -367,49 +1019,51 @@ static int diffie_hellman_sha1(LIBSSH2_S
LIBSSH2_DH_GEX_OPTGROUP);
_libssh2_htonu32(exchange_state->h_sig_comp + 8,
LIBSSH2_DH_GEX_MAXGROUP);
- libssh2_sha1_update(exchange_state->exchange_hash,
- exchange_state->h_sig_comp, 12);
+ 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_sha1_update(exchange_state->exchange_hash,
- exchange_state->h_sig_comp, 4);
+ libssh2_sha256_update(exchange_hash_ctx,
+ exchange_state->h_sig_comp, 4);
#endif
}
if (midhash) {
- libssh2_sha1_update(exchange_state->exchange_hash, midhash,
- midhash_len);
+ libssh2_sha256_update(exchange_hash_ctx, midhash,
+ midhash_len);
}
- libssh2_sha1_update(exchange_state->exchange_hash,
- exchange_state->e_packet + 1,
- exchange_state->e_packet_len - 1);
+ 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_sha1_update(exchange_state->exchange_hash,
- exchange_state->h_sig_comp, 4);
- libssh2_sha1_update(exchange_state->exchange_hash,
- exchange_state->f_value,
- exchange_state->f_value_len);
-
- libssh2_sha1_update(exchange_state->exchange_hash,
- exchange_state->k_value,
- exchange_state->k_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_sha1_final(exchange_state->exchange_hash,
- exchange_state->h_sig_comp);
+ 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,
- 20, &session->server_hostkey_abstract)) {
+ 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;
@@ -449,15 +1103,15 @@ static int diffie_hellman_sha1(LIBSSH2_S
LIBSSH2_FREE(session, exchange_state->tmp);
if (!session->session_id) {
- session->session_id = LIBSSH2_ALLOC(session, SHA_DIGEST_LENGTH);
+ 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,
- SHA_DIGEST_LENGTH);
- session->session_id_len = SHA_DIGEST_LENGTH;
+ SHA256_DIGEST_LENGTH);
+ session->session_id_len = SHA256_DIGEST_LENGTH;
_libssh2_debug(session, LIBSSH2_TRACE_KEX, "session_id calculated");
}
@@ -472,16 +1126,16 @@ static int diffie_hellman_sha1(LIBSSH2_S
unsigned char *iv = NULL, *secret = NULL;
int free_iv = 0, free_secret = 0;
- LIBSSH2_KEX_METHOD_DIFFIE_HELLMAN_SHA1_HASH(iv,
- session->local.crypt->
- iv_len, "A");
+ 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_SHA1_HASH(secret,
- session->local.crypt->
- secret_len, "C");
+ 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;
@@ -519,16 +1173,16 @@ static int diffie_hellman_sha1(LIBSSH2_S
unsigned char *iv = NULL, *secret = NULL;
int free_iv = 0, free_secret = 0;
- LIBSSH2_KEX_METHOD_DIFFIE_HELLMAN_SHA1_HASH(iv,
- session->remote.crypt->
- iv_len, "B");
+ 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_SHA1_HASH(secret,
- session->remote.crypt->
- secret_len, "D");
+ 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;
@@ -564,9 +1218,9 @@ static int diffie_hellman_sha1(LIBSSH2_S
unsigned char *key = NULL;
int free_key = 0;
- LIBSSH2_KEX_METHOD_DIFFIE_HELLMAN_SHA1_HASH(key,
- session->local.mac->
- key_len, "E");
+ LIBSSH2_KEX_METHOD_DIFFIE_HELLMAN_SHA256_HASH(key,
+ session->local.mac->
+ key_len, "E");
if (!key) {
ret = LIBSSH2_ERROR_KEX_FAILURE;
goto clean_exit;
@@ -590,9 +1244,9 @@ static int diffie_hellman_sha1(LIBSSH2_S
unsigned char *key = NULL;
int free_key = 0;
- LIBSSH2_KEX_METHOD_DIFFIE_HELLMAN_SHA1_HASH(key,
- session->remote.mac->
- key_len, "F");
+ LIBSSH2_KEX_METHOD_DIFFIE_HELLMAN_SHA256_HASH(key,
+ session->remote.mac->
+ key_len, "F");
if (!key) {
ret = LIBSSH2_ERROR_KEX_FAILURE;
goto clean_exit;
@@ -914,6 +1568,105 @@ kex_method_diffie_hellman_group_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_SIGN_HOSTKEY 0x0002
@@ -936,7 +1689,16 @@ kex_method_diffie_helman_group_exchange_
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[] = {
+ &kex_method_diffie_helman_group_exchange_sha256,
+ &kex_method_diffie_helman_group_exchange_sha1,
&kex_method_diffie_helman_group14_sha1,
&kex_method_diffie_helman_group_exchange_sha1,
&kex_method_diffie_helman_group1_sha1,
@@ -1593,21 +2355,21 @@ static int kex_agree_methods(LIBSSH2_SES
/* Locate each string */
if(kex_string_pair(&s, data, data_len, &kex_len, &kex))
- return -1;
+ return -1;
if(kex_string_pair(&s, data, data_len, &hostkey_len, &hostkey))
- return -1;
+ return -1;
if(kex_string_pair(&s, data, data_len, &crypt_cs_len, &crypt_cs))
- return -1;
+ return -1;
if(kex_string_pair(&s, data, data_len, &crypt_sc_len, &crypt_sc))
- return -1;
+ return -1;
if(kex_string_pair(&s, data, data_len, &mac_cs_len, &mac_cs))
- return -1;
+ return -1;
if(kex_string_pair(&s, data, data_len, &mac_sc_len, &mac_sc))
- return -1;
+ return -1;
if(kex_string_pair(&s, data, data_len, &comp_cs_len, &comp_cs))
- return -1;
+ return -1;
if(kex_string_pair(&s, data, data_len, &comp_sc_len, &comp_sc))
- return -1;
+ return -1;
/* If the server sent an optimistic packet, assume that it guessed wrong.
* If the guess is determined to be right (by kex_agree_kex_hostkey)
@@ -1675,7 +2437,7 @@ static int kex_agree_methods(LIBSSH2_SES
*/
int
_libssh2_kex_exchange(LIBSSH2_SESSION * session, int reexchange,
- key_exchange_state_t * key_state)
+ key_exchange_state_t * key_state)
{
int rc = 0;
int retcode;
Index: libssh2-1.4.3/src/libgcrypt.h
===================================================================
--- libssh2-1.4.3.orig/src/libgcrypt.h 2016-02-23 15:28:39.264493076 +0100
+++ libssh2-1.4.3/src/libgcrypt.h 2016-02-23 15:29:40.190481788 +0100
@@ -57,6 +57,7 @@
#define MD5_DIGEST_LENGTH 16
#define SHA_DIGEST_LENGTH 20
+#define SHA256_DIGEST_LENGTH 32
#define _libssh2_random(buf, len) \
(gcry_randomize ((buf), (len), GCRY_STRONG_RANDOM), 1)
@@ -69,6 +70,15 @@
#define libssh2_sha1(message, len, out) \
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
/* returns 0 in case of failure */
Index: libssh2-1.4.3/src/libssh2_priv.h
===================================================================
--- libssh2-1.4.3.orig/src/libssh2_priv.h 2016-02-23 15:28:39.264493076 +0100
+++ libssh2-1.4.3/src/libssh2_priv.h 2016-02-23 15:29:40.190481788 +0100
@@ -152,6 +152,7 @@ static inline int writev(int sock, struc
* padding length, payload, padding, and MAC.)."
*/
#define MAX_SSH_PACKET_LEN 35000
+#define MAX_SHA_DIGEST_LEN SHA256_DIGEST_LENGTH
#define LIBSSH2_ALLOC(session, count) \
session->alloc((count), &(session)->abstract)
@@ -231,13 +232,13 @@ typedef struct packet_requirev_state_t
time_t start;
} packet_requirev_state_t;
-typedef struct kmdhgGPsha1kex_state_t
+typedef struct kmdhgGPshakex_state_t
{
libssh2_nonblocking_states state;
unsigned char *e_packet;
unsigned char *s_packet;
unsigned char *tmp;
- unsigned char h_sig_comp[SHA_DIGEST_LENGTH];
+ unsigned char h_sig_comp[MAX_SHA_DIGEST_LEN];
unsigned char c;
size_t e_packet_len;
size_t s_packet_len;
@@ -254,16 +255,16 @@ typedef struct kmdhgGPsha1kex_state_t
size_t f_value_len;
size_t k_value_len;
size_t h_sig_len;
- libssh2_sha1_ctx exchange_hash;
+ void *exchange_hash;
packet_require_state_t req_state;
libssh2_nonblocking_states burn_state;
-} kmdhgGPsha1kex_state_t;
+} kmdhgGPshakex_state_t;
typedef struct key_exchange_state_low_t
{
libssh2_nonblocking_states 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 *g; /* SSH2 defined value (2) */
unsigned char request[13];
@@ -599,6 +600,8 @@ struct _LIBSSH2_SESSION
unsigned char server_hostkey_md5[MD5_DIGEST_LENGTH];
int server_hostkey_md5_valid;
#endif /* ! LIBSSH2_MD5 */
+ int server_hostkey_sha1_valid;
+
unsigned char server_hostkey_sha1[SHA_DIGEST_LENGTH];
/* (remote as source of data -- packet_read ) */
@@ -954,7 +957,7 @@ _libssh2_debug(LIBSSH2_SESSION * session
#define SSH_MSG_KEXDH_INIT 30
#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 34
#define SSH_MSG_KEX_DH_GEX_GROUP 31
Index: libssh2-1.4.3/src/openssl.c
===================================================================
--- libssh2-1.4.3.orig/src/openssl.c 2016-02-23 15:28:39.264493076 +0100
+++ libssh2-1.4.3/src/openssl.c 2016-02-23 15:29:40.190481788 +0100
@@ -801,4 +801,26 @@ _libssh2_pub_priv_keyfile(LIBSSH2_SESSIO
return st;
}
+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 */
+}
+
#endif /* !LIBSSH2_LIBGCRYPT */
Index: libssh2-1.4.3/src/openssl.h
===================================================================
--- libssh2-1.4.3.orig/src/openssl.h 2016-02-23 15:29:38.014446452 +0100
+++ libssh2-1.4.3/src/openssl.h 2016-02-23 15:32:43.823469135 +0100
@@ -47,6 +47,7 @@
#include <openssl/bn.h>
#include <openssl/pem.h>
#include <openssl/rand.h>
+#include <openssl/engine.h>
#ifdef OPENSSL_NO_RSA
# define LIBSSH2_RSA 0
@@ -115,6 +116,17 @@
#define libssh2_sha1_final(ctx, out) EVP_DigestFinal(&(ctx), out, NULL)
void libssh2_sha1(const unsigned char *message, unsigned long len, unsigned char *out);
+#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
/* returns 0 in case of failure */
@@ -128,21 +140,25 @@ void libssh2_md5(const unsigned char *me
#define libssh2_hmac_ctx_init(ctx) \
HMAC_CTX_init(&ctx)
#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) \
- HMAC_Init(ctx, key, keylen, EVP_md5())
+ HMAC_Init_ex(ctx, key, keylen, EVP_md5(), NULL)
#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) \
- HMAC_Init(ctx, key, keylen, EVP_sha256())
+ HMAC_Init_ex(ctx, key, keylen, EVP_sha256(), NULL)
#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) \
HMAC_Update(&(ctx), data, datalen)
#define libssh2_hmac_final(ctx, data) HMAC_Final(&(ctx), data, NULL)
#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_rsa_ctx RSA