mirror of
https://git.freebsd.org/ports.git
synced 2025-05-14 08:11:50 -04:00
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)
727 lines
18 KiB
C
727 lines
18 KiB
C
--- 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,
|