Skip site navigation (1)Skip section navigation (2)
Date:      Thu, 31 Jan 2019 00:08:47 +0000 (UTC)
From:      Jung-uk Kim <jkim@FreeBSD.org>
To:        ports-committers@freebsd.org, svn-ports-all@freebsd.org, svn-ports-head@freebsd.org
Subject:   svn commit: r491663 - in head/security/libssh2: . files
Message-ID:  <201901310008.x0V08l5E069579@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
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@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 ***



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201901310008.x0V08l5E069579>