summaryrefslogtreecommitdiff
path: root/libs/libssh2/src/openssl.c
diff options
context:
space:
mode:
Diffstat (limited to 'libs/libssh2/src/openssl.c')
-rw-r--r--libs/libssh2/src/openssl.c2620
1 files changed, 2334 insertions, 286 deletions
diff --git a/libs/libssh2/src/openssl.c b/libs/libssh2/src/openssl.c
index 4f63ef92bc..04d5ec2ffd 100644
--- a/libs/libssh2/src/openssl.c
+++ b/libs/libssh2/src/openssl.c
@@ -43,12 +43,38 @@
#ifdef LIBSSH2_OPENSSL /* compile only if we build with openssl */
#include <string.h>
+#include "misc.h"
#ifndef EVP_MAX_BLOCK_LENGTH
#define EVP_MAX_BLOCK_LENGTH 32
#endif
int
+read_openssh_private_key_from_memory(void **key_ctx, LIBSSH2_SESSION *session,
+ const char *key_type,
+ const char *filedata,
+ size_t filedata_len,
+ unsigned const char *passphrase);
+
+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,
unsigned long elen,
@@ -81,7 +107,7 @@ _libssh2_rsa_new(libssh2_rsa_ctx ** rsa,
n = BN_new();
BN_bin2bn(ndata, nlen, n);
- if (ddata) {
+ if(ddata) {
d = BN_new();
BN_bin2bn(ddata, dlen, d);
@@ -107,6 +133,7 @@ _libssh2_rsa_new(libssh2_rsa_ctx ** rsa,
#else
(*rsa)->e = e;
(*rsa)->n = n;
+ (*rsa)->d = d;
#endif
#ifdef HAVE_OPAQUE_STRUCTS
@@ -135,7 +162,7 @@ _libssh2_rsa_sha1_verify(libssh2_rsa_ctx * rsactx,
unsigned char hash[SHA_DIGEST_LENGTH];
int ret;
- if (_libssh2_sha1(m, m_len, hash))
+ if(_libssh2_sha1(m, m_len, hash))
return -1; /* failure */
ret = RSA_verify(NID_sha1, hash, SHA_DIGEST_LENGTH,
(unsigned char *) sig, sig_len, rsactx);
@@ -173,7 +200,7 @@ _libssh2_dsa_new(libssh2_dsa_ctx ** dsactx,
pub_key = BN_new();
BN_bin2bn(y, y_len, pub_key);
- if (x_len) {
+ if(x_len) {
priv_key = BN_new();
BN_bin2bn(x, x_len, priv_key);
}
@@ -220,7 +247,7 @@ _libssh2_dsa_sha1_verify(libssh2_dsa_ctx * dsactx,
dsasig->r = r;
dsasig->s = s;
#endif
- if (!_libssh2_sha1(m, m_len, hash))
+ if(!_libssh2_sha1(m, m_len, hash))
/* _libssh2_sha1() succeeded */
ret = DSA_do_verify(hash, SHA_DIGEST_LENGTH, dsasig, dsactx);
@@ -230,6 +257,147 @@ _libssh2_dsa_sha1_verify(libssh2_dsa_ctx * dsactx,
}
#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);
+
+#ifdef 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);
+ }
+
+#ifdef 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),
@@ -259,7 +427,7 @@ _libssh2_cipher_crypt(_libssh2_cipher_ctx * ctx,
#else
ret = EVP_Cipher(ctx, buf, block, blocksize);
#endif
- if (ret == 1) {
+ if(ret == 1) {
memcpy(block, buf, blocksize);
}
return ret == 1 ? 0 : 1;
@@ -289,7 +457,7 @@ aes_ctr_init(EVP_CIPHER_CTX *ctx, const unsigned char *key,
const EVP_CIPHER *aes_cipher;
(void) enc;
- switch (EVP_CIPHER_CTX_key_length(ctx)) {
+ switch(EVP_CIPHER_CTX_key_length(ctx)) {
case 16:
aes_cipher = EVP_aes_128_ecb();
break;
@@ -304,7 +472,7 @@ aes_ctr_init(EVP_CIPHER_CTX *ctx, const unsigned char *key,
}
c = malloc(sizeof(*c));
- if (c == NULL)
+ if(c == NULL)
return 0;
#ifdef HAVE_OPAQUE_STRUCTS
@@ -312,12 +480,12 @@ aes_ctr_init(EVP_CIPHER_CTX *ctx, const unsigned char *key,
#else
c->aes_ctx = malloc(sizeof(EVP_CIPHER_CTX));
#endif
- if (c->aes_ctx == NULL) {
+ if(c->aes_ctx == NULL) {
free(c);
return 0;
}
- if (EVP_EncryptInit(c->aes_ctx, aes_cipher, key, NULL) != 1) {
+ if(EVP_EncryptInit(c->aes_ctx, aes_cipher, key, NULL) != 1) {
#ifdef HAVE_OPAQUE_STRUCTS
EVP_CIPHER_CTX_free(c->aes_ctx);
#else
@@ -343,13 +511,12 @@ aes_ctr_do_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out,
{
aes_ctr_ctx *c = EVP_CIPHER_CTX_get_app_data(ctx);
unsigned char b1[AES_BLOCK_SIZE];
- size_t i = 0;
int outlen = 0;
- if (inl != 16) /* libssh2 only ever encrypt one block */
+ if(inl != 16) /* libssh2 only ever encrypt one block */
return 0;
- if (c == NULL) {
+ if(c == NULL) {
return 0;
}
@@ -360,19 +527,13 @@ aes_ctr_do_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out,
the ciphertext block C1. The counter X is then incremented
*/
- if (EVP_EncryptUpdate(c->aes_ctx, b1, &outlen, c->ctr, AES_BLOCK_SIZE) != 1) {
+ if(EVP_EncryptUpdate(c->aes_ctx, b1, &outlen,
+ c->ctr, AES_BLOCK_SIZE) != 1) {
return 0;
}
- for (i = 0; i < 16; i++)
- *out++ = *in++ ^ b1[i];
-
- i = 15;
- while (c->ctr[i]++ == 0xFF) {
- if (i == 0)
- break;
- i--;
- }
+ _libssh2_xor_data(out, in, b1, AES_BLOCK_SIZE);
+ _libssh2_aes_ctr_increment(c->ctr, AES_BLOCK_SIZE);
return 1;
}
@@ -382,11 +543,11 @@ aes_ctr_cleanup(EVP_CIPHER_CTX *ctx) /* cleanup ctx */
{
aes_ctr_ctx *c = EVP_CIPHER_CTX_get_app_data(ctx);
- if (c == NULL) {
+ if(c == NULL) {
return 1;
}
- if (c->aes_ctx != NULL) {
+ if(c->aes_ctx != NULL) {
#ifdef HAVE_OPAQUE_STRUCTS
EVP_CIPHER_CTX_free(c->aes_ctx);
#else
@@ -401,27 +562,27 @@ aes_ctr_cleanup(EVP_CIPHER_CTX *ctx) /* cleanup ctx */
}
static const EVP_CIPHER *
-make_ctr_evp (size_t keylen, EVP_CIPHER *aes_ctr_cipher, int type)
+make_ctr_evp (size_t keylen, EVP_CIPHER **aes_ctr_cipher, int type)
{
#ifdef HAVE_OPAQUE_STRUCTS
- aes_ctr_cipher = EVP_CIPHER_meth_new(type, 16, keylen);
- if (aes_ctr_cipher) {
- EVP_CIPHER_meth_set_iv_length(aes_ctr_cipher, 16);
- EVP_CIPHER_meth_set_init(aes_ctr_cipher, aes_ctr_init);
- EVP_CIPHER_meth_set_do_cipher(aes_ctr_cipher, aes_ctr_do_cipher);
- EVP_CIPHER_meth_set_cleanup(aes_ctr_cipher, aes_ctr_cleanup);
+ *aes_ctr_cipher = EVP_CIPHER_meth_new(type, 16, keylen);
+ if(*aes_ctr_cipher) {
+ EVP_CIPHER_meth_set_iv_length(*aes_ctr_cipher, 16);
+ EVP_CIPHER_meth_set_init(*aes_ctr_cipher, aes_ctr_init);
+ EVP_CIPHER_meth_set_do_cipher(*aes_ctr_cipher, aes_ctr_do_cipher);
+ EVP_CIPHER_meth_set_cleanup(*aes_ctr_cipher, aes_ctr_cleanup);
}
#else
- aes_ctr_cipher->nid = type;
- aes_ctr_cipher->block_size = 16;
- aes_ctr_cipher->key_len = keylen;
- aes_ctr_cipher->iv_len = 16;
- aes_ctr_cipher->init = aes_ctr_init;
- aes_ctr_cipher->do_cipher = aes_ctr_do_cipher;
- aes_ctr_cipher->cleanup = aes_ctr_cleanup;
+ (*aes_ctr_cipher)->nid = type;
+ (*aes_ctr_cipher)->block_size = 16;
+ (*aes_ctr_cipher)->key_len = keylen;
+ (*aes_ctr_cipher)->iv_len = 16;
+ (*aes_ctr_cipher)->init = aes_ctr_init;
+ (*aes_ctr_cipher)->do_cipher = aes_ctr_do_cipher;
+ (*aes_ctr_cipher)->cleanup = aes_ctr_cleanup;
#endif
- return aes_ctr_cipher;
+ return *aes_ctr_cipher;
}
const EVP_CIPHER *
@@ -429,12 +590,13 @@ _libssh2_EVP_aes_128_ctr(void)
{
#ifdef HAVE_OPAQUE_STRUCTS
static EVP_CIPHER * aes_ctr_cipher;
- return !aes_ctr_cipher?
- make_ctr_evp (16, aes_ctr_cipher, NID_aes_128_ctr) : aes_ctr_cipher;
+ return !aes_ctr_cipher ?
+ make_ctr_evp(16, &aes_ctr_cipher, NID_aes_128_ctr) : aes_ctr_cipher;
#else
static EVP_CIPHER aes_ctr_cipher;
- return !aes_ctr_cipher.key_len?
- make_ctr_evp (16, &aes_ctr_cipher, 0) : &aes_ctr_cipher;
+ static EVP_CIPHER * aes_ctr_cipher_ptr = &aes_ctr_cipher;
+ return !aes_ctr_cipher.key_len ?
+ make_ctr_evp(16, &aes_ctr_cipher_ptr, 0) : &aes_ctr_cipher;
#endif
}
@@ -443,12 +605,13 @@ _libssh2_EVP_aes_192_ctr(void)
{
#ifdef HAVE_OPAQUE_STRUCTS
static EVP_CIPHER * aes_ctr_cipher;
- return !aes_ctr_cipher?
- make_ctr_evp (24, aes_ctr_cipher, NID_aes_192_ctr) : aes_ctr_cipher;
+ return !aes_ctr_cipher ?
+ make_ctr_evp(24, &aes_ctr_cipher, NID_aes_192_ctr) : aes_ctr_cipher;
#else
static EVP_CIPHER aes_ctr_cipher;
- return !aes_ctr_cipher.key_len?
- make_ctr_evp (24, &aes_ctr_cipher, 0) : &aes_ctr_cipher;
+ static EVP_CIPHER * aes_ctr_cipher_ptr = &aes_ctr_cipher;
+ return !aes_ctr_cipher.key_len ?
+ make_ctr_evp(24, &aes_ctr_cipher_ptr, 0) : &aes_ctr_cipher;
#endif
}
@@ -457,25 +620,70 @@ _libssh2_EVP_aes_256_ctr(void)
{
#ifdef HAVE_OPAQUE_STRUCTS
static EVP_CIPHER * aes_ctr_cipher;
- return !aes_ctr_cipher?
- make_ctr_evp (32, aes_ctr_cipher, NID_aes_256_ctr) : aes_ctr_cipher;
+ return !aes_ctr_cipher ?
+ make_ctr_evp(32, &aes_ctr_cipher, NID_aes_256_ctr) : aes_ctr_cipher;
#else
static EVP_CIPHER aes_ctr_cipher;
- return !aes_ctr_cipher.key_len?
- make_ctr_evp (32, &aes_ctr_cipher, 0) : &aes_ctr_cipher;
+ static EVP_CIPHER * aes_ctr_cipher_ptr = &aes_ctr_cipher;
+ return !aes_ctr_cipher.key_len ?
+ make_ctr_evp(32, &aes_ctr_cipher_ptr, 0) : &aes_ctr_cipher;
#endif
}
-void _libssh2_init_aes_ctr(void)
+#endif /* LIBSSH2_AES_CTR */
+
+#ifndef HAVE_EVP_AES_128_CTR
+static EVP_CIPHER * aes_128_ctr_cipher = NULL;
+static EVP_CIPHER * aes_192_ctr_cipher = NULL;
+static EVP_CIPHER * aes_256_ctr_cipher = NULL;
+#endif
+
+void _libssh2_openssl_crypto_init(void)
{
- _libssh2_EVP_aes_128_ctr();
- _libssh2_EVP_aes_192_ctr();
- _libssh2_EVP_aes_256_ctr();
+#if OPENSSL_VERSION_NUMBER >= 0x10100000L && \
+ !defined(LIBRESSL_VERSION_NUMBER)
+#ifndef OPENSSL_NO_ENGINE
+ ENGINE_load_builtin_engines();
+ ENGINE_register_all_complete();
+#endif
+#else
+ OpenSSL_add_all_algorithms();
+ OpenSSL_add_all_ciphers();
+ OpenSSL_add_all_digests();
+#ifndef OPENSSL_NO_ENGINE
+ ENGINE_load_builtin_engines();
+ ENGINE_register_all_complete();
+#endif
+#endif
+#ifndef HAVE_EVP_AES_128_CTR
+ aes_128_ctr_cipher = (EVP_CIPHER *)_libssh2_EVP_aes_128_ctr();
+ aes_192_ctr_cipher = (EVP_CIPHER *)_libssh2_EVP_aes_192_ctr();
+ aes_256_ctr_cipher = (EVP_CIPHER *)_libssh2_EVP_aes_256_ctr();
+#endif
}
-#else
-void _libssh2_init_aes_ctr(void) {}
-#endif /* LIBSSH2_AES_CTR */
+void _libssh2_openssl_crypto_exit(void)
+{
+#ifndef HAVE_EVP_AES_128_CTR
+#ifdef HAVE_OPAQUE_STRUCTS
+ if(aes_128_ctr_cipher) {
+ EVP_CIPHER_meth_free(aes_128_ctr_cipher);
+ }
+
+ if(aes_192_ctr_cipher) {
+ EVP_CIPHER_meth_free(aes_192_ctr_cipher);
+ }
+
+ if(aes_256_ctr_cipher) {
+ EVP_CIPHER_meth_free(aes_256_ctr_cipher);
+ }
+#endif
+
+ aes_128_ctr_cipher = NULL;
+ aes_192_ctr_cipher = NULL;
+ aes_256_ctr_cipher = NULL;
+#endif
+}
/* TODO: Optionally call a passphrase callback specified by the
* calling program
@@ -486,7 +694,7 @@ passphrase_cb(char *buf, int size, int rwflag, char *passphrase)
int passphrase_len = strlen(passphrase);
(void) rwflag;
- if (passphrase_len > (size - 1)) {
+ if(passphrase_len > (size - 1)) {
passphrase_len = size - 1;
}
memcpy(buf, passphrase, passphrase_len);
@@ -496,12 +704,12 @@ passphrase_cb(char *buf, int size, int rwflag, char *passphrase)
}
typedef void * (*pem_read_bio_func)(BIO *, void **, pem_password_cb *,
- void * u);
+ void *u);
static int
-read_private_key_from_memory(void ** key_ctx,
+read_private_key_from_memory(void **key_ctx,
pem_read_bio_func read_private_key,
- const char * filedata,
+ const char *filedata,
size_t filedata_len,
unsigned const char *passphrase)
{
@@ -510,7 +718,7 @@ read_private_key_from_memory(void ** key_ctx,
*key_ctx = NULL;
bp = BIO_new_mem_buf((char *)filedata, filedata_len);
- if (!bp) {
+ if(!bp) {
return -1;
}
*key_ctx = read_private_key(bp, NULL, (pem_password_cb *) passphrase_cb,
@@ -520,10 +728,12 @@ read_private_key_from_memory(void ** key_ctx,
return (*key_ctx) ? 0 : -1;
}
+
+
static int
-read_private_key_from_file(void ** key_ctx,
+read_private_key_from_file(void **key_ctx,
pem_read_bio_func read_private_key,
- const char * filename,
+ const char *filename,
unsigned const char *passphrase)
{
BIO * bp;
@@ -531,7 +741,7 @@ read_private_key_from_file(void ** key_ctx,
*key_ctx = NULL;
bp = BIO_new_file(filename, "r");
- if (!bp) {
+ if(!bp) {
return -1;
}
@@ -548,14 +758,350 @@ _libssh2_rsa_new_private_frommemory(libssh2_rsa_ctx ** rsa,
const char *filedata, size_t filedata_len,
unsigned const char *passphrase)
{
+ int rc;
+
pem_read_bio_func read_rsa =
(pem_read_bio_func) &PEM_read_bio_RSAPrivateKey;
(void) session;
_libssh2_init_if_needed();
- return read_private_key_from_memory((void **) rsa, read_rsa,
- filedata, filedata_len, passphrase);
+ rc = read_private_key_from_memory((void **) rsa, read_rsa,
+ filedata, filedata_len, passphrase);
+
+ if(rc) {
+ rc = read_openssh_private_key_from_memory((void **)rsa, session,
+ "ssh-rsa", filedata, filedata_len, passphrase);
+ }
+
+return rc;
+}
+
+static unsigned char *
+gen_publickey_from_rsa(LIBSSH2_SESSION *session, RSA *rsa,
+ size_t *key_len)
+{
+ int e_bytes, n_bytes;
+ unsigned long len;
+ unsigned char *key;
+ unsigned char *p;
+ const BIGNUM * e;
+ const BIGNUM * n;
+#ifdef HAVE_OPAQUE_STRUCTS
+ RSA_get0_key(rsa, &n, &e, NULL);
+#else
+ e = rsa->e;
+ n = rsa->n;
+#endif
+ e_bytes = BN_num_bytes(e) + 1;
+ n_bytes = BN_num_bytes(n) + 1;
+
+ /* Key form is "ssh-rsa" + e + n. */
+ len = 4 + 7 + 4 + e_bytes + 4 + n_bytes;
+
+ key = LIBSSH2_ALLOC(session, len);
+ if(key == NULL) {
+ return NULL;
+ }
+
+ /* Process key encoding. */
+ p = key;
+
+ _libssh2_htonu32(p, 7); /* Key type. */
+ p += 4;
+ memcpy(p, "ssh-rsa", 7);
+ p += 7;
+
+ p = write_bn(p, e, e_bytes);
+ p = write_bn(p, n, n_bytes);
+
+ *key_len = (size_t)(p - key);
+ return key;
+}
+
+static int
+gen_publickey_from_rsa_evp(LIBSSH2_SESSION *session,
+ unsigned char **method,
+ size_t *method_len,
+ unsigned char **pubkeydata,
+ size_t *pubkeydata_len,
+ EVP_PKEY *pk)
+{
+ RSA* rsa = NULL;
+ unsigned char *key;
+ unsigned char *method_buf = NULL;
+ size_t key_len;
+
+ _libssh2_debug(session,
+ LIBSSH2_TRACE_AUTH,
+ "Computing public key from RSA private key envelop");
+
+ rsa = EVP_PKEY_get1_RSA(pk);
+ if(rsa == NULL) {
+ /* Assume memory allocation error... what else could it be ? */
+ goto __alloc_error;
+ }
+
+ method_buf = LIBSSH2_ALLOC(session, 7); /* ssh-rsa. */
+ if(method_buf == NULL) {
+ goto __alloc_error;
+ }
+
+ key = gen_publickey_from_rsa(session, rsa, &key_len);
+ if(key == NULL) {
+ goto __alloc_error;
+ }
+ RSA_free(rsa);
+
+ memcpy(method_buf, "ssh-rsa", 7);
+ *method = method_buf;
+ *method_len = 7;
+ *pubkeydata = key;
+ *pubkeydata_len = key_len;
+ return 0;
+
+ __alloc_error:
+ if(rsa != NULL) {
+ RSA_free(rsa);
+ }
+ if(method_buf != NULL) {
+ LIBSSH2_FREE(session, method_buf);
+ }
+
+ return _libssh2_error(session,
+ LIBSSH2_ERROR_ALLOC,
+ "Unable to allocate memory for private key data");
+}
+
+static int _libssh2_rsa_new_additional_parameters(RSA *rsa)
+{
+ BN_CTX *ctx = NULL;
+ BIGNUM *aux = NULL;
+ BIGNUM *dmp1 = NULL;
+ BIGNUM *dmq1 = NULL;
+ const BIGNUM *p = NULL;
+ const BIGNUM *q = NULL;
+ const BIGNUM *d = NULL;
+ int rc = 0;
+
+#ifdef HAVE_OPAQUE_STRUCTS
+ RSA_get0_key(rsa, NULL, NULL, &d);
+ RSA_get0_factors(rsa, &p, &q);
+#else
+ d = (*rsa).d;
+ p = (*rsa).p;
+ q = (*rsa).q;
+#endif
+
+ ctx = BN_CTX_new();
+ if(ctx == NULL)
+ return -1;
+
+ aux = BN_new();
+ if(aux == NULL) {
+ rc = -1;
+ goto out;
+ }
+
+ dmp1 = BN_new();
+ if(dmp1 == NULL) {
+ rc = -1;
+ goto out;
+ }
+
+ dmq1 = BN_new();
+ if(dmq1 == NULL) {
+ rc = -1;
+ goto out;
+ }
+
+ if((BN_sub(aux, q, BN_value_one()) == 0) ||
+ (BN_mod(dmq1, d, aux, ctx) == 0) ||
+ (BN_sub(aux, p, BN_value_one()) == 0) ||
+ (BN_mod(dmp1, d, aux, ctx) == 0)) {
+ rc = -1;
+ goto out;
+ }
+
+#ifdef HAVE_OPAQUE_STRUCTS
+ RSA_set0_crt_params(rsa, dmp1, dmq1, NULL);
+#else
+ (*rsa).dmp1 = dmp1;
+ (*rsa).dmq1 = dmq1;
+#endif
+
+out:
+ if(aux)
+ BN_clear_free(aux);
+ BN_CTX_free(ctx);
+
+ if(rc != 0) {
+ if(dmp1)
+ BN_clear_free(dmp1);
+ if(dmq1)
+ BN_clear_free(dmq1);
+ }
+
+ return rc;
+}
+
+static int
+gen_publickey_from_rsa_openssh_priv_data(LIBSSH2_SESSION *session,
+ struct string_buf *decrypted,
+ unsigned char **method,
+ size_t *method_len,
+ unsigned char **pubkeydata,
+ size_t *pubkeydata_len,
+ libssh2_rsa_ctx **rsa_ctx)
+{
+ int rc = 0;
+ size_t nlen, elen, dlen, plen, qlen, coefflen, commentlen;
+ unsigned char *n, *e, *d, *p, *q, *coeff, *comment;
+ RSA *rsa = NULL;
+
+ _libssh2_debug(session,
+ LIBSSH2_TRACE_AUTH,
+ "Computing RSA keys from private key data");
+
+ /* public key data */
+ if(_libssh2_get_bignum_bytes(decrypted, &n, &nlen)) {
+ _libssh2_error(session, LIBSSH2_ERROR_PROTO,
+ "RSA no n");
+ return -1;
+ }
+
+ if(_libssh2_get_bignum_bytes(decrypted, &e, &elen)) {
+ _libssh2_error(session, LIBSSH2_ERROR_PROTO,
+ "RSA no e");
+ return -1;
+ }
+
+ /* private key data */
+ if(_libssh2_get_bignum_bytes(decrypted, &d, &dlen)) {
+ _libssh2_error(session, LIBSSH2_ERROR_PROTO,
+ "RSA no d");
+ return -1;
+ }
+
+ if(_libssh2_get_bignum_bytes(decrypted, &coeff, &coefflen)) {
+ _libssh2_error(session, LIBSSH2_ERROR_PROTO,
+ "RSA no coeff");
+ return -1;
+ }
+
+ if(_libssh2_get_bignum_bytes(decrypted, &p, &plen)) {
+ _libssh2_error(session, LIBSSH2_ERROR_PROTO,
+ "RSA no p");
+ return -1;
+ }
+
+ if(_libssh2_get_bignum_bytes(decrypted, &q, &qlen)) {
+ _libssh2_error(session, LIBSSH2_ERROR_PROTO,
+ "RSA no q");
+ return -1;
+ }
+
+ if(_libssh2_get_string(decrypted, &comment, &commentlen)) {
+ _libssh2_error(session, LIBSSH2_ERROR_PROTO,
+ "RSA no comment");
+ return -1;
+ }
+
+ if((rc = _libssh2_rsa_new(&rsa, e, elen, n, nlen, d, dlen, p, plen,
+ q, qlen, NULL, 0, NULL, 0,
+ coeff, coefflen)) != 0) {
+ _libssh2_debug(session,
+ LIBSSH2_TRACE_AUTH,
+ "Could not create RSA private key");
+ goto fail;
+ }
+
+ if(rsa != NULL)
+ rc = _libssh2_rsa_new_additional_parameters(rsa);
+
+ if(rsa != NULL && pubkeydata != NULL && method != NULL) {
+ EVP_PKEY *pk = EVP_PKEY_new();
+ EVP_PKEY_set1_RSA(pk, rsa);
+
+ rc = gen_publickey_from_rsa_evp(session, method, method_len,
+ pubkeydata, pubkeydata_len,
+ pk);
+
+ if(pk)
+ EVP_PKEY_free(pk);
+ }
+
+ if(rsa_ctx != NULL)
+ *rsa_ctx = rsa;
+ else
+ RSA_free(rsa);
+
+ return rc;
+
+fail:
+
+ if(rsa != NULL)
+ RSA_free(rsa);
+
+ return _libssh2_error(session,
+ LIBSSH2_ERROR_ALLOC,
+ "Unable to allocate memory for private key data");
+}
+
+static int
+_libssh2_rsa_new_openssh_private(libssh2_rsa_ctx ** rsa,
+ LIBSSH2_SESSION * session,
+ const char *filename,
+ unsigned const char *passphrase)
+{
+ FILE *fp;
+ int rc;
+ unsigned char *buf = NULL;
+ struct string_buf *decrypted = NULL;
+
+ if(session == NULL) {
+ _libssh2_error(session, LIBSSH2_ERROR_PROTO,
+ "Session is required");
+ return -1;
+ }
+
+ _libssh2_init_if_needed();
+
+ fp = fopen(filename, "r");
+ if(!fp) {
+ _libssh2_error(session, LIBSSH2_ERROR_FILE,
+ "Unable to open OpenSSH RSA private key file");
+ return -1;
+ }
+
+ rc = _libssh2_openssh_pem_parse(session, passphrase, fp, &decrypted);
+ fclose(fp);
+ if(rc) {
+ return rc;
+ }
+
+ /* We have a new key file, now try and parse it using supported types */
+ rc = _libssh2_get_string(decrypted, &buf, NULL);
+
+ if(rc != 0 || buf == NULL) {
+ _libssh2_error(session, LIBSSH2_ERROR_PROTO,
+ "Public key type in decrypted key data not found");
+ return -1;
+ }
+
+ if(strcmp("ssh-rsa", (const char *)buf) == 0) {
+ rc = gen_publickey_from_rsa_openssh_priv_data(session, decrypted,
+ NULL, 0,
+ NULL, 0, rsa);
+ }
+ else {
+ rc = -1;
+ }
+
+ if(decrypted)
+ _libssh2_string_buf_free(session, decrypted);
+
+ return rc;
}
int
@@ -563,14 +1109,23 @@ _libssh2_rsa_new_private(libssh2_rsa_ctx ** rsa,
LIBSSH2_SESSION * session,
const char *filename, unsigned const char *passphrase)
{
+ int rc;
+
pem_read_bio_func read_rsa =
(pem_read_bio_func) &PEM_read_bio_RSAPrivateKey;
(void) session;
- _libssh2_init_if_needed ();
+ _libssh2_init_if_needed();
+
+ rc = read_private_key_from_file((void **) rsa, read_rsa,
+ filename, passphrase);
+
+ if(rc) {
+ rc = _libssh2_rsa_new_openssh_private(rsa, session,
+ filename, passphrase);
+ }
- return read_private_key_from_file((void **) rsa, read_rsa,
- filename, passphrase);
+ return rc;
}
#if LIBSSH2_DSA
@@ -580,14 +1135,275 @@ _libssh2_dsa_new_private_frommemory(libssh2_dsa_ctx ** dsa,
const char *filedata, size_t filedata_len,
unsigned const char *passphrase)
{
+ int rc;
+
pem_read_bio_func read_dsa =
(pem_read_bio_func) &PEM_read_bio_DSAPrivateKey;
(void) session;
_libssh2_init_if_needed();
- return read_private_key_from_memory((void **) dsa, read_dsa,
- filedata, filedata_len, passphrase);
+ rc = read_private_key_from_memory((void **)dsa, read_dsa,
+ filedata, filedata_len, passphrase);
+
+ if(rc) {
+ rc = read_openssh_private_key_from_memory((void **)dsa, session,
+ "ssh-dsa", filedata, filedata_len, passphrase);
+ }
+
+ return rc;
+}
+
+static unsigned char *
+gen_publickey_from_dsa(LIBSSH2_SESSION* session, DSA *dsa,
+ size_t *key_len)
+{
+ int p_bytes, q_bytes, g_bytes, k_bytes;
+ unsigned long len;
+ unsigned char *key;
+ unsigned char *p;
+
+ const BIGNUM * p_bn;
+ const BIGNUM * q;
+ const BIGNUM * g;
+ const BIGNUM * pub_key;
+#ifdef HAVE_OPAQUE_STRUCTS
+ DSA_get0_pqg(dsa, &p_bn, &q, &g);
+#else
+ p_bn = dsa->p;
+ q = dsa->q;
+ g = dsa->g;
+#endif
+
+#ifdef HAVE_OPAQUE_STRUCTS
+ DSA_get0_key(dsa, &pub_key, NULL);
+#else
+ pub_key = dsa->pub_key;
+#endif
+ p_bytes = BN_num_bytes(p_bn) + 1;
+ q_bytes = BN_num_bytes(q) + 1;
+ g_bytes = BN_num_bytes(g) + 1;
+ k_bytes = BN_num_bytes(pub_key) + 1;
+
+ /* Key form is "ssh-dss" + p + q + g + pub_key. */
+ len = 4 + 7 + 4 + p_bytes + 4 + q_bytes + 4 + g_bytes + 4 + k_bytes;
+
+ key = LIBSSH2_ALLOC(session, len);
+ if(key == NULL) {
+ return NULL;
+ }
+
+ /* Process key encoding. */
+ p = key;
+
+ _libssh2_htonu32(p, 7); /* Key type. */
+ p += 4;
+ memcpy(p, "ssh-dss", 7);
+ p += 7;
+
+ p = write_bn(p, p_bn, p_bytes);
+ p = write_bn(p, q, q_bytes);
+ p = write_bn(p, g, g_bytes);
+ p = write_bn(p, pub_key, k_bytes);
+
+ *key_len = (size_t)(p - key);
+ return key;
+}
+
+static int
+gen_publickey_from_dsa_evp(LIBSSH2_SESSION *session,
+ unsigned char **method,
+ size_t *method_len,
+ unsigned char **pubkeydata,
+ size_t *pubkeydata_len,
+ EVP_PKEY *pk)
+{
+ DSA* dsa = NULL;
+ unsigned char *key;
+ unsigned char *method_buf = NULL;
+ size_t key_len;
+
+ _libssh2_debug(session,
+ LIBSSH2_TRACE_AUTH,
+ "Computing public key from DSA private key envelop");
+
+ dsa = EVP_PKEY_get1_DSA(pk);
+ if(dsa == NULL) {
+ /* Assume memory allocation error... what else could it be ? */
+ goto __alloc_error;
+ }
+
+ method_buf = LIBSSH2_ALLOC(session, 7); /* ssh-dss. */
+ if(method_buf == NULL) {
+ goto __alloc_error;
+ }
+
+ key = gen_publickey_from_dsa(session, dsa, &key_len);
+ if(key == NULL) {
+ goto __alloc_error;
+ }
+ DSA_free(dsa);
+
+ memcpy(method_buf, "ssh-dss", 7);
+ *method = method_buf;
+ *method_len = 7;
+ *pubkeydata = key;
+ *pubkeydata_len = key_len;
+ return 0;
+
+ __alloc_error:
+ if(dsa != NULL) {
+ DSA_free(dsa);
+ }
+ if(method_buf != NULL) {
+ LIBSSH2_FREE(session, method_buf);
+ }
+
+ return _libssh2_error(session,
+ LIBSSH2_ERROR_ALLOC,
+ "Unable to allocate memory for private key data");
+}
+
+static int
+gen_publickey_from_dsa_openssh_priv_data(LIBSSH2_SESSION *session,
+ struct string_buf *decrypted,
+ unsigned char **method,
+ size_t *method_len,
+ unsigned char **pubkeydata,
+ size_t *pubkeydata_len,
+ libssh2_dsa_ctx **dsa_ctx)
+{
+ int rc = 0;
+ size_t plen, qlen, glen, pub_len, priv_len;
+ unsigned char *p, *q, *g, *pub_key, *priv_key;
+ DSA *dsa = NULL;
+
+ _libssh2_debug(session,
+ LIBSSH2_TRACE_AUTH,
+ "Computing DSA keys from private key data");
+
+ if(_libssh2_get_bignum_bytes(decrypted, &p, &plen)) {
+ _libssh2_error(session, LIBSSH2_ERROR_PROTO,
+ "DSA no p");
+ return -1;
+ }
+
+ if(_libssh2_get_bignum_bytes(decrypted, &q, &qlen)) {
+ _libssh2_error(session, LIBSSH2_ERROR_PROTO,
+ "DSA no q");
+ return -1;
+ }
+
+ if(_libssh2_get_bignum_bytes(decrypted, &g, &glen)) {
+ _libssh2_error(session, LIBSSH2_ERROR_PROTO,
+ "DSA no g");
+ return -1;
+ }
+
+ if(_libssh2_get_bignum_bytes(decrypted, &pub_key, &pub_len)) {
+ _libssh2_error(session, LIBSSH2_ERROR_PROTO,
+ "DSA no public key");
+ return -1;
+ }
+
+ if(_libssh2_get_bignum_bytes(decrypted, &priv_key, &priv_len)) {
+ _libssh2_error(session, LIBSSH2_ERROR_PROTO,
+ "DSA no private key");
+ return -1;
+ }
+
+ rc = _libssh2_dsa_new(&dsa, p, plen, q, qlen, g, glen, pub_key, pub_len,
+ priv_key, priv_len);
+ if(rc != 0) {
+ _libssh2_debug(session,
+ LIBSSH2_ERROR_PROTO,
+ "Could not create DSA private key");
+ goto fail;
+ }
+
+ if(dsa != NULL && pubkeydata != NULL && method != NULL) {
+ EVP_PKEY *pk = EVP_PKEY_new();
+ EVP_PKEY_set1_DSA(pk, dsa);
+
+ rc = gen_publickey_from_dsa_evp(session, method, method_len,
+ pubkeydata, pubkeydata_len,
+ pk);
+
+ if(pk)
+ EVP_PKEY_free(pk);
+ }
+
+ if(dsa_ctx != NULL)
+ *dsa_ctx = dsa;
+ else
+ DSA_free(dsa);
+
+ return rc;
+
+fail:
+
+ if(dsa != NULL)
+ DSA_free(dsa);
+
+ return _libssh2_error(session,
+ LIBSSH2_ERROR_ALLOC,
+ "Unable to allocate memory for private key data");
+}
+
+static int
+_libssh2_dsa_new_openssh_private(libssh2_dsa_ctx ** dsa,
+ LIBSSH2_SESSION * session,
+ const char *filename,
+ unsigned const char *passphrase)
+{
+ FILE *fp;
+ int rc;
+ unsigned char *buf = NULL;
+ struct string_buf *decrypted = NULL;
+
+ if(session == NULL) {
+ _libssh2_error(session, LIBSSH2_ERROR_PROTO,
+ "Session is required");
+ return -1;
+ }
+
+ _libssh2_init_if_needed();
+
+ fp = fopen(filename, "r");
+ if(!fp) {
+ _libssh2_error(session, LIBSSH2_ERROR_FILE,
+ "Unable to open OpenSSH DSA private key file");
+ return -1;
+ }
+
+ rc = _libssh2_openssh_pem_parse(session, passphrase, fp, &decrypted);
+ fclose(fp);
+ if(rc) {
+ return rc;
+ }
+
+ /* We have a new key file, now try and parse it using supported types */
+ rc = _libssh2_get_string(decrypted, &buf, NULL);
+
+ if(rc != 0 || buf == NULL) {
+ _libssh2_error(session, LIBSSH2_ERROR_PROTO,
+ "Public key type in decrypted key data not found");
+ return -1;
+ }
+
+ if(strcmp("ssh-dss", (const char *)buf) == 0) {
+ rc = gen_publickey_from_dsa_openssh_priv_data(session, decrypted,
+ NULL, 0,
+ NULL, 0, dsa);
+ }
+ else {
+ rc = -1;
+ }
+
+ if(decrypted)
+ _libssh2_string_buf_free(session, decrypted);
+
+ return rc;
}
int
@@ -595,17 +1411,438 @@ _libssh2_dsa_new_private(libssh2_dsa_ctx ** dsa,
LIBSSH2_SESSION * session,
const char *filename, unsigned const char *passphrase)
{
+ int rc;
+
pem_read_bio_func read_dsa =
(pem_read_bio_func) &PEM_read_bio_DSAPrivateKey;
(void) session;
- _libssh2_init_if_needed ();
+ _libssh2_init_if_needed();
+
+ rc = read_private_key_from_file((void **) dsa, read_dsa,
+ filename, passphrase);
+
+ if(rc) {
+ rc = _libssh2_dsa_new_openssh_private(dsa, session,
+ filename, passphrase);
+ }
- return read_private_key_from_file((void **) dsa, read_dsa,
- filename, passphrase);
+ return rc;
}
+
#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)
+{
+ int rc;
+
+ pem_read_bio_func read_ec =
+ (pem_read_bio_func) &PEM_read_bio_ECPrivateKey;
+ (void) session;
+
+ _libssh2_init_if_needed();
+
+ rc = read_private_key_from_memory((void **) ec_ctx, read_ec,
+ filedata, filedata_len, passphrase);
+
+ if(rc) {
+ rc = read_openssh_private_key_from_memory((void **)ec_ctx, session,
+ "ssh-ecdsa", filedata,
+ filedata_len, passphrase);
+ }
+
+ return rc;
+}
+
+#endif /* LIBSSH2_ECDSA */
+
+
+#if LIBSSH2_ED25519
+
+int
+_libssh2_curve25519_new(LIBSSH2_SESSION *session, libssh2_x25519_ctx **out_ctx,
+ unsigned char **out_public_key,
+ unsigned char **out_private_key)
+{
+ EVP_PKEY *key = NULL;
+ EVP_PKEY_CTX *pctx = NULL;
+ PKCS8_PRIV_KEY_INFO *info = NULL;
+ ASN1_OCTET_STRING *oct = NULL;
+ X509_PUBKEY *pubkey = NULL;
+ libssh2_ed25519_ctx *ctx = NULL;
+ const unsigned char *pkcs, *priv, *pub;
+ int privLen, pubLen, pkcsLen;
+ int rc = -1;
+
+ pctx = EVP_PKEY_CTX_new_id(EVP_PKEY_X25519, NULL);
+ if(pctx == NULL)
+ return -1;
+
+ EVP_PKEY_keygen_init(pctx);
+ EVP_PKEY_keygen(pctx, &key);
+ info = EVP_PKEY2PKCS8(key);
+
+ if(info == NULL || !PKCS8_pkey_get0(NULL, &pkcs, &pkcsLen, NULL, info))
+ goto cleanExit;
+
+ oct = d2i_ASN1_OCTET_STRING(NULL, &pkcs, pkcsLen);
+ if(oct == NULL) {
+ goto cleanExit;
+ }
+
+ priv = ASN1_STRING_get0_data(oct);
+ privLen = ASN1_STRING_length(oct);
+
+ if(privLen != LIBSSH2_ED25519_KEY_LEN)
+ goto cleanExit;
+
+ pubkey = X509_PUBKEY_new();
+ if(pubkey == NULL || !X509_PUBKEY_set(&pubkey, key))
+ goto cleanExit;
+
+ if(!X509_PUBKEY_get0_param(NULL, &pub, &pubLen, NULL, pubkey))
+ goto cleanExit;
+
+ if(pubLen != LIBSSH2_ED25519_KEY_LEN)
+ goto cleanExit;
+
+ if(out_private_key != NULL) {
+ *out_private_key = LIBSSH2_ALLOC(session, LIBSSH2_ED25519_KEY_LEN);
+ if(*out_private_key == NULL)
+ goto cleanExit;
+
+ memcpy(*out_private_key, priv, LIBSSH2_ED25519_KEY_LEN);
+ }
+
+ if(out_public_key != NULL) {
+ *out_public_key = LIBSSH2_ALLOC(session, LIBSSH2_ED25519_KEY_LEN);
+ if(*out_public_key == NULL)
+ goto cleanExit;
+
+ memcpy(*out_public_key, pub, LIBSSH2_ED25519_KEY_LEN);
+ }
+
+ if(out_ctx != NULL) {
+ ctx = malloc(sizeof(libssh2_x25519_ctx));
+ if(ctx == NULL)
+ goto cleanExit;
+
+ ctx->private_key =
+ EVP_PKEY_new_raw_private_key(EVP_PKEY_X25519, NULL,
+ (const unsigned char *)priv,
+ LIBSSH2_ED25519_KEY_LEN);
+
+ ctx->public_key =
+ EVP_PKEY_new_raw_public_key(EVP_PKEY_X25519, NULL,
+ (const unsigned char *)pub,
+ LIBSSH2_ED25519_KEY_LEN);
+
+ if(ctx->public_key == NULL || ctx->private_key == NULL) {
+ _libssh2_x25519_free(ctx);
+ goto cleanExit;
+ }
+
+ *out_ctx = ctx;
+ }
+
+ /* success */
+ rc = 0;
+
+cleanExit:
+
+ if(info)
+ PKCS8_PRIV_KEY_INFO_free(info);
+ if(pctx)
+ EVP_PKEY_CTX_free(pctx);
+ if(oct)
+ ASN1_OCTET_STRING_free(oct);
+ if(pubkey)
+ X509_PUBKEY_free(pubkey);
+ if(key)
+ EVP_PKEY_free(key);
+
+ return rc;
+}
+
+static int
+gen_publickey_from_ed25519_openssh_priv_data(LIBSSH2_SESSION *session,
+ struct string_buf *decrypted,
+ unsigned char **method,
+ size_t *method_len,
+ unsigned char **pubkeydata,
+ size_t *pubkeydata_len,
+ libssh2_ed25519_ctx **out_ctx)
+{
+ libssh2_ed25519_ctx *ctx = NULL;
+ unsigned char *method_buf = NULL;
+ unsigned char *key = NULL;
+ int i, ret = 0;
+ unsigned char *pub_key, *priv_key, *buf;
+ size_t key_len = 0, tmp_len = 0;
+ unsigned char *p;
+
+ _libssh2_debug(session,
+ LIBSSH2_TRACE_AUTH,
+ "Computing ED25519 keys from private key data");
+
+ if(_libssh2_get_string(decrypted, &pub_key, &tmp_len) ||
+ tmp_len != LIBSSH2_ED25519_KEY_LEN) {
+ _libssh2_error(session, LIBSSH2_ERROR_PROTO,
+ "Wrong public key length");
+ return -1;
+ }
+
+ if(_libssh2_get_string(decrypted, &priv_key, &tmp_len) ||
+ tmp_len != LIBSSH2_ED25519_PRIVATE_KEY_LEN) {
+ _libssh2_error(session, LIBSSH2_ERROR_PROTO,
+ "Wrong private key length");
+ ret = -1;
+ goto clean_exit;
+ }
+
+ ctx = _libssh2_ed25519_new_ctx();
+ if(ctx == NULL) {
+ _libssh2_error(session, LIBSSH2_ERROR_ALLOC,
+ "Unable to allocate memory for ed25519 key");
+ ret = -1;
+ goto clean_exit;
+ }
+
+ /* first 32 bytes of priv_key is the private key, the last 32 bytes are
+ the public key */
+ ctx->private_key =
+ EVP_PKEY_new_raw_private_key(EVP_PKEY_ED25519, NULL,
+ (const unsigned char *)priv_key,
+ LIBSSH2_ED25519_KEY_LEN);
+
+ ctx->public_key =
+ EVP_PKEY_new_raw_public_key(EVP_PKEY_ED25519, NULL,
+ (const unsigned char *)pub_key,
+ LIBSSH2_ED25519_KEY_LEN);
+
+ /* comment */
+ if(_libssh2_get_string(decrypted, &buf, &tmp_len)) {
+ _libssh2_error(session, LIBSSH2_ERROR_PROTO,
+ "Unable to read comment");
+ ret = -1;
+ goto clean_exit;
+ }
+
+ if(tmp_len > 0) {
+ unsigned char *comment = LIBSSH2_CALLOC(session, tmp_len + 1);
+ if(comment != NULL) {
+ memcpy(comment, buf, tmp_len);
+ memcpy(comment + tmp_len, "\0", 1);
+
+ _libssh2_debug(session, LIBSSH2_TRACE_AUTH, "Key comment: %s",
+ comment);
+
+ LIBSSH2_FREE(session, comment);
+ }
+ }
+
+ /* Padding */
+ i = 1;
+ while(decrypted->dataptr < decrypted->data + decrypted->len) {
+ if(*decrypted->dataptr != i) {
+ _libssh2_error(session, LIBSSH2_ERROR_PROTO,
+ "Wrong padding");
+ ret = -1;
+ goto clean_exit;
+ }
+ i++;
+ decrypted->dataptr++;
+ }
+
+ if(ret == 0) {
+ _libssh2_debug(session,
+ LIBSSH2_TRACE_AUTH,
+ "Computing public key from ED25519 "
+ "private key envelop");
+
+ method_buf = LIBSSH2_ALLOC(session, 11); /* ssh-ed25519. */
+ if(method_buf == NULL) {
+ goto clean_exit;
+ }
+
+ /* Key form is: type_len(4) + type(11) + pub_key_len(4) +
+ pub_key(32). */
+ key_len = LIBSSH2_ED25519_KEY_LEN + 19;
+ key = LIBSSH2_CALLOC(session, key_len);
+ if(key == NULL) {
+ goto clean_exit;
+ }
+
+ p = key;
+
+ _libssh2_store_str(&p, "ssh-ed25519", 11);
+ _libssh2_store_str(&p, (const char *)pub_key, LIBSSH2_ED25519_KEY_LEN);
+
+ memcpy(method_buf, "ssh-ed25519", 11);
+
+ if(method != NULL)
+ *method = method_buf;
+ else
+ LIBSSH2_FREE(session, method_buf);
+
+ if(method_len != NULL)
+ *method_len = 11;
+
+ if(pubkeydata != NULL)
+ *pubkeydata = key;
+ else
+ LIBSSH2_FREE(session, key);
+
+ if(pubkeydata_len != NULL)
+ *pubkeydata_len = key_len;
+
+ if(out_ctx != NULL)
+ *out_ctx = ctx;
+ else if(ctx != NULL)
+ _libssh2_ed25519_free(ctx);
+
+ return 0;
+ }
+
+clean_exit:
+
+ if(ctx)
+ _libssh2_ed25519_free(ctx);
+
+ if(method_buf)
+ LIBSSH2_FREE(session, method_buf);
+
+ if(key)
+ LIBSSH2_FREE(session, key);
+
+ return -1;
+}
+
+int
+_libssh2_ed25519_new_private(libssh2_ed25519_ctx ** ed_ctx,
+ LIBSSH2_SESSION * session,
+ const char *filename, const uint8_t *passphrase)
+{
+ int rc;
+ FILE *fp;
+ unsigned char *buf;
+ struct string_buf *decrypted = NULL;
+ libssh2_ed25519_ctx *ctx = NULL;
+
+ if(session == NULL) {
+ _libssh2_error(session, LIBSSH2_ERROR_PROTO,
+ "Session is required");
+ return -1;
+ }
+
+ _libssh2_init_if_needed();
+
+ fp = fopen(filename, "r");
+ if(!fp) {
+ _libssh2_error(session, LIBSSH2_ERROR_FILE,
+ "Unable to open ED25519 private key file");
+ return -1;
+ }
+
+ rc = _libssh2_openssh_pem_parse(session, passphrase, fp, &decrypted);
+ fclose(fp);
+ if(rc) {
+ return rc;
+ }
+
+ /* We have a new key file, now try and parse it using supported types */
+ rc = _libssh2_get_string(decrypted, &buf, NULL);
+
+ if(rc != 0 || buf == NULL) {
+ _libssh2_error(session, LIBSSH2_ERROR_PROTO,
+ "Public key type in decrypted key data not found");
+ return -1;
+ }
+
+ if(strcmp("ssh-ed25519", (const char *)buf) == 0) {
+ rc = gen_publickey_from_ed25519_openssh_priv_data(session,
+ decrypted,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ &ctx);
+ }
+ else {
+ rc = -1;
+ }
+
+ if(decrypted)
+ _libssh2_string_buf_free(session, decrypted);
+
+ if(rc == 0) {
+ if(ed_ctx != NULL)
+ *ed_ctx = ctx;
+ else if(ctx != NULL)
+ _libssh2_ed25519_free(ctx);
+ }
+
+ return rc;
+}
+
+int
+_libssh2_ed25519_new_private_frommemory(libssh2_ed25519_ctx ** ed_ctx,
+ LIBSSH2_SESSION * session,
+ const char *filedata,
+ size_t filedata_len,
+ unsigned const char *passphrase)
+{
+ return read_openssh_private_key_from_memory((void **)ed_ctx, session,
+ "ssh-ed25519",
+ filedata, filedata_len,
+ passphrase);
+}
+
+int
+_libssh2_ed25519_new_public(libssh2_ed25519_ctx ** ed_ctx,
+ LIBSSH2_SESSION * session,
+ const unsigned char *raw_pub_key,
+ const uint8_t key_len)
+{
+ libssh2_ed25519_ctx *ctx = NULL;
+ EVP_PKEY *public_key = NULL;
+
+ if(ed_ctx == NULL)
+ return -1;
+
+ public_key =
+ EVP_PKEY_new_raw_public_key(EVP_PKEY_ED25519, NULL,
+ (const unsigned char *)raw_pub_key,
+ key_len);
+ if(public_key == NULL) {
+ return _libssh2_error(session, LIBSSH2_ERROR_PROTO,
+ "could not create ED25519 public key");
+ }
+
+ ctx = _libssh2_ed25519_new_ctx();
+ if(ctx == NULL) {
+ return _libssh2_error(session, LIBSSH2_ERROR_ALLOC,
+ "could not alloc public/private key");
+ }
+
+ ctx->public_key = public_key;
+
+ if(ed_ctx != NULL)
+ *ed_ctx = ctx;
+ else if(ctx != NULL)
+ _libssh2_ed25519_free(ctx);
+
+ return 0;
+}
+
+#endif /* LIBSSH2_ED25519 */
+
int
_libssh2_rsa_sha1_sign(LIBSSH2_SESSION * session,
libssh2_rsa_ctx * rsactx,
@@ -620,13 +1857,13 @@ _libssh2_rsa_sha1_sign(LIBSSH2_SESSION * session,
sig_len = RSA_size(rsactx);
sig = LIBSSH2_ALLOC(session, sig_len);
- if (!sig) {
+ if(!sig) {
return -1;
}
ret = RSA_sign(NID_sha1, hash, hash_len, sig, &sig_len, rsactx);
- if (!ret) {
+ if(!ret) {
LIBSSH2_FREE(session, sig);
return -1;
}
@@ -650,7 +1887,7 @@ _libssh2_dsa_sha1_sign(libssh2_dsa_ctx * dsactx,
(void) hash_len;
sig = DSA_do_sign(hash, SHA_DIGEST_LENGTH, dsactx);
- if (!sig) {
+ if(!sig) {
return -1;
}
@@ -661,12 +1898,12 @@ _libssh2_dsa_sha1_sign(libssh2_dsa_ctx * dsactx,
s = sig->s;
#endif
r_len = BN_num_bytes(r);
- if (r_len < 1 || r_len > 20) {
+ if(r_len < 1 || r_len > 20) {
DSA_SIG_free(sig);
return -1;
}
s_len = BN_num_bytes(s);
- if (s_len < 1 || s_len > 20) {
+ if(s_len < 1 || s_len > 20) {
DSA_SIG_free(sig);
return -1;
}
@@ -682,16 +1919,79 @@ _libssh2_dsa_sha1_sign(libssh2_dsa_ctx * dsactx,
}
#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;
+#ifdef 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)
{
#ifdef HAVE_OPAQUE_STRUCTS
*ctx = EVP_MD_CTX_new();
- if (*ctx == NULL)
+ if(*ctx == NULL)
return 0;
- if (EVP_DigestInit(*ctx, EVP_get_digestbyname("sha1")))
+ if(EVP_DigestInit(*ctx, EVP_get_digestbyname("sha1")))
return 1;
EVP_MD_CTX_free(*ctx);
@@ -711,10 +2011,10 @@ _libssh2_sha1(const unsigned char *message, unsigned long len,
#ifdef HAVE_OPAQUE_STRUCTS
EVP_MD_CTX * ctx = EVP_MD_CTX_new();
- if (ctx == NULL)
+ if(ctx == NULL)
return 1; /* error */
- if (EVP_DigestInit(ctx, EVP_get_digestbyname("sha1"))) {
+ if(EVP_DigestInit(ctx, EVP_get_digestbyname("sha1"))) {
EVP_DigestUpdate(ctx, message, len);
EVP_DigestFinal(ctx, out, NULL);
EVP_MD_CTX_free(ctx);
@@ -725,7 +2025,7 @@ _libssh2_sha1(const unsigned char *message, unsigned long len,
EVP_MD_CTX ctx;
EVP_MD_CTX_init(&ctx);
- if (EVP_DigestInit(&ctx, EVP_get_digestbyname("sha1"))) {
+ if(EVP_DigestInit(&ctx, EVP_get_digestbyname("sha1"))) {
EVP_DigestUpdate(&ctx, message, len);
EVP_DigestFinal(&ctx, out, NULL);
return 0; /* success */
@@ -740,10 +2040,10 @@ _libssh2_sha256_init(libssh2_sha256_ctx *ctx)
#ifdef HAVE_OPAQUE_STRUCTS
*ctx = EVP_MD_CTX_new();
- if (*ctx == NULL)
+ if(*ctx == NULL)
return 0;
- if (EVP_DigestInit(*ctx, EVP_get_digestbyname("sha256")))
+ if(EVP_DigestInit(*ctx, EVP_get_digestbyname("sha256")))
return 1;
EVP_MD_CTX_free(*ctx);
@@ -763,7 +2063,7 @@ _libssh2_sha256(const unsigned char *message, unsigned long len,
#ifdef HAVE_OPAQUE_STRUCTS
EVP_MD_CTX * ctx = EVP_MD_CTX_new();
- if (ctx == NULL)
+ if(ctx == NULL)
return 1; /* error */
if(EVP_DigestInit(ctx, EVP_get_digestbyname("sha256"))) {
@@ -787,15 +2087,15 @@ _libssh2_sha256(const unsigned char *message, unsigned long len,
}
int
-_libssh2_md5_init(libssh2_md5_ctx *ctx)
+_libssh2_sha384_init(libssh2_sha384_ctx *ctx)
{
#ifdef HAVE_OPAQUE_STRUCTS
*ctx = EVP_MD_CTX_new();
- if (*ctx == NULL)
+ 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,237 +2104,804 @@ _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 */
}
-static unsigned char *
-gen_publickey_from_rsa(LIBSSH2_SESSION *session, RSA *rsa,
- size_t *key_len)
+int
+_libssh2_sha512_init(libssh2_sha512_ctx *ctx)
{
- int e_bytes, n_bytes;
- unsigned long len;
- unsigned char* key;
- unsigned char* p;
- const BIGNUM * e;
- const BIGNUM * n;
#ifdef HAVE_OPAQUE_STRUCTS
- RSA_get0_key(rsa, &n, &e, NULL);
-#else
- e = rsa->e;
- n = rsa->n;
-#endif
- e_bytes = BN_num_bytes(e) + 1;
- n_bytes = BN_num_bytes(n) + 1;
-
- /* Key form is "ssh-rsa" + e + n. */
- len = 4 + 7 + 4 + e_bytes + 4 + n_bytes;
-
- key = LIBSSH2_ALLOC(session, len);
- if (key == NULL) {
- return NULL;
- }
+ *ctx = EVP_MD_CTX_new();
- /* Process key encoding. */
- p = key;
+ if(*ctx == NULL)
+ return 0;
- _libssh2_htonu32(p, 7); /* Key type. */
- p += 4;
- memcpy(p, "ssh-rsa", 7);
- p += 7;
+ if(EVP_DigestInit(*ctx, EVP_get_digestbyname("sha512")))
+ return 1;
- p = write_bn(p, e, e_bytes);
- p = write_bn(p, n, n_bytes);
+ EVP_MD_CTX_free(*ctx);
+ *ctx = NULL;
- *key_len = (size_t)(p - key);
- return key;
+ return 0;
+#else
+ EVP_MD_CTX_init(ctx);
+ return EVP_DigestInit(ctx, EVP_get_digestbyname("sha512"));
+#endif
}
-#if LIBSSH2_DSA
-static unsigned char *
-gen_publickey_from_dsa(LIBSSH2_SESSION* session, DSA *dsa,
- size_t *key_len)
+int
+_libssh2_sha512(const unsigned char *message, unsigned long len,
+ unsigned char *out)
{
- int p_bytes, q_bytes, g_bytes, k_bytes;
- unsigned long len;
- unsigned char* key;
- unsigned char* p;
-
- const BIGNUM * p_bn;
- const BIGNUM * q;
- const BIGNUM * g;
- const BIGNUM * pub_key;
#ifdef HAVE_OPAQUE_STRUCTS
- DSA_get0_pqg(dsa, &p_bn, &q, &g);
+ 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
- p_bn = dsa->p;
- q = dsa->q;
- g = dsa->g;
+ 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
- DSA_get0_key(dsa, &pub_key, NULL);
+ *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
- pub_key = dsa->pub_key;
+ EVP_MD_CTX_init(ctx);
+ return EVP_DigestInit(ctx, EVP_get_digestbyname("md5"));
#endif
- p_bytes = BN_num_bytes(p_bn) + 1;
- q_bytes = BN_num_bytes(q) + 1;
- g_bytes = BN_num_bytes(g) + 1;
- k_bytes = BN_num_bytes(pub_key) + 1;
+}
- /* Key form is "ssh-dss" + p + q + g + pub_key. */
- len = 4 + 7 + 4 + p_bytes + 4 + q_bytes + 4 + g_bytes + 4 + k_bytes;
+#if LIBSSH2_ECDSA
- key = LIBSSH2_ALLOC(session, len);
- if (key == NULL) {
- return NULL;
+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;
- _libssh2_htonu32(p, 7); /* Key type. */
- p += 4;
- memcpy(p, "ssh-dss", 7);
- p += 7;
+ /* Key type */
+ _libssh2_store_str(&p, (const char *)method_buf, 19);
- p = write_bn(p, p_bn, p_bytes);
- p = write_bn(p, q, q_bytes);
- p = write_bn(p, g, g_bytes);
- p = write_bn(p, pub_key, k_bytes);
+ /* Name domain */
+ _libssh2_store_str(&p, (const char *)method_buf + 11, 8);
- *key_len = (size_t)(p - key);
- return key;
+ /* 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;
}
-#endif /* LIBSSH_DSA */
static int
-gen_publickey_from_rsa_evp(LIBSSH2_SESSION *session,
- unsigned char **method,
- size_t *method_len,
- unsigned char **pubkeydata,
- size_t *pubkeydata_len,
- EVP_PKEY *pk)
+gen_publickey_from_ecdsa_openssh_priv_data(LIBSSH2_SESSION *session,
+ libssh2_curve_type curve_type,
+ struct string_buf *decrypted,
+ unsigned char **method,
+ size_t *method_len,
+ unsigned char **pubkeydata,
+ size_t *pubkeydata_len,
+ libssh2_ecdsa_ctx **ec_ctx)
{
- RSA* rsa = NULL;
- unsigned char* key;
- unsigned char* method_buf = NULL;
- size_t key_len;
+ int rc = 0;
+ size_t curvelen, exponentlen, pointlen;
+ unsigned char *curve, *exponent, *point_buf;
+ EC_KEY *ec_key = NULL;
+ BIGNUM *bn_exponent;
_libssh2_debug(session,
LIBSSH2_TRACE_AUTH,
- "Computing public key from RSA private key envelop");
+ "Computing ECDSA keys from private key data");
- rsa = EVP_PKEY_get1_RSA(pk);
- if (rsa == NULL) {
- /* Assume memory allocation error... what else could it be ? */
- goto __alloc_error;
+ if(_libssh2_get_string(decrypted, &curve, &curvelen) ||
+ curvelen == 0) {
+ _libssh2_error(session, LIBSSH2_ERROR_PROTO,
+ "ECDSA no curve");
+ return -1;
}
- method_buf = LIBSSH2_ALLOC(session, 7); /* ssh-rsa. */
- if (method_buf == NULL) {
- goto __alloc_error;
+ if(_libssh2_get_string(decrypted, &point_buf, &pointlen)) {
+ _libssh2_error(session, LIBSSH2_ERROR_PROTO,
+ "ECDSA no point");
+ return -1;
}
- key = gen_publickey_from_rsa(session, rsa, &key_len);
- if (key == NULL) {
- goto __alloc_error;
+ if(_libssh2_get_bignum_bytes(decrypted, &exponent, &exponentlen)) {
+ _libssh2_error(session, LIBSSH2_ERROR_PROTO,
+ "ECDSA no exponent");
+ return -1;
}
- RSA_free(rsa);
- memcpy(method_buf, "ssh-rsa", 7);
- *method = method_buf;
- *method_len = 7;
- *pubkeydata = key;
- *pubkeydata_len = key_len;
- return 0;
+ if((rc = _libssh2_ecdsa_curve_name_with_octal_new(&ec_key, point_buf,
+ pointlen, curve_type)) != 0) {
+ _libssh2_error(session, LIBSSH2_ERROR_PROTO,
+ "ECDSA could not create key");
+ goto fail;
+ }
- __alloc_error:
- if (rsa != NULL) {
- RSA_free(rsa);
+ bn_exponent = BN_new();
+ if(bn_exponent == NULL) {
+ rc = -1;
+ goto fail;
}
- if (method_buf != NULL) {
- LIBSSH2_FREE(session, method_buf);
+
+ BN_bin2bn(exponent, exponentlen, bn_exponent);
+ rc = (EC_KEY_set_private_key(ec_key, bn_exponent) != 1);
+
+ if(rc == 0 && ec_key != NULL && pubkeydata != NULL && method != NULL) {
+ EVP_PKEY *pk = EVP_PKEY_new();
+ EVP_PKEY_set1_EC_KEY(pk, ec_key);
+
+ rc = gen_publickey_from_ec_evp(session, method, method_len,
+ pubkeydata, pubkeydata_len,
+ pk);
+
+ if(pk)
+ EVP_PKEY_free(pk);
}
+ if(ec_ctx != NULL)
+ *ec_ctx = ec_key;
+ else
+ EC_KEY_free(ec_key);
+
+ return rc;
+
+fail:
+
+ if(ec_key != NULL)
+ EC_KEY_free(ec_key);
+
return _libssh2_error(session,
LIBSSH2_ERROR_ALLOC,
"Unable to allocate memory for private key data");
+
+
}
-#if LIBSSH2_DSA
static int
-gen_publickey_from_dsa_evp(LIBSSH2_SESSION *session,
- unsigned char **method,
- size_t *method_len,
- unsigned char **pubkeydata,
- size_t *pubkeydata_len,
- EVP_PKEY *pk)
+_libssh2_ecdsa_new_openssh_private(libssh2_ecdsa_ctx ** ec_ctx,
+ LIBSSH2_SESSION * session,
+ const char *filename,
+ unsigned const char *passphrase)
{
- DSA* dsa = NULL;
- unsigned char* key;
- unsigned char* method_buf = NULL;
- size_t key_len;
+ FILE *fp;
+ int rc;
+ unsigned char *buf = NULL;
+ libssh2_curve_type type;
+ struct string_buf *decrypted = NULL;
+
+ if(session == NULL) {
+ _libssh2_error(session, LIBSSH2_ERROR_PROTO,
+ "Session is required");
+ return -1;
+ }
- _libssh2_debug(session,
- LIBSSH2_TRACE_AUTH,
- "Computing public key from DSA private key envelop");
+ _libssh2_init_if_needed();
- dsa = EVP_PKEY_get1_DSA(pk);
- if (dsa == NULL) {
- /* Assume memory allocation error... what else could it be ? */
- goto __alloc_error;
+ fp = fopen(filename, "r");
+ if(!fp) {
+ _libssh2_error(session, LIBSSH2_ERROR_FILE,
+ "Unable to open OpenSSH ECDSA private key file");
+ return -1;
}
- method_buf = LIBSSH2_ALLOC(session, 7); /* ssh-dss. */
- if (method_buf == NULL) {
- goto __alloc_error;
+ rc = _libssh2_openssh_pem_parse(session, passphrase, fp, &decrypted);
+ fclose(fp);
+ if(rc) {
+ return rc;
}
- key = gen_publickey_from_dsa(session, dsa, &key_len);
- if (key == NULL) {
- goto __alloc_error;
+ /* We have a new key file, now try and parse it using supported types */
+ rc = _libssh2_get_string(decrypted, &buf, NULL);
+
+ if(rc != 0 || buf == NULL) {
+ _libssh2_error(session, LIBSSH2_ERROR_PROTO,
+ "Public key type in decrypted key data not found");
+ return -1;
}
- DSA_free(dsa);
- memcpy(method_buf, "ssh-dss", 7);
- *method = method_buf;
- *method_len = 7;
- *pubkeydata = key;
- *pubkeydata_len = key_len;
- return 0;
+ rc = _libssh2_ecdsa_curve_type_from_name((const char *)buf, &type);
- __alloc_error:
- if (dsa != NULL) {
- DSA_free(dsa);
+ if(rc == 0) {
+ rc = gen_publickey_from_ecdsa_openssh_priv_data(session, type,
+ decrypted, NULL, 0,
+ NULL, 0, ec_ctx);
}
- if (method_buf != NULL) {
- LIBSSH2_FREE(session, method_buf);
+ else {
+ rc = -1;
}
- return _libssh2_error(session,
- LIBSSH2_ERROR_ALLOC,
- "Unable to allocate memory for private key data");
+ if(decrypted)
+ _libssh2_string_buf_free(session, decrypted);
+
+ return rc;
+}
+
+int
+_libssh2_ecdsa_new_private(libssh2_ecdsa_ctx ** ec_ctx,
+ LIBSSH2_SESSION * session,
+ const char *filename, unsigned const char *passphrase)
+{
+ int rc;
+
+ pem_read_bio_func read_ec = (pem_read_bio_func) &PEM_read_bio_ECPrivateKey;
+ (void) session;
+
+ _libssh2_init_if_needed();
+
+ rc = read_private_key_from_file((void **) ec_ctx, read_ec,
+ filename, passphrase);
+
+ if(rc) {
+ return _libssh2_ecdsa_new_openssh_private(ec_ctx, session,
+ filename, passphrase);
+ }
+
+ return rc;
+}
+
+/*
+ * _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_SESSION *session,
+ _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 = LIBSSH2_ALLOC(session, 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 = NULL;
+ 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 */
+
+#if LIBSSH2_ED25519
+
+int
+_libssh2_ed25519_sign(libssh2_ed25519_ctx *ctx, LIBSSH2_SESSION *session,
+ uint8_t **out_sig, size_t *out_sig_len,
+ const uint8_t *message, size_t message_len)
+{
+ int rc = -1;
+ EVP_MD_CTX *md_ctx = EVP_MD_CTX_new();
+ size_t sig_len = 0;
+ unsigned char *sig = NULL;
+
+ if(md_ctx != NULL) {
+ if(EVP_DigestSignInit(md_ctx, NULL, NULL, NULL, ctx->private_key) != 1)
+ goto clean_exit;
+ if(EVP_DigestSign(md_ctx, NULL, &sig_len, message, message_len) != 1)
+ goto clean_exit;
+
+ if(sig_len != LIBSSH2_ED25519_SIG_LEN)
+ goto clean_exit;
+
+ sig = LIBSSH2_CALLOC(session, sig_len);
+ if(sig == NULL)
+ goto clean_exit;
+
+ rc = EVP_DigestSign(md_ctx, sig, &sig_len, message, message_len);
+ }
+
+ if(rc == 1) {
+ *out_sig = sig;
+ *out_sig_len = sig_len;
+ }
+ else {
+ *out_sig_len = 0;
+ *out_sig = NULL;
+ LIBSSH2_FREE(session, sig);
+ }
+
+clean_exit:
+
+ if(md_ctx)
+ EVP_MD_CTX_free(md_ctx);
+
+ return (rc == 1 ? 0 : -1);
+}
+
+int
+_libssh2_curve25519_gen_k(_libssh2_bn **k,
+ uint8_t private_key[LIBSSH2_ED25519_KEY_LEN],
+ uint8_t server_public_key[LIBSSH2_ED25519_KEY_LEN])
+{
+ int rc = -1;
+ unsigned char out_shared_key[LIBSSH2_ED25519_KEY_LEN];
+ EVP_PKEY *peer_key = NULL, *server_key = NULL;
+ EVP_PKEY_CTX *server_key_ctx = NULL;
+ BN_CTX *bn_ctx = NULL;
+ size_t out_len = 0;
+
+ if(k == NULL || *k == NULL)
+ return -1;
+
+ bn_ctx = BN_CTX_new();
+ if(bn_ctx == NULL)
+ return -1;
+
+ peer_key = EVP_PKEY_new_raw_public_key(EVP_PKEY_X25519, NULL,
+ server_public_key,
+ LIBSSH2_ED25519_KEY_LEN);
+
+ server_key = EVP_PKEY_new_raw_private_key(EVP_PKEY_X25519, NULL,
+ private_key,
+ LIBSSH2_ED25519_KEY_LEN);
+
+ if(peer_key == NULL || server_key == NULL) {
+ goto cleanExit;
+ }
+
+ server_key_ctx = EVP_PKEY_CTX_new(server_key, NULL);
+ if(server_key_ctx == NULL) {
+ goto cleanExit;
+ }
+
+ rc = EVP_PKEY_derive_init(server_key_ctx);
+ if(rc <= 0) goto cleanExit;
+
+ rc = EVP_PKEY_derive_set_peer(server_key_ctx, peer_key);
+ if(rc <= 0) goto cleanExit;
+
+ rc = EVP_PKEY_derive(server_key_ctx, NULL, &out_len);
+ if(rc <= 0) goto cleanExit;
+
+ if(out_len != LIBSSH2_ED25519_KEY_LEN) {
+ rc = -1;
+ goto cleanExit;
+ }
+
+ rc = EVP_PKEY_derive(server_key_ctx, out_shared_key, &out_len);
+
+ if(rc == 1 && out_len == LIBSSH2_ED25519_KEY_LEN) {
+ BN_bin2bn(out_shared_key, LIBSSH2_ED25519_KEY_LEN, *k);
+ }
+ else {
+ rc = -1;
+ }
+
+cleanExit:
+
+ if(server_key_ctx)
+ EVP_PKEY_CTX_free(server_key_ctx);
+ if(peer_key)
+ EVP_PKEY_free(peer_key);
+ if(server_key)
+ EVP_PKEY_free(server_key);
+ if(bn_ctx != NULL)
+ BN_CTX_free(bn_ctx);
+
+ return (rc == 1) ? 0 : -1;
+}
+
+
+int
+_libssh2_ed25519_verify(libssh2_ed25519_ctx *ctx, const uint8_t *s,
+ size_t s_len, const uint8_t *m, size_t m_len)
+{
+ int ret = -1;
+
+ EVP_MD_CTX *md_ctx = EVP_MD_CTX_new();
+ if(NULL == md_ctx)
+ return -1;
+
+ ret = EVP_DigestVerifyInit(md_ctx, NULL, NULL, NULL, ctx->public_key);
+ if(ret != 1)
+ goto clean_exit;
+
+ ret = EVP_DigestVerify(md_ctx, s, s_len, m, m_len);
+
+ clean_exit:
+
+ EVP_MD_CTX_free(md_ctx);
+
+ return (ret == 1) ? 0 : -1;
+}
+
+#endif /* LIBSSH2_ED25519 */
+
+static int
+_libssh2_pub_priv_openssh_keyfile(LIBSSH2_SESSION *session,
+ unsigned char **method,
+ size_t *method_len,
+ unsigned char **pubkeydata,
+ size_t *pubkeydata_len,
+ const char *privatekey,
+ const char *passphrase)
+{
+ FILE *fp;
+ unsigned char *buf = NULL;
+ struct string_buf *decrypted = NULL;
+ int rc = 0;
+
+ if(session == NULL) {
+ _libssh2_error(session, LIBSSH2_ERROR_PROTO,
+ "Session is required");
+ return -1;
+ }
+
+ _libssh2_init_if_needed();
+
+ fp = fopen(privatekey, "r");
+ if(!fp) {
+ _libssh2_error(session, LIBSSH2_ERROR_FILE,
+ "Unable to open private key file");
+ return -1;
+ }
+
+ rc = _libssh2_openssh_pem_parse(session, (const unsigned char *)passphrase,
+ fp, &decrypted);
+ fclose(fp);
+ if(rc) {
+ _libssh2_error(session, LIBSSH2_ERROR_FILE,
+ "Not an OpenSSH key file");
+ return rc;
+ }
+
+ /* We have a new key file, now try and parse it using supported types */
+ rc = _libssh2_get_string(decrypted, &buf, NULL);
+
+ if(rc != 0 || buf == NULL) {
+ _libssh2_error(session, LIBSSH2_ERROR_PROTO,
+ "Public key type in decrypted key data not found");
+ return -1;
+ }
+
+ rc = -1;
+
+#if LIBSSH2_ED25519
+ if(strcmp("ssh-ed25519", (const char *)buf) == 0) {
+ rc = gen_publickey_from_ed25519_openssh_priv_data(session, decrypted,
+ method, method_len,
+ pubkeydata,
+ pubkeydata_len,
+ NULL);
+ }
+#endif
+#if LIBSSH2_RSA
+ if(strcmp("ssh-rsa", (const char *)buf) == 0) {
+ rc = gen_publickey_from_rsa_openssh_priv_data(session, decrypted,
+ method, method_len,
+ pubkeydata,
+ pubkeydata_len,
+ NULL);
+ }
+#endif
+#if LIBSSH2_DSA
+ if(strcmp("ssh-dss", (const char *)buf) == 0) {
+ rc = gen_publickey_from_dsa_openssh_priv_data(session, decrypted,
+ method, method_len,
+ pubkeydata,
+ pubkeydata_len,
+ NULL);
+ }
+#endif
+#if LIBSSH2_ECDSA
+ {
+ libssh2_curve_type type;
+
+ if(_libssh2_ecdsa_curve_type_from_name((const char *)buf,
+ &type) == 0) {
+ rc = gen_publickey_from_ecdsa_openssh_priv_data(session, type,
+ decrypted,
+ method, method_len,
+ pubkeydata,
+ pubkeydata_len,
+ NULL);
+ }
+ }
+#endif
+
+ if(decrypted)
+ _libssh2_string_buf_free(session, decrypted);
+
+ if(rc != 0) {
+ _libssh2_error(session, LIBSSH2_ERROR_FILE,
+ "Unsupported OpenSSH key type");
+ }
+
+ return rc;
}
-#endif /* LIBSSH_DSA */
int
_libssh2_pub_priv_keyfile(LIBSSH2_SESSION *session,
@@ -1049,6 +2916,7 @@ _libssh2_pub_priv_keyfile(LIBSSH2_SESSION *session,
BIO* bp;
EVP_PKEY* pk;
int pktype;
+ int rc;
_libssh2_debug(session,
LIBSSH2_TRACE_AUTH,
@@ -1056,31 +2924,35 @@ _libssh2_pub_priv_keyfile(LIBSSH2_SESSION *session,
privatekey);
bp = BIO_new_file(privatekey, "r");
- if (bp == NULL) {
+ if(bp == NULL) {
return _libssh2_error(session,
LIBSSH2_ERROR_FILE,
"Unable to extract public key from private key "
"file: Unable to open private key file");
}
- if (!EVP_get_cipherbyname("des")) {
- /* If this cipher isn't loaded it's a pretty good indication that none
- * are. I have *NO DOUBT* that there's a better way to deal with this
- * ($#&%#$(%$#( Someone buy me an OpenSSL manual and I'll read up on
- * it.
- */
- OpenSSL_add_all_ciphers();
- }
+
BIO_reset(bp);
- pk = PEM_read_bio_PrivateKey(bp, NULL, NULL, (void*)passphrase);
+ pk = PEM_read_bio_PrivateKey(bp, NULL, NULL, (void *)passphrase);
BIO_free(bp);
- if (pk == NULL) {
- return _libssh2_error(session,
- LIBSSH2_ERROR_FILE,
- "Unable to extract public key "
- "from private key file: "
- "Wrong passphrase or invalid/unrecognized "
- "private key file format");
+ if(pk == NULL) {
+
+ /* Try OpenSSH format */
+ rc = _libssh2_pub_priv_openssh_keyfile(session,
+ method,
+ method_len,
+ pubkeydata, pubkeydata_len,
+ privatekey, passphrase);
+ if(rc != 0) {
+ return _libssh2_error(session,
+ LIBSSH2_ERROR_FILE,
+ "Unable to extract public key "
+ "from private key file: "
+ "Wrong passphrase or invalid/unrecognized "
+ "private key file format");
+ }
+
+ return 0;
}
#ifdef HAVE_OPAQUE_STRUCTS
@@ -1089,7 +2961,7 @@ _libssh2_pub_priv_keyfile(LIBSSH2_SESSION *session,
pktype = pk->type;
#endif
- switch (pktype) {
+ switch(pktype) {
case EVP_PKEY_RSA :
st = gen_publickey_from_rsa_evp(
session, method, method_len, pubkeydata, pubkeydata_len, pk);
@@ -1102,6 +2974,13 @@ _libssh2_pub_priv_keyfile(LIBSSH2_SESSION *session,
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,
@@ -1115,6 +2994,129 @@ _libssh2_pub_priv_keyfile(LIBSSH2_SESSION *session,
return st;
}
+static int
+_libssh2_pub_priv_openssh_keyfilememory(LIBSSH2_SESSION *session,
+ void **key_ctx,
+ const char *key_type,
+ unsigned char **method,
+ size_t *method_len,
+ unsigned char **pubkeydata,
+ size_t *pubkeydata_len,
+ const char *privatekeydata,
+ size_t privatekeydata_len,
+ unsigned const char *passphrase)
+{
+ int rc;
+ unsigned char *buf = NULL;
+ struct string_buf *decrypted = NULL;
+
+ if(key_ctx != NULL)
+ *key_ctx = NULL;
+
+ if(session == NULL) {
+ _libssh2_error(session, LIBSSH2_ERROR_PROTO,
+ "Session is required");
+ return -1;
+ }
+
+ if(key_type != NULL && (strlen(key_type) > 11 || strlen(key_type) < 7)) {
+ _libssh2_error(session, LIBSSH2_ERROR_PROTO,
+ "type is invalid");
+ return -1;
+ }
+
+ _libssh2_init_if_needed();
+
+ rc = _libssh2_openssh_pem_parse_memory(session, passphrase,
+ privatekeydata,
+ privatekeydata_len, &decrypted);
+
+ if(rc) {
+ return rc;
+ }
+
+ /* We have a new key file, now try and parse it using supported types */
+ rc = _libssh2_get_string(decrypted, &buf, NULL);
+
+ if(rc != 0 || buf == NULL) {
+ _libssh2_error(session, LIBSSH2_ERROR_PROTO,
+ "Public key type in decrypted key data not found");
+ return -1;
+ }
+
+ rc = -1;
+
+#if LIBSSH2_ED25519
+ if(strcmp("ssh-ed25519", (const char *)buf) == 0) {
+ if(key_type == NULL || strcmp("ssh-ed25519", key_type) == 0) {
+ rc = gen_publickey_from_ed25519_openssh_priv_data(session,
+ decrypted,
+ method,
+ method_len,
+ pubkeydata,
+ pubkeydata_len,
+ (libssh2_ed25519_ctx**)key_ctx);
+ }
+ }
+#endif
+#if LIBSSH2_RSA
+ if(strcmp("ssh-rsa", (const char *)buf) == 0) {
+ if(key_type == NULL || strcmp("ssh-rsa", key_type) == 0) {
+ rc = gen_publickey_from_rsa_openssh_priv_data(session, decrypted,
+ method, method_len,
+ pubkeydata,
+ pubkeydata_len,
+ (libssh2_rsa_ctx**)key_ctx);
+ }
+ }
+#endif
+#if LIBSSH2_DSA
+ if(strcmp("ssh-dss", (const char *)buf) == 0) {
+ if(key_type == NULL || strcmp("ssh-dss", key_type) == 0) {
+ rc = gen_publickey_from_dsa_openssh_priv_data(session, decrypted,
+ method, method_len,
+ pubkeydata,
+ pubkeydata_len,
+ (libssh2_dsa_ctx**)key_ctx);
+ }
+ }
+#endif
+#if LIBSSH2_ECDSA
+{
+ libssh2_curve_type type;
+
+ if(_libssh2_ecdsa_curve_type_from_name((const char *)buf, &type) == 0) {
+ if(key_type == NULL || strcmp("ssh-ecdsa", key_type) == 0) {
+ rc = gen_publickey_from_ecdsa_openssh_priv_data(session, type,
+ decrypted,
+ method, method_len,
+ pubkeydata,
+ pubkeydata_len,
+ (libssh2_ecdsa_ctx**)key_ctx);
+ }
+ }
+}
+#endif
+
+ if(decrypted)
+ _libssh2_string_buf_free(session, decrypted);
+
+ return rc;
+}
+
+int
+read_openssh_private_key_from_memory(void **key_ctx, LIBSSH2_SESSION *session,
+ const char *key_type,
+ const char *filedata,
+ size_t filedata_len,
+ unsigned const char *passphrase)
+{
+ return _libssh2_pub_priv_openssh_keyfilememory(session, key_ctx, key_type,
+ NULL, NULL, NULL, NULL,
+ filedata, filedata_len,
+ passphrase);
+}
+
int
_libssh2_pub_priv_keyfilememory(LIBSSH2_SESSION *session,
unsigned char **method,
@@ -1135,28 +3137,34 @@ _libssh2_pub_priv_keyfilememory(LIBSSH2_SESSION *session,
"Computing public key from private key.");
bp = BIO_new_mem_buf((char *)privatekeydata, privatekeydata_len);
- if (!bp) {
+ if(!bp) {
return -1;
}
- if (!EVP_get_cipherbyname("des")) {
- /* If this cipher isn't loaded it's a pretty good indication that none
- * are. I have *NO DOUBT* that there's a better way to deal with this
- * ($#&%#$(%$#( Someone buy me an OpenSSL manual and I'll read up on
- * it.
- */
- OpenSSL_add_all_ciphers();
- }
+
BIO_reset(bp);
- pk = PEM_read_bio_PrivateKey(bp, NULL, NULL, (void*)passphrase);
+ pk = PEM_read_bio_PrivateKey(bp, NULL, NULL, (void *)passphrase);
BIO_free(bp);
- if (pk == NULL) {
- return _libssh2_error(session,
- LIBSSH2_ERROR_FILE,
- "Unable to extract public key "
- "from private key file: "
- "Wrong passphrase or invalid/unrecognized "
- "private key file format");
+ if(pk == NULL) {
+ /* Try OpenSSH format */
+ st = _libssh2_pub_priv_openssh_keyfilememory(session, NULL, NULL,
+ method,
+ method_len,
+ pubkeydata,
+ pubkeydata_len,
+ privatekeydata,
+ privatekeydata_len,
+ (unsigned const char *)passphrase);
+ if(st != 0) {
+ return _libssh2_error(session,
+ LIBSSH2_ERROR_FILE,
+ "Unable to extract public key "
+ "from private key file: "
+ "Wrong passphrase or invalid/unrecognized "
+ "private key file format");
+ }
+
+ return 0;
}
#ifdef HAVE_OPAQUE_STRUCTS
@@ -1165,7 +3173,7 @@ _libssh2_pub_priv_keyfilememory(LIBSSH2_SESSION *session,
pktype = pk->type;
#endif
- switch (pktype) {
+ switch(pktype) {
case EVP_PKEY_RSA :
st = gen_publickey_from_rsa_evp(session, method, method_len,
pubkeydata, pubkeydata_len, pk);
@@ -1176,6 +3184,12 @@ _libssh2_pub_priv_keyfilememory(LIBSSH2_SESSION *session,
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 /* LIBSSH2_ECDSA */
default :
st = _libssh2_error(session,
LIBSSH2_ERROR_FILE,
@@ -1189,4 +3203,38 @@ _libssh2_pub_priv_keyfilememory(LIBSSH2_SESSION *session,
return st;
}
+void
+_libssh2_dh_init(_libssh2_dh_ctx *dhctx)
+{
+ *dhctx = BN_new(); /* Random from client */
+}
+
+int
+_libssh2_dh_key_pair(_libssh2_dh_ctx *dhctx, _libssh2_bn *public,
+ _libssh2_bn *g, _libssh2_bn *p, int group_order,
+ _libssh2_bn_ctx *bnctx)
+{
+ /* Generate x and e */
+ BN_rand(*dhctx, group_order * 8 - 1, 0, -1);
+ BN_mod_exp(public, g, *dhctx, p, bnctx);
+ return 0;
+}
+
+int
+_libssh2_dh_secret(_libssh2_dh_ctx *dhctx, _libssh2_bn *secret,
+ _libssh2_bn *f, _libssh2_bn *p,
+ _libssh2_bn_ctx *bnctx)
+{
+ /* Compute the shared secret */
+ BN_mod_exp(secret, f, *dhctx, p, bnctx);
+ return 0;
+}
+
+void
+_libssh2_dh_dtor(_libssh2_dh_ctx *dhctx)
+{
+ BN_clear_free(*dhctx);
+ *dhctx = NULL;
+}
+
#endif /* LIBSSH2_OPENSSL */