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>