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)
This commit is contained in:
Jung-uk Kim 2019-01-31 00:08:46 +00:00
parent cffa68613d
commit 0b987dd74d
Notes: svn2git 2021-03-31 03:12:20 +00:00
svn path=/head/; revision=491663
15 changed files with 2775 additions and 0 deletions

View file

@ -3,6 +3,7 @@
PORTNAME= libssh2
PORTVERSION= 1.8.0
PORTREVISION= 1
PORTEPOCH= 3
CATEGORIES= security devel
MASTER_SITES= http://www.libssh2.org/download/ \

View file

@ -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,

View file

@ -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,

View file

@ -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;
}
-

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,34 @@
--- src/knownhost.c.orig 2015-03-19 13:01:33 UTC
+++ src/knownhost.c
@@ -777,6 +777,12 @@ static int hostline(LIBSSH2_KNOWNHOSTS *
key_type = LIBSSH2_KNOWNHOST_KEY_SSHDSS;
else if (!strncmp(key_type_name, "ssh-rsa", key_type_len))
key_type = LIBSSH2_KNOWNHOST_KEY_SSHRSA;
+ else if (!strncmp(key_type_name, "ecdsa-sha2-nistp256", key_type_len))
+ key_type = LIBSSH2_KNOWNHOST_KEY_ECDSA_256;
+ else if (!strncmp(key_type_name, "ecdsa-sha2-nistp384", key_type_len))
+ key_type = LIBSSH2_KNOWNHOST_KEY_ECDSA_384;
+ else if (!strncmp(key_type_name, "ecdsa-sha2-nistp521", key_type_len))
+ key_type = LIBSSH2_KNOWNHOST_KEY_ECDSA_521;
else
key_type = LIBSSH2_KNOWNHOST_KEY_UNKNOWN;
@@ -1016,6 +1022,18 @@ knownhost_writeline(LIBSSH2_KNOWNHOSTS *
key_type_name = "ssh-dss";
key_type_len = 7;
break;
+ case LIBSSH2_KNOWNHOST_KEY_ECDSA_256:
+ key_type_name = "ecdsa-sha2-nistp256";
+ key_type_len = 19;
+ break;
+ case LIBSSH2_KNOWNHOST_KEY_ECDSA_384:
+ key_type_name = "ecdsa-sha2-nistp384";
+ key_type_len = 19;
+ break;
+ case LIBSSH2_KNOWNHOST_KEY_ECDSA_521:
+ key_type_name = "ecdsa-sha2-nistp521";
+ key_type_len = 19;
+ break;
case LIBSSH2_KNOWNHOST_KEY_UNKNOWN:
key_type_name = node->key_type_name;
if (key_type_name) {

View file

@ -0,0 +1,59 @@
--- src/libgcrypt.h.orig 2016-01-18 12:41:58 UTC
+++ src/libgcrypt.h
@@ -54,10 +54,15 @@
#define LIBSSH2_RSA 1
#define LIBSSH2_DSA 1
+#define LIBSSH2_ECDSA 0
#define MD5_DIGEST_LENGTH 16
#define SHA_DIGEST_LENGTH 20
#define SHA256_DIGEST_LENGTH 32
+#define SHA384_DIGEST_LENGTH 48
+#define SHA512_DIGEST_LENGTH 64
+
+#define EC_MAX_POINT_LEN ((528 * 2 / 8) + 1)
#define _libssh2_random(buf, len) \
(gcry_randomize ((buf), (len), GCRY_STRONG_RANDOM), 1)
@@ -87,6 +92,28 @@
#define libssh2_sha256(message, len, out) \
gcry_md_hash_buffer (GCRY_MD_SHA256, out, message, len)
+#define libssh2_sha384_ctx gcry_md_hd_t
+
+#define libssh2_sha384_init(ctx) \
+ (GPG_ERR_NO_ERROR == gcry_md_open (ctx, GCRY_MD_SHA384, 0))
+#define libssh2_sha384_update(ctx, data, len) \
+ gcry_md_write (ctx, (unsigned char *) data, len)
+#define libssh2_sha384_final(ctx, out) \
+ memcpy (out, gcry_md_read (ctx, 0), SHA384_DIGEST_LENGTH), gcry_md_close (ctx)
+#define libssh2_sha384(message, len, out) \
+ gcry_md_hash_buffer (GCRY_MD_SHA384, out, message, len)
+
+#define libssh2_sha512_ctx gcry_md_hd_t
+
+#define libssh2_sha512_init(ctx) \
+ (GPG_ERR_NO_ERROR == gcry_md_open (ctx, GCRY_MD_SHA512, 0))
+#define libssh2_sha512_update(ctx, data, len) \
+ gcry_md_write (ctx, (unsigned char *) data, len)
+#define libssh2_sha512_final(ctx, out) \
+ memcpy (out, gcry_md_read (ctx, 0), SHA512_DIGEST_LENGTH), gcry_md_close (ctx)
+#define libssh2_sha512(message, len, out) \
+ gcry_md_hash_buffer (GCRY_MD_SHA512, out, message, len)
+
#define libssh2_md5_ctx gcry_md_hd_t
/* returns 0 in case of failure */
@@ -135,6 +162,11 @@
#define _libssh2_dsa_free(dsactx) gcry_sexp_release (dsactx)
+#if LIBSSH2_ECDSA
+#else
+#define _libssh2_ec_key void
+#endif
+
#define _libssh2_cipher_type(name) int name
#define _libssh2_cipher_ctx gcry_cipher_hd_t

View file

@ -0,0 +1,47 @@
--- src/libssh2_priv.h.orig 2016-02-24 22:44:12 UTC
+++ src/libssh2_priv.h
@@ -154,7 +154,7 @@ static inline int writev(int sock, struc
* padding length, payload, padding, and MAC.)."
*/
#define MAX_SSH_PACKET_LEN 35000
-#define MAX_SHA_DIGEST_LEN SHA256_DIGEST_LENGTH
+#define MAX_SHA_DIGEST_LEN SHA512_DIGEST_LENGTH
#define LIBSSH2_ALLOC(session, count) \
session->alloc((count), &(session)->abstract)
@@ -271,10 +271,13 @@ typedef struct key_exchange_state_low_t
kmdhgGPshakex_state_t exchange_state;
_libssh2_bn *p; /* SSH2 defined value (p_value) */
_libssh2_bn *g; /* SSH2 defined value (2) */
- unsigned char request[13];
+ unsigned char request[256]; /* Must fit EC_MAX_POINT_LEN + data */
unsigned char *data;
size_t request_len;
size_t data_len;
+ _libssh2_ec_key *private_key; /* SSH2 ecdh private key */
+ unsigned char *public_key_oct; /* SSH2 ecdh public key octal value */
+ size_t public_key_oct_len; /* SSH2 ecdh public key octal value length */
} key_exchange_state_low_t;
typedef struct key_exchange_state_t
@@ -609,6 +612,9 @@ struct _LIBSSH2_SESSION
unsigned char server_hostkey_sha1[SHA_DIGEST_LENGTH];
int server_hostkey_sha1_valid;
+ unsigned char server_hostkey_sha256[SHA256_DIGEST_LENGTH];
+ int server_hostkey_sha256_valid;
+
/* (remote as source of data -- packet_read ) */
libssh2_endpoint_data remote;
@@ -983,6 +989,10 @@ _libssh2_debug(LIBSSH2_SESSION * session
#define SSH_MSG_KEX_DH_GEX_INIT 32
#define SSH_MSG_KEX_DH_GEX_REPLY 33
+/* ecdh */
+#define SSH2_MSG_KEX_ECDH_INIT 30
+#define SSH2_MSG_KEX_ECDH_REPLY 31
+
/* User Authentication */
#define SSH_MSG_USERAUTH_REQUEST 50
#define SSH_MSG_USERAUTH_FAILURE 51

View file

@ -0,0 +1,57 @@
--- src/mbedtls.h.orig 2016-09-27 06:06:29 UTC
+++ src/mbedtls.h
@@ -27,12 +27,21 @@
#define LIBSSH2_RSA 1
#define LIBSSH2_DSA 0
+#define LIBSSH2_ECDSA 0
#define MD5_DIGEST_LENGTH 16
#define SHA_DIGEST_LENGTH 20
#define SHA256_DIGEST_LENGTH 32
+#define SHA384_DIGEST_LENGTH 48
#define SHA512_DIGEST_LENGTH 64
+#define EC_MAX_POINT_LEN ((528 * 2 / 8) + 1)
+
+#if LIBSSH2_ECDSA
+#else
+#define _libssh2_ec_key void
+#endif
+
/*******************************************************************/
/*
* mbedTLS backend: Global context handles
@@ -80,6 +89,8 @@ mbedtls_ctr_drbg_context _libssh2_mbedtl
_libssh2_mbedtls_hash_init(pctx, MBEDTLS_MD_RIPEMD160, key, keylen)
#define libssh2_hmac_sha256_init(pctx, key, keylen) \
_libssh2_mbedtls_hash_init(pctx, MBEDTLS_MD_SHA256, key, keylen)
+#define libssh2_hmac_sha384_init(pctx, key, keylen) \
+ _libssh2_mbedtls_hash_init(pctx, MBEDTLS_MD_SHA384, key, keylen)
#define libssh2_hmac_sha512_init(pctx, key, keylen) \
_libssh2_mbedtls_hash_init(pctx, MBEDTLS_MD_SHA512, key, keylen)
@@ -119,6 +130,23 @@ mbedtls_ctr_drbg_context _libssh2_mbedtl
/*******************************************************************/
/*
+ * mbedTLS backend: SHA384 functions
+ */
+
+#define libssh2_sha384_ctx mbedtls_md_context_t
+
+#define libssh2_sha384_init(pctx) \
+ _libssh2_mbedtls_hash_init(pctx, MBEDTLS_MD_SHA384, NULL, 0)
+#define libssh2_sha384_update(ctx, data, datalen) \
+ mbedtls_md_update(&ctx, (unsigned char *) data, datalen)
+#define libssh2_sha384_final(ctx, hash) \
+ _libssh2_mbedtls_hash_final(&ctx, hash)
+#define libssh2_sha384(data, datalen, hash) \
+ _libssh2_mbedtls_hash(data, datalen, MBEDTLS_MD_SHA384, hash)
+
+
+/*******************************************************************/
+/*
* mbedTLS backend: SHA512 functions
*/

View file

@ -0,0 +1,727 @@
--- src/openssl.c.orig 2016-10-22 14:16:47 UTC
+++ src/openssl.c
@@ -48,6 +48,24 @@
#define EVP_MAX_BLOCK_LENGTH 32
#endif
+static unsigned char *
+write_bn(unsigned char *buf, const BIGNUM *bn, int bn_bytes)
+{
+ unsigned char *p = buf;
+
+ /* Left space for bn size which will be written below. */
+ p += 4;
+
+ *p = 0;
+ BN_bn2bin(bn, p + 1);
+ if (!(*(p + 1) & 0x80)) {
+ memmove(p, p + 1, --bn_bytes);
+ }
+ _libssh2_htonu32(p - 4, bn_bytes); /* Post write bn size. */
+
+ return p + bn_bytes;
+}
+
int
_libssh2_rsa_new(libssh2_rsa_ctx ** rsa,
const unsigned char *edata,
@@ -230,6 +248,144 @@ _libssh2_dsa_sha1_verify(libssh2_dsa_ctx
}
#endif /* LIBSSH_DSA */
+#if LIBSSH2_ECDSA
+
+/* _libssh2_ecdsa_key_get_curve_type
+ *
+ * returns key curve type that maps to libssh2_curve_type
+ *
+ */
+
+libssh2_curve_type
+_libssh2_ecdsa_key_get_curve_type(_libssh2_ec_key *key)
+{
+ const EC_GROUP *group = EC_KEY_get0_group(key);
+ return EC_GROUP_get_curve_name(group);
+}
+
+/* _libssh2_ecdsa_curve_type_from_name
+ *
+ * returns 0 for success, key curve type that maps to libssh2_curve_type
+ *
+ */
+
+int
+_libssh2_ecdsa_curve_type_from_name(const char *name, libssh2_curve_type *out_type)
+{
+ int ret = 0;
+ libssh2_curve_type type;
+
+ if ( name == NULL || strlen(name) != 19 )
+ return -1;
+
+ if ( strcmp(name, "ecdsa-sha2-nistp256") == 0)
+ type = LIBSSH2_EC_CURVE_NISTP256;
+ else if ( strcmp(name, "ecdsa-sha2-nistp384") == 0)
+ type = LIBSSH2_EC_CURVE_NISTP384;
+ else if ( strcmp(name, "ecdsa-sha2-nistp521") == 0)
+ type = LIBSSH2_EC_CURVE_NISTP521;
+ else {
+ ret = -1;
+ }
+
+ if (ret == 0 && out_type) {
+ *out_type = type;
+ }
+
+ return ret;
+}
+
+/* _libssh2_ecdsa_curve_name_with_octal_new
+ *
+ * Creates a new public key given an octal string, length and type
+ *
+ */
+
+int
+_libssh2_ecdsa_curve_name_with_octal_new(libssh2_ecdsa_ctx ** ec_ctx,
+ const unsigned char *k,
+ size_t k_len, libssh2_curve_type curve)
+{
+
+ int ret = 0;
+ const EC_GROUP *ec_group = NULL;
+ EC_KEY *ec_key = EC_KEY_new_by_curve_name(curve);
+ EC_POINT *point = NULL;
+
+ if ( ec_key ) {
+ ec_group = EC_KEY_get0_group(ec_key);
+ point = EC_POINT_new(ec_group);
+ ret = EC_POINT_oct2point(ec_group, point, k, k_len, NULL);
+ ret = EC_KEY_set_public_key(ec_key, point);
+
+ if (point != NULL)
+ EC_POINT_free(point);
+
+ if ( ec_ctx != NULL )
+ *ec_ctx = ec_key;
+ }
+
+ return (ret == 1) ? 0 : -1;
+}
+
+#define LIBSSH2_ECDSA_VERIFY(digest_type) \
+{ \
+ unsigned char hash[SHA##digest_type##_DIGEST_LENGTH]; \
+ libssh2_sha##digest_type(m, m_len, hash); \
+ ret = ECDSA_do_verify(hash, SHA##digest_type##_DIGEST_LENGTH, \
+ ecdsa_sig, ec_key); \
+ \
+}
+
+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 ret = 0;
+ EC_KEY *ec_key = (EC_KEY*)ctx;
+ libssh2_curve_type type = _libssh2_ecdsa_key_get_curve_type(ec_key);
+
+#if HAVE_OPAQUE_STRUCTS
+ ECDSA_SIG *ecdsa_sig = ECDSA_SIG_new();
+ BIGNUM *pr = BN_new();
+ BIGNUM *ps = BN_new();
+
+ BN_bin2bn(r, r_len, pr);
+ BN_bin2bn(s, s_len, ps);
+ ECDSA_SIG_set0(ecdsa_sig, pr, ps);
+
+#else
+ ECDSA_SIG ecdsa_sig_;
+ ECDSA_SIG *ecdsa_sig = &ecdsa_sig_;
+ ecdsa_sig_.r = BN_new();
+ BN_bin2bn(r, r_len, ecdsa_sig_.r);
+ ecdsa_sig_.s = BN_new();
+ BN_bin2bn(s, s_len, ecdsa_sig_.s);
+#endif
+
+ if ( type == LIBSSH2_EC_CURVE_NISTP256 ) {
+ LIBSSH2_ECDSA_VERIFY(256);
+ }else if ( type == LIBSSH2_EC_CURVE_NISTP384 ) {
+ LIBSSH2_ECDSA_VERIFY(384);
+ }else if ( type == LIBSSH2_EC_CURVE_NISTP521 ) {
+ LIBSSH2_ECDSA_VERIFY(512);
+ }
+
+#if HAVE_OPAQUE_STRUCTS
+ if ( ecdsa_sig )
+ ECDSA_SIG_free(ecdsa_sig);
+#else
+ BN_clear_free(ecdsa_sig_.s);
+ BN_clear_free(ecdsa_sig_.r);
+#endif
+
+ return (ret == 1) ? 0 : -1;
+}
+
+#endif /* LIBSSH2_ECDSA */
+
int
_libssh2_cipher_init(_libssh2_cipher_ctx * h,
_libssh2_cipher_type(algo),
@@ -606,6 +762,41 @@ _libssh2_dsa_new_private(libssh2_dsa_ctx
}
#endif /* LIBSSH_DSA */
+#if LIBSSH2_ECDSA
+
+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)
+{
+ pem_read_bio_func read_ec =
+ (pem_read_bio_func) &PEM_read_bio_ECPrivateKey;
+ (void) session;
+
+ _libssh2_init_if_needed();
+
+ return read_private_key_from_memory((void **) ec_ctx, read_ec,
+ filedata, filedata_len, passphrase);
+}
+
+int
+_libssh2_ecdsa_new_private(libssh2_ecdsa_ctx ** ec_ctx,
+ LIBSSH2_SESSION * session,
+ const char *filename, unsigned const char *passphrase)
+{
+ pem_read_bio_func read_ec = (pem_read_bio_func) &PEM_read_bio_ECPrivateKey;
+ (void) session;
+
+ _libssh2_init_if_needed ();
+
+ return read_private_key_from_file((void **) ec_ctx, read_ec,
+ filename, passphrase);
+}
+
+#endif /* LIBSSH2_ECDSA */
+
+
int
_libssh2_rsa_sha1_sign(LIBSSH2_SESSION * session,
libssh2_rsa_ctx * rsactx,
@@ -682,6 +873,69 @@ _libssh2_dsa_sha1_sign(libssh2_dsa_ctx *
}
#endif /* LIBSSH_DSA */
+#if LIBSSH2_ECDSA
+
+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 r_len, s_len;
+ int rc = 0;
+ size_t out_buffer_len = 0;
+ unsigned char *sp;
+ const BIGNUM *pr = NULL, *ps = NULL;
+ unsigned char *temp_buffer = NULL;
+ unsigned char *out_buffer = NULL;
+
+ ECDSA_SIG *sig = ECDSA_do_sign(hash, hash_len, ec_ctx);
+ if ( sig == NULL )
+ return -1;
+#if HAVE_OPAQUE_STRUCTS
+ ECDSA_SIG_get0(sig, &pr, &ps);
+#else
+ pr = sig->r;
+ ps = sig->s;
+#endif
+
+ r_len = BN_num_bytes(pr) + 1;
+ s_len = BN_num_bytes(ps) + 1;
+
+ temp_buffer = malloc(r_len + s_len + 8);
+ if ( temp_buffer == NULL ) {
+ rc = -1;
+ goto clean_exit;
+ }
+
+ sp = temp_buffer;
+ sp = write_bn(sp, pr, r_len);
+ sp = write_bn(sp, ps, s_len);
+
+ out_buffer_len = (size_t)(sp - temp_buffer);
+
+ out_buffer = LIBSSH2_CALLOC(session, out_buffer_len);
+ if ( out_buffer == NULL ) {
+ rc = -1;
+ goto clean_exit;
+ }
+
+ memcpy(out_buffer, temp_buffer, out_buffer_len);
+
+ *signature = out_buffer;
+ *signature_len = out_buffer_len;
+
+clean_exit:
+
+ if ( temp_buffer != NULL )
+ free(temp_buffer);
+
+ if ( sig )
+ ECDSA_SIG_free(sig);
+
+ return rc;
+}
+#endif /* LIBSSH2_ECDSA */
+
int
_libssh2_sha1_init(libssh2_sha1_ctx *ctx)
{
@@ -787,7 +1041,7 @@ _libssh2_sha256(const unsigned char *mes
}
int
-_libssh2_md5_init(libssh2_md5_ctx *ctx)
+_libssh2_sha384_init(libssh2_sha384_ctx *ctx)
{
#ifdef HAVE_OPAQUE_STRUCTS
*ctx = EVP_MD_CTX_new();
@@ -795,7 +1049,7 @@ _libssh2_md5_init(libssh2_md5_ctx *ctx)
if (*ctx == NULL)
return 0;
- if (EVP_DigestInit(*ctx, EVP_get_digestbyname("md5")))
+ if (EVP_DigestInit(*ctx, EVP_get_digestbyname("sha384")))
return 1;
EVP_MD_CTX_free(*ctx);
@@ -804,26 +1058,112 @@ _libssh2_md5_init(libssh2_md5_ctx *ctx)
return 0;
#else
EVP_MD_CTX_init(ctx);
- return EVP_DigestInit(ctx, EVP_get_digestbyname("md5"));
+ return EVP_DigestInit(ctx, EVP_get_digestbyname("sha384"));
#endif
}
-static unsigned char *
-write_bn(unsigned char *buf, const BIGNUM *bn, int bn_bytes)
+int
+_libssh2_sha384(const unsigned char *message, unsigned long len,
+ unsigned char *out)
{
- unsigned char *p = buf;
+#ifdef HAVE_OPAQUE_STRUCTS
+ EVP_MD_CTX * ctx = EVP_MD_CTX_new();
- /* Left space for bn size which will be written below. */
- p += 4;
+ if (ctx == NULL)
+ return 1; /* error */
- *p = 0;
- BN_bn2bin(bn, p + 1);
- if (!(*(p + 1) & 0x80)) {
- memmove(p, p + 1, --bn_bytes);
+ if(EVP_DigestInit(ctx, EVP_get_digestbyname("sha384"))) {
+ EVP_DigestUpdate(ctx, message, len);
+ EVP_DigestFinal(ctx, out, NULL);
+ EVP_MD_CTX_free(ctx);
+ return 0; /* success */
}
- _libssh2_htonu32(p - 4, bn_bytes); /* Post write bn size. */
+ EVP_MD_CTX_free(ctx);
+#else
+ EVP_MD_CTX ctx;
- return p + bn_bytes;
+ EVP_MD_CTX_init(&ctx);
+ if(EVP_DigestInit(&ctx, EVP_get_digestbyname("sha384"))) {
+ EVP_DigestUpdate(&ctx, message, len);
+ EVP_DigestFinal(&ctx, out, NULL);
+ return 0; /* success */
+ }
+#endif
+ return 1; /* error */
+}
+
+int
+_libssh2_sha512_init(libssh2_sha512_ctx *ctx)
+{
+#ifdef HAVE_OPAQUE_STRUCTS
+ *ctx = EVP_MD_CTX_new();
+
+ if (*ctx == NULL)
+ return 0;
+
+ if (EVP_DigestInit(*ctx, EVP_get_digestbyname("sha512")))
+ return 1;
+
+ EVP_MD_CTX_free(*ctx);
+ *ctx = NULL;
+
+ return 0;
+#else
+ EVP_MD_CTX_init(ctx);
+ return EVP_DigestInit(ctx, EVP_get_digestbyname("sha512"));
+#endif
+}
+
+int
+_libssh2_sha512(const unsigned char *message, unsigned long len,
+ unsigned char *out)
+{
+#ifdef HAVE_OPAQUE_STRUCTS
+ EVP_MD_CTX * ctx = EVP_MD_CTX_new();
+
+ if (ctx == NULL)
+ return 1; /* error */
+
+ if(EVP_DigestInit(ctx, EVP_get_digestbyname("sha512"))) {
+ EVP_DigestUpdate(ctx, message, len);
+ EVP_DigestFinal(ctx, out, NULL);
+ EVP_MD_CTX_free(ctx);
+ return 0; /* success */
+ }
+ EVP_MD_CTX_free(ctx);
+#else
+ EVP_MD_CTX ctx;
+
+ EVP_MD_CTX_init(&ctx);
+ if(EVP_DigestInit(&ctx, EVP_get_digestbyname("sha512"))) {
+ EVP_DigestUpdate(&ctx, message, len);
+ EVP_DigestFinal(&ctx, out, NULL);
+ return 0; /* success */
+ }
+#endif
+ return 1; /* error */
+}
+
+int
+_libssh2_md5_init(libssh2_md5_ctx *ctx)
+{
+#ifdef HAVE_OPAQUE_STRUCTS
+ *ctx = EVP_MD_CTX_new();
+
+ if (*ctx == NULL)
+ return 0;
+
+ if (EVP_DigestInit(*ctx, EVP_get_digestbyname("md5")))
+ return 1;
+
+ EVP_MD_CTX_free(*ctx);
+ *ctx = NULL;
+
+ return 0;
+#else
+ EVP_MD_CTX_init(ctx);
+ return EVP_DigestInit(ctx, EVP_get_digestbyname("md5"));
+#endif
}
static unsigned char *
@@ -1036,6 +1376,272 @@ gen_publickey_from_dsa_evp(LIBSSH2_SESSI
}
#endif /* LIBSSH_DSA */
+#if LIBSSH2_ECDSA
+
+static int
+gen_publickey_from_ec_evp(LIBSSH2_SESSION *session,
+ unsigned char **method,
+ size_t *method_len,
+ unsigned char **pubkeydata,
+ size_t *pubkeydata_len,
+ EVP_PKEY *pk)
+{
+ int rc = 0;
+ EC_KEY *ec = NULL;
+ unsigned char *p;
+ unsigned char* method_buf = NULL;
+ unsigned char *key;
+ size_t key_len = 0;
+ unsigned char *octal_value = NULL;
+ size_t octal_len;
+ const EC_POINT *public_key;
+ const EC_GROUP *group;
+ BN_CTX *bn_ctx;
+ libssh2_curve_type type;
+
+ _libssh2_debug(session,
+ LIBSSH2_TRACE_AUTH,
+ "Computing public key from EC private key envelop");
+
+ bn_ctx = BN_CTX_new();
+ if ( bn_ctx == NULL )
+ return -1;
+
+ ec = EVP_PKEY_get1_EC_KEY(pk);
+ if ( ec == NULL ) {
+ rc = -1;
+ goto clean_exit;
+ }
+
+ public_key = EC_KEY_get0_public_key(ec);
+ group = EC_KEY_get0_group(ec);
+ type = _libssh2_ecdsa_key_get_curve_type(ec);
+
+ method_buf = LIBSSH2_ALLOC(session, 19);
+ if (method_buf == NULL) {
+ return _libssh2_error(session, LIBSSH2_ERROR_ALLOC,
+ "out of memory");
+ }
+
+ if ( type == LIBSSH2_EC_CURVE_NISTP256 )
+ memcpy(method_buf, "ecdsa-sha2-nistp256", 19);
+ else if ( type == LIBSSH2_EC_CURVE_NISTP384 )
+ memcpy(method_buf, "ecdsa-sha2-nistp384", 19);
+ else if ( type == LIBSSH2_EC_CURVE_NISTP521 )
+ memcpy(method_buf, "ecdsa-sha2-nistp521", 19);
+ else {
+ _libssh2_debug(session,
+ LIBSSH2_TRACE_ERROR,
+ "Unsupported EC private key type");
+ rc = -1;
+ goto clean_exit;
+ }
+
+ /* get length */
+ octal_len = EC_POINT_point2oct(group, public_key, POINT_CONVERSION_UNCOMPRESSED, NULL, 0, bn_ctx);
+ if (octal_len > EC_MAX_POINT_LEN) {
+ rc = -1;
+ goto clean_exit;
+ }
+
+ octal_value = malloc(octal_len);
+ if ( octal_value == NULL ) {
+ rc = -1;
+ goto clean_exit;
+ }
+
+ /* convert to octal */
+ if (EC_POINT_point2oct(group, public_key, POINT_CONVERSION_UNCOMPRESSED,
+ octal_value, octal_len, bn_ctx) != octal_len) {
+ rc = -1;
+ goto clean_exit;
+ }
+
+ /* Key form is: type_len(4) + type(19) + domain_len(4) + domain(8) + pub_key_len(4) + pub_key(~65). */
+ key_len = 4 + 19 + 4 + 8 + 4 + octal_len;
+ key = LIBSSH2_ALLOC(session, key_len);
+ if (key == NULL) {
+ rc = -1;
+ goto clean_exit;
+ }
+
+ /* Process key encoding. */
+ p = key;
+
+ /* Key type */
+ _libssh2_store_str(&p, (const char*)method_buf, 19);
+
+ /* Name domain */
+ _libssh2_store_str(&p, (const char*)method_buf + 11, 8);
+
+ /* Public key */
+ _libssh2_store_str(&p, (const char*)octal_value, octal_len);
+
+ *method = method_buf;
+ *method_len = 19;
+ *pubkeydata = key;
+ *pubkeydata_len = key_len;
+
+clean_exit:
+
+ if ( ec != NULL)
+ EC_KEY_free(ec);
+
+ if (bn_ctx != NULL) {
+ BN_CTX_free(bn_ctx);
+ }
+
+ if ( octal_value != NULL )
+ free(octal_value);
+
+ if ( rc == 0 )
+ return 0;
+
+ if (method_buf != NULL )
+ LIBSSH2_FREE(session, method_buf);
+
+ return -1;
+}
+
+/*
+ * _libssh2_ecdsa_create_key
+ *
+ * Creates a local private key based on input curve
+ * and returns octal value and octal length
+ *
+ */
+
+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 ret = 1;
+ size_t octal_len = 0;
+ unsigned char octal_value[EC_MAX_POINT_LEN];
+ const EC_POINT *public_key = NULL;
+ EC_KEY *private_key = NULL;
+ const EC_GROUP *group = NULL;
+
+ /* create key */
+ BN_CTX *bn_ctx = BN_CTX_new();
+ if (!bn_ctx)
+ return -1;
+
+ private_key = EC_KEY_new_by_curve_name(curve_type);
+ group = EC_KEY_get0_group(private_key);
+
+ EC_KEY_generate_key(private_key);
+ public_key = EC_KEY_get0_public_key(private_key);
+
+ /* get length */
+ octal_len = EC_POINT_point2oct(group, public_key, POINT_CONVERSION_UNCOMPRESSED, NULL, 0, bn_ctx);
+ if (octal_len > EC_MAX_POINT_LEN) {
+ ret = -1;
+ goto clean_exit;
+ }
+
+ /* convert to octal */
+ if (EC_POINT_point2oct(group, public_key, POINT_CONVERSION_UNCOMPRESSED,
+ octal_value, octal_len, bn_ctx) != octal_len){
+ ret = -1;
+ goto clean_exit;
+ }
+
+ if (out_private_key != NULL)
+ *out_private_key = private_key;
+
+ if (out_public_key_octal) {
+ *out_public_key_octal = malloc(octal_len);
+ if (out_public_key_octal == NULL) {
+ ret = -1;
+ goto clean_exit;
+ }
+
+ memcpy(*out_public_key_octal, octal_value, octal_len);
+ }
+
+ if (out_public_key_octal_len != NULL)
+ *out_public_key_octal_len = octal_len;
+
+clean_exit:
+
+ if (bn_ctx)
+ BN_CTX_free(bn_ctx);
+
+ return (ret == 1) ? 0 : -1;
+}
+
+/* _libssh2_ecdh_gen_k
+ *
+ * Computes the shared secret K given a local private key,
+ * remote public key and length
+ */
+
+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 ret = 0;
+ int rc;
+ size_t secret_len;
+ unsigned char *secret;
+ const EC_GROUP *private_key_group;
+ EC_POINT *server_public_key_point;
+
+ BN_CTX *bn_ctx = BN_CTX_new();
+
+ if ( !bn_ctx )
+ return -1;
+
+ if ( k == NULL )
+ return -1;
+
+ private_key_group = EC_KEY_get0_group(private_key);
+
+ server_public_key_point = EC_POINT_new(private_key_group);
+ if ( server_public_key_point == NULL )
+ return -1;
+
+ rc = EC_POINT_oct2point(private_key_group, server_public_key_point, server_public_key, server_public_key_len, bn_ctx);
+ if ( rc != 1 ) {
+ ret = -1;
+ goto clean_exit;
+ }
+
+ secret_len = (EC_GROUP_get_degree(private_key_group) + 7) / 8;
+ secret = malloc(secret_len);
+ if (!secret) {
+ ret = -1;
+ goto clean_exit;
+ }
+
+ secret_len = ECDH_compute_key(secret, secret_len, server_public_key_point, private_key, NULL);
+
+ if( secret_len <= 0 || secret_len > EC_MAX_POINT_LEN ) {
+ ret = -1;
+ goto clean_exit;
+ }
+
+ BN_bin2bn(secret, secret_len, *k);
+
+clean_exit:
+
+ if ( server_public_key_point != NULL )
+ EC_POINT_free(server_public_key_point);
+
+ if ( bn_ctx != NULL )
+ BN_CTX_free(bn_ctx);
+
+ if ( secret != NULL )
+ free(secret);
+
+ return ret;
+}
+
+
+#endif /* LIBSSH2_ECDSA */
+
int
_libssh2_pub_priv_keyfile(LIBSSH2_SESSION *session,
unsigned char **method,
@@ -1102,6 +1708,13 @@ _libssh2_pub_priv_keyfile(LIBSSH2_SESSIO
break;
#endif /* LIBSSH_DSA */
+#if LIBSSH2_ECDSA
+ case EVP_PKEY_EC :
+ st = gen_publickey_from_ec_evp(
+ session, method, method_len, pubkeydata, pubkeydata_len, pk);
+ break;
+#endif
+
default :
st = _libssh2_error(session,
LIBSSH2_ERROR_FILE,
@@ -1176,6 +1789,12 @@ _libssh2_pub_priv_keyfilememory(LIBSSH2_
pubkeydata, pubkeydata_len, pk);
break;
#endif /* LIBSSH_DSA */
+#if LIBSSH2_ECDSA
+ case EVP_PKEY_EC :
+ st = gen_publickey_from_ec_evp(session, method, method_len,
+ pubkeydata, pubkeydata_len, pk);
+ break;
+#endif
default :
st = _libssh2_error(session,
LIBSSH2_ERROR_FILE,

View file

@ -0,0 +1,107 @@
--- src/openssl.h.orig 2016-02-17 21:59:57 UTC
+++ src/openssl.h
@@ -70,6 +70,12 @@
# define LIBSSH2_DSA 1
#endif
+#ifdef OPENSSL_NO_ECDSA
+# define LIBSSH2_ECDSA 0
+#else
+# define LIBSSH2_ECDSA 1
+#endif
+
#ifdef OPENSSL_NO_MD5
# define LIBSSH2_MD5 0
#else
@@ -117,6 +123,8 @@
# define LIBSSH2_3DES 1
#endif
+#define EC_MAX_POINT_LEN ((528 * 2 / 8) + 1)
+
#define _libssh2_random(buf, len) RAND_bytes ((buf), (len))
#define libssh2_prepare_iovec(vec, len) /* Empty. */
@@ -168,6 +176,52 @@ int _libssh2_sha256(const unsigned char
#define libssh2_sha256(x,y,z) _libssh2_sha256(x,y,z)
#ifdef HAVE_OPAQUE_STRUCTS
+#define libssh2_sha384_ctx EVP_MD_CTX *
+#else
+#define libssh2_sha384_ctx EVP_MD_CTX
+#endif
+
+/* returns 0 in case of failure */
+int _libssh2_sha384_init(libssh2_sha384_ctx *ctx);
+#define libssh2_sha384_init(x) _libssh2_sha384_init(x)
+#ifdef HAVE_OPAQUE_STRUCTS
+#define libssh2_sha384_update(ctx, data, len) EVP_DigestUpdate(ctx, data, len)
+#define libssh2_sha384_final(ctx, out) do { \
+ EVP_DigestFinal(ctx, out, NULL); \
+ EVP_MD_CTX_free(ctx); \
+ } while(0)
+#else
+#define libssh2_sha384_update(ctx, data, len) EVP_DigestUpdate(&(ctx), data, len)
+#define libssh2_sha384_final(ctx, out) EVP_DigestFinal(&(ctx), out, NULL)
+#endif
+int _libssh2_sha384(const unsigned char *message, unsigned long len,
+ unsigned char *out);
+#define libssh2_sha384(x,y,z) _libssh2_sha384(x,y,z)
+
+#ifdef HAVE_OPAQUE_STRUCTS
+#define libssh2_sha512_ctx EVP_MD_CTX *
+#else
+#define libssh2_sha512_ctx EVP_MD_CTX
+#endif
+
+/* returns 0 in case of failure */
+int _libssh2_sha512_init(libssh2_sha512_ctx *ctx);
+#define libssh2_sha512_init(x) _libssh2_sha512_init(x)
+#ifdef HAVE_OPAQUE_STRUCTS
+#define libssh2_sha512_update(ctx, data, len) EVP_DigestUpdate(ctx, data, len)
+#define libssh2_sha512_final(ctx, out) do { \
+ EVP_DigestFinal(ctx, out, NULL); \
+ EVP_MD_CTX_free(ctx); \
+ } while(0)
+#else
+#define libssh2_sha512_update(ctx, data, len) EVP_DigestUpdate(&(ctx), data, len)
+#define libssh2_sha512_final(ctx, out) EVP_DigestFinal(&(ctx), out, NULL)
+#endif
+int _libssh2_sha512(const unsigned char *message, unsigned long len,
+ unsigned char *out);
+#define libssh2_sha512(x,y,z) _libssh2_sha512(x,y,z)
+
+#ifdef HAVE_OPAQUE_STRUCTS
#define libssh2_md5_ctx EVP_MD_CTX *
#else
#define libssh2_md5_ctx EVP_MD_CTX
@@ -239,9 +293,23 @@ int _libssh2_md5_init(libssh2_md5_ctx *c
#define libssh2_dsa_ctx DSA
-
#define _libssh2_dsa_free(dsactx) DSA_free(dsactx)
+#if LIBSSH2_ECDSA
+#define libssh2_ecdsa_ctx EC_KEY
+#define _libssh2_ecdsa_free(ecdsactx) EC_KEY_free(ecdsactx)
+#define _libssh2_ec_key EC_KEY
+
+typedef enum {
+ LIBSSH2_EC_CURVE_NISTP256 = NID_X9_62_prime256v1,
+ LIBSSH2_EC_CURVE_NISTP384 = NID_secp384r1,
+ LIBSSH2_EC_CURVE_NISTP521 = NID_secp521r1,
+}
+libssh2_curve_type;
+#else
+#define _libssh2_ec_key void
+#endif
+
#define _libssh2_cipher_type(name) const EVP_CIPHER *(*name)(void)
#ifdef HAVE_OPAQUE_STRUCTS
#define _libssh2_cipher_ctx EVP_CIPHER_CTX *
@@ -290,4 +358,3 @@ int _libssh2_md5_init(libssh2_md5_ctx *c
const EVP_CIPHER *_libssh2_EVP_aes_128_ctr(void);
const EVP_CIPHER *_libssh2_EVP_aes_192_ctr(void);
const EVP_CIPHER *_libssh2_EVP_aes_256_ctr(void);
-

View file

@ -0,0 +1,13 @@
--- tests/openssh_server/Dockerfile.orig 2016-08-20 15:37:25 UTC
+++ tests/openssh_server/Dockerfile
@@ -50,6 +50,10 @@ COPY ssh_host_rsa_key /tmp/etc/ssh/ssh_h
RUN mv /tmp/etc/ssh/ssh_host_rsa_key /etc/ssh/ssh_host_rsa_key
RUN chmod 600 /etc/ssh/ssh_host_rsa_key
+COPY ssh_host_ecdsa_key /tmp/etc/ssh/ssh_host_ecdsa_key
+RUN mv /tmp/etc/ssh/ssh_host_ecdsa_key /etc/ssh/ssh_host_ecdsa_key
+RUN chmod 600 /etc/ssh/ssh_host_ecdsa_key
+
RUN adduser --disabled-password --gecos 'Test user for libssh2 integration tests' libssh2
RUN echo 'libssh2:my test password' | chpasswd

View file

@ -0,0 +1,8 @@
--- tests/openssh_server/ssh_host_ecdsa_key.orig 2019-01-29 21:00:05 UTC
+++ tests/openssh_server/ssh_host_ecdsa_key
@@ -0,0 +1,5 @@
+-----BEGIN EC PRIVATE KEY-----
+MHcCAQEEIKdqGrp+52U1ehslMI4fX0cmvgHFmKSkMzQGmj6B07ecoAoGCCqGSM49
+AwEHoUQDQgAEL7+zLJ4okP10LZkf1DuIkZF5HhgzetQIyxLKeTJeiN19IKUYIxjs
+m9aW3fQRKNi/GhN9JEbHpa9qpgr+8+hhDg==
+-----END EC PRIVATE KEY-----

View file

@ -0,0 +1,47 @@
--- tests/test_hostkey.c.orig 2016-08-20 15:37:25 UTC
+++ tests/test_hostkey.c
@@ -4,7 +4,7 @@
#include <stdio.h>
-const char *EXPECTED_HOSTKEY =
+const char *EXPECTED_RSA_HOSTKEY =
"AAAAB3NzaC1yc2EAAAABIwAAAQEArrr/JuJmaZligyfS8vcNur+mWR2ddDQtVdhHzdKU"
"UoR6/Om6cvxpe61H1YZO1xCpLUBXmkki4HoNtYOpPB2W4V+8U4BDeVBD5crypEOE1+7B"
"Am99fnEDxYIOZq2/jTP0yQmzCpWYS3COyFmkOL7sfX1wQMeW5zQT2WKcxC6FSWbhDqrB"
@@ -12,6 +12,10 @@ const char *EXPECTED_HOSTKEY =
"i6ELfP3r+q6wdu0P4jWaoo3De1aYxnToV/ldXykpipON4NPamsb6Ph2qlJQKypq7J4iQ"
"gkIIbCU1A31+4ExvcIVoxLQw/aTSbw==";
+const char *EXPECTED_ECDSA_HOSTKEY =
+ "AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBC+/syyeKJD9dC2ZH"
+ "9Q7iJGReR4YM3rUCMsSynkyXojdfSClGCMY7JvWlt30ESjYvxoTfSRGx6WvaqYK/vPoYQ4=";
+
int test(LIBSSH2_SESSION *session)
{
int rc;
@@ -26,14 +30,19 @@ int test(LIBSSH2_SESSION *session)
return 1;
}
- if (type != LIBSSH2_HOSTKEY_TYPE_RSA) {
- /* Hostkey configured in docker container is RSA */
- fprintf(stderr, "Wrong type of hostkey\n");
+ if(type == LIBSSH2_HOSTKEY_TYPE_ECDSA_256) {
+ rc = libssh2_base64_decode(session, &expected_hostkey, &expected_len,
+ EXPECTED_ECDSA_HOSTKEY, strlen(EXPECTED_ECDSA_HOSTKEY));
+ }
+ else if (type == LIBSSH2_HOSTKEY_TYPE_RSA) {
+ rc = libssh2_base64_decode(session, &expected_hostkey, &expected_len,
+ EXPECTED_RSA_HOSTKEY, strlen(EXPECTED_RSA_HOSTKEY));
+ }
+ else {
+ fprintf(stderr, "Unexpected type of hostkey: %i\n", type);
return 1;
}
- rc = libssh2_base64_decode(session, &expected_hostkey, &expected_len,
- EXPECTED_HOSTKEY, strlen(EXPECTED_HOSTKEY));
if (rc != 0) {
print_last_session_error("libssh2_base64_decode");
return 1;

View file

@ -0,0 +1,173 @@
--- tests/test_hostkey_hash.c.orig 2016-08-20 15:37:25 UTC
+++ tests/test_hostkey_hash.c
@@ -5,7 +5,7 @@
#include <stdio.h>
-const char *EXPECTED_HOSTKEY =
+const char *EXPECTED_RSA_HOSTKEY =
"AAAAB3NzaC1yc2EAAAABIwAAAQEArrr/JuJmaZligyfS8vcNur+mWR2ddDQtVdhHzdKU"
"UoR6/Om6cvxpe61H1YZO1xCpLUBXmkki4HoNtYOpPB2W4V+8U4BDeVBD5crypEOE1+7B"
"Am99fnEDxYIOZq2/jTP0yQmzCpWYS3COyFmkOL7sfX1wQMeW5zQT2WKcxC6FSWbhDqrB"
@@ -13,13 +13,27 @@ const char *EXPECTED_HOSTKEY =
"i6ELfP3r+q6wdu0P4jWaoo3De1aYxnToV/ldXykpipON4NPamsb6Ph2qlJQKypq7J4iQ"
"gkIIbCU1A31+4ExvcIVoxLQw/aTSbw==";
-const char *EXPECTED_MD5_HASH_DIGEST = "0C0ED1A5BB10275F76924CE187CE5C5E";
+const char *EXPECTED_ECDSA_HOSTKEY =
+ "AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBC+/syyeKJD9dC2ZH"
+ "9Q7iJGReR4YM3rUCMsSynkyXojdfSClGCMY7JvWlt30ESjYvxoTfSRGx6WvaqYK/vPoYQ4=";
-const char *EXPECTED_SHA1_HASH_DIGEST =
+const char *EXPECTED_RSA_MD5_HASH_DIGEST = "0C0ED1A5BB10275F76924CE187CE5C5E";
+
+const char *EXPECTED_RSA_SHA1_HASH_DIGEST =
"F3CD59E2913F4422B80F7B0A82B2B89EAE449387";
+const char *EXPECTED_RSA_SHA256_HASH_DIGEST = "92E3DA49DF3C7F99A828F505ED8239397A5D1F62914459760F878F7510F563A3";
+
+const char *EXPECTED_ECDSA_MD5_HASH_DIGEST = "0402E4D897580BBC911379CBD88BCD3D";
+
+const char *EXPECTED_ECDSA_SHA1_HASH_DIGEST =
+ "12FDAD1E3B31B10BABB00F2A8D1B9A62C326BD2F";
+
+const char *EXPECTED_ECDSA_SHA256_HASH_DIGEST = "56FCD975B166C3F0342D0036E44C311A86C0EAE40713B53FC776369BAE7F5264";
+
const int MD5_HASH_SIZE = 16;
const int SHA1_HASH_SIZE = 20;
+const int SHA256_HASH_SIZE = 32;
static void calculate_digest(const char *hash, size_t hash_len, char *buffer,
size_t buffer_len)
@@ -39,34 +53,111 @@ int test(LIBSSH2_SESSION *session)
const char *md5_hash;
const char *sha1_hash;
+ const char *sha256_hash;
+ int type;
+ size_t len;
- md5_hash = libssh2_hostkey_hash(session, LIBSSH2_HOSTKEY_HASH_MD5);
- if (md5_hash == NULL) {
- print_last_session_error(
- "libssh2_hostkey_hash(LIBSSH2_HOSTKEY_HASH_MD5)");
+ const char *hostkey = libssh2_session_hostkey(session, &len, &type);
+ if (hostkey == NULL) {
+ print_last_session_error("libssh2_session_hostkey");
return 1;
}
- calculate_digest(md5_hash, MD5_HASH_SIZE, buf, BUFSIZ);
+ if(type == LIBSSH2_HOSTKEY_TYPE_ECDSA_256) {
- if (strcmp(buf, EXPECTED_MD5_HASH_DIGEST) != 0) {
- fprintf(stderr, "MD5 hash not as expected - digest %s != %s\n", buf,
- EXPECTED_MD5_HASH_DIGEST);
- return 1;
- }
+ md5_hash = libssh2_hostkey_hash(session, LIBSSH2_HOSTKEY_HASH_MD5);
+ if (md5_hash == NULL) {
+ print_last_session_error(
+ "libssh2_hostkey_hash(LIBSSH2_HOSTKEY_HASH_MD5)");
+ return 1;
+ }
- sha1_hash = libssh2_hostkey_hash(session, LIBSSH2_HOSTKEY_HASH_SHA1);
- if (sha1_hash == NULL) {
- print_last_session_error(
- "libssh2_hostkey_hash(LIBSSH2_HOSTKEY_HASH_SHA1)");
- return 1;
- }
+ calculate_digest(md5_hash, MD5_HASH_SIZE, buf, BUFSIZ);
- calculate_digest(sha1_hash, SHA1_HASH_SIZE, buf, BUFSIZ);
+ if (strcmp(buf, EXPECTED_ECDSA_MD5_HASH_DIGEST) != 0) {
+ fprintf(stderr, "ECDSA MD5 hash not as expected - digest %s != %s\n", buf,
+ EXPECTED_ECDSA_MD5_HASH_DIGEST);
+ return 1;
+ }
- if (strcmp(buf, EXPECTED_SHA1_HASH_DIGEST) != 0) {
- fprintf(stderr, "SHA1 hash not as expected - digest %s != %s\n", buf,
- EXPECTED_SHA1_HASH_DIGEST);
+ sha1_hash = libssh2_hostkey_hash(session, LIBSSH2_HOSTKEY_HASH_SHA1);
+ if (sha1_hash == NULL) {
+ print_last_session_error(
+ "libssh2_hostkey_hash(LIBSSH2_HOSTKEY_HASH_SHA1)");
+ return 1;
+ }
+
+ calculate_digest(sha1_hash, SHA1_HASH_SIZE, buf, BUFSIZ);
+
+ if (strcmp(buf, EXPECTED_ECDSA_SHA1_HASH_DIGEST) != 0) {
+ fprintf(stderr, "ECDSA SHA1 hash not as expected - digest %s != %s\n", buf,
+ EXPECTED_ECDSA_SHA1_HASH_DIGEST);
+ return 1;
+ }
+
+ sha256_hash = libssh2_hostkey_hash(session, LIBSSH2_HOSTKEY_HASH_SHA256);
+ if (sha256_hash == NULL) {
+ print_last_session_error(
+ "libssh2_hostkey_hash(LIBSSH2_HOSTKEY_HASH_SHA256)");
+ return 1;
+ }
+
+ calculate_digest(sha256_hash, SHA256_HASH_SIZE, buf, BUFSIZ);
+
+ if (strcmp(buf, EXPECTED_ECDSA_SHA256_HASH_DIGEST) != 0) {
+ fprintf(stderr, "ECDSA SHA256 hash not as expected - digest %s != %s\n", buf,
+ EXPECTED_ECDSA_SHA256_HASH_DIGEST);
+ return 1;
+ }
+
+ } else if ( type == LIBSSH2_HOSTKEY_TYPE_RSA ) {
+
+ md5_hash = libssh2_hostkey_hash(session, LIBSSH2_HOSTKEY_HASH_MD5);
+ if (md5_hash == NULL) {
+ print_last_session_error(
+ "libssh2_hostkey_hash(LIBSSH2_HOSTKEY_HASH_MD5)");
+ return 1;
+ }
+
+ calculate_digest(md5_hash, MD5_HASH_SIZE, buf, BUFSIZ);
+
+ if (strcmp(buf, EXPECTED_RSA_MD5_HASH_DIGEST) != 0) {
+ fprintf(stderr, "MD5 hash not as expected - digest %s != %s\n", buf,
+ EXPECTED_RSA_MD5_HASH_DIGEST);
+ return 1;
+ }
+
+ sha1_hash = libssh2_hostkey_hash(session, LIBSSH2_HOSTKEY_HASH_SHA1);
+ if (sha1_hash == NULL) {
+ print_last_session_error(
+ "libssh2_hostkey_hash(LIBSSH2_HOSTKEY_HASH_SHA1)");
+ return 1;
+ }
+
+ calculate_digest(sha1_hash, SHA1_HASH_SIZE, buf, BUFSIZ);
+
+ if (strcmp(buf, EXPECTED_RSA_SHA1_HASH_DIGEST) != 0) {
+ fprintf(stderr, "SHA1 hash not as expected - digest %s != %s\n", buf,
+ EXPECTED_RSA_SHA1_HASH_DIGEST);
+ return 1;
+ }
+
+ sha256_hash = libssh2_hostkey_hash(session, LIBSSH2_HOSTKEY_HASH_SHA256);
+ if (sha256_hash == NULL) {
+ print_last_session_error(
+ "libssh2_hostkey_hash(LIBSSH2_HOSTKEY_HASH_SHA256)");
+ return 1;
+ }
+
+ calculate_digest(sha256_hash, SHA256_HASH_SIZE, buf, BUFSIZ);
+
+ if (strcmp(buf, EXPECTED_RSA_SHA256_HASH_DIGEST) != 0) {
+ fprintf(stderr, "SHA256 hash not as expected - digest %s != %s\n", buf,
+ EXPECTED_RSA_SHA256_HASH_DIGEST);
+ return 1;
+ }
+ } else {
+ fprintf(stderr, "Unexpected type of hostkey: %i\n", type);
return 1;
}