summaryrefslogtreecommitdiff
path: root/libs/libssh2/src/openssl.c
diff options
context:
space:
mode:
authorGeorge Hazan <george.hazan@gmail.com>2023-06-09 21:40:16 +0300
committerGeorge Hazan <george.hazan@gmail.com>2023-06-09 21:40:16 +0300
commit927f00cc19b7239a1fe12abe30b472d61b753d8d (patch)
tree68a190dd83dc2dcceb82464a1953f2701af2a109 /libs/libssh2/src/openssl.c
parent1b241cad53b8c3c5300409fe681de18e636dcf3d (diff)
fixes #3551 (Update libssh2 to 1.11.0)
Diffstat (limited to 'libs/libssh2/src/openssl.c')
-rw-r--r--libs/libssh2/src/openssl.c2164
1 files changed, 1504 insertions, 660 deletions
diff --git a/libs/libssh2/src/openssl.c b/libs/libssh2/src/openssl.c
index 04d5ec2ffd..2dc2340c3b 100644
--- a/libs/libssh2/src/openssl.c
+++ b/libs/libssh2/src/openssl.c
@@ -1,8 +1,7 @@
-/* Copyright (C) 2009, 2010 Simon Josefsson
- * Copyright (C) 2006, 2007 The Written Word, Inc. All rights reserved.
- * Copyright (c) 2004-2006, Sara Golemon <sarag@libssh2.org>
- *
- * Author: Simon Josefsson
+/* Copyright (C) Simon Josefsson
+ * Copyright (C) The Written Word, Inc.
+ * Copyright (C) Sara Golemon <sarag@libssh2.org>
+ * All rights reserved.
*
* Redistribution and use in source and binary forms,
* with or without modification, are permitted provided
@@ -36,14 +35,14 @@
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
*/
-#include "libssh2_priv.h"
-
-#ifdef LIBSSH2_OPENSSL /* compile only if we build with openssl */
+#ifdef LIBSSH2_CRYPTO_C /* Compile this via crypto.c */
-#include <string.h>
-#include "misc.h"
+#include <stdlib.h>
+#include <assert.h>
#ifndef EVP_MAX_BLOCK_LENGTH
#define EVP_MAX_BLOCK_LENGTH 32
@@ -56,6 +55,24 @@ read_openssh_private_key_from_memory(void **key_ctx, LIBSSH2_SESSION *session,
size_t filedata_len,
unsigned const char *passphrase);
+static int
+_libssh2_sk_pub_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,
+ int *algorithm,
+ unsigned char *flags,
+ const char **application,
+ const unsigned char **key_handle,
+ size_t *handle_len,
+ const char *privatekeydata,
+ size_t privatekeydata_len,
+ unsigned const char *passphrase);
+
+#if LIBSSH2_RSA || LIBSSH2_DSA || LIBSSH2_ECDSA
static unsigned char *
write_bn(unsigned char *buf, const BIGNUM *bn, int bn_bytes)
{
@@ -73,7 +90,19 @@ write_bn(unsigned char *buf, const BIGNUM *bn, int bn_bytes)
return p + bn_bytes;
}
+#endif
+
+int
+_libssh2_openssl_random(void *buf, size_t len)
+{
+ if(len > INT_MAX) {
+ return -1;
+ }
+
+ return RAND_bytes(buf, (int)len) == 1 ? 0 : -1;
+}
+#if LIBSSH2_RSA
int
_libssh2_rsa_new(libssh2_rsa_ctx ** rsa,
const unsigned char *edata,
@@ -102,29 +131,29 @@ _libssh2_rsa_new(libssh2_rsa_ctx ** rsa,
BIGNUM * iqmp = 0;
e = BN_new();
- BN_bin2bn(edata, elen, e);
+ BN_bin2bn(edata, (int) elen, e);
n = BN_new();
- BN_bin2bn(ndata, nlen, n);
+ BN_bin2bn(ndata, (int) nlen, n);
if(ddata) {
d = BN_new();
- BN_bin2bn(ddata, dlen, d);
+ BN_bin2bn(ddata, (int) dlen, d);
p = BN_new();
- BN_bin2bn(pdata, plen, p);
+ BN_bin2bn(pdata, (int) plen, p);
q = BN_new();
- BN_bin2bn(qdata, qlen, q);
+ BN_bin2bn(qdata, (int) qlen, q);
dmp1 = BN_new();
- BN_bin2bn(e1data, e1len, dmp1);
+ BN_bin2bn(e1data, (int) e1len, dmp1);
dmq1 = BN_new();
- BN_bin2bn(e2data, e2len, dmq1);
+ BN_bin2bn(e2data, (int) e2len, dmq1);
iqmp = BN_new();
- BN_bin2bn(coeffdata, coefflen, iqmp);
+ BN_bin2bn(coeffdata, (int) coefflen, iqmp);
}
*rsa = RSA_new();
@@ -154,21 +183,67 @@ _libssh2_rsa_new(libssh2_rsa_ctx ** rsa,
}
int
-_libssh2_rsa_sha1_verify(libssh2_rsa_ctx * rsactx,
+_libssh2_rsa_sha2_verify(libssh2_rsa_ctx * rsactx,
+ size_t hash_len,
const unsigned char *sig,
- unsigned long sig_len,
- const unsigned char *m, unsigned long m_len)
+ size_t sig_len,
+ const unsigned char *m, size_t m_len)
{
- unsigned char hash[SHA_DIGEST_LENGTH];
int ret;
+ int nid_type;
+ unsigned char *hash = malloc(hash_len);
+ if(!hash)
+ return -1;
+
+ if(hash_len == SHA_DIGEST_LENGTH) {
+ nid_type = NID_sha1;
+ ret = _libssh2_sha1(m, m_len, hash);
+ }
+ else if(hash_len == SHA256_DIGEST_LENGTH) {
+ nid_type = NID_sha256;
+ ret = _libssh2_sha256(m, m_len, hash);
+
+ }
+ else if(hash_len == SHA512_DIGEST_LENGTH) {
+ nid_type = NID_sha512;
+ ret = _libssh2_sha512(m, m_len, hash);
+ }
+ else {
+/* silence:
+ warning C4701: potentially uninitialized local variable 'nid_type' used */
+#if defined(_MSC_VER)
+ nid_type = 0;
+#endif
+ ret = -1; /* unsupported digest */
+ }
- if(_libssh2_sha1(m, m_len, hash))
+ if(ret) {
+ free(hash);
return -1; /* failure */
- ret = RSA_verify(NID_sha1, hash, SHA_DIGEST_LENGTH,
- (unsigned char *) sig, sig_len, rsactx);
+ }
+
+ ret = RSA_verify(nid_type, hash, (unsigned int) hash_len,
+ (unsigned char *) sig,
+ (unsigned int) sig_len, rsactx);
+
+ free(hash);
+
return (ret == 1) ? 0 : -1;
}
+#if LIBSSH2_RSA_SHA1
+int
+_libssh2_rsa_sha1_verify(libssh2_rsa_ctx * rsactx,
+ const unsigned char *sig,
+ size_t sig_len,
+ const unsigned char *m, size_t m_len)
+{
+ return _libssh2_rsa_sha2_verify(rsactx, SHA_DIGEST_LENGTH, sig, sig_len, m,
+ m_len);
+}
+#endif
+#endif
+
#if LIBSSH2_DSA
int
_libssh2_dsa_new(libssh2_dsa_ctx ** dsactx,
@@ -189,20 +264,20 @@ _libssh2_dsa_new(libssh2_dsa_ctx ** dsactx,
BIGNUM * priv_key = NULL;
p_bn = BN_new();
- BN_bin2bn(p, p_len, p_bn);
+ BN_bin2bn(p, (int) p_len, p_bn);
q_bn = BN_new();
- BN_bin2bn(q, q_len, q_bn);
+ BN_bin2bn(q, (int) q_len, q_bn);
g_bn = BN_new();
- BN_bin2bn(g, g_len, g_bn);
+ BN_bin2bn(g, (int) g_len, g_bn);
pub_key = BN_new();
- BN_bin2bn(y, y_len, pub_key);
+ BN_bin2bn(y, (int) y_len, pub_key);
if(x_len) {
priv_key = BN_new();
- BN_bin2bn(x, x_len, priv_key);
+ BN_bin2bn(x, (int) x_len, priv_key);
}
*dsactx = DSA_new();
@@ -227,7 +302,7 @@ _libssh2_dsa_new(libssh2_dsa_ctx ** dsactx,
int
_libssh2_dsa_sha1_verify(libssh2_dsa_ctx * dsactx,
const unsigned char *sig,
- const unsigned char *m, unsigned long m_len)
+ const unsigned char *m, size_t m_len)
{
unsigned char hash[SHA_DIGEST_LENGTH];
DSA_SIG * dsasig;
@@ -259,16 +334,16 @@ _libssh2_dsa_sha1_verify(libssh2_dsa_ctx * dsactx,
#if LIBSSH2_ECDSA
-/* _libssh2_ecdsa_key_get_curve_type
+/* _libssh2_ecdsa_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)
+_libssh2_ecdsa_get_curve_type(libssh2_ecdsa_ctx *ec_ctx)
{
- const EC_GROUP *group = EC_KEY_get0_group(key);
+ const EC_GROUP *group = EC_KEY_get0_group(ec_ctx);
return EC_GROUP_get_curve_name(group);
}
@@ -282,10 +357,9 @@ 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)
+ if(!name || strlen(name) != 19)
return -1;
if(strcmp(name, "ecdsa-sha2-nistp256") == 0)
@@ -295,14 +369,14 @@ _libssh2_ecdsa_curve_type_from_name(const char *name,
else if(strcmp(name, "ecdsa-sha2-nistp521") == 0)
type = LIBSSH2_EC_CURVE_NISTP521;
else {
- ret = -1;
+ return -1;
}
- if(ret == 0 && out_type) {
+ if(out_type) {
*out_type = type;
}
- return ret;
+ return 0;
}
/* _libssh2_ecdsa_curve_name_with_octal_new
@@ -328,51 +402,50 @@ _libssh2_ecdsa_curve_name_with_octal_new(libssh2_ecdsa_ctx ** ec_ctx,
ret = EC_POINT_oct2point(ec_group, point, k, k_len, NULL);
ret = EC_KEY_set_public_key(ec_key, point);
- if(point != NULL)
+ if(point)
EC_POINT_free(point);
- if(ec_ctx != NULL)
+ if(ec_ctx)
*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); \
- \
-}
+#define LIBSSH2_ECDSA_VERIFY(digest_type) \
+ do { \
+ 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); \
+ } while(0)
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)
+ 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);
+ libssh2_curve_type type = _libssh2_ecdsa_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);
+ BN_bin2bn(r, (int) r_len, pr);
+ BN_bin2bn(s, (int) 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);
+ BN_bin2bn(r, (int) r_len, ecdsa_sig_.r);
ecdsa_sig_.s = BN_new();
- BN_bin2bn(s, s_len, ecdsa_sig_.s);
+ BN_bin2bn(s, (int) s_len, ecdsa_sig_.s);
#endif
if(type == LIBSSH2_EC_CURVE_NISTP256) {
@@ -404,9 +477,26 @@ _libssh2_cipher_init(_libssh2_cipher_ctx * h,
unsigned char *iv, unsigned char *secret, int encrypt)
{
#ifdef HAVE_OPAQUE_STRUCTS
+#if LIBSSH2_AES_GCM
+ const int is_aesgcm = (algo == EVP_aes_128_gcm) ||
+ (algo == EVP_aes_256_gcm);
+#endif /* LIBSSH2_AES_GCM */
+ int rc;
+
*h = EVP_CIPHER_CTX_new();
- return !EVP_CipherInit(*h, algo(), secret, iv, encrypt);
+ rc = !EVP_CipherInit(*h, algo(), secret, iv, encrypt);
+#if LIBSSH2_AES_GCM
+ if(is_aesgcm) {
+ /* Sets both fixed and invocation_counter parts of IV */
+ rc |= !EVP_CIPHER_CTX_ctrl(*h, EVP_CTRL_AEAD_SET_IV_FIXED, -1, iv);
+ }
+#endif /* LIBSSH2_AES_GCM */
+
+ return rc;
#else
+# if LIBSSH2_AES_GCM
+# error AES-GCM is only supported with opaque structs in use
+# endif /* LIBSSH2_AES_GCM */
EVP_CIPHER_CTX_init(h);
return !EVP_CipherInit(h, algo(), secret, iv, encrypt);
#endif
@@ -415,229 +505,116 @@ _libssh2_cipher_init(_libssh2_cipher_ctx * h,
int
_libssh2_cipher_crypt(_libssh2_cipher_ctx * ctx,
_libssh2_cipher_type(algo),
- int encrypt, unsigned char *block, size_t blocksize)
+ int encrypt, unsigned char *block, size_t blocksize,
+ int firstlast)
{
unsigned char buf[EVP_MAX_BLOCK_LENGTH];
- int ret;
- (void) algo;
- (void) encrypt;
+ int ret = 1;
+ int rc = 1;
-#ifdef HAVE_OPAQUE_STRUCTS
- ret = EVP_Cipher(*ctx, buf, block, blocksize);
+#if LIBSSH2_AES_GCM
+ const int is_aesgcm = (algo == EVP_aes_128_gcm) ||
+ (algo == EVP_aes_256_gcm);
+ char lastiv[1];
#else
- ret = EVP_Cipher(ctx, buf, block, blocksize);
-#endif
- if(ret == 1) {
- memcpy(block, buf, blocksize);
- }
- return ret == 1 ? 0 : 1;
-}
-
-#if LIBSSH2_AES_CTR && !defined(HAVE_EVP_AES_128_CTR)
-
-#include <openssl/aes.h>
-#include <openssl/evp.h>
-
-typedef struct
-{
- AES_KEY key;
- EVP_CIPHER_CTX *aes_ctx;
- unsigned char ctr[AES_BLOCK_SIZE];
-} aes_ctr_ctx;
-
-static int
-aes_ctr_init(EVP_CIPHER_CTX *ctx, const unsigned char *key,
- const unsigned char *iv, int enc) /* init key */
-{
- /*
- * variable "c" is leaked from this scope, but is later freed
- * in aes_ctr_cleanup
- */
- aes_ctr_ctx *c;
- const EVP_CIPHER *aes_cipher;
- (void) enc;
+ const int is_aesgcm = 0;
+#endif /* LIBSSH2_AES_GCM */
+ /* length of AES-GCM Authentication Tag */
+ const int authlen = is_aesgcm ? 16 : 0;
+ /* length of AAD, only on the first block */
+ const int aadlen = (is_aesgcm && IS_FIRST(firstlast)) ? 4 : 0;
+ /* size of AT, if present */
+ const int authenticationtag = IS_LAST(firstlast) ? authlen : 0;
+ /* length to encrypt */
+ const int cryptlen = (unsigned int)blocksize - aadlen - authenticationtag;
+
+ (void)algo;
+
+ assert(blocksize <= sizeof(buf));
+ assert(cryptlen >= 0);
+
+#if LIBSSH2_AES_GCM
+ /* First block */
+ if(IS_FIRST(firstlast)) {
+ /* Increments invocation_counter portion of IV */
+ if(is_aesgcm) {
+ ret = EVP_CIPHER_CTX_ctrl(*ctx, EVP_CTRL_GCM_IV_GEN, 1, lastiv);
+ }
- switch(EVP_CIPHER_CTX_key_length(ctx)) {
- case 16:
- aes_cipher = EVP_aes_128_ecb();
- break;
- case 24:
- aes_cipher = EVP_aes_192_ecb();
- break;
- case 32:
- aes_cipher = EVP_aes_256_ecb();
- break;
- default:
- return 0;
+ if(aadlen) {
+ /* Include the 4 byte packet length as AAD */
+ ret = EVP_Cipher(*ctx, NULL, block, aadlen);
+ }
}
- c = malloc(sizeof(*c));
- if(c == NULL)
- return 0;
-
-#ifdef HAVE_OPAQUE_STRUCTS
- c->aes_ctx = EVP_CIPHER_CTX_new();
-#else
- c->aes_ctx = malloc(sizeof(EVP_CIPHER_CTX));
-#endif
- if(c->aes_ctx == NULL) {
- free(c);
- return 0;
+ /* Last portion of block to encrypt/decrypt */
+ if(IS_LAST(firstlast)) {
+ if(is_aesgcm && !encrypt) {
+ /* set tag on decryption */
+ ret = EVP_CIPHER_CTX_ctrl(*ctx, EVP_CTRL_GCM_SET_TAG, authlen,
+ block + blocksize - authlen);
+ }
}
-
- if(EVP_EncryptInit(c->aes_ctx, aes_cipher, key, NULL) != 1) {
-#ifdef HAVE_OPAQUE_STRUCTS
- EVP_CIPHER_CTX_free(c->aes_ctx);
#else
- free(c->aes_ctx);
-#endif
- free(c);
- return 0;
- }
-
- EVP_CIPHER_CTX_set_padding(c->aes_ctx, 0);
-
- memcpy(c->ctr, iv, AES_BLOCK_SIZE);
-
- EVP_CIPHER_CTX_set_app_data(ctx, c);
-
- return 1;
-}
-
-static int
-aes_ctr_do_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out,
- const unsigned char *in,
- size_t inl) /* encrypt/decrypt data */
-{
- aes_ctr_ctx *c = EVP_CIPHER_CTX_get_app_data(ctx);
- unsigned char b1[AES_BLOCK_SIZE];
- int outlen = 0;
-
- if(inl != 16) /* libssh2 only ever encrypt one block */
- return 0;
-
- if(c == NULL) {
- return 0;
- }
+ (void)encrypt;
+ (void)firstlast;
+#endif /* LIBSSH2_AES_GCM */
-/*
- To encrypt a packet P=P1||P2||...||Pn (where P1, P2, ..., Pn are each
- blocks of length L), the encryptor first encrypts <X> with <cipher>
- to obtain a block B1. The block B1 is then XORed with P1 to generate
- the ciphertext block C1. The counter X is then incremented
-*/
-
- if(EVP_EncryptUpdate(c->aes_ctx, b1, &outlen,
- c->ctr, AES_BLOCK_SIZE) != 1) {
- return 0;
- }
-
- _libssh2_xor_data(out, in, b1, AES_BLOCK_SIZE);
- _libssh2_aes_ctr_increment(c->ctr, AES_BLOCK_SIZE);
-
- return 1;
-}
-
-static int
-aes_ctr_cleanup(EVP_CIPHER_CTX *ctx) /* cleanup ctx */
-{
- aes_ctr_ctx *c = EVP_CIPHER_CTX_get_app_data(ctx);
-
- if(c == NULL) {
- return 1;
- }
-
- if(c->aes_ctx != NULL) {
+ if(cryptlen > 0) {
#ifdef HAVE_OPAQUE_STRUCTS
- EVP_CIPHER_CTX_free(c->aes_ctx);
+ ret = EVP_Cipher(*ctx, buf + aadlen, block + aadlen, cryptlen);
#else
- _libssh2_cipher_dtor(c->aes_ctx);
- free(c->aes_ctx);
+ ret = EVP_Cipher(ctx, buf + aadlen, block + aadlen, cryptlen);
#endif
}
- free(c);
-
- return 1;
-}
-
-static const EVP_CIPHER *
-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);
- }
-#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;
-#endif
-
- return *aes_ctr_cipher;
-}
-
-const EVP_CIPHER *
-_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;
+#if (defined(OPENSSL_VERSION_MAJOR) && OPENSSL_VERSION_MAJOR >= 3) || \
+ defined(LIBSSH2_WOLFSSL)
+ if(ret != -1)
#else
- static EVP_CIPHER 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;
+ if(ret >= 1)
#endif
-}
-
-const EVP_CIPHER *
-_libssh2_EVP_aes_192_ctr(void)
-{
+ {
+ rc = 0;
+ if(IS_LAST(firstlast)) {
+ /* This is the last block.
+ encrypt: compute tag, if applicable
+ decrypt: verify tag, if applicable
+ in!=NULL is equivalent to EVP_CipherUpdate
+ in==NULL is equivalent to EVP_CipherFinal */
#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;
+ ret = EVP_Cipher(*ctx, NULL, NULL, 0); /* final */
#else
- static EVP_CIPHER 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;
+ ret = EVP_Cipher(ctx, NULL, NULL, 0); /* final */
#endif
-}
+ if(ret < 0) {
+ ret = 0;
+ }
+ else {
+ ret = 1;
+#if LIBSSH2_AES_GCM
+ if(is_aesgcm && encrypt) {
+ /* write the Authentication Tag a.k.a. MAC at the end
+ of the block */
+ assert(authenticationtag == authlen);
+ ret = EVP_CIPHER_CTX_ctrl(*ctx, EVP_CTRL_GCM_GET_TAG,
+ authlen, block + blocksize - authenticationtag);
+ }
+#endif /* LIBSSH2_AES_GCM */
+ }
+ }
+ /* Copy en/decrypted data back to the caller.
+ The first aadlen should not be touched because they weren't
+ encrypted and are unmodified. */
+ memcpy(block + aadlen, buf + aadlen, cryptlen);
+ rc = !ret;
+ }
-const EVP_CIPHER *
-_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;
-#else
- static EVP_CIPHER 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
+ /* TODO: the return code should distinguish between decryption errors and
+ invalid MACs */
+ return rc;
}
-#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)
{
#if OPENSSL_VERSION_NUMBER >= 0x10100000L && \
@@ -655,44 +632,22 @@ void _libssh2_openssl_crypto_init(void)
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
}
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
}
+#if LIBSSH2_RSA || LIBSSH2_DSA || LIBSSH2_ECDSA || LIBSSH2_ED25519
/* TODO: Optionally call a passphrase callback specified by the
* calling program
*/
static int
passphrase_cb(char *buf, int size, int rwflag, char *passphrase)
{
- int passphrase_len = strlen(passphrase);
- (void) rwflag;
+ int passphrase_len = (int) strlen(passphrase);
+
+ (void)rwflag;
if(passphrase_len > (size - 1)) {
passphrase_len = size - 1;
@@ -717,19 +672,24 @@ read_private_key_from_memory(void **key_ctx,
*key_ctx = NULL;
- bp = BIO_new_mem_buf((char *)filedata, filedata_len);
+#if OPENSSL_VERSION_NUMBER >= 0x1000200fL
+ bp = BIO_new_mem_buf(filedata, (int)filedata_len);
+#else
+ bp = BIO_new_mem_buf((char *)filedata, (int)filedata_len);
+#endif
if(!bp) {
return -1;
}
+
*key_ctx = read_private_key(bp, NULL, (pem_password_cb *) passphrase_cb,
(void *) passphrase);
BIO_free(bp);
return (*key_ctx) ? 0 : -1;
}
+#endif
-
-
+#if LIBSSH2_RSA || LIBSSH2_DSA || LIBSSH2_ECDSA
static int
read_private_key_from_file(void **key_ctx,
pem_read_bio_func read_private_key,
@@ -751,7 +711,9 @@ read_private_key_from_file(void **key_ctx,
BIO_free(bp);
return (*key_ctx) ? 0 : -1;
}
+#endif
+#if LIBSSH2_RSA
int
_libssh2_rsa_new_private_frommemory(libssh2_rsa_ctx ** rsa,
LIBSSH2_SESSION * session,
@@ -762,7 +724,6 @@ _libssh2_rsa_new_private_frommemory(libssh2_rsa_ctx ** rsa,
pem_read_bio_func read_rsa =
(pem_read_bio_func) &PEM_read_bio_RSAPrivateKey;
- (void) session;
_libssh2_init_if_needed();
@@ -774,7 +735,7 @@ _libssh2_rsa_new_private_frommemory(libssh2_rsa_ctx ** rsa,
"ssh-rsa", filedata, filedata_len, passphrase);
}
-return rc;
+ return rc;
}
static unsigned char *
@@ -800,7 +761,7 @@ gen_publickey_from_rsa(LIBSSH2_SESSION *session, RSA *rsa,
len = 4 + 7 + 4 + e_bytes + 4 + n_bytes;
key = LIBSSH2_ALLOC(session, len);
- if(key == NULL) {
+ if(!key) {
return NULL;
}
@@ -832,23 +793,23 @@ gen_publickey_from_rsa_evp(LIBSSH2_SESSION *session,
unsigned char *method_buf = NULL;
size_t key_len;
- _libssh2_debug(session,
+ _libssh2_debug((session,
LIBSSH2_TRACE_AUTH,
- "Computing public key from RSA private key envelop");
+ "Computing public key from RSA private key envelope"));
rsa = EVP_PKEY_get1_RSA(pk);
- if(rsa == NULL) {
+ if(!rsa) {
/* Assume memory allocation error... what else could it be ? */
goto __alloc_error;
}
method_buf = LIBSSH2_ALLOC(session, 7); /* ssh-rsa. */
- if(method_buf == NULL) {
+ if(!method_buf) {
goto __alloc_error;
}
key = gen_publickey_from_rsa(session, rsa, &key_len);
- if(key == NULL) {
+ if(!key) {
goto __alloc_error;
}
RSA_free(rsa);
@@ -860,11 +821,11 @@ gen_publickey_from_rsa_evp(LIBSSH2_SESSION *session,
*pubkeydata_len = key_len;
return 0;
- __alloc_error:
- if(rsa != NULL) {
+__alloc_error:
+ if(rsa) {
RSA_free(rsa);
}
- if(method_buf != NULL) {
+ if(method_buf) {
LIBSSH2_FREE(session, method_buf);
}
@@ -894,23 +855,23 @@ static int _libssh2_rsa_new_additional_parameters(RSA *rsa)
#endif
ctx = BN_CTX_new();
- if(ctx == NULL)
+ if(!ctx)
return -1;
aux = BN_new();
- if(aux == NULL) {
+ if(!aux) {
rc = -1;
goto out;
}
dmp1 = BN_new();
- if(dmp1 == NULL) {
+ if(!dmp1) {
rc = -1;
goto out;
}
dmq1 = BN_new();
- if(dmq1 == NULL) {
+ if(!dmq1) {
rc = -1;
goto out;
}
@@ -935,7 +896,7 @@ out:
BN_clear_free(aux);
BN_CTX_free(ctx);
- if(rc != 0) {
+ if(rc) {
if(dmp1)
BN_clear_free(dmp1);
if(dmq1)
@@ -959,9 +920,9 @@ gen_publickey_from_rsa_openssh_priv_data(LIBSSH2_SESSION *session,
unsigned char *n, *e, *d, *p, *q, *coeff, *comment;
RSA *rsa = NULL;
- _libssh2_debug(session,
+ _libssh2_debug((session,
LIBSSH2_TRACE_AUTH,
- "Computing RSA keys from private key data");
+ "Computing RSA keys from private key data"));
/* public key data */
if(_libssh2_get_bignum_bytes(decrypted, &n, &nlen)) {
@@ -1007,19 +968,25 @@ gen_publickey_from_rsa_openssh_priv_data(LIBSSH2_SESSION *session,
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,
+ rc = _libssh2_rsa_new(&rsa,
+ e, (unsigned long)elen,
+ n, (unsigned long)nlen,
+ d, (unsigned long)dlen,
+ p, (unsigned long)plen,
+ q, (unsigned long)qlen,
+ NULL, 0, NULL, 0,
+ coeff, (unsigned long)coefflen);
+ if(rc) {
+ _libssh2_debug((session,
LIBSSH2_TRACE_AUTH,
- "Could not create RSA private key");
+ "Could not create RSA private key"));
goto fail;
}
- if(rsa != NULL)
+ if(rsa)
rc = _libssh2_rsa_new_additional_parameters(rsa);
- if(rsa != NULL && pubkeydata != NULL && method != NULL) {
+ if(rsa && pubkeydata && method) {
EVP_PKEY *pk = EVP_PKEY_new();
EVP_PKEY_set1_RSA(pk, rsa);
@@ -1031,7 +998,7 @@ gen_publickey_from_rsa_openssh_priv_data(LIBSSH2_SESSION *session,
EVP_PKEY_free(pk);
}
- if(rsa_ctx != NULL)
+ if(rsa_ctx)
*rsa_ctx = rsa;
else
RSA_free(rsa);
@@ -1040,7 +1007,7 @@ gen_publickey_from_rsa_openssh_priv_data(LIBSSH2_SESSION *session,
fail:
- if(rsa != NULL)
+ if(rsa)
RSA_free(rsa);
return _libssh2_error(session,
@@ -1059,7 +1026,7 @@ _libssh2_rsa_new_openssh_private(libssh2_rsa_ctx ** rsa,
unsigned char *buf = NULL;
struct string_buf *decrypted = NULL;
- if(session == NULL) {
+ if(!session) {
_libssh2_error(session, LIBSSH2_ERROR_PROTO,
"Session is required");
return -1;
@@ -1083,7 +1050,7 @@ _libssh2_rsa_new_openssh_private(libssh2_rsa_ctx ** rsa,
/* 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) {
+ if(rc || !buf) {
_libssh2_error(session, LIBSSH2_ERROR_PROTO,
"Public key type in decrypted key data not found");
return -1;
@@ -1113,7 +1080,6 @@ _libssh2_rsa_new_private(libssh2_rsa_ctx ** rsa,
pem_read_bio_func read_rsa =
(pem_read_bio_func) &PEM_read_bio_RSAPrivateKey;
- (void) session;
_libssh2_init_if_needed();
@@ -1127,6 +1093,7 @@ _libssh2_rsa_new_private(libssh2_rsa_ctx ** rsa,
return rc;
}
+#endif
#if LIBSSH2_DSA
int
@@ -1139,16 +1106,18 @@ _libssh2_dsa_new_private_frommemory(libssh2_dsa_ctx ** dsa,
pem_read_bio_func read_dsa =
(pem_read_bio_func) &PEM_read_bio_DSAPrivateKey;
- (void) session;
_libssh2_init_if_needed();
rc = read_private_key_from_memory((void **)dsa, read_dsa,
- filedata, filedata_len, passphrase);
+ filedata, filedata_len,
+ passphrase);
if(rc) {
rc = read_openssh_private_key_from_memory((void **)dsa, session,
- "ssh-dsa", filedata, filedata_len, passphrase);
+ "ssh-dsa",
+ filedata, filedata_len,
+ passphrase);
}
return rc;
@@ -1189,7 +1158,7 @@ gen_publickey_from_dsa(LIBSSH2_SESSION* session, DSA *dsa,
len = 4 + 7 + 4 + p_bytes + 4 + q_bytes + 4 + g_bytes + 4 + k_bytes;
key = LIBSSH2_ALLOC(session, len);
- if(key == NULL) {
+ if(!key) {
return NULL;
}
@@ -1223,23 +1192,23 @@ gen_publickey_from_dsa_evp(LIBSSH2_SESSION *session,
unsigned char *method_buf = NULL;
size_t key_len;
- _libssh2_debug(session,
+ _libssh2_debug((session,
LIBSSH2_TRACE_AUTH,
- "Computing public key from DSA private key envelop");
+ "Computing public key from DSA private key envelope"));
dsa = EVP_PKEY_get1_DSA(pk);
- if(dsa == NULL) {
+ if(!dsa) {
/* Assume memory allocation error... what else could it be ? */
goto __alloc_error;
}
method_buf = LIBSSH2_ALLOC(session, 7); /* ssh-dss. */
- if(method_buf == NULL) {
+ if(!method_buf) {
goto __alloc_error;
}
key = gen_publickey_from_dsa(session, dsa, &key_len);
- if(key == NULL) {
+ if(!key) {
goto __alloc_error;
}
DSA_free(dsa);
@@ -1251,11 +1220,11 @@ gen_publickey_from_dsa_evp(LIBSSH2_SESSION *session,
*pubkeydata_len = key_len;
return 0;
- __alloc_error:
- if(dsa != NULL) {
+__alloc_error:
+ if(dsa) {
DSA_free(dsa);
}
- if(method_buf != NULL) {
+ if(method_buf) {
LIBSSH2_FREE(session, method_buf);
}
@@ -1278,9 +1247,9 @@ gen_publickey_from_dsa_openssh_priv_data(LIBSSH2_SESSION *session,
unsigned char *p, *q, *g, *pub_key, *priv_key;
DSA *dsa = NULL;
- _libssh2_debug(session,
+ _libssh2_debug((session,
LIBSSH2_TRACE_AUTH,
- "Computing DSA keys from private key data");
+ "Computing DSA keys from private key data"));
if(_libssh2_get_bignum_bytes(decrypted, &p, &plen)) {
_libssh2_error(session, LIBSSH2_ERROR_PROTO,
@@ -1312,16 +1281,20 @@ gen_publickey_from_dsa_openssh_priv_data(LIBSSH2_SESSION *session,
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,
+ rc = _libssh2_dsa_new(&dsa,
+ p, (unsigned long)plen,
+ q, (unsigned long)qlen,
+ g, (unsigned long)glen,
+ pub_key, (unsigned long)pub_len,
+ priv_key, (unsigned long)priv_len);
+ if(rc) {
+ _libssh2_debug((session,
LIBSSH2_ERROR_PROTO,
- "Could not create DSA private key");
+ "Could not create DSA private key"));
goto fail;
}
- if(dsa != NULL && pubkeydata != NULL && method != NULL) {
+ if(dsa && pubkeydata && method) {
EVP_PKEY *pk = EVP_PKEY_new();
EVP_PKEY_set1_DSA(pk, dsa);
@@ -1333,7 +1306,7 @@ gen_publickey_from_dsa_openssh_priv_data(LIBSSH2_SESSION *session,
EVP_PKEY_free(pk);
}
- if(dsa_ctx != NULL)
+ if(dsa_ctx)
*dsa_ctx = dsa;
else
DSA_free(dsa);
@@ -1342,7 +1315,7 @@ gen_publickey_from_dsa_openssh_priv_data(LIBSSH2_SESSION *session,
fail:
- if(dsa != NULL)
+ if(dsa)
DSA_free(dsa);
return _libssh2_error(session,
@@ -1361,7 +1334,7 @@ _libssh2_dsa_new_openssh_private(libssh2_dsa_ctx ** dsa,
unsigned char *buf = NULL;
struct string_buf *decrypted = NULL;
- if(session == NULL) {
+ if(!session) {
_libssh2_error(session, LIBSSH2_ERROR_PROTO,
"Session is required");
return -1;
@@ -1385,7 +1358,7 @@ _libssh2_dsa_new_openssh_private(libssh2_dsa_ctx ** dsa,
/* 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) {
+ if(rc || !buf) {
_libssh2_error(session, LIBSSH2_ERROR_PROTO,
"Public key type in decrypted key data not found");
return -1;
@@ -1415,7 +1388,6 @@ _libssh2_dsa_new_private(libssh2_dsa_ctx ** dsa,
pem_read_bio_func read_dsa =
(pem_read_bio_func) &PEM_read_bio_DSAPrivateKey;
- (void) session;
_libssh2_init_if_needed();
@@ -1429,147 +1401,204 @@ _libssh2_dsa_new_private(libssh2_dsa_ctx ** dsa,
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)
+ 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);
+ filedata, filedata_len,
+ passphrase);
if(rc) {
rc = read_openssh_private_key_from_memory((void **)ec_ctx, session,
- "ssh-ecdsa", filedata,
- filedata_len, passphrase);
+ "ssh-ecdsa",
+ filedata, filedata_len,
+ passphrase);
}
return rc;
}
+int _libssh2_ecdsa_new_private_frommemory_sk(libssh2_ecdsa_ctx ** ec_ctx,
+ unsigned char *flags,
+ const char **application,
+ const unsigned char **key_handle,
+ size_t *handle_len,
+ LIBSSH2_SESSION * session,
+ const char *filedata,
+ size_t filedata_len,
+ unsigned const char *passphrase)
+{
+ int algorithm;
+ return _libssh2_sk_pub_openssh_keyfilememory(session,
+ (void **)ec_ctx,
+ "sk-ecdsa-sha2-nistp256@openssh.com",
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ &algorithm,
+ flags,
+ application,
+ key_handle,
+ handle_len,
+ filedata,
+ filedata_len,
+ passphrase);
+}
+
#endif /* LIBSSH2_ECDSA */
#if LIBSSH2_ED25519
int
-_libssh2_curve25519_new(LIBSSH2_SESSION *session, libssh2_x25519_ctx **out_ctx,
+_libssh2_curve25519_new(LIBSSH2_SESSION *session,
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;
+ unsigned char *priv = NULL, *pub = NULL;
+ size_t privLen, pubLen;
int rc = -1;
pctx = EVP_PKEY_CTX_new_id(EVP_PKEY_X25519, NULL);
- if(pctx == NULL)
+ if(!pctx)
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;
+ if(EVP_PKEY_keygen_init(pctx) != 1 ||
+ EVP_PKEY_keygen(pctx, &key) != 1) {
+ goto clean_exit;
}
- 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_private_key) {
+ privLen = LIBSSH2_ED25519_KEY_LEN;
+ priv = LIBSSH2_ALLOC(session, privLen);
+ if(!priv)
+ goto clean_exit;
- if(out_public_key != NULL) {
- *out_public_key = LIBSSH2_ALLOC(session, LIBSSH2_ED25519_KEY_LEN);
- if(*out_public_key == NULL)
- goto cleanExit;
+ if(EVP_PKEY_get_raw_private_key(key, priv, &privLen) != 1 ||
+ privLen != LIBSSH2_ED25519_KEY_LEN) {
+ goto clean_exit;
+ }
- memcpy(*out_public_key, pub, LIBSSH2_ED25519_KEY_LEN);
+ *out_private_key = priv;
+ priv = NULL;
}
- 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(out_public_key) {
+ pubLen = LIBSSH2_ED25519_KEY_LEN;
+ pub = LIBSSH2_ALLOC(session, pubLen);
+ if(!pub)
+ goto clean_exit;
- if(ctx->public_key == NULL || ctx->private_key == NULL) {
- _libssh2_x25519_free(ctx);
- goto cleanExit;
+ if(EVP_PKEY_get_raw_public_key(key, pub, &pubLen) != 1 ||
+ pubLen != LIBSSH2_ED25519_KEY_LEN) {
+ goto clean_exit;
}
- *out_ctx = ctx;
+ *out_public_key = pub;
+ pub = NULL;
}
/* success */
rc = 0;
-cleanExit:
+clean_exit:
- 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);
+ if(priv)
+ LIBSSH2_FREE(session, priv);
+ if(pub)
+ LIBSSH2_FREE(session, pub);
return rc;
}
+
+static int
+gen_publickey_from_ed_evp(LIBSSH2_SESSION *session,
+ unsigned char **method,
+ size_t *method_len,
+ unsigned char **pubkeydata,
+ size_t *pubkeydata_len,
+ EVP_PKEY *pk)
+{
+ const char methodName[] = "ssh-ed25519";
+ unsigned char *methodBuf = NULL;
+ size_t rawKeyLen = 0;
+ unsigned char *keyBuf = NULL;
+ size_t bufLen = 0;
+ unsigned char *bufPos = NULL;
+
+ _libssh2_debug((session, LIBSSH2_TRACE_AUTH,
+ "Computing public key from ED private key envelope"));
+
+ methodBuf = LIBSSH2_ALLOC(session, sizeof(methodName) - 1);
+ if(!methodBuf) {
+ _libssh2_error(session, LIBSSH2_ERROR_ALLOC,
+ "Unable to allocate memory for private key data");
+ goto fail;
+ }
+ memcpy(methodBuf, methodName, sizeof(methodName) - 1);
+
+ if(EVP_PKEY_get_raw_public_key(pk, NULL, &rawKeyLen) != 1) {
+ _libssh2_error(session, LIBSSH2_ERROR_PROTO,
+ "EVP_PKEY_get_raw_public_key failed");
+ goto fail;
+ }
+
+ /* Key form is: type_len(4) + type(11) + pub_key_len(4) + pub_key(32). */
+ bufLen = 4 + sizeof(methodName) - 1 + 4 + rawKeyLen;
+ bufPos = keyBuf = LIBSSH2_ALLOC(session, bufLen);
+ if(!keyBuf) {
+ _libssh2_error(session, LIBSSH2_ERROR_ALLOC,
+ "Unable to allocate memory for private key data");
+ goto fail;
+ }
+
+ _libssh2_store_str(&bufPos, methodName, sizeof(methodName) - 1);
+ _libssh2_store_u32(&bufPos, (uint32_t) rawKeyLen);
+
+ if(EVP_PKEY_get_raw_public_key(pk, bufPos, &rawKeyLen) != 1) {
+ _libssh2_error(session, LIBSSH2_ERROR_PROTO,
+ "EVP_PKEY_get_raw_public_key failed");
+ goto fail;
+ }
+
+ *method = methodBuf;
+ *method_len = sizeof(methodName) - 1;
+ *pubkeydata = keyBuf;
+ *pubkeydata_len = bufLen;
+ return 0;
+
+fail:
+ if(methodBuf)
+ LIBSSH2_FREE(session, methodBuf);
+ if(keyBuf)
+ LIBSSH2_FREE(session, keyBuf);
+ return -1;
+}
+
+
static int
gen_publickey_from_ed25519_openssh_priv_data(LIBSSH2_SESSION *session,
struct string_buf *decrypted,
@@ -1587,9 +1616,9 @@ gen_publickey_from_ed25519_openssh_priv_data(LIBSSH2_SESSION *session,
size_t key_len = 0, tmp_len = 0;
unsigned char *p;
- _libssh2_debug(session,
+ _libssh2_debug((session,
LIBSSH2_TRACE_AUTH,
- "Computing ED25519 keys from private key data");
+ "Computing ED25519 keys from private key data"));
if(_libssh2_get_string(decrypted, &pub_key, &tmp_len) ||
tmp_len != LIBSSH2_ED25519_KEY_LEN) {
@@ -1606,25 +1635,11 @@ gen_publickey_from_ed25519_openssh_priv_data(LIBSSH2_SESSION *session,
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);
+ ctx = EVP_PKEY_new_raw_private_key(EVP_PKEY_ED25519, NULL,
+ (const unsigned char *)priv_key,
+ LIBSSH2_ED25519_KEY_LEN);
/* comment */
if(_libssh2_get_string(decrypted, &buf, &tmp_len)) {
@@ -1636,12 +1651,12 @@ gen_publickey_from_ed25519_openssh_priv_data(LIBSSH2_SESSION *session,
if(tmp_len > 0) {
unsigned char *comment = LIBSSH2_CALLOC(session, tmp_len + 1);
- if(comment != NULL) {
+ if(comment) {
memcpy(comment, buf, tmp_len);
memcpy(comment + tmp_len, "\0", 1);
- _libssh2_debug(session, LIBSSH2_TRACE_AUTH, "Key comment: %s",
- comment);
+ _libssh2_debug((session, LIBSSH2_TRACE_AUTH, "Key comment: %s",
+ comment));
LIBSSH2_FREE(session, comment);
}
@@ -1661,13 +1676,15 @@ gen_publickey_from_ed25519_openssh_priv_data(LIBSSH2_SESSION *session,
}
if(ret == 0) {
- _libssh2_debug(session,
+ _libssh2_debug((session,
LIBSSH2_TRACE_AUTH,
"Computing public key from ED25519 "
- "private key envelop");
+ "private key envelope"));
method_buf = LIBSSH2_ALLOC(session, 11); /* ssh-ed25519. */
- if(method_buf == NULL) {
+ if(!method_buf) {
+ _libssh2_error(session, LIBSSH2_ERROR_ALLOC,
+ "Unable to allocate memory for ED25519 key");
goto clean_exit;
}
@@ -1675,7 +1692,9 @@ gen_publickey_from_ed25519_openssh_priv_data(LIBSSH2_SESSION *session,
pub_key(32). */
key_len = LIBSSH2_ED25519_KEY_LEN + 19;
key = LIBSSH2_CALLOC(session, key_len);
- if(key == NULL) {
+ if(!key) {
+ _libssh2_error(session, LIBSSH2_ERROR_ALLOC,
+ "Unable to allocate memory for ED25519 key");
goto clean_exit;
}
@@ -1686,25 +1705,168 @@ gen_publickey_from_ed25519_openssh_priv_data(LIBSSH2_SESSION *session,
memcpy(method_buf, "ssh-ed25519", 11);
- if(method != NULL)
+ if(method)
*method = method_buf;
else
LIBSSH2_FREE(session, method_buf);
- if(method_len != NULL)
+ if(method_len)
*method_len = 11;
- if(pubkeydata != NULL)
+ if(pubkeydata)
*pubkeydata = key;
else
LIBSSH2_FREE(session, key);
- if(pubkeydata_len != NULL)
+ if(pubkeydata_len)
+ *pubkeydata_len = key_len;
+
+ if(out_ctx)
+ *out_ctx = ctx;
+ else if(ctx)
+ _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;
+}
+
+static int
+gen_publickey_from_sk_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,
+ unsigned char *flags,
+ const char **application,
+ const unsigned char **key_handle,
+ size_t *handle_len,
+ libssh2_ed25519_ctx **out_ctx)
+{
+ const char *key_type = "sk-ssh-ed25519@openssh.com";
+
+ libssh2_ed25519_ctx *ctx = NULL;
+ unsigned char *method_buf = NULL;
+ unsigned char *key = NULL;
+ int ret = 0;
+ unsigned char *pub_key, *app;
+ size_t key_len = 0, app_len = 0, tmp_len = 0;
+ unsigned char *p;
+
+ _libssh2_debug((session,
+ LIBSSH2_TRACE_AUTH,
+ "Computing sk-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, &app, &app_len)) {
+ _libssh2_error(session, LIBSSH2_ERROR_PROTO,
+ "No SK application.");
+ return -1;
+ }
+
+ if(flags && _libssh2_get_byte(decrypted, flags)) {
+ _libssh2_error(session, LIBSSH2_ERROR_PROTO,
+ "No SK flags.");
+ return -1;
+ }
+
+ if(key_handle && handle_len) {
+ unsigned char *handle = NULL;
+ if(_libssh2_get_string(decrypted, &handle, handle_len)) {
+ _libssh2_error(session, LIBSSH2_ERROR_PROTO,
+ "No SK key_handle.");
+ return -1;
+ }
+
+ if(*handle_len > 0) {
+ *key_handle = LIBSSH2_ALLOC(session, *handle_len);
+
+ if(key_handle) {
+ memcpy((void *)*key_handle, handle, *handle_len);
+ }
+ }
+ }
+
+ ctx = EVP_PKEY_new_raw_public_key(EVP_PKEY_ED25519, NULL,
+ (const unsigned char *)pub_key,
+ LIBSSH2_ED25519_KEY_LEN);
+
+ if(ret == 0) {
+ _libssh2_debug((session,
+ LIBSSH2_TRACE_AUTH,
+ "Computing public key from ED25519 "
+ "private key envelope"));
+
+ /* sk-ssh-ed25519@openssh.com. */
+ method_buf = LIBSSH2_ALLOC(session, strlen(key_type));
+ if(!method_buf) {
+ _libssh2_error(session, LIBSSH2_ERROR_ALLOC,
+ "Unable to allocate memory for ED25519 key");
+ goto clean_exit;
+ }
+
+ /* Key form is: type_len(4) + type(26) + pub_key_len(4) +
+ pub_key(32) + application_len(4) + application(X). */
+ key_len = LIBSSH2_ED25519_KEY_LEN + 38 + app_len;
+ key = LIBSSH2_CALLOC(session, key_len);
+ if(!key) {
+ _libssh2_error(session, LIBSSH2_ERROR_ALLOC,
+ "Unable to allocate memory for ED25519 key");
+ goto clean_exit;
+ }
+
+ p = key;
+
+ _libssh2_store_str(&p, key_type, strlen(key_type));
+ _libssh2_store_str(&p, (const char *)pub_key, LIBSSH2_ED25519_KEY_LEN);
+ _libssh2_store_str(&p, (const char *)app, app_len);
+
+ if(application && app_len > 0) {
+ *application = (const char *)LIBSSH2_ALLOC(session, app_len + 1);
+ _libssh2_explicit_zero((void *)*application, app_len + 1);
+ memcpy((void *)*application, app, app_len);
+ }
+
+ memcpy(method_buf, key_type, strlen(key_type));
+
+ if(method)
+ *method = method_buf;
+ else
+ LIBSSH2_FREE(session, method_buf);
+
+ if(method_len)
+ *method_len = strlen(key_type);
+
+ if(pubkeydata)
+ *pubkeydata = key;
+ else if(key)
+ LIBSSH2_FREE(session, key);
+
+ if(pubkeydata_len)
*pubkeydata_len = key_len;
- if(out_ctx != NULL)
+ if(out_ctx)
*out_ctx = ctx;
- else if(ctx != NULL)
+ else if(ctx)
_libssh2_ed25519_free(ctx);
return 0;
@@ -1721,9 +1883,20 @@ clean_exit:
if(key)
LIBSSH2_FREE(session, key);
+ if(application && *application) {
+ LIBSSH2_FREE(session, (void *)application);
+ *application = NULL;
+ }
+
+ if(key_handle && *key_handle) {
+ LIBSSH2_FREE(session, (void *)key_handle);
+ *key_handle = NULL;
+ }
+
return -1;
}
+
int
_libssh2_ed25519_new_private(libssh2_ed25519_ctx ** ed_ctx,
LIBSSH2_SESSION * session,
@@ -1735,7 +1908,7 @@ _libssh2_ed25519_new_private(libssh2_ed25519_ctx ** ed_ctx,
struct string_buf *decrypted = NULL;
libssh2_ed25519_ctx *ctx = NULL;
- if(session == NULL) {
+ if(!session) {
_libssh2_error(session, LIBSSH2_ERROR_PROTO,
"Session is required");
return -1;
@@ -1759,7 +1932,7 @@ _libssh2_ed25519_new_private(libssh2_ed25519_ctx ** ed_ctx,
/* 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) {
+ if(rc || !buf) {
_libssh2_error(session, LIBSSH2_ERROR_PROTO,
"Public key type in decrypted key data not found");
return -1;
@@ -1782,9 +1955,85 @@ _libssh2_ed25519_new_private(libssh2_ed25519_ctx ** ed_ctx,
_libssh2_string_buf_free(session, decrypted);
if(rc == 0) {
- if(ed_ctx != NULL)
+ if(ed_ctx)
+ *ed_ctx = ctx;
+ else if(ctx)
+ _libssh2_ed25519_free(ctx);
+ }
+
+ return rc;
+}
+
+int
+_libssh2_ed25519_new_private_sk(libssh2_ed25519_ctx **ed_ctx,
+ unsigned char *flags,
+ const char **application,
+ const unsigned char **key_handle,
+ size_t *handle_len,
+ 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) {
+ _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 SK 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 || !buf) {
+ _libssh2_error(session, LIBSSH2_ERROR_PROTO,
+ "Public key type in decrypted key data not found");
+ return -1;
+ }
+
+ if(strcmp("sk-ssh-ed25519@openssh.com", (const char *)buf) == 0) {
+ rc = gen_publickey_from_sk_ed25519_openssh_priv_data(session,
+ decrypted,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ flags,
+ application,
+ key_handle,
+ handle_len,
+ &ctx);
+ }
+ else {
+ rc = -1;
+ }
+
+ if(decrypted)
+ _libssh2_string_buf_free(session, decrypted);
+
+ if(rc == 0) {
+ if(ed_ctx)
*ed_ctx = ctx;
- else if(ctx != NULL)
+ else if(ctx)
_libssh2_ed25519_free(ctx);
}
@@ -1798,6 +2047,25 @@ _libssh2_ed25519_new_private_frommemory(libssh2_ed25519_ctx ** ed_ctx,
size_t filedata_len,
unsigned const char *passphrase)
{
+ libssh2_ed25519_ctx *ctx = NULL;
+
+ _libssh2_init_if_needed();
+
+ if(read_private_key_from_memory((void **)&ctx,
+ (pem_read_bio_func)
+ &PEM_read_bio_PrivateKey,
+ filedata, filedata_len,
+ passphrase) == 0) {
+ if(EVP_PKEY_id(ctx) != EVP_PKEY_ED25519) {
+ _libssh2_ed25519_free(ctx);
+ return _libssh2_error(session, LIBSSH2_ERROR_PROTO,
+ "Private key is not an ED25519 key");
+ }
+
+ *ed_ctx = ctx;
+ return 0;
+ }
+
return read_openssh_private_key_from_memory((void **)ed_ctx, session,
"ssh-ed25519",
filedata, filedata_len,
@@ -1805,46 +2073,64 @@ _libssh2_ed25519_new_private_frommemory(libssh2_ed25519_ctx ** ed_ctx,
}
int
+_libssh2_ed25519_new_private_frommemory_sk(libssh2_ed25519_ctx **ed_ctx,
+ unsigned char *flags,
+ const char **application,
+ const unsigned char **key_handle,
+ size_t *handle_len,
+ LIBSSH2_SESSION *session,
+ const char *filedata,
+ size_t filedata_len,
+ unsigned const char *passphrase)
+{
+ int algorithm;
+ return _libssh2_sk_pub_openssh_keyfilememory(session,
+ (void **)ed_ctx,
+ "sk-ssh-ed25519@openssh.com",
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ &algorithm,
+ flags,
+ application,
+ key_handle,
+ handle_len,
+ 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)
+ const size_t key_len)
{
libssh2_ed25519_ctx *ctx = NULL;
- EVP_PKEY *public_key = NULL;
- if(ed_ctx == NULL)
+ if(!ed_ctx)
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) {
+ ctx = EVP_PKEY_new_raw_public_key(EVP_PKEY_ED25519, NULL,
+ raw_pub_key, key_len);
+ if(!ctx)
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)
+ if(ed_ctx)
*ed_ctx = ctx;
- else if(ctx != NULL)
+ else if(ctx)
_libssh2_ed25519_free(ctx);
return 0;
}
-
#endif /* LIBSSH2_ED25519 */
+
+#if LIBSSH2_RSA
int
-_libssh2_rsa_sha1_sign(LIBSSH2_SESSION * session,
+_libssh2_rsa_sha2_sign(LIBSSH2_SESSION * session,
libssh2_rsa_ctx * rsactx,
const unsigned char *hash,
size_t hash_len,
@@ -1861,7 +2147,20 @@ _libssh2_rsa_sha1_sign(LIBSSH2_SESSION * session,
return -1;
}
- ret = RSA_sign(NID_sha1, hash, hash_len, sig, &sig_len, rsactx);
+ if(hash_len == SHA_DIGEST_LENGTH)
+ ret = RSA_sign(NID_sha1,
+ hash, (unsigned int) hash_len, sig, &sig_len, rsactx);
+ else if(hash_len == SHA256_DIGEST_LENGTH)
+ ret = RSA_sign(NID_sha256,
+ hash, (unsigned int) hash_len, sig, &sig_len, rsactx);
+ else if(hash_len == SHA512_DIGEST_LENGTH)
+ ret = RSA_sign(NID_sha512,
+ hash, (unsigned int) hash_len, sig, &sig_len, rsactx);
+ else {
+ _libssh2_error(session, LIBSSH2_ERROR_PROTO,
+ "Unsupported hash digest length");
+ ret = -1;
+ }
if(!ret) {
LIBSSH2_FREE(session, sig);
@@ -1874,17 +2173,32 @@ _libssh2_rsa_sha1_sign(LIBSSH2_SESSION * session,
return 0;
}
+#if LIBSSH2_RSA_SHA1
+int
+_libssh2_rsa_sha1_sign(LIBSSH2_SESSION * session,
+ libssh2_rsa_ctx * rsactx,
+ const unsigned char *hash,
+ size_t hash_len,
+ unsigned char **signature, size_t *signature_len)
+{
+ return _libssh2_rsa_sha2_sign(session, rsactx, hash, hash_len,
+ signature, signature_len);
+}
+#endif
+#endif
+
#if LIBSSH2_DSA
int
_libssh2_dsa_sha1_sign(libssh2_dsa_ctx * dsactx,
const unsigned char *hash,
- unsigned long hash_len, unsigned char *signature)
+ size_t hash_len, unsigned char *signature)
{
DSA_SIG *sig;
const BIGNUM * r;
const BIGNUM * s;
int r_len, s_len;
- (void) hash_len;
+
+ (void)hash_len;
sig = DSA_do_sign(hash, SHA_DIGEST_LENGTH, dsactx);
if(!sig) {
@@ -1923,8 +2237,8 @@ _libssh2_dsa_sha1_sign(libssh2_dsa_ctx * dsactx,
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)
+ const unsigned char *hash, size_t hash_len,
+ unsigned char **signature, size_t *signature_len)
{
int r_len, s_len;
int rc = 0;
@@ -1934,8 +2248,8 @@ _libssh2_ecdsa_sign(LIBSSH2_SESSION * session, libssh2_ecdsa_ctx * ec_ctx,
unsigned char *temp_buffer = NULL;
unsigned char *out_buffer = NULL;
- ECDSA_SIG *sig = ECDSA_do_sign(hash, hash_len, ec_ctx);
- if(sig == NULL)
+ ECDSA_SIG *sig = ECDSA_do_sign(hash, (int) hash_len, ec_ctx);
+ if(!sig)
return -1;
#ifdef HAVE_OPAQUE_STRUCTS
ECDSA_SIG_get0(sig, &pr, &ps);
@@ -1948,7 +2262,7 @@ _libssh2_ecdsa_sign(LIBSSH2_SESSION * session, libssh2_ecdsa_ctx * ec_ctx,
s_len = BN_num_bytes(ps) + 1;
temp_buffer = malloc(r_len + s_len + 8);
- if(temp_buffer == NULL) {
+ if(!temp_buffer) {
rc = -1;
goto clean_exit;
}
@@ -1960,7 +2274,7 @@ _libssh2_ecdsa_sign(LIBSSH2_SESSION * session, libssh2_ecdsa_ctx * ec_ctx,
out_buffer_len = (size_t)(sp - temp_buffer);
out_buffer = LIBSSH2_CALLOC(session, out_buffer_len);
- if(out_buffer == NULL) {
+ if(!out_buffer) {
rc = -1;
goto clean_exit;
}
@@ -1972,7 +2286,7 @@ _libssh2_ecdsa_sign(LIBSSH2_SESSION * session, libssh2_ecdsa_ctx * ec_ctx,
clean_exit:
- if(temp_buffer != NULL)
+ if(temp_buffer)
free(temp_buffer);
if(sig)
@@ -1988,7 +2302,7 @@ _libssh2_sha1_init(libssh2_sha1_ctx *ctx)
#ifdef HAVE_OPAQUE_STRUCTS
*ctx = EVP_MD_CTX_new();
- if(*ctx == NULL)
+ if(!*ctx)
return 0;
if(EVP_DigestInit(*ctx, EVP_get_digestbyname("sha1")))
@@ -2005,13 +2319,13 @@ _libssh2_sha1_init(libssh2_sha1_ctx *ctx)
}
int
-_libssh2_sha1(const unsigned char *message, unsigned long len,
+_libssh2_sha1(const unsigned char *message, size_t len,
unsigned char *out)
{
#ifdef HAVE_OPAQUE_STRUCTS
EVP_MD_CTX * ctx = EVP_MD_CTX_new();
- if(ctx == NULL)
+ if(!ctx)
return 1; /* error */
if(EVP_DigestInit(ctx, EVP_get_digestbyname("sha1"))) {
@@ -2040,7 +2354,7 @@ _libssh2_sha256_init(libssh2_sha256_ctx *ctx)
#ifdef HAVE_OPAQUE_STRUCTS
*ctx = EVP_MD_CTX_new();
- if(*ctx == NULL)
+ if(!*ctx)
return 0;
if(EVP_DigestInit(*ctx, EVP_get_digestbyname("sha256")))
@@ -2057,13 +2371,13 @@ _libssh2_sha256_init(libssh2_sha256_ctx *ctx)
}
int
-_libssh2_sha256(const unsigned char *message, unsigned long len,
+_libssh2_sha256(const unsigned char *message, size_t len,
unsigned char *out)
{
#ifdef HAVE_OPAQUE_STRUCTS
EVP_MD_CTX * ctx = EVP_MD_CTX_new();
- if(ctx == NULL)
+ if(!ctx)
return 1; /* error */
if(EVP_DigestInit(ctx, EVP_get_digestbyname("sha256"))) {
@@ -2092,7 +2406,7 @@ _libssh2_sha384_init(libssh2_sha384_ctx *ctx)
#ifdef HAVE_OPAQUE_STRUCTS
*ctx = EVP_MD_CTX_new();
- if(*ctx == NULL)
+ if(!*ctx)
return 0;
if(EVP_DigestInit(*ctx, EVP_get_digestbyname("sha384")))
@@ -2109,13 +2423,13 @@ _libssh2_sha384_init(libssh2_sha384_ctx *ctx)
}
int
-_libssh2_sha384(const unsigned char *message, unsigned long len,
- unsigned char *out)
+_libssh2_sha384(const unsigned char *message, size_t len,
+ unsigned char *out)
{
#ifdef HAVE_OPAQUE_STRUCTS
EVP_MD_CTX * ctx = EVP_MD_CTX_new();
- if(ctx == NULL)
+ if(!ctx)
return 1; /* error */
if(EVP_DigestInit(ctx, EVP_get_digestbyname("sha384"))) {
@@ -2144,7 +2458,7 @@ _libssh2_sha512_init(libssh2_sha512_ctx *ctx)
#ifdef HAVE_OPAQUE_STRUCTS
*ctx = EVP_MD_CTX_new();
- if(*ctx == NULL)
+ if(!*ctx)
return 0;
if(EVP_DigestInit(*ctx, EVP_get_digestbyname("sha512")))
@@ -2161,13 +2475,13 @@ _libssh2_sha512_init(libssh2_sha512_ctx *ctx)
}
int
-_libssh2_sha512(const unsigned char *message, unsigned long len,
- unsigned char *out)
+_libssh2_sha512(const unsigned char *message, size_t len,
+ unsigned char *out)
{
#ifdef HAVE_OPAQUE_STRUCTS
EVP_MD_CTX * ctx = EVP_MD_CTX_new();
- if(ctx == NULL)
+ if(!ctx)
return 1; /* error */
if(EVP_DigestInit(ctx, EVP_get_digestbyname("sha512"))) {
@@ -2193,10 +2507,24 @@ _libssh2_sha512(const unsigned char *message, unsigned long len,
int
_libssh2_md5_init(libssh2_md5_ctx *ctx)
{
+ /* MD5 digest is not supported in OpenSSL FIPS mode
+ * Trying to init it will result in a latent OpenSSL error:
+ * "digital envelope routines:FIPS_DIGESTINIT:disabled for fips"
+ * So, just return 0 in FIPS mode
+ */
+#if OPENSSL_VERSION_NUMBER >= 0x000907000L && \
+ defined(OPENSSL_VERSION_MAJOR) && \
+ OPENSSL_VERSION_MAJOR < 3 && \
+ !defined(LIBRESSL_VERSION_NUMBER)
+
+ if(FIPS_mode())
+ return 0;
+#endif
+
#ifdef HAVE_OPAQUE_STRUCTS
*ctx = EVP_MD_CTX_new();
- if(*ctx == NULL)
+ if(!*ctx)
return 0;
if(EVP_DigestInit(*ctx, EVP_get_digestbyname("md5")))
@@ -2220,6 +2548,7 @@ gen_publickey_from_ec_evp(LIBSSH2_SESSION *session,
size_t *method_len,
unsigned char **pubkeydata,
size_t *pubkeydata_len,
+ int is_sk,
EVP_PKEY *pk)
{
int rc = 0;
@@ -2235,40 +2564,47 @@ gen_publickey_from_ec_evp(LIBSSH2_SESSION *session,
BN_CTX *bn_ctx;
libssh2_curve_type type;
- _libssh2_debug(session,
- LIBSSH2_TRACE_AUTH,
- "Computing public key from EC private key envelop");
+ _libssh2_debug((session,
+ LIBSSH2_TRACE_AUTH,
+ "Computing public key from EC private key envelope"));
bn_ctx = BN_CTX_new();
- if(bn_ctx == NULL)
+ if(!bn_ctx)
return -1;
ec = EVP_PKEY_get1_EC_KEY(pk);
- if(ec == NULL) {
+ if(!ec) {
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);
+ type = _libssh2_ecdsa_get_curve_type(ec);
+
+ if(is_sk)
+ *method_len = 34;
+ else
+ *method_len = 19;
- method_buf = LIBSSH2_ALLOC(session, 19);
- if(method_buf == NULL) {
+ method_buf = LIBSSH2_ALLOC(session, *method_len);
+ if(!method_buf) {
return _libssh2_error(session, LIBSSH2_ERROR_ALLOC,
- "out of memory");
+ "out of memory");
}
- if(type == LIBSSH2_EC_CURVE_NISTP256)
- memcpy(method_buf, "ecdsa-sha2-nistp256", 19);
+ if(is_sk)
+ memcpy(method_buf, "sk-ecdsa-sha2-nistp256@openssh.com", *method_len);
+ else if(type == LIBSSH2_EC_CURVE_NISTP256)
+ memcpy(method_buf, "ecdsa-sha2-nistp256", *method_len);
else if(type == LIBSSH2_EC_CURVE_NISTP384)
- memcpy(method_buf, "ecdsa-sha2-nistp384", 19);
+ memcpy(method_buf, "ecdsa-sha2-nistp384", *method_len);
else if(type == LIBSSH2_EC_CURVE_NISTP521)
- memcpy(method_buf, "ecdsa-sha2-nistp521", 19);
+ memcpy(method_buf, "ecdsa-sha2-nistp521", *method_len);
else {
- _libssh2_debug(session,
- LIBSSH2_TRACE_ERROR,
- "Unsupported EC private key type");
+ _libssh2_debug((session,
+ LIBSSH2_TRACE_ERROR,
+ "Unsupported EC private key type"));
rc = -1;
goto clean_exit;
}
@@ -2283,7 +2619,7 @@ gen_publickey_from_ec_evp(LIBSSH2_SESSION *session,
}
octal_value = malloc(octal_len);
- if(octal_value == NULL) {
+ if(!octal_value) {
rc = -1;
goto clean_exit;
}
@@ -2291,52 +2627,56 @@ gen_publickey_from_ec_evp(LIBSSH2_SESSION *session,
/* 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;
+ 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 form is: type_len(4) + type(method_len) + domain_len(4) + domain(8)
+ + pub_key_len(4) + pub_key(~65). */
+ key_len = 4 + *method_len + 4 + 8 + 4 + octal_len;
key = LIBSSH2_ALLOC(session, key_len);
- if(key == NULL) {
+ if(!key) {
rc = -1;
- goto clean_exit;
+ goto clean_exit;
}
/* Process key encoding. */
p = key;
/* Key type */
- _libssh2_store_str(&p, (const char *)method_buf, 19);
+ _libssh2_store_str(&p, (const char *)method_buf, *method_len);
/* Name domain */
- _libssh2_store_str(&p, (const char *)method_buf + 11, 8);
+ if(is_sk) {
+ _libssh2_store_str(&p, "nistp256", 8);
+ }
+ else {
+ _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)
+ if(ec)
EC_KEY_free(ec);
- if(bn_ctx != NULL) {
+ if(bn_ctx) {
BN_CTX_free(bn_ctx);
}
- if(octal_value != NULL)
+ if(octal_value)
free(octal_value);
if(rc == 0)
return 0;
- if(method_buf != NULL)
+ if(method_buf)
LIBSSH2_FREE(session, method_buf);
return -1;
@@ -2358,9 +2698,9 @@ gen_publickey_from_ecdsa_openssh_priv_data(LIBSSH2_SESSION *session,
EC_KEY *ec_key = NULL;
BIGNUM *bn_exponent;
- _libssh2_debug(session,
+ _libssh2_debug((session,
LIBSSH2_TRACE_AUTH,
- "Computing ECDSA keys from private key data");
+ "Computing ECDSA keys from private key data"));
if(_libssh2_get_string(decrypted, &curve, &curvelen) ||
curvelen == 0) {
@@ -2381,35 +2721,40 @@ gen_publickey_from_ecdsa_openssh_priv_data(LIBSSH2_SESSION *session,
return -1;
}
- if((rc = _libssh2_ecdsa_curve_name_with_octal_new(&ec_key, point_buf,
- pointlen, curve_type)) != 0) {
+ rc = _libssh2_ecdsa_curve_name_with_octal_new(&ec_key,
+ point_buf, pointlen,
+ curve_type);
+ if(rc) {
+ rc = -1;
_libssh2_error(session, LIBSSH2_ERROR_PROTO,
"ECDSA could not create key");
goto fail;
}
bn_exponent = BN_new();
- if(bn_exponent == NULL) {
+ if(!bn_exponent) {
rc = -1;
+ _libssh2_error(session, LIBSSH2_ERROR_ALLOC,
+ "Unable to allocate memory for private key data");
goto fail;
}
- BN_bin2bn(exponent, exponentlen, bn_exponent);
+ BN_bin2bn(exponent, (int) exponentlen, bn_exponent);
rc = (EC_KEY_set_private_key(ec_key, bn_exponent) != 1);
- if(rc == 0 && ec_key != NULL && pubkeydata != NULL && method != NULL) {
+ if(rc == 0 && ec_key && pubkeydata && method) {
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);
+ 0, pk);
if(pk)
EVP_PKEY_free(pk);
}
- if(ec_ctx != NULL)
+ if(ec_ctx)
*ec_ctx = ec_key;
else
EC_KEY_free(ec_key);
@@ -2417,17 +2762,152 @@ gen_publickey_from_ecdsa_openssh_priv_data(LIBSSH2_SESSION *session,
return rc;
fail:
+ if(ec_key)
+ EC_KEY_free(ec_key);
+
+ return rc;
+}
+
+static int
+gen_publickey_from_sk_ecdsa_openssh_priv_data(LIBSSH2_SESSION *session,
+ struct string_buf *decrypted,
+ unsigned char **method,
+ size_t *method_len,
+ unsigned char **pubkeydata,
+ size_t *pubkeydata_len,
+ uint8_t *flags,
+ const char **application,
+ const unsigned char **key_handle,
+ size_t *handle_len,
+ libssh2_ecdsa_ctx **ec_ctx)
+{
+ int rc = 0;
+ size_t curvelen, pointlen, key_len, app_len;
+ unsigned char *curve, *point_buf, *p, *key, *app;
+ EC_KEY *ec_key = NULL;
+
+ _libssh2_debug((session,
+ LIBSSH2_TRACE_AUTH,
+ "Extracting ECDSA-SK public key"));
+
+ if(_libssh2_get_string(decrypted, &curve, &curvelen) ||
+ curvelen == 0) {
+ _libssh2_error(session, LIBSSH2_ERROR_PROTO,
+ "ECDSA no curve");
+ return -1;
+ }
+
+ if(_libssh2_get_string(decrypted, &point_buf, &pointlen)) {
+ _libssh2_error(session, LIBSSH2_ERROR_PROTO,
+ "ECDSA no point");
+ return -1;
+ }
+
+ rc = _libssh2_ecdsa_curve_name_with_octal_new(&ec_key,
+ point_buf, pointlen,
+ LIBSSH2_EC_CURVE_NISTP256);
+ if(rc) {
+ rc = -1;
+ _libssh2_error(session, LIBSSH2_ERROR_PROTO,
+ "ECDSA could not create key");
+ goto fail;
+ }
+
+ if(_libssh2_get_string(decrypted, &app, &app_len)) {
+ _libssh2_error(session, LIBSSH2_ERROR_PROTO,
+ "No SK application.");
+ goto fail;
+ }
+
+ if(flags && _libssh2_get_byte(decrypted, flags)) {
+ _libssh2_error(session, LIBSSH2_ERROR_PROTO,
+ "No SK flags.");
+ goto fail;
+ }
+
+ if(key_handle && handle_len) {
+ unsigned char *handle = NULL;
+ if(_libssh2_get_string(decrypted, &handle, handle_len)) {
+ _libssh2_error(session, LIBSSH2_ERROR_PROTO,
+ "No SK key_handle.");
+ goto fail;
+ }
+
+ if(*handle_len > 0) {
+ *key_handle = LIBSSH2_ALLOC(session, *handle_len);
+
+ if(*key_handle) {
+ memcpy((void *)*key_handle, handle, *handle_len);
+ }
+ }
+ }
+
+ if(rc == 0 && ec_key && pubkeydata && method) {
+ 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,
+ 1, pk);
+
+ if(pk)
+ EVP_PKEY_free(pk);
+ }
+
+ if(rc == 0 && pubkeydata) {
+ key_len = *pubkeydata_len + app_len + 4;
+ key = LIBSSH2_ALLOC(session, key_len);
+
+ if(!key) {
+ rc = -1;
+ goto fail;
+ }
+
+ p = key + *pubkeydata_len;
+
+ memcpy(key, *pubkeydata, *pubkeydata_len);
+ _libssh2_store_str(&p, (const char *)app, app_len);
- if(ec_key != NULL)
+ if(application && app_len > 0) {
+ *application = (const char *)LIBSSH2_ALLOC(session, app_len + 1);
+ _libssh2_explicit_zero((void *)*application, app_len + 1);
+ memcpy((void *)*application, app, app_len);
+ }
+
+ LIBSSH2_FREE(session, *pubkeydata);
+ *pubkeydata_len = key_len;
+
+ if(pubkeydata)
+ *pubkeydata = key;
+ else if(key)
+ LIBSSH2_FREE(session, key);
+ }
+
+ if(ec_ctx)
+ *ec_ctx = ec_key;
+ else
EC_KEY_free(ec_key);
- return _libssh2_error(session,
- LIBSSH2_ERROR_ALLOC,
- "Unable to allocate memory for private key data");
+ return rc;
+
+fail:
+ if(ec_key)
+ EC_KEY_free(ec_key);
+ if(application && *application) {
+ LIBSSH2_FREE(session, (void *)application);
+ *application = NULL;
+ }
+ if(key_handle && *key_handle) {
+ LIBSSH2_FREE(session, (void *)key_handle);
+ *key_handle = NULL;
+ }
+
+ return rc;
}
+
static int
_libssh2_ecdsa_new_openssh_private(libssh2_ecdsa_ctx ** ec_ctx,
LIBSSH2_SESSION * session,
@@ -2440,9 +2920,9 @@ _libssh2_ecdsa_new_openssh_private(libssh2_ecdsa_ctx ** ec_ctx,
libssh2_curve_type type;
struct string_buf *decrypted = NULL;
- if(session == NULL) {
+ if(!session) {
_libssh2_error(session, LIBSSH2_ERROR_PROTO,
- "Session is required");
+ "Session is required");
return -1;
}
@@ -2464,7 +2944,7 @@ _libssh2_ecdsa_new_openssh_private(libssh2_ecdsa_ctx ** ec_ctx,
/* 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) {
+ if(rc || !buf) {
_libssh2_error(session, LIBSSH2_ERROR_PROTO,
"Public key type in decrypted key data not found");
return -1;
@@ -2487,6 +2967,72 @@ _libssh2_ecdsa_new_openssh_private(libssh2_ecdsa_ctx ** ec_ctx,
return rc;
}
+static int
+_libssh2_ecdsa_new_openssh_private_sk(libssh2_ecdsa_ctx ** ec_ctx,
+ uint8_t *flags,
+ const char **application,
+ const unsigned char **key_handle,
+ size_t *handle_len,
+ 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) {
+ _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 ECDSA 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 || !buf) {
+ _libssh2_error(session, LIBSSH2_ERROR_PROTO,
+ "Public key type in decrypted key data not found");
+ return -1;
+ }
+
+ if(strcmp("sk-ecdsa-sha2-nistp256@openssh.com", (const char *)buf) == 0) {
+ rc = gen_publickey_from_sk_ecdsa_openssh_priv_data(session,
+ decrypted,
+ NULL, 0,
+ NULL, 0,
+ flags,
+ application,
+ key_handle,
+ handle_len,
+ ec_ctx);
+ }
+ else {
+ rc = -1;
+ }
+
+ if(decrypted)
+ _libssh2_string_buf_free(session, decrypted);
+
+ return rc;
+}
+
int
_libssh2_ecdsa_new_private(libssh2_ecdsa_ctx ** ec_ctx,
LIBSSH2_SESSION * session,
@@ -2495,7 +3041,6 @@ _libssh2_ecdsa_new_private(libssh2_ecdsa_ctx ** ec_ctx,
int rc;
pem_read_bio_func read_ec = (pem_read_bio_func) &PEM_read_bio_ECPrivateKey;
- (void) session;
_libssh2_init_if_needed();
@@ -2510,6 +3055,40 @@ _libssh2_ecdsa_new_private(libssh2_ecdsa_ctx ** ec_ctx,
return rc;
}
+int
+_libssh2_ecdsa_new_private_sk(libssh2_ecdsa_ctx ** ec_ctx,
+ unsigned char *flags,
+ const char **application,
+ const unsigned char **key_handle,
+ size_t *handle_len,
+ 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;
+
+ _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_sk(ec_ctx,
+ flags,
+ application,
+ key_handle,
+ handle_len,
+ session,
+ filename,
+ passphrase);
+ }
+
+ return rc;
+}
+
+
/*
* _libssh2_ecdsa_create_key
*
@@ -2555,16 +3134,16 @@ _libssh2_ecdsa_create_key(LIBSSH2_SESSION *session,
/* 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;
+ ret = -1;
+ goto clean_exit;
}
- if(out_private_key != NULL)
+ if(out_private_key)
*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) {
+ if(!*out_public_key_octal) {
ret = -1;
goto clean_exit;
}
@@ -2572,7 +3151,7 @@ _libssh2_ecdsa_create_key(LIBSSH2_SESSION *session,
memcpy(*out_public_key_octal, octal_value, octal_len);
}
- if(out_public_key_octal_len != NULL)
+ if(out_public_key_octal_len)
*out_public_key_octal_len = octal_len;
clean_exit:
@@ -2605,13 +3184,13 @@ _libssh2_ecdh_gen_k(_libssh2_bn **k, _libssh2_ec_key *private_key,
if(!bn_ctx)
return -1;
- if(k == NULL)
+ if(!k)
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)
+ if(!server_public_key_point)
return -1;
rc = EC_POINT_oct2point(private_key_group, server_public_key_point,
@@ -2636,17 +3215,17 @@ _libssh2_ecdh_gen_k(_libssh2_bn **k, _libssh2_ec_key *private_key,
goto clean_exit;
}
- BN_bin2bn(secret, secret_len, *k);
+ BN_bin2bn(secret, (int) secret_len, *k);
clean_exit:
- if(server_public_key_point != NULL)
+ if(server_public_key_point)
EC_POINT_free(server_public_key_point);
- if(bn_ctx != NULL)
+ if(bn_ctx)
BN_CTX_free(bn_ctx);
- if(secret != NULL)
+ if(secret)
free(secret);
return ret;
@@ -2667,8 +3246,8 @@ _libssh2_ed25519_sign(libssh2_ed25519_ctx *ctx, LIBSSH2_SESSION *session,
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)
+ if(md_ctx) {
+ if(EVP_DigestSignInit(md_ctx, NULL, NULL, NULL, ctx) != 1)
goto clean_exit;
if(EVP_DigestSign(md_ctx, NULL, &sig_len, message, message_len) != 1)
goto clean_exit;
@@ -2677,7 +3256,7 @@ _libssh2_ed25519_sign(libssh2_ed25519_ctx *ctx, LIBSSH2_SESSION *session,
goto clean_exit;
sig = LIBSSH2_CALLOC(session, sig_len);
- if(sig == NULL)
+ if(!sig)
goto clean_exit;
rc = EVP_DigestSign(md_ctx, sig, &sig_len, message, message_len);
@@ -2698,7 +3277,7 @@ clean_exit:
if(md_ctx)
EVP_MD_CTX_free(md_ctx);
- return (rc == 1 ? 0 : -1);
+ return (rc == 1) ? 0 : -1;
}
int
@@ -2713,11 +3292,11 @@ _libssh2_curve25519_gen_k(_libssh2_bn **k,
BN_CTX *bn_ctx = NULL;
size_t out_len = 0;
- if(k == NULL || *k == NULL)
+ if(!k || !*k)
return -1;
bn_ctx = BN_CTX_new();
- if(bn_ctx == NULL)
+ if(!bn_ctx)
return -1;
peer_key = EVP_PKEY_new_raw_public_key(EVP_PKEY_X25519, NULL,
@@ -2728,27 +3307,33 @@ _libssh2_curve25519_gen_k(_libssh2_bn **k,
private_key,
LIBSSH2_ED25519_KEY_LEN);
- if(peer_key == NULL || server_key == NULL) {
- goto cleanExit;
+ if(!peer_key || !server_key) {
+ goto clean_exit;
}
server_key_ctx = EVP_PKEY_CTX_new(server_key, NULL);
- if(server_key_ctx == NULL) {
- goto cleanExit;
+ if(!server_key_ctx) {
+ goto clean_exit;
}
rc = EVP_PKEY_derive_init(server_key_ctx);
- if(rc <= 0) goto cleanExit;
+ if(rc <= 0) {
+ goto clean_exit;
+ }
rc = EVP_PKEY_derive_set_peer(server_key_ctx, peer_key);
- if(rc <= 0) goto cleanExit;
+ if(rc <= 0) {
+ goto clean_exit;
+ }
rc = EVP_PKEY_derive(server_key_ctx, NULL, &out_len);
- if(rc <= 0) goto cleanExit;
+ if(rc <= 0) {
+ goto clean_exit;
+ }
if(out_len != LIBSSH2_ED25519_KEY_LEN) {
rc = -1;
- goto cleanExit;
+ goto clean_exit;
}
rc = EVP_PKEY_derive(server_key_ctx, out_shared_key, &out_len);
@@ -2760,7 +3345,7 @@ _libssh2_curve25519_gen_k(_libssh2_bn **k,
rc = -1;
}
-cleanExit:
+clean_exit:
if(server_key_ctx)
EVP_PKEY_CTX_free(server_key_ctx);
@@ -2768,7 +3353,7 @@ cleanExit:
EVP_PKEY_free(peer_key);
if(server_key)
EVP_PKEY_free(server_key);
- if(bn_ctx != NULL)
+ if(bn_ctx)
BN_CTX_free(bn_ctx);
return (rc == 1) ? 0 : -1;
@@ -2782,16 +3367,16 @@ _libssh2_ed25519_verify(libssh2_ed25519_ctx *ctx, const uint8_t *s,
int ret = -1;
EVP_MD_CTX *md_ctx = EVP_MD_CTX_new();
- if(NULL == md_ctx)
+ if(!md_ctx)
return -1;
- ret = EVP_DigestVerifyInit(md_ctx, NULL, NULL, NULL, ctx->public_key);
+ ret = EVP_DigestVerifyInit(md_ctx, NULL, NULL, NULL, ctx);
if(ret != 1)
goto clean_exit;
ret = EVP_DigestVerify(md_ctx, s, s_len, m, m_len);
- clean_exit:
+clean_exit:
EVP_MD_CTX_free(md_ctx);
@@ -2814,7 +3399,7 @@ _libssh2_pub_priv_openssh_keyfile(LIBSSH2_SESSION *session,
struct string_buf *decrypted = NULL;
int rc = 0;
- if(session == NULL) {
+ if(!session) {
_libssh2_error(session, LIBSSH2_ERROR_PROTO,
"Session is required");
return -1;
@@ -2841,7 +3426,7 @@ _libssh2_pub_priv_openssh_keyfile(LIBSSH2_SESSION *session,
/* 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) {
+ if(rc || !buf) {
_libssh2_error(session, LIBSSH2_ERROR_PROTO,
"Public key type in decrypted key data not found");
return -1;
@@ -2849,6 +3434,12 @@ _libssh2_pub_priv_openssh_keyfile(LIBSSH2_SESSION *session,
rc = -1;
+ /* Avoid unused variable warnings when all branches below are disabled */
+ (void)method;
+ (void)method_len;
+ (void)pubkeydata;
+ (void)pubkeydata_len;
+
#if LIBSSH2_ED25519
if(strcmp("ssh-ed25519", (const char *)buf) == 0) {
rc = gen_publickey_from_ed25519_openssh_priv_data(session, decrypted,
@@ -2895,7 +3486,7 @@ _libssh2_pub_priv_openssh_keyfile(LIBSSH2_SESSION *session,
if(decrypted)
_libssh2_string_buf_free(session, decrypted);
- if(rc != 0) {
+ if(rc) {
_libssh2_error(session, LIBSSH2_ERROR_FILE,
"Unsupported OpenSSH key type");
}
@@ -2918,13 +3509,13 @@ _libssh2_pub_priv_keyfile(LIBSSH2_SESSION *session,
int pktype;
int rc;
- _libssh2_debug(session,
+ _libssh2_debug((session,
LIBSSH2_TRACE_AUTH,
"Computing public key from private key file: %s",
- privatekey);
+ privatekey));
bp = BIO_new_file(privatekey, "r");
- if(bp == NULL) {
+ if(!bp) {
return _libssh2_error(session,
LIBSSH2_ERROR_FILE,
"Unable to extract public key from private key "
@@ -2935,7 +3526,7 @@ _libssh2_pub_priv_keyfile(LIBSSH2_SESSION *session,
pk = PEM_read_bio_PrivateKey(bp, NULL, NULL, (void *)passphrase);
BIO_free(bp);
- if(pk == NULL) {
+ if(!pk) {
/* Try OpenSSH format */
rc = _libssh2_pub_priv_openssh_keyfile(session,
@@ -2943,7 +3534,7 @@ _libssh2_pub_priv_keyfile(LIBSSH2_SESSION *session,
method_len,
pubkeydata, pubkeydata_len,
privatekey, passphrase);
- if(rc != 0) {
+ if(rc) {
return _libssh2_error(session,
LIBSSH2_ERROR_FILE,
"Unable to extract public key "
@@ -2962,26 +3553,31 @@ _libssh2_pub_priv_keyfile(LIBSSH2_SESSION *session,
#endif
switch(pktype) {
- case EVP_PKEY_RSA :
+#if LIBSSH2_ED25519
+ case EVP_PKEY_ED25519:
+ st = gen_publickey_from_ed_evp(
+ session, method, method_len, pubkeydata, pubkeydata_len, pk);
+ break;
+#endif /* LIBSSH2_ED25519 */
+#if LIBSSH2_RSA
+ case EVP_PKEY_RSA:
st = gen_publickey_from_rsa_evp(
session, method, method_len, pubkeydata, pubkeydata_len, pk);
break;
-
+#endif /* LIBSSH2_RSA */
#if LIBSSH2_DSA
- case EVP_PKEY_DSA :
+ case EVP_PKEY_DSA:
st = gen_publickey_from_dsa_evp(
session, method, method_len, pubkeydata, pubkeydata_len, pk);
break;
-#endif /* LIBSSH_DSA */
-
+#endif /* LIBSSH2_DSA */
#if LIBSSH2_ECDSA
- case EVP_PKEY_EC :
+ case EVP_PKEY_EC:
st = gen_publickey_from_ec_evp(
- session, method, method_len, pubkeydata, pubkeydata_len, pk);
+ session, method, method_len, pubkeydata, pubkeydata_len, 0, pk);
break;
-#endif
-
- default :
+#endif /* LIBSSH2_ECDSA */
+ default:
st = _libssh2_error(session,
LIBSSH2_ERROR_FILE,
"Unable to extract public key "
@@ -3010,20 +3606,16 @@ _libssh2_pub_priv_openssh_keyfilememory(LIBSSH2_SESSION *session,
unsigned char *buf = NULL;
struct string_buf *decrypted = NULL;
- if(key_ctx != NULL)
+ if(key_ctx)
*key_ctx = NULL;
- if(session == NULL) {
- _libssh2_error(session, LIBSSH2_ERROR_PROTO,
- "Session is required");
- return -1;
- }
+ if(!session)
+ return _libssh2_error(session, LIBSSH2_ERROR_PROTO,
+ "Session is required");
- if(key_type != NULL && (strlen(key_type) > 11 || strlen(key_type) < 7)) {
- _libssh2_error(session, LIBSSH2_ERROR_PROTO,
- "type is invalid");
- return -1;
- }
+ if(key_type && (strlen(key_type) > 11 || strlen(key_type) < 7))
+ return _libssh2_error(session, LIBSSH2_ERROR_PROTO,
+ "type is invalid");
_libssh2_init_if_needed();
@@ -3031,24 +3623,28 @@ _libssh2_pub_priv_openssh_keyfilememory(LIBSSH2_SESSION *session,
privatekeydata,
privatekeydata_len, &decrypted);
- if(rc) {
+ 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);
+ /* 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(rc || !buf)
+ return _libssh2_error(session, LIBSSH2_ERROR_PROTO,
+ "Public key type in decrypted "
+ "key data not found");
+
+ rc = LIBSSH2_ERROR_FILE;
- rc = -1;
+ /* Avoid unused variable warnings when all branches below are disabled */
+ (void)method;
+ (void)method_len;
+ (void)pubkeydata;
+ (void)pubkeydata_len;
#if LIBSSH2_ED25519
if(strcmp("ssh-ed25519", (const char *)buf) == 0) {
- if(key_type == NULL || strcmp("ssh-ed25519", key_type) == 0) {
+ if(!key_type || strcmp("ssh-ed25519", key_type) == 0) {
rc = gen_publickey_from_ed25519_openssh_priv_data(session,
decrypted,
method,
@@ -3057,47 +3653,187 @@ _libssh2_pub_priv_openssh_keyfilememory(LIBSSH2_SESSION *session,
pubkeydata_len,
(libssh2_ed25519_ctx**)key_ctx);
}
- }
+ }
+
+ if(strcmp("sk-ssh-ed25519@openssh.com", (const char *)buf) == 0) {
+ if(!key_type ||
+ strcmp("sk-ssh-ed25519@openssh.com", key_type) == 0) {
+ rc = gen_publickey_from_sk_ed25519_openssh_priv_data(session,
+ decrypted,
+ method,
+ method_len,
+ pubkeydata,
+ pubkeydata_len,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ (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) {
+ if(!key_type || 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);
+ (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) {
+ if(!key_type || strcmp("ssh-dss", key_type) == 0) {
rc = gen_publickey_from_dsa_openssh_priv_data(session, decrypted,
- method, method_len,
+ method, method_len,
pubkeydata,
pubkeydata_len,
- (libssh2_dsa_ctx**)key_ctx);
+ (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,
+ if(strcmp("sk-ecdsa-sha2-nistp256@openssh.com", (const char *)buf) == 0) {
+ rc = gen_publickey_from_sk_ecdsa_openssh_priv_data(session, decrypted,
method, method_len,
pubkeydata,
pubkeydata_len,
- (libssh2_ecdsa_ctx**)key_ctx);
+ NULL,
+ NULL, NULL,
+ NULL,
+ (libssh2_ecdsa_ctx**)key_ctx);
+ }
+ else if(_libssh2_ecdsa_curve_type_from_name((const char *)buf, &type)
+ == 0) {
+ if(!key_type || 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(rc == LIBSSH2_ERROR_FILE)
+ rc = _libssh2_error(session, LIBSSH2_ERROR_FILE,
+ "Unable to extract public key from private key file: "
+ "invalid/unrecognized private key file format");
+
+ if(decrypted)
+ _libssh2_string_buf_free(session, decrypted);
+
+ return rc;
+}
+
+static int
+_libssh2_sk_pub_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,
+ int *algorithm,
+ unsigned char *flags,
+ const char **application,
+ const unsigned char **key_handle,
+ size_t *handle_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)
+ *key_ctx = NULL;
+
+ if(!session)
+ return _libssh2_error(session, LIBSSH2_ERROR_PROTO,
+ "Session is required");
+
+ if(key_type && strlen(key_type) < 7)
+ return _libssh2_error(session, LIBSSH2_ERROR_PROTO,
+ "type is invalid");
+
+ _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 || !buf)
+ return _libssh2_error(session, LIBSSH2_ERROR_PROTO,
+ "Public key type in decrypted "
+ "key data not found");
+
+ rc = LIBSSH2_ERROR_FILE;
+
+ /* Avoid unused variable warnings when all branches below are disabled */
+ (void)method;
+ (void)method_len;
+ (void)pubkeydata;
+ (void)pubkeydata_len;
+ (void)algorithm;
+ (void)flags;
+ (void)application;
+ (void)key_handle;
+ (void)handle_len;
+
+#if LIBSSH2_ED25519
+ if(strcmp("sk-ssh-ed25519@openssh.com", (const char *)buf) == 0) {
+ *algorithm = LIBSSH2_HOSTKEY_TYPE_ED25519;
+ if(!key_type ||
+ strcmp("sk-ssh-ed25519@openssh.com", key_type) == 0) {
+ rc = gen_publickey_from_sk_ed25519_openssh_priv_data(session,
+ decrypted,
+ method,
+ method_len,
+ pubkeydata,
+ pubkeydata_len,
+ flags,
+ application,
+ key_handle,
+ handle_len,
+ (libssh2_ed25519_ctx**)key_ctx);
+ }
+ }
+#endif
+#if LIBSSH2_ECDSA
+ if(strcmp("sk-ecdsa-sha2-nistp256@openssh.com", (const char *)buf) == 0) {
+ *algorithm = LIBSSH2_HOSTKEY_TYPE_ECDSA_256;
+ rc = gen_publickey_from_sk_ecdsa_openssh_priv_data(session, decrypted,
+ method, method_len,
+ pubkeydata,
+ pubkeydata_len,
+ flags,
+ application,
+ key_handle,
+ handle_len,
+ (libssh2_ecdsa_ctx**)key_ctx);
+ }
+#endif
+
+ if(rc == LIBSSH2_ERROR_FILE)
+ rc = _libssh2_error(session, LIBSSH2_ERROR_FILE,
+ "Unable to extract public key from private key file: "
+ "invalid/unrecognized private key file format");
+
if(decrypted)
_libssh2_string_buf_free(session, decrypted);
@@ -3117,6 +3853,10 @@ read_openssh_private_key_from_memory(void **key_ctx, LIBSSH2_SESSION *session,
passphrase);
}
+#if OPENSSL_VERSION_NUMBER >= 0x30000000L
+#define HAVE_SSLERROR_BAD_DECRYPT
+#endif
+
int
_libssh2_pub_priv_keyfilememory(LIBSSH2_SESSION *session,
unsigned char **method,
@@ -3131,21 +3871,31 @@ _libssh2_pub_priv_keyfilememory(LIBSSH2_SESSION *session,
BIO* bp;
EVP_PKEY* pk;
int pktype;
+#ifdef HAVE_SSLERROR_BAD_DECRYPT
+ unsigned long sslError;
+#endif
- _libssh2_debug(session,
+ _libssh2_debug((session,
LIBSSH2_TRACE_AUTH,
- "Computing public key from private key.");
-
- bp = BIO_new_mem_buf((char *)privatekeydata, privatekeydata_len);
- if(!bp) {
- return -1;
- }
+ "Computing public key from private key."));
+#if OPENSSL_VERSION_NUMBER >= 0x1000200fL
+ bp = BIO_new_mem_buf(privatekeydata, (int)privatekeydata_len);
+#else
+ bp = BIO_new_mem_buf((char *)privatekeydata, (int)privatekeydata_len);
+#endif
+ if(!bp)
+ return _libssh2_error(session, LIBSSH2_ERROR_ALLOC,
+ "Unable to allocate memory when"
+ "computing public key");
BIO_reset(bp);
pk = PEM_read_bio_PrivateKey(bp, NULL, NULL, (void *)passphrase);
+#ifdef HAVE_SSLERROR_BAD_DECRYPT
+ sslError = ERR_get_error();
+#endif
BIO_free(bp);
- if(pk == NULL) {
+ if(!pk) {
/* Try OpenSSH format */
st = _libssh2_pub_priv_openssh_keyfilememory(session, NULL, NULL,
method,
@@ -3154,17 +3904,23 @@ _libssh2_pub_priv_keyfilememory(LIBSSH2_SESSION *session,
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;
+ (unsigned const char *)passphrase);
+ if(st == 0)
+ return 0;
+
+#ifdef HAVE_SSLERROR_BAD_DECRYPT
+ if((ERR_GET_LIB(sslError) == ERR_LIB_PEM &&
+ ERR_GET_REASON(sslError) == PEM_R_BAD_DECRYPT) ||
+ (ERR_GET_LIB(sslError) == ERR_LIB_PROV &&
+ ERR_GET_REASON(sslError) == EVP_R_BAD_DECRYPT))
+ return _libssh2_error(session, LIBSSH2_ERROR_KEYFILE_AUTH_FAILED,
+ "Wrong passphrase for private key");
+#endif
+ return _libssh2_error(session,
+ LIBSSH2_ERROR_FILE,
+ "Unable to extract public key "
+ "from private key file: "
+ "Unsupported private key file format");
}
#ifdef HAVE_OPAQUE_STRUCTS
@@ -3174,23 +3930,32 @@ _libssh2_pub_priv_keyfilememory(LIBSSH2_SESSION *session,
#endif
switch(pktype) {
- case EVP_PKEY_RSA :
+#if LIBSSH2_ED25519
+ case EVP_PKEY_ED25519:
+ st = gen_publickey_from_ed_evp(
+ session, method, method_len, pubkeydata, pubkeydata_len, pk);
+ break;
+#endif /* LIBSSH2_ED25519 */
+#if LIBSSH2_RSA
+ case EVP_PKEY_RSA:
st = gen_publickey_from_rsa_evp(session, method, method_len,
pubkeydata, pubkeydata_len, pk);
break;
+#endif /* LIBSSH2_RSA */
#if LIBSSH2_DSA
- case EVP_PKEY_DSA :
+ case EVP_PKEY_DSA:
st = gen_publickey_from_dsa_evp(session, method, method_len,
pubkeydata, pubkeydata_len, pk);
break;
-#endif /* LIBSSH_DSA */
+#endif /* LIBSSH2_DSA */
#if LIBSSH2_ECDSA
- case EVP_PKEY_EC :
+ case EVP_PKEY_EC:
st = gen_publickey_from_ec_evp(session, method, method_len,
- pubkeydata, pubkeydata_len, pk);
+ pubkeydata, pubkeydata_len,
+ 0, pk);
break;
#endif /* LIBSSH2_ECDSA */
- default :
+ default:
st = _libssh2_error(session,
LIBSSH2_ERROR_FILE,
"Unable to extract public key "
@@ -3203,6 +3968,62 @@ _libssh2_pub_priv_keyfilememory(LIBSSH2_SESSION *session,
return st;
}
+int
+_libssh2_sk_pub_keyfilememory(LIBSSH2_SESSION *session,
+ unsigned char **method,
+ size_t *method_len,
+ unsigned char **pubkeydata,
+ size_t *pubkeydata_len,
+ int *algorithm,
+ unsigned char *flags,
+ const char **application,
+ const unsigned char **key_handle,
+ size_t *handle_len,
+ const char *privatekeydata,
+ size_t privatekeydata_len,
+ const char *passphrase)
+{
+ int st = -1;
+ BIO* bp;
+ EVP_PKEY* pk;
+
+ _libssh2_debug((session,
+ LIBSSH2_TRACE_AUTH,
+ "Computing public key from private key."));
+
+#if OPENSSL_VERSION_NUMBER >= 0x1000200fL
+ bp = BIO_new_mem_buf(privatekeydata, (int)privatekeydata_len);
+#else
+ bp = BIO_new_mem_buf((char *)privatekeydata, (int)privatekeydata_len);
+#endif
+ if(!bp)
+ return _libssh2_error(session, LIBSSH2_ERROR_ALLOC,
+ "Unable to allocate memory when"
+ "computing public key");
+ BIO_reset(bp);
+ pk = PEM_read_bio_PrivateKey(bp, NULL, NULL, (void *)passphrase);
+ BIO_free(bp);
+
+ if(!pk) {
+ /* Try OpenSSH format */
+ st = _libssh2_sk_pub_openssh_keyfilememory(session, NULL, NULL,
+ method,
+ method_len,
+ pubkeydata,
+ pubkeydata_len,
+ algorithm,
+ flags,
+ application,
+ key_handle,
+ handle_len,
+ privatekeydata,
+ privatekeydata_len,
+ (unsigned const char *)passphrase);
+ }
+
+ return st;
+}
+
void
_libssh2_dh_init(_libssh2_dh_ctx *dhctx)
{
@@ -3237,4 +4058,27 @@ _libssh2_dh_dtor(_libssh2_dh_ctx *dhctx)
*dhctx = NULL;
}
-#endif /* LIBSSH2_OPENSSL */
+/* _libssh2_supported_key_sign_algorithms
+ *
+ * Return supported key hash algo upgrades, see crypto.h
+ *
+ */
+
+const char *
+_libssh2_supported_key_sign_algorithms(LIBSSH2_SESSION *session,
+ unsigned char *key_method,
+ size_t key_method_len)
+{
+ (void)session;
+
+#if LIBSSH2_RSA_SHA2
+ if(key_method_len == 7 &&
+ memcmp(key_method, "ssh-rsa", key_method_len) == 0) {
+ return "rsa-sha2-512,rsa-sha2-256,ssh-rsa";
+ }
+#endif
+
+ return NULL;
+}
+
+#endif /* LIBSSH2_CRYPTO_C */