summaryrefslogtreecommitdiff
path: root/libs/libssh2/src/hostkey.c
diff options
context:
space:
mode:
authordartraiden <wowemuh@gmail.com>2019-06-20 22:31:19 +0300
committerdartraiden <wowemuh@gmail.com>2019-06-20 22:31:19 +0300
commit1d72e07ffb7b349ac9a8f825eae7cce082b5e2cd (patch)
tree03a97724b412a04a7a3848dc8c5edb24b2d29c0e /libs/libssh2/src/hostkey.c
parentfdf29bb66f0b9be0b8518db0a827cc2bd20a38ac (diff)
iibssh2: update to 1.9.0
Diffstat (limited to 'libs/libssh2/src/hostkey.c')
-rw-r--r--libs/libssh2/src/hostkey.c708
1 files changed, 632 insertions, 76 deletions
diff --git a/libs/libssh2/src/hostkey.c b/libs/libssh2/src/hostkey.c
index 2a0a8f943b..a8bd42b7a0 100644
--- a/libs/libssh2/src/hostkey.c
+++ b/libs/libssh2/src/hostkey.c
@@ -1,5 +1,5 @@
/* Copyright (c) 2004-2006, Sara Golemon <sarag@libssh2.org>
- * Copyright (c) 2009-2014 by Daniel Stenberg
+ * Copyright (c) 2009-2019 by Daniel Stenberg
* All rights reserved.
*
* Redistribution and use in source and binary forms,
@@ -64,38 +64,36 @@ hostkey_method_ssh_rsa_init(LIBSSH2_SESSION * session,
void **abstract)
{
libssh2_rsa_ctx *rsactx;
- const unsigned char *s, *e, *n;
- unsigned long len, e_len, n_len;
- int ret;
-
- (void) hostkey_data_len;
+ unsigned char *e, *n;
+ size_t e_len, n_len;
+ struct string_buf buf;
- if (*abstract) {
+ if(*abstract) {
hostkey_method_ssh_rsa_dtor(session, abstract);
*abstract = NULL;
}
- s = hostkey_data;
- len = _libssh2_ntohu32(s);
- s += 4;
-
- if (len != 7 || strncmp((char *) s, "ssh-rsa", 7) != 0) {
+ if(hostkey_data_len < 19) {
+ _libssh2_debug(session, LIBSSH2_TRACE_ERROR,
+ "host key length too short");
return -1;
}
- s += 7;
- e_len = _libssh2_ntohu32(s);
- s += 4;
+ buf.data = (unsigned char *)hostkey_data;
+ buf.dataptr = buf.data;
+ buf.len = hostkey_data_len;
- e = s;
- s += e_len;
- n_len = _libssh2_ntohu32(s);
- s += 4;
- n = s;
+ if(_libssh2_match_string(&buf, "ssh-rsa"))
+ return -1;
+
+ if(_libssh2_get_string(&buf, &e, &e_len))
+ return -1;
+
+ if(_libssh2_get_string(&buf, &n, &n_len))
+ return -1;
- ret = _libssh2_rsa_new(&rsactx, e, e_len, n, n_len, NULL, 0,
- NULL, 0, NULL, 0, NULL, 0, NULL, 0, NULL, 0);
- if (ret) {
+ if(_libssh2_rsa_new(&rsactx, e, e_len, n, n_len, NULL, 0,
+ NULL, 0, NULL, 0, NULL, 0, NULL, 0, NULL, 0)) {
return -1;
}
@@ -118,13 +116,13 @@ hostkey_method_ssh_rsa_initPEM(LIBSSH2_SESSION * session,
libssh2_rsa_ctx *rsactx;
int ret;
- if (*abstract) {
+ if(*abstract) {
hostkey_method_ssh_rsa_dtor(session, abstract);
*abstract = NULL;
}
ret = _libssh2_rsa_new_private(&rsactx, session, privkeyfile, passphrase);
- if (ret) {
+ if(ret) {
return -1;
}
@@ -148,7 +146,7 @@ hostkey_method_ssh_rsa_initPEMFromMemory(LIBSSH2_SESSION * session,
libssh2_rsa_ctx *rsactx;
int ret;
- if (*abstract) {
+ if(*abstract) {
hostkey_method_ssh_rsa_dtor(session, abstract);
*abstract = NULL;
}
@@ -156,7 +154,7 @@ hostkey_method_ssh_rsa_initPEMFromMemory(LIBSSH2_SESSION * session,
ret = _libssh2_rsa_new_private_frommemory(&rsactx, session,
privkeyfiledata,
privkeyfiledata_len, passphrase);
- if (ret) {
+ if(ret) {
return -1;
}
@@ -181,6 +179,9 @@ hostkey_method_ssh_rsa_sig_verify(LIBSSH2_SESSION * session,
(void) session;
/* Skip past keyname_len(4) + keyname(7){"ssh-rsa"} + signature_len(4) */
+ if(sig_len < 15)
+ return -1;
+
sig += 15;
sig_len -= 15;
return _libssh2_rsa_sha1_verify(rsactx, sig, sig_len, m, m_len);
@@ -218,7 +219,7 @@ hostkey_method_ssh_rsa_signv(LIBSSH2_SESSION * session,
ret = _libssh2_rsa_sha1_sign(session, rsactx, hash, SHA_DIGEST_LENGTH,
signature, signature_len);
- if (ret) {
+ if(ret) {
return -1;
}
@@ -281,45 +282,42 @@ hostkey_method_ssh_dss_init(LIBSSH2_SESSION * session,
void **abstract)
{
libssh2_dsa_ctx *dsactx;
- const unsigned char *p, *q, *g, *y, *s;
- unsigned long p_len, q_len, g_len, y_len, len;
- int ret;
-
- (void) hostkey_data_len;
+ unsigned char *p, *q, *g, *y;
+ size_t p_len, q_len, g_len, y_len;
+ struct string_buf buf;
- if (*abstract) {
+ if(*abstract) {
hostkey_method_ssh_dss_dtor(session, abstract);
*abstract = NULL;
}
- s = hostkey_data;
- len = _libssh2_ntohu32(s);
- s += 4;
- if (len != 7 || strncmp((char *) s, "ssh-dss", 7) != 0) {
+ if(hostkey_data_len < 27) {
+ _libssh2_debug(session, LIBSSH2_TRACE_ERROR,
+ "host key length too short");
return -1;
}
- s += 7;
- p_len = _libssh2_ntohu32(s);
- s += 4;
- p = s;
- s += p_len;
- q_len = _libssh2_ntohu32(s);
- s += 4;
- q = s;
- s += q_len;
- g_len = _libssh2_ntohu32(s);
- s += 4;
- g = s;
- s += g_len;
- y_len = _libssh2_ntohu32(s);
- s += 4;
- y = s;
- /* s += y_len; */
+ buf.data = (unsigned char *)hostkey_data;
+ buf.dataptr = buf.data;
+ buf.len = hostkey_data_len;
+
+ if(_libssh2_match_string(&buf, "ssh-dss"))
+ return -1;
+
+ if(_libssh2_get_string(&buf, &p, &p_len))
+ return -1;
+
+ if(_libssh2_get_string(&buf, &q, &q_len))
+ return -1;
+
+ if(_libssh2_get_string(&buf, &g, &g_len))
+ return -1;
+
+ if(_libssh2_get_string(&buf, &y, &y_len))
+ return -1;
- ret = _libssh2_dsa_new(&dsactx, p, p_len, q, q_len,
- g, g_len, y, y_len, NULL, 0);
- if (ret) {
+ if(_libssh2_dsa_new(&dsactx, p, p_len, q, q_len,
+ g, g_len, y, y_len, NULL, 0)) {
return -1;
}
@@ -342,13 +340,13 @@ hostkey_method_ssh_dss_initPEM(LIBSSH2_SESSION * session,
libssh2_dsa_ctx *dsactx;
int ret;
- if (*abstract) {
+ if(*abstract) {
hostkey_method_ssh_dss_dtor(session, abstract);
*abstract = NULL;
}
ret = _libssh2_dsa_new_private(&dsactx, session, privkeyfile, passphrase);
- if (ret) {
+ if(ret) {
return -1;
}
@@ -372,7 +370,7 @@ hostkey_method_ssh_dss_initPEMFromMemory(LIBSSH2_SESSION * session,
libssh2_dsa_ctx *dsactx;
int ret;
- if (*abstract) {
+ if(*abstract) {
hostkey_method_ssh_dss_dtor(session, abstract);
*abstract = NULL;
}
@@ -380,7 +378,7 @@ hostkey_method_ssh_dss_initPEMFromMemory(LIBSSH2_SESSION * session,
ret = _libssh2_dsa_new_private_frommemory(&dsactx, session,
privkeyfiledata,
privkeyfiledata_len, passphrase);
- if (ret) {
+ if(ret) {
return -1;
}
@@ -404,12 +402,14 @@ hostkey_method_ssh_dss_sig_verify(LIBSSH2_SESSION * session,
libssh2_dsa_ctx *dsactx = (libssh2_dsa_ctx *) (*abstract);
/* Skip past keyname_len(4) + keyname(7){"ssh-dss"} + signature_len(4) */
- sig += 15;
- sig_len -= 15;
- if (sig_len != 40) {
+ if(sig_len != 55) {
return _libssh2_error(session, LIBSSH2_ERROR_PROTO,
"Invalid DSS signature length");
}
+
+ sig += 15;
+ sig_len -= 15;
+
return _libssh2_dsa_sha1_verify(dsactx, sig, m, m_len);
}
@@ -432,7 +432,7 @@ hostkey_method_ssh_dss_signv(LIBSSH2_SESSION * session,
int i;
*signature = LIBSSH2_CALLOC(session, 2 * SHA_DIGEST_LENGTH);
- if (!*signature) {
+ if(!*signature) {
return -1;
}
@@ -444,7 +444,7 @@ hostkey_method_ssh_dss_signv(LIBSSH2_SESSION * session,
}
libssh2_sha1_final(ctx, hash);
- if (_libssh2_dsa_sha1_sign(dsactx, hash, SHA_DIGEST_LENGTH, *signature)) {
+ if(_libssh2_dsa_sha1_sign(dsactx, hash, SHA_DIGEST_LENGTH, *signature)) {
LIBSSH2_FREE(session, *signature);
return -1;
}
@@ -483,7 +483,526 @@ static const LIBSSH2_HOSTKEY_METHOD hostkey_method_ssh_dss = {
};
#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;
+ unsigned char *type_str, *domain, *public_key;
+ size_t key_len, len;
+ libssh2_curve_type type;
+ struct string_buf buf;
+
+ if(abstract != NULL && *abstract) {
+ hostkey_method_ssh_ecdsa_dtor(session, abstract);
+ *abstract = NULL;
+ }
+
+ if(hostkey_data_len < 39) {
+ _libssh2_debug(session, LIBSSH2_TRACE_ERROR,
+ "host key length too short");
+ return -1;
+ }
+
+ buf.data = (unsigned char *)hostkey_data;
+ buf.dataptr = buf.data;
+ buf.len = hostkey_data_len;
+
+ if(_libssh2_get_string(&buf, &type_str, &len) || len != 19)
+ return -1;
+
+ if(strncmp((char *) type_str, "ecdsa-sha2-nistp256", 19) == 0) {
+ type = LIBSSH2_EC_CURVE_NISTP256;
+ }
+ else if(strncmp((char *) type_str, "ecdsa-sha2-nistp384", 19) == 0) {
+ type = LIBSSH2_EC_CURVE_NISTP384;
+ }
+ else if(strncmp((char *) type_str, "ecdsa-sha2-nistp521", 19) == 0) {
+ type = LIBSSH2_EC_CURVE_NISTP521;
+ }
+ else {
+ return -1;
+ }
+
+ if(_libssh2_get_string(&buf, &domain, &len) || len != 8)
+ return -1;
+
+ if(type == LIBSSH2_EC_CURVE_NISTP256 &&
+ strncmp((char *)domain, "nistp256", 8) != 0) {
+ return -1;
+ }
+ else if(type == LIBSSH2_EC_CURVE_NISTP384 &&
+ strncmp((char *)domain, "nistp384", 8) != 0) {
+ return -1;
+ }
+ else if(type == LIBSSH2_EC_CURVE_NISTP521 &&
+ strncmp((char *)domain, "nistp521", 8) != 0) {
+ return -1;
+ }
+
+ /* public key */
+ if(_libssh2_get_string(&buf, &public_key, &key_len))
+ return -1;
+
+ if(_libssh2_ecdsa_curve_name_with_octal_new(&ecdsactx, public_key,
+ 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)
+{
+ unsigned char *r, *s, *name;
+ size_t r_len, s_len, name_len;
+ unsigned int len;
+ struct string_buf buf;
+ libssh2_ecdsa_ctx *ctx = (libssh2_ecdsa_ctx *) (*abstract);
+
+ (void) session;
+
+ if(sig_len < 35)
+ return -1;
+
+ /* keyname_len(4) + keyname(19){"ecdsa-sha2-nistp256"} +
+ signature_len(4) */
+ buf.data = (unsigned char *)sig;
+ buf.dataptr = buf.data;
+ buf.len = sig_len;
+
+ if(_libssh2_get_string(&buf, &name, &name_len) || name_len != 19)
+ return -1;
+
+ if(_libssh2_get_u32(&buf, &len) != 0 || len < 8)
+ return -1;
+
+ if(_libssh2_get_string(&buf, &r, &r_len))
+ return -1;
+
+ if(_libssh2_get_string(&buf, &s, &s_len))
+ return -1;
+
+ 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 */
+
+#if LIBSSH2_ED25519
+
+/* ***********
+ * ed25519 *
+ *********** */
+
+static int hostkey_method_ssh_ed25519_dtor(LIBSSH2_SESSION * session,
+ void **abstract);
+
+/*
+ * hostkey_method_ssh_ed25519_init
+ *
+ * Initialize the server hostkey working area with e/n pair
+ */
+static int
+hostkey_method_ssh_ed25519_init(LIBSSH2_SESSION * session,
+ const unsigned char *hostkey_data,
+ size_t hostkey_data_len,
+ void **abstract)
+{
+ const unsigned char *s;
+ unsigned long len, key_len;
+ libssh2_ed25519_ctx *ctx = NULL;
+
+ if(*abstract) {
+ hostkey_method_ssh_ed25519_dtor(session, abstract);
+ *abstract = NULL;
+ }
+
+ if(hostkey_data_len < 19) {
+ _libssh2_debug(session, LIBSSH2_TRACE_ERROR,
+ "host key length too short");
+ return -1;
+ }
+
+ s = hostkey_data;
+ len = _libssh2_ntohu32(s);
+ s += 4;
+
+ if(len != 11 || strncmp((char *) s, "ssh-ed25519", 11) != 0) {
+ return -1;
+ }
+
+ s += 11;
+
+ /* public key */
+ key_len = _libssh2_ntohu32(s);
+ s += 4;
+
+ if(_libssh2_ed25519_new_public(&ctx, session, s, key_len) != 0) {
+ return -1;
+ }
+
+ *abstract = ctx;
+
+ return 0;
+}
+
+/*
+ * hostkey_method_ssh_ed25519_initPEM
+ *
+ * Load a Private Key from a PEM file
+ */
+static int
+hostkey_method_ssh_ed25519_initPEM(LIBSSH2_SESSION * session,
+ const char *privkeyfile,
+ unsigned const char *passphrase,
+ void **abstract)
+{
+ libssh2_ed25519_ctx *ec_ctx = NULL;
+ int ret;
+
+ if(*abstract) {
+ hostkey_method_ssh_ed25519_dtor(session, abstract);
+ *abstract = NULL;
+ }
+
+ ret = _libssh2_ed25519_new_private(&ec_ctx, session,
+ privkeyfile, passphrase);
+ if(ret) {
+ return -1;
+ }
+
+ *abstract = ec_ctx;
+
+ return ret;
+}
+
+/*
+ * hostkey_method_ssh_ed25519_initPEMFromMemory
+ *
+ * Load a Private Key from memory
+ */
+static int
+hostkey_method_ssh_ed25519_initPEMFromMemory(LIBSSH2_SESSION * session,
+ const char *privkeyfiledata,
+ size_t privkeyfiledata_len,
+ unsigned const char *passphrase,
+ void **abstract)
+{
+ libssh2_ed25519_ctx *ed_ctx = NULL;
+ int ret;
+
+ if(abstract != NULL && *abstract) {
+ hostkey_method_ssh_ed25519_dtor(session, abstract);
+ *abstract = NULL;
+ }
+
+ ret = _libssh2_ed25519_new_private_frommemory(&ed_ctx, session,
+ privkeyfiledata,
+ privkeyfiledata_len,
+ passphrase);
+ if(ret) {
+ return -1;
+ }
+
+ if(abstract != NULL)
+ *abstract = ed_ctx;
+
+ return 0;
+}
+
+/*
+ * hostkey_method_ssh_ed25519_sig_verify
+ *
+ * Verify signature created by remote
+ */
+static int
+hostkey_method_ssh_ed25519_sig_verify(LIBSSH2_SESSION * session,
+ const unsigned char *sig,
+ size_t sig_len,
+ const unsigned char *m,
+ size_t m_len, void **abstract)
+{
+ libssh2_ed25519_ctx *ctx = (libssh2_ed25519_ctx *) (*abstract);
+ (void) session;
+
+ if(sig_len < 19)
+ return -1;
+
+ /* Skip past keyname_len(4) + keyname(11){"ssh-ed25519"} +
+ signature_len(4) */
+ sig += 19;
+ sig_len -= 19;
+
+ if(sig_len != LIBSSH2_ED25519_SIG_LEN)
+ return -1;
+
+ return _libssh2_ed25519_verify(ctx, sig, sig_len, m, m_len);
+}
+
+/*
+ * hostkey_method_ssh_ed25519_signv
+ *
+ * Construct a signature from an array of vectors
+ */
+static int
+hostkey_method_ssh_ed25519_signv(LIBSSH2_SESSION * session,
+ unsigned char **signature,
+ size_t *signature_len,
+ int veccount,
+ const struct iovec datavec[],
+ void **abstract)
+{
+ libssh2_ed25519_ctx *ctx = (libssh2_ed25519_ctx *) (*abstract);
+
+ if(veccount != 1) {
+ return -1;
+ }
+
+ return _libssh2_ed25519_sign(ctx, session, signature, signature_len,
+ datavec[0].iov_base, datavec[0].iov_len);
+}
+
+
+/*
+ * hostkey_method_ssh_ed25519_dtor
+ *
+ * Shutdown the hostkey by freeing key context
+ */
+static int
+hostkey_method_ssh_ed25519_dtor(LIBSSH2_SESSION * session, void **abstract)
+{
+ libssh2_ed25519_ctx *keyctx = (libssh2_ed25519_ctx*) (*abstract);
+ (void) session;
+
+ if(keyctx)
+ _libssh2_ed25519_free(keyctx);
+
+ *abstract = NULL;
+
+ return 0;
+}
+
+static const LIBSSH2_HOSTKEY_METHOD hostkey_method_ssh_ed25519 = {
+ "ssh-ed25519",
+ SHA256_DIGEST_LENGTH,
+ hostkey_method_ssh_ed25519_init,
+ hostkey_method_ssh_ed25519_initPEM,
+ hostkey_method_ssh_ed25519_initPEMFromMemory,
+ hostkey_method_ssh_ed25519_sig_verify,
+ hostkey_method_ssh_ed25519_signv,
+ NULL, /* encrypt */
+ hostkey_method_ssh_ed25519_dtor,
+};
+
+#endif /*LIBSSH2_ED25519*/
+
+
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_ED25519
+ &hostkey_method_ssh_ed25519,
+#endif
#if LIBSSH2_RSA
&hostkey_method_ssh_rsa,
#endif /* LIBSSH2_RSA */
@@ -505,12 +1024,12 @@ 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)
{
- switch (hash_type) {
+ switch(hash_type) {
#if LIBSSH2_MD5
case LIBSSH2_HOSTKEY_HASH_MD5:
return (session->server_hostkey_md5_valid)
@@ -523,6 +1042,11 @@ libssh2_hostkey_hash(LIBSSH2_SESSION * session, int hash_type)
? (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;
}
@@ -530,22 +1054,55 @@ libssh2_hostkey_hash(LIBSSH2_SESSION * session, int hash_type)
static int hostkey_type(const unsigned char *hostkey, size_t len)
{
- const unsigned char rsa[] = {
+ static const unsigned char rsa[] = {
0, 0, 0, 0x07, 's', 's', 'h', '-', 'r', 's', 'a'
};
- const unsigned char dss[] = {
+ static const unsigned char dss[] = {
0, 0, 0, 0x07, 's', 's', 'h', '-', 'd', 's', 's'
};
+ static 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'
+ };
+ static 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'
+ };
+ static 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'
+ };
+ static const unsigned char ed25519[] = {
+ 0, 0, 0, 0x0b, 's', 's', 'h', '-', 'e', 'd', '2', '5', '5', '1', '9'
+ };
- if (len < 11)
+ if(len < 11)
return LIBSSH2_HOSTKEY_TYPE_UNKNOWN;
- if (!memcmp(rsa, hostkey, 11))
+ if(!memcmp(rsa, hostkey, 11))
return LIBSSH2_HOSTKEY_TYPE_RSA;
- if (!memcmp(dss, hostkey, 11))
+ if(!memcmp(dss, hostkey, 11))
return LIBSSH2_HOSTKEY_TYPE_DSS;
+ if(len < 15)
+ return LIBSSH2_HOSTKEY_TYPE_UNKNOWN;
+
+ if(!memcmp(ed25519, hostkey, 15))
+ return LIBSSH2_HOSTKEY_TYPE_ED25519;
+
+ 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;
}
@@ -561,7 +1118,7 @@ libssh2_session_hostkey(LIBSSH2_SESSION *session, size_t *len, int *type)
if(session->server_hostkey_len) {
if(len)
*len = session->server_hostkey_len;
- if (type)
+ if(type)
*type = hostkey_type(session->server_hostkey,
session->server_hostkey_len);
return (char *) session->server_hostkey;
@@ -570,4 +1127,3 @@ libssh2_session_hostkey(LIBSSH2_SESSION *session, size_t *len, int *type)
*len = 0;
return NULL;
}
-