svn commit: r491663 - in head/security/libssh2: . files
Jung-uk Kim
jkim at FreeBSD.org
Thu Jan 31 00:08:49 UTC 2019
Author: jkim
Date: Thu Jan 31 00:08:46 2019
New Revision: 491663
URL: https://svnweb.freebsd.org/changeset/ports/491663
Log:
Add support for ECDSA key exchange and SHA256 MAC.
Note these patches were cherry-piecked from the following upstream commits:
https://github.com/libssh2/libssh2/commit/bbc43cb
https://github.com/libssh2/libssh2/commit/aba34f5
https://github.com/libssh2/libssh2/commit/62b825c
Submitted by: Andrew Heybey <ath at heybey.org>
Reviewed by: sbz (maintainer)
Added:
head/security/libssh2/files/patch-include_libssh2.h (contents, props changed)
head/security/libssh2/files/patch-src_crypto.h (contents, props changed)
head/security/libssh2/files/patch-src_hostkey.c (contents, props changed)
head/security/libssh2/files/patch-src_kex.c (contents, props changed)
head/security/libssh2/files/patch-src_knownhost.c (contents, props changed)
head/security/libssh2/files/patch-src_libgcrypt.h (contents, props changed)
head/security/libssh2/files/patch-src_libssh2__priv.h (contents, props changed)
head/security/libssh2/files/patch-src_mbedtls.h (contents, props changed)
head/security/libssh2/files/patch-src_openssl.c (contents, props changed)
head/security/libssh2/files/patch-src_openssl.h (contents, props changed)
head/security/libssh2/files/patch-tests_openssh__server_Dockerfile (contents, props changed)
head/security/libssh2/files/patch-tests_openssh__server_ssh__host__ecdsa__key (contents, props changed)
head/security/libssh2/files/patch-tests_test__hostkey.c (contents, props changed)
head/security/libssh2/files/patch-tests_test__hostkey__hash.c (contents, props changed)
Modified:
head/security/libssh2/Makefile
Modified: head/security/libssh2/Makefile
==============================================================================
--- head/security/libssh2/Makefile Wed Jan 30 23:18:51 2019 (r491662)
+++ head/security/libssh2/Makefile Thu Jan 31 00:08:46 2019 (r491663)
@@ -3,6 +3,7 @@
PORTNAME= libssh2
PORTVERSION= 1.8.0
+PORTREVISION= 1
PORTEPOCH= 3
CATEGORIES= security devel
MASTER_SITES= http://www.libssh2.org/download/ \
Added: head/security/libssh2/files/patch-include_libssh2.h
==============================================================================
--- /dev/null 00:00:00 1970 (empty, because file is newly added)
+++ head/security/libssh2/files/patch-include_libssh2.h Thu Jan 31 00:08:46 2019 (r491663)
@@ -0,0 +1,43 @@
+--- include/libssh2.h.orig 2016-10-25 06:44:34 UTC
++++ include/libssh2.h
+@@ -403,11 +403,15 @@ typedef struct _LIBSSH2_POLLFD {
+ /* Hash Types */
+ #define LIBSSH2_HOSTKEY_HASH_MD5 1
+ #define LIBSSH2_HOSTKEY_HASH_SHA1 2
++#define LIBSSH2_HOSTKEY_HASH_SHA256 3
+
+ /* Hostkey Types */
+-#define LIBSSH2_HOSTKEY_TYPE_UNKNOWN 0
+-#define LIBSSH2_HOSTKEY_TYPE_RSA 1
+-#define LIBSSH2_HOSTKEY_TYPE_DSS 2
++#define LIBSSH2_HOSTKEY_TYPE_UNKNOWN 0
++#define LIBSSH2_HOSTKEY_TYPE_RSA 1
++#define LIBSSH2_HOSTKEY_TYPE_DSS 2
++#define LIBSSH2_HOSTKEY_TYPE_ECDSA_256 3
++#define LIBSSH2_HOSTKEY_TYPE_ECDSA_384 4
++#define LIBSSH2_HOSTKEY_TYPE_ECDSA_521 5
+
+ /* Disconnect Codes (defined by SSH protocol) */
+ #define SSH_DISCONNECT_HOST_NOT_ALLOWED_TO_CONNECT 1
+@@ -960,12 +964,15 @@ libssh2_knownhost_init(LIBSSH2_SESSION *
+ #define LIBSSH2_KNOWNHOST_KEYENC_BASE64 (2<<16)
+
+ /* type of key (2 bits) */
+-#define LIBSSH2_KNOWNHOST_KEY_MASK (7<<18)
+-#define LIBSSH2_KNOWNHOST_KEY_SHIFT 18
+-#define LIBSSH2_KNOWNHOST_KEY_RSA1 (1<<18)
+-#define LIBSSH2_KNOWNHOST_KEY_SSHRSA (2<<18)
+-#define LIBSSH2_KNOWNHOST_KEY_SSHDSS (3<<18)
+-#define LIBSSH2_KNOWNHOST_KEY_UNKNOWN (7<<18)
++#define LIBSSH2_KNOWNHOST_KEY_MASK (7<<18)
++#define LIBSSH2_KNOWNHOST_KEY_SHIFT 18
++#define LIBSSH2_KNOWNHOST_KEY_RSA1 (1<<18)
++#define LIBSSH2_KNOWNHOST_KEY_SSHRSA (2<<18)
++#define LIBSSH2_KNOWNHOST_KEY_SSHDSS (3<<18)
++#define LIBSSH2_KNOWNHOST_KEY_ECDSA_256 (4<<18)
++#define LIBSSH2_KNOWNHOST_KEY_ECDSA_384 (5<<18)
++#define LIBSSH2_KNOWNHOST_KEY_ECDSA_521 (6<<18)
++#define LIBSSH2_KNOWNHOST_KEY_UNKNOWN (7<<18)
+
+ LIBSSH2_API int
+ libssh2_knownhost_add(LIBSSH2_KNOWNHOSTS *hosts,
Added: head/security/libssh2/files/patch-src_crypto.h
==============================================================================
--- /dev/null 00:00:00 1970 (empty, because file is newly added)
+++ head/security/libssh2/files/patch-src_crypto.h Thu Jan 31 00:08:46 2019 (r491663)
@@ -0,0 +1,56 @@
+--- src/crypto.h.orig 2016-10-17 14:28:29 UTC
++++ src/crypto.h
+@@ -120,6 +120,53 @@ int _libssh2_dsa_new_private_frommemory(
+ unsigned const char *passphrase);
+ #endif
+
++#if LIBSSH2_ECDSA
++int
++_libssh2_ecdsa_curve_name_with_octal_new(libssh2_ecdsa_ctx ** ecdsactx,
++ const unsigned char *k,
++ size_t k_len, libssh2_curve_type type);
++int
++_libssh2_ecdsa_new_private(libssh2_ecdsa_ctx ** ec_ctx,
++ LIBSSH2_SESSION * session,
++ const char *filename, unsigned const char *passphrase);
++
++int _libssh2_ecdsa_new_openssh_private(libssh2_ecdsa_ctx ** dsa,
++ LIBSSH2_SESSION * session,
++ const char *filename,
++ unsigned const char *passphrase);
++int
++_libssh2_ecdsa_verify(libssh2_ecdsa_ctx * ctx,
++ const unsigned char *r, size_t r_len,
++ const unsigned char *s, size_t s_len,
++ const unsigned char *m, size_t m_len);
++
++int
++_libssh2_ecdsa_create_key(_libssh2_ec_key **out_private_key,
++ unsigned char **out_public_key_octal,
++ size_t *out_public_key_octal_len, libssh2_curve_type curve_type);
++
++int
++_libssh2_ecdh_gen_k(_libssh2_bn **k, _libssh2_ec_key *private_key,
++ const unsigned char *server_public_key, size_t server_public_key_len);
++
++int
++_libssh2_ecdsa_sign(LIBSSH2_SESSION *session, libssh2_ecdsa_ctx *ec_ctx,
++ const unsigned char *hash, unsigned long hash_len,
++ unsigned char **signature, size_t *signature_len);
++
++int _libssh2_ecdsa_new_private_frommemory(libssh2_ecdsa_ctx ** ec_ctx,
++ LIBSSH2_SESSION * session,
++ const char *filedata, size_t filedata_len,
++ unsigned const char *passphrase);
++
++libssh2_curve_type
++_libssh2_ecdsa_key_get_curve_type(_libssh2_ec_key *key);
++
++int
++_libssh2_ecdsa_curve_type_from_name(const char *name, libssh2_curve_type *out_type);
++
++#endif /* LIBSSH2_ECDSA */
++
+ int _libssh2_cipher_init(_libssh2_cipher_ctx * h,
+ _libssh2_cipher_type(algo),
+ unsigned char *iv,
Added: head/security/libssh2/files/patch-src_hostkey.c
==============================================================================
--- /dev/null 00:00:00 1970 (empty, because file is newly added)
+++ head/security/libssh2/files/patch-src_hostkey.c Thu Jan 31 00:08:46 2019 (r491663)
@@ -0,0 +1,363 @@
+--- src/hostkey.c.orig 2016-01-18 12:41:58 UTC
++++ src/hostkey.c
+@@ -483,7 +483,296 @@ static const LIBSSH2_HOSTKEY_METHOD host
+ };
+ #endif /* LIBSSH2_DSA */
+
++#if LIBSSH2_ECDSA
++
++/* ***********
++ * ecdsa-sha2-nistp256/384/521 *
++ *********** */
++
++static int
++hostkey_method_ssh_ecdsa_dtor(LIBSSH2_SESSION * session,
++ void **abstract);
++
++/*
++ * hostkey_method_ssh_ecdsa_init
++ *
++ * Initialize the server hostkey working area with e/n pair
++ */
++static int
++hostkey_method_ssh_ecdsa_init(LIBSSH2_SESSION * session,
++ const unsigned char *hostkey_data,
++ size_t hostkey_data_len,
++ void **abstract)
++{
++ libssh2_ecdsa_ctx *ecdsactx = NULL;
++ const unsigned char *s, *k;
++ size_t len, key_len, n_len;
++ libssh2_curve_type type;
++
++ if (abstract != NULL && *abstract) {
++ hostkey_method_ssh_ecdsa_dtor(session, abstract);
++ *abstract = NULL;
++ }
++
++ if ( hostkey_data_len < 23 )
++ return -1;
++
++ s = hostkey_data;
++ len = _libssh2_ntohu32(s);
++ s += 4;
++
++ if (len != 19 )
++ return -1;
++
++ if (strncmp((char*) s, "ecdsa-sha2-nistp256", 19) == 0 ) {
++ type = LIBSSH2_EC_CURVE_NISTP256;
++ } else if(strncmp((char*) s, "ecdsa-sha2-nistp384", 19) == 0 ) {
++ type = LIBSSH2_EC_CURVE_NISTP384;
++ } else if(strncmp((char*) s, "ecdsa-sha2-nistp521", 19) == 0 ) {
++ type = LIBSSH2_EC_CURVE_NISTP521;
++ } else {
++ return -1;
++ }
++ s += 19;
++
++ /* Domain length */
++ n_len = _libssh2_ntohu32(s);
++ s += 4;
++
++ if (n_len != 8)
++ return -1;
++
++ if ( type == LIBSSH2_EC_CURVE_NISTP256 && strncmp((char*)s, "nistp256", 8) != 0) {
++ return -1;
++ } else if ( type == LIBSSH2_EC_CURVE_NISTP384 && strncmp((char*)s, "nistp384", 8) != 0) {
++ return -1;
++ } else if ( type == LIBSSH2_EC_CURVE_NISTP521 && strncmp((char*)s, "nistp521", 8) != 0) {
++ return -1;
++ }
++
++ s += 8;
++
++ /* public key */
++ key_len = _libssh2_ntohu32(s);
++ s += 4;
++
++ k = s;
++
++ if (_libssh2_ecdsa_curve_name_with_octal_new(&ecdsactx, k, key_len, type) )
++ return -1;
++
++ if ( abstract != NULL )
++ *abstract = ecdsactx;
++
++ return 0;
++}
++
++/*
++ * hostkey_method_ssh_ecdsa_initPEM
++ *
++ * Load a Private Key from a PEM file
++ */
++static int
++hostkey_method_ssh_ecdsa_initPEM(LIBSSH2_SESSION * session,
++ const char *privkeyfile,
++ unsigned const char *passphrase,
++ void **abstract)
++{
++ libssh2_ecdsa_ctx *ec_ctx = NULL;
++ int ret;
++
++ if (abstract != NULL && *abstract) {
++ hostkey_method_ssh_ecdsa_dtor(session, abstract);
++ *abstract = NULL;
++ }
++
++ ret = _libssh2_ecdsa_new_private(&ec_ctx, session, privkeyfile, passphrase);
++
++ if ( abstract != NULL )
++ *abstract = ec_ctx;
++
++ return ret;
++}
++
++/*
++ * hostkey_method_ssh_ecdsa_initPEMFromMemory
++ *
++ * Load a Private Key from memory
++ */
++static int
++hostkey_method_ssh_ecdsa_initPEMFromMemory(LIBSSH2_SESSION * session,
++ const char *privkeyfiledata,
++ size_t privkeyfiledata_len,
++ unsigned const char *passphrase,
++ void **abstract)
++{
++ libssh2_ecdsa_ctx *ec_ctx = NULL;
++ int ret;
++
++ if (abstract != NULL && *abstract) {
++ hostkey_method_ssh_ecdsa_dtor(session, abstract);
++ *abstract = NULL;
++ }
++
++ ret = _libssh2_ecdsa_new_private_frommemory(&ec_ctx, session,
++ privkeyfiledata,
++ privkeyfiledata_len, passphrase);
++ if (ret) {
++ return -1;
++ }
++
++ if (abstract != NULL)
++ *abstract = ec_ctx;
++
++ return 0;
++}
++
++/*
++ * hostkey_method_ecdsa_sig_verify
++ *
++ * Verify signature created by remote
++ */
++static int
++hostkey_method_ssh_ecdsa_sig_verify(LIBSSH2_SESSION * session,
++ const unsigned char *sig,
++ size_t sig_len,
++ const unsigned char *m,
++ size_t m_len, void **abstract)
++{
++ const unsigned char *r, *s, *p;
++ size_t r_len, s_len;
++ libssh2_ecdsa_ctx *ctx = (libssh2_ecdsa_ctx *) (*abstract);
++
++ (void) session;
++
++ if ( sig_len < 35 )
++ return -1;
++
++ /* Skip past keyname_len(4) + keyname(19){"ecdsa-sha2-nistp256"} + signature_len(4) */
++ p = sig;
++ p += 27;
++
++ r_len = _libssh2_ntohu32(p);
++ p += 4;
++ r = p;
++ p += r_len;
++
++ s_len = _libssh2_ntohu32(p);
++ p += 4;
++ s = p;
++
++ return _libssh2_ecdsa_verify(ctx, r, r_len, s, s_len, m, m_len);
++}
++
++
++#define LIBSSH2_HOSTKEY_METHOD_EC_SIGNV_HASH(digest_type) \
++{ \
++ unsigned char hash[SHA##digest_type##_DIGEST_LENGTH]; \
++ libssh2_sha##digest_type##_ctx ctx; \
++ int i; \
++ libssh2_sha##digest_type##_init(&ctx); \
++ for(i = 0; i < veccount; i++) { \
++ libssh2_sha##digest_type##_update(ctx, datavec[i].iov_base, datavec[i].iov_len); \
++ } \
++ libssh2_sha##digest_type##_final(ctx, hash); \
++ ret = _libssh2_ecdsa_sign(session, ec_ctx, hash, SHA##digest_type##_DIGEST_LENGTH, \
++ signature, signature_len); \
++}
++
++
++/*
++ * hostkey_method_ecdsa_signv
++ *
++ * Construct a signature from an array of vectors
++ */
++static int
++hostkey_method_ssh_ecdsa_signv(LIBSSH2_SESSION * session,
++ unsigned char **signature,
++ size_t *signature_len,
++ int veccount,
++ const struct iovec datavec[],
++ void **abstract)
++{
++ libssh2_ecdsa_ctx *ec_ctx = (libssh2_ecdsa_ctx *) (*abstract);
++ libssh2_curve_type type = _libssh2_ecdsa_key_get_curve_type(ec_ctx);
++ int ret = 0;
++
++ if ( type == LIBSSH2_EC_CURVE_NISTP256 ) {
++ LIBSSH2_HOSTKEY_METHOD_EC_SIGNV_HASH(256);
++ }else if ( type == LIBSSH2_EC_CURVE_NISTP384 ) {
++ LIBSSH2_HOSTKEY_METHOD_EC_SIGNV_HASH(384);
++ }else if ( type == LIBSSH2_EC_CURVE_NISTP521 ){
++ LIBSSH2_HOSTKEY_METHOD_EC_SIGNV_HASH(512);
++ }else{
++ return -1;
++ }
++
++ return ret;
++}
++
++/*
++ * hostkey_method_ssh_ecdsa_dtor
++ *
++ * Shutdown the hostkey by freeing EC_KEY context
++ */
++static int
++hostkey_method_ssh_ecdsa_dtor(LIBSSH2_SESSION * session, void **abstract)
++{
++ libssh2_ecdsa_ctx *keyctx = (libssh2_ecdsa_ctx *) (*abstract);
++ (void) session;
++
++ if (keyctx != NULL)
++ _libssh2_ecdsa_free(keyctx);
++
++ *abstract = NULL;
++
++ return 0;
++}
++
++static const LIBSSH2_HOSTKEY_METHOD hostkey_method_ecdsa_ssh_nistp256 = {
++ "ecdsa-sha2-nistp256",
++ SHA256_DIGEST_LENGTH,
++ hostkey_method_ssh_ecdsa_init,
++ hostkey_method_ssh_ecdsa_initPEM,
++ hostkey_method_ssh_ecdsa_initPEMFromMemory,
++ hostkey_method_ssh_ecdsa_sig_verify,
++ hostkey_method_ssh_ecdsa_signv,
++ NULL, /* encrypt */
++ hostkey_method_ssh_ecdsa_dtor,
++};
++
++static const LIBSSH2_HOSTKEY_METHOD hostkey_method_ecdsa_ssh_nistp384 = {
++ "ecdsa-sha2-nistp384",
++ SHA384_DIGEST_LENGTH,
++ hostkey_method_ssh_ecdsa_init,
++ hostkey_method_ssh_ecdsa_initPEM,
++ hostkey_method_ssh_ecdsa_initPEMFromMemory,
++ hostkey_method_ssh_ecdsa_sig_verify,
++ hostkey_method_ssh_ecdsa_signv,
++ NULL, /* encrypt */
++ hostkey_method_ssh_ecdsa_dtor,
++};
++
++static const LIBSSH2_HOSTKEY_METHOD hostkey_method_ecdsa_ssh_nistp521 = {
++ "ecdsa-sha2-nistp521",
++ SHA512_DIGEST_LENGTH,
++ hostkey_method_ssh_ecdsa_init,
++ hostkey_method_ssh_ecdsa_initPEM,
++ hostkey_method_ssh_ecdsa_initPEMFromMemory,
++ hostkey_method_ssh_ecdsa_sig_verify,
++ hostkey_method_ssh_ecdsa_signv,
++ NULL, /* encrypt */
++ hostkey_method_ssh_ecdsa_dtor,
++};
++#endif /* LIBSSH2_ECDSA */
++
++
+ static const LIBSSH2_HOSTKEY_METHOD *hostkey_methods[] = {
++#if LIBSSH2_ECDSA
++ &hostkey_method_ecdsa_ssh_nistp256,
++ &hostkey_method_ecdsa_ssh_nistp384,
++ &hostkey_method_ecdsa_ssh_nistp521,
++#endif
+ #if LIBSSH2_RSA
+ &hostkey_method_ssh_rsa,
+ #endif /* LIBSSH2_RSA */
+@@ -505,7 +794,7 @@ libssh2_hostkey_methods(void)
+ * Returns hash signature
+ * Returned buffer should NOT be freed
+ * Length of buffer is determined by hash type
+- * i.e. MD5 == 16, SHA1 == 20
++ * i.e. MD5 == 16, SHA1 == 20, SHA256 == 32
+ */
+ LIBSSH2_API const char *
+ libssh2_hostkey_hash(LIBSSH2_SESSION * session, int hash_type)
+@@ -523,6 +812,11 @@ libssh2_hostkey_hash(LIBSSH2_SESSION * s
+ ? (char *) session->server_hostkey_sha1
+ : NULL;
+ break;
++ case LIBSSH2_HOSTKEY_HASH_SHA256:
++ return (session->server_hostkey_sha256_valid)
++ ? (char *) session->server_hostkey_sha256
++ : NULL;
++ break;
+ default:
+ return NULL;
+ }
+@@ -536,6 +830,15 @@ static int hostkey_type(const unsigned c
+ const unsigned char dss[] = {
+ 0, 0, 0, 0x07, 's', 's', 'h', '-', 'd', 's', 's'
+ };
++ const unsigned char ecdsa_256[] = {
++ 0, 0, 0, 0x13, 'e', 'c', 'd', 's', 'a', '-', 's', 'h', 'a', '2', '-', 'n', 'i', 's', 't', 'p', '2', '5', '6'
++ };
++ const unsigned char ecdsa_384[] = {
++ 0, 0, 0, 0x13, 'e', 'c', 'd', 's', 'a', '-', 's', 'h', 'a', '2', '-', 'n', 'i', 's', 't', 'p', '3', '8', '4'
++ };
++ const unsigned char ecdsa_521[] = {
++ 0, 0, 0, 0x13, 'e', 'c', 'd', 's', 'a', '-', 's', 'h', 'a', '2', '-', 'n', 'i', 's', 't', 'p', '5', '2', '1'
++ };
+
+ if (len < 11)
+ return LIBSSH2_HOSTKEY_TYPE_UNKNOWN;
+@@ -546,6 +849,21 @@ static int hostkey_type(const unsigned c
+ if (!memcmp(dss, hostkey, 11))
+ return LIBSSH2_HOSTKEY_TYPE_DSS;
+
++ if ( len < 15 )
++ return LIBSSH2_HOSTKEY_TYPE_UNKNOWN;
++
++ if ( len < 23 )
++ return LIBSSH2_HOSTKEY_TYPE_UNKNOWN;
++
++ if(!memcmp(ecdsa_256, hostkey, 23))
++ return LIBSSH2_HOSTKEY_TYPE_ECDSA_256;
++
++ if(!memcmp(ecdsa_384, hostkey, 23))
++ return LIBSSH2_HOSTKEY_TYPE_ECDSA_384;
++
++ if(!memcmp(ecdsa_521, hostkey, 23))
++ return LIBSSH2_HOSTKEY_TYPE_ECDSA_521;
++
+ return LIBSSH2_HOSTKEY_TYPE_UNKNOWN;
+ }
+
+@@ -570,4 +888,3 @@ libssh2_session_hostkey(LIBSSH2_SESSION
+ *len = 0;
+ return NULL;
+ }
+-
Added: head/security/libssh2/files/patch-src_kex.c
==============================================================================
--- /dev/null 00:00:00 1970 (empty, because file is newly added)
+++ head/security/libssh2/files/patch-src_kex.c Thu Jan 31 00:08:46 2019 (r491663)
@@ -0,0 +1,1040 @@
+--- src/kex.c.orig 2016-10-17 14:28:29 UTC
++++ src/kex.c
+@@ -68,34 +68,47 @@
+ libssh2_sha1_final(hash, (value) + len); \
+ len += SHA_DIGEST_LENGTH; \
+ } \
+- }
++ } \
+
+
+-/* 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; \
+- } \
++#define LIBSSH2_KEX_METHOD_EC_SHA_VALUE_HASH(value, reqlen, version) \
++ { \
++ if (type == LIBSSH2_EC_CURVE_NISTP256) { \
++ LIBSSH2_KEX_METHOD_SHA_VALUE_HASH(256, value, reqlen, version); \
++ } \
++ else if (type == LIBSSH2_EC_CURVE_NISTP384 ) { \
++ LIBSSH2_KEX_METHOD_SHA_VALUE_HASH(384, value, reqlen, version); \
++ } \
++ else if (type == LIBSSH2_EC_CURVE_NISTP521 ) { \
++ LIBSSH2_KEX_METHOD_SHA_VALUE_HASH(512, value, reqlen, version); \
++ } \
++} \
++
++
++#define LIBSSH2_KEX_METHOD_SHA_VALUE_HASH(digest_type, value, reqlen, version) \
++ { \
++ libssh2_sha##digest_type##_ctx hash; \
++ unsigned long len = 0; \
++ if (!(value)) { \
++ value = LIBSSH2_ALLOC(session, reqlen + SHA##digest_type##_DIGEST_LENGTH); \
++ } \
++ if (value) \
++ while (len < (unsigned long)reqlen) { \
++ libssh2_sha##digest_type##_init(&hash); \
++ libssh2_sha##digest_type##_update(hash, exchange_state->k_value, \
++ exchange_state->k_value_len); \
++ libssh2_sha##digest_type##_update(hash, exchange_state->h_sig_comp, \
++ SHA##digest_type##_DIGEST_LENGTH); \
++ if (len > 0) { \
++ libssh2_sha##digest_type##_update(hash, value, len); \
++ } else { \
++ libssh2_sha##digest_type##_update(hash, (version), 1); \
++ libssh2_sha##digest_type##_update(hash, session->session_id, \
++ session->session_id_len); \
++ } \
++ libssh2_sha##digest_type##_final(hash, (value) + len); \
++ len += SHA##digest_type##_DIGEST_LENGTH; \
++ } \
+ }
+
+
+@@ -304,6 +317,62 @@ static int diffie_hellman_sha1(LIBSSH2_S
+ "Server's SHA1 Fingerprint: %s", fingerprint);
+ }
+ #endif /* LIBSSH2DEBUG */
++
++ {
++ libssh2_sha256_ctx fingerprint_ctx;
++
++ if (libssh2_sha256_init(&fingerprint_ctx)) {
++ libssh2_sha256_update(fingerprint_ctx, session->server_hostkey,
++ session->server_hostkey_len);
++ libssh2_sha256_final(fingerprint_ctx,
++ session->server_hostkey_sha256);
++ session->server_hostkey_sha256_valid = TRUE;
++ }
++ else {
++ session->server_hostkey_sha256_valid = FALSE;
++ }
++ }
++#ifdef LIBSSH2DEBUG
++ {
++ char *base64Fingerprint = NULL;
++ _libssh2_base64_encode(session, (const char*)session->server_hostkey_sha256,
++ SHA256_DIGEST_LENGTH, &base64Fingerprint);
++ if (base64Fingerprint != NULL) {
++ _libssh2_debug(session, LIBSSH2_TRACE_KEX,
++ "Server's SHA256 Fingerprint: %s", base64Fingerprint);
++ LIBSSH2_FREE(session, base64Fingerprint);
++ }
++ }
++#endif /* LIBSSH2DEBUG */
++
++
++ {
++ libssh2_sha256_ctx fingerprint_ctx;
++
++ if (libssh2_sha256_init(&fingerprint_ctx)) {
++ libssh2_sha256_update(fingerprint_ctx, session->server_hostkey,
++ session->server_hostkey_len);
++ libssh2_sha256_final(fingerprint_ctx,
++ session->server_hostkey_sha256);
++ session->server_hostkey_sha256_valid = TRUE;
++ }
++ else {
++ session->server_hostkey_sha256_valid = FALSE;
++ }
++ }
++#ifdef LIBSSH2DEBUG
++ {
++ char *base64Fingerprint = NULL;
++ _libssh2_base64_encode(session, (const char*)session->server_hostkey_sha256,
++ SHA256_DIGEST_LENGTH, &base64Fingerprint);
++ if (base64Fingerprint != NULL) {
++ _libssh2_debug(session, LIBSSH2_TRACE_KEX,
++ "Server's SHA256 Fingerprint: %s", base64Fingerprint);
++ LIBSSH2_FREE(session, base64Fingerprint);
++ }
++ }
++#endif /* LIBSSH2DEBUG */
++
+
+ if (session->hostkey->init(session, session->server_hostkey,
+ session->server_hostkey_len,
+@@ -924,6 +993,60 @@ static int diffie_hellman_sha256(LIBSSH2
+ "Server's SHA1 Fingerprint: %s", fingerprint);
+ }
+ #endif /* LIBSSH2DEBUG */
++
++ {
++ libssh2_sha256_ctx fingerprint_ctx;
++
++ if (libssh2_sha256_init(&fingerprint_ctx)) {
++ libssh2_sha256_update(fingerprint_ctx, session->server_hostkey,
++ session->server_hostkey_len);
++ libssh2_sha256_final(fingerprint_ctx,
++ session->server_hostkey_sha256);
++ session->server_hostkey_sha256_valid = TRUE;
++ }
++ else {
++ session->server_hostkey_sha256_valid = FALSE;
++ }
++ }
++#ifdef LIBSSH2DEBUG
++ {
++ char *base64Fingerprint = NULL;
++ _libssh2_base64_encode(session, (const char*)session->server_hostkey_sha256,
++ SHA256_DIGEST_LENGTH, &base64Fingerprint);
++ if (base64Fingerprint != NULL) {
++ _libssh2_debug(session, LIBSSH2_TRACE_KEX,
++ "Server's SHA256 Fingerprint: %s", base64Fingerprint);
++ LIBSSH2_FREE(session, base64Fingerprint);
++ }
++ }
++#endif /* LIBSSH2DEBUG */
++
++ {
++ libssh2_sha256_ctx fingerprint_ctx;
++
++ if (libssh2_sha256_init(&fingerprint_ctx)) {
++ libssh2_sha256_update(fingerprint_ctx, session->server_hostkey,
++ session->server_hostkey_len);
++ libssh2_sha256_final(fingerprint_ctx,
++ session->server_hostkey_sha256);
++ session->server_hostkey_sha256_valid = TRUE;
++ }
++ else {
++ session->server_hostkey_sha256_valid = FALSE;
++ }
++ }
++#ifdef LIBSSH2DEBUG
++ {
++ char *base64Fingerprint = NULL;
++ _libssh2_base64_encode(session, (const char*)session->server_hostkey_sha256,
++ SHA256_DIGEST_LENGTH, &base64Fingerprint);
++ if (base64Fingerprint != NULL) {
++ _libssh2_debug(session, LIBSSH2_TRACE_KEX,
++ "Server's SHA256 Fingerprint: %s", base64Fingerprint);
++ LIBSSH2_FREE(session, base64Fingerprint);
++ }
++ }
++#endif /* LIBSSH2DEBUG */
+
+ if (session->hostkey->init(session, session->server_hostkey,
+ session->server_hostkey_len,
+@@ -1137,16 +1260,18 @@ static int diffie_hellman_sha256(LIBSSH2
+ 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");
++ LIBSSH2_KEX_METHOD_SHA_VALUE_HASH(256, iv,
++ session->local.crypt->
++ iv_len,
++ (const unsigned char *)"A");
+ if (!iv) {
+ ret = -1;
+ goto clean_exit;
+ }
+- LIBSSH2_KEX_METHOD_DIFFIE_HELLMAN_SHA256_HASH(secret,
+- session->local.crypt->
+- secret_len, "C");
++ LIBSSH2_KEX_METHOD_SHA_VALUE_HASH(256, secret,
++ session->local.crypt->
++ secret_len,
++ (const unsigned char *)"C");
+ if (!secret) {
+ LIBSSH2_FREE(session, iv);
+ ret = LIBSSH2_ERROR_KEX_FAILURE;
+@@ -1184,16 +1309,18 @@ static int diffie_hellman_sha256(LIBSSH2
+ 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");
++ LIBSSH2_KEX_METHOD_SHA_VALUE_HASH(256, iv,
++ session->remote.crypt->
++ iv_len,
++ (const unsigned char *)"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");
++ LIBSSH2_KEX_METHOD_SHA_VALUE_HASH(256, secret,
++ session->remote.crypt->
++ secret_len,
++ (const unsigned char *)"D");
+ if (!secret) {
+ LIBSSH2_FREE(session, iv);
+ ret = LIBSSH2_ERROR_KEX_FAILURE;
+@@ -1229,9 +1356,10 @@ static int diffie_hellman_sha256(LIBSSH2
+ unsigned char *key = NULL;
+ int free_key = 0;
+
+- LIBSSH2_KEX_METHOD_DIFFIE_HELLMAN_SHA256_HASH(key,
+- session->local.mac->
+- key_len, "E");
++ LIBSSH2_KEX_METHOD_SHA_VALUE_HASH(256, key,
++ session->local.mac->
++ key_len,
++ (const unsigned char *)"E");
+ if (!key) {
+ ret = LIBSSH2_ERROR_KEX_FAILURE;
+ goto clean_exit;
+@@ -1255,9 +1383,10 @@ static int diffie_hellman_sha256(LIBSSH2
+ unsigned char *key = NULL;
+ int free_key = 0;
+
+- LIBSSH2_KEX_METHOD_DIFFIE_HELLMAN_SHA256_HASH(key,
+- session->remote.mac->
+- key_len, "F");
++ LIBSSH2_KEX_METHOD_SHA_VALUE_HASH(256, key,
++ session->remote.mac->
++ key_len,
++ (const unsigned char *)"F");
+ if (!key) {
+ ret = LIBSSH2_ERROR_KEX_FAILURE;
+ goto clean_exit;
+@@ -1678,6 +1807,725 @@ kex_method_diffie_hellman_group_exchange
+ }
+
+
++#if LIBSSH2_ECDSA
++
++/* kex_session_ecdh_curve_type
++ * returns the EC curve type by name used in key exchange
++ */
++
++static int
++kex_session_ecdh_curve_type(const char *name, libssh2_curve_type *out_type)
++{
++ int ret = 0;
++ libssh2_curve_type type;
++
++ if ( name == NULL )
++ return -1;
++
++ if ( strcmp(name, "ecdh-sha2-nistp256") == 0)
++ type = LIBSSH2_EC_CURVE_NISTP256;
++ else if ( strcmp(name, "ecdh-sha2-nistp384") == 0)
++ type = LIBSSH2_EC_CURVE_NISTP384;
++ else if ( strcmp(name, "ecdh-sha2-nistp521") == 0)
++ type = LIBSSH2_EC_CURVE_NISTP521;
++ else {
++ ret = -1;
++ }
++
++ if (ret == 0 && out_type) {
++ *out_type = type;
++ }
++
++ return ret;
++}
++
++
++/* LIBSSH2_KEX_METHOD_EC_SHA_HASH_CREATE_VERIFY
++ *
++ * Macro that create and verifies EC SHA hash with a given digest bytes
++ *
++ * Payload format:
++ *
++ * string V_C, client's identification string (CR and LF excluded)
++ * string V_S, server's identification string (CR and LF excluded)
++ * string I_C, payload of the client's SSH_MSG_KEXINIT
++ * string I_S, payload of the server's SSH_MSG_KEXINIT
++ * string K_S, server's public host key
++ * string Q_C, client's ephemeral public key octet string
++ * string Q_S, server's ephemeral public key octet string
++ * mpint K, shared secret
++ *
++ */
++
++#define LIBSSH2_KEX_METHOD_EC_SHA_HASH_CREATE_VERIFY(digest_type) \
++ { \
++ \
++ libssh2_sha##digest_type##_ctx ctx; \
++ exchange_state->exchange_hash = (void*)&ctx; \
++ \
++ libssh2_sha##digest_type##_init(&ctx); \
++ if (session->local.banner) { \
++ _libssh2_htonu32(exchange_state->h_sig_comp, \
++ strlen((char *) session->local.banner) - 2); \
++ libssh2_sha##digest_type##_update(ctx, \
++ exchange_state->h_sig_comp, 4); \
++ libssh2_sha##digest_type##_update(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_sha##digest_type##_update(ctx, \
++ exchange_state->h_sig_comp, 4); \
++ libssh2_sha##digest_type##_update(ctx, \
++ LIBSSH2_SSH_DEFAULT_BANNER, \
++ sizeof(LIBSSH2_SSH_DEFAULT_BANNER) - 1); \
++ } \
++ \
++ _libssh2_htonu32(exchange_state->h_sig_comp, \
++ strlen((char *) session->remote.banner)); \
++ libssh2_sha##digest_type##_update(ctx, \
++ exchange_state->h_sig_comp, 4); \
++ libssh2_sha##digest_type##_update(ctx, \
++ session->remote.banner, \
++ strlen((char *) session->remote.banner)); \
++ \
++ _libssh2_htonu32(exchange_state->h_sig_comp, \
++ session->local.kexinit_len); \
++ libssh2_sha##digest_type##_update(ctx, \
++ exchange_state->h_sig_comp, 4); \
++ libssh2_sha##digest_type##_update(ctx, \
++ session->local.kexinit, \
++ session->local.kexinit_len); \
++ \
++ _libssh2_htonu32(exchange_state->h_sig_comp, \
++ session->remote.kexinit_len); \
++ libssh2_sha##digest_type##_update(ctx, \
++ exchange_state->h_sig_comp, 4); \
++ libssh2_sha##digest_type##_update(ctx, \
++ session->remote.kexinit, \
++ session->remote.kexinit_len); \
++ \
++ _libssh2_htonu32(exchange_state->h_sig_comp, \
++ session->server_hostkey_len); \
++ libssh2_sha##digest_type##_update(ctx, \
++ exchange_state->h_sig_comp, 4); \
++ libssh2_sha##digest_type##_update(ctx, \
++ session->server_hostkey, \
++ session->server_hostkey_len); \
++ \
++ _libssh2_htonu32(exchange_state->h_sig_comp, \
++ public_key_len); \
++ libssh2_sha##digest_type##_update(ctx, \
++ exchange_state->h_sig_comp, 4); \
++ libssh2_sha##digest_type##_update(ctx, \
++ public_key, \
++ public_key_len); \
++ \
++ _libssh2_htonu32(exchange_state->h_sig_comp, \
++ server_public_key_len); \
++ libssh2_sha##digest_type##_update(ctx, \
++ exchange_state->h_sig_comp, 4); \
++ libssh2_sha##digest_type##_update(ctx, \
++ server_public_key, \
++ server_public_key_len); \
++ \
++ libssh2_sha##digest_type##_update(ctx, \
++ exchange_state->k_value, \
++ exchange_state->k_value_len); \
++ \
++ libssh2_sha##digest_type##_final(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, \
++ SHA##digest_type##_DIGEST_LENGTH, &session->server_hostkey_abstract)) { \
++ rc = -1; \
++ } \
++ } \
++
++
++/* ecdh_sha2_nistp
++ * Elliptic Curve Diffie Hellman Key Exchange
++ */
++
++static int ecdh_sha2_nistp(LIBSSH2_SESSION *session, libssh2_curve_type type,
++ unsigned char *data, size_t data_len, unsigned char *public_key,
++ size_t public_key_len, _libssh2_ec_key *private_key,
++ kmdhgGPshakex_state_t *exchange_state)
++{
++ int ret = 0;
++ int rc;
++
++ if (exchange_state->state == libssh2_NB_state_idle) {
++
++ /* Setup initial values */
++ exchange_state->k = _libssh2_bn_init();
++
++ exchange_state->state = libssh2_NB_state_created;
++ }
++
++ if ( exchange_state->state == libssh2_NB_state_created )
++ {
++ /* parse INIT reply data */
++
++ /* 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;
++
++ 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, s, session->server_hostkey_len);
++ 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);
*** DIFF OUTPUT TRUNCATED AT 1000 LINES ***
More information about the svn-ports-head
mailing list