aboutsummaryrefslogtreecommitdiff
path: root/src/libcrypto.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/libcrypto.c')
-rw-r--r--src/libcrypto.c807
1 files changed, 472 insertions, 335 deletions
diff --git a/src/libcrypto.c b/src/libcrypto.c
index c14eeeea..f45ffa96 100644
--- a/src/libcrypto.c
+++ b/src/libcrypto.c
@@ -26,26 +26,31 @@
#include <string.h>
#ifdef HAVE_SYS_TIME_H
#include <sys/time.h>
-#endif
+#endif /* HAVE_SYS_TIME_H */
#include "libssh/priv.h"
#include "libssh/session.h"
#include "libssh/crypto.h"
#include "libssh/wrapper.h"
#include "libssh/libcrypto.h"
-#if defined(HAVE_OPENSSL_EVP_CHACHA20) && defined(HAVE_OPENSSL_EVP_POLY1305)
+#include "libssh/pki.h"
+#ifdef HAVE_OPENSSL_EVP_CHACHA20
#include "libssh/bytearray.h"
#include "libssh/chacha20-poly1305-common.h"
#endif
#ifdef HAVE_LIBCRYPTO
+#include <openssl/opensslv.h>
#include <openssl/sha.h>
#include <openssl/md5.h>
-#include <openssl/dsa.h>
+#if OPENSSL_VERSION_NUMBER < 0x30000000L
#include <openssl/rsa.h>
#include <openssl/hmac.h>
-#include <openssl/opensslv.h>
+#else
+#include <openssl/param_build.h>
+#include <openssl/core_names.h>
+#endif /* OPENSSL_VERSION_NUMBER */
#include <openssl/rand.h>
#include <openssl/engine.h>
@@ -54,11 +59,11 @@
#ifdef HAVE_OPENSSL_AES_H
#define HAS_AES
#include <openssl/aes.h>
-#endif
+#endif /* HAVE_OPENSSL_AES_H */
#ifdef HAVE_OPENSSL_DES_H
#define HAS_DES
#include <openssl/des.h>
-#endif
+#endif /* HAVE_OPENSSL_DES_H */
#if (defined(HAVE_VALGRIND_VALGRIND_H) && defined(HAVE_OPENSSL_IA32CAP_LOC))
#include <valgrind/valgrind.h>
@@ -67,14 +72,19 @@
#include "libssh/crypto.h"
-#ifdef HAVE_OPENSSL_EVP_KDF_CTX_NEW_ID
+#ifdef HAVE_OPENSSL_EVP_KDF_CTX
#include <openssl/kdf.h>
-#endif
+#if OPENSSL_VERSION_NUMBER >= 0x30000000L
+#include <openssl/param_build.h>
+#include <openssl/core_names.h>
+#endif /* OPENSSL_VERSION_NUMBER */
+#endif /* HAVE_OPENSSL_EVP_KDF_CTX */
#include "libssh/crypto.h"
static int libcrypto_initialized = 0;
+
void ssh_reseed(void){
#ifndef _WIN32
struct timeval tv;
@@ -83,265 +93,42 @@ void ssh_reseed(void){
#endif
}
-/**
- * @brief Get random bytes
- *
- * Make sure to always check the return code of this function!
- *
- * @param[in] where The buffer to fill with random bytes
- *
- * @param[in] len The size of the buffer to fill.
- *
- * @param[in] strong Use a strong or private RNG source.
- *
- * @return 1 on success, 0 on error.
- */
-int ssh_get_random(void *where, int len, int strong)
-{
-#ifdef HAVE_OPENSSL_RAND_PRIV_BYTES
- if (strong) {
- /* Returns -1 when not supported, 0 on error, 1 on success */
- return !!RAND_priv_bytes(where, len);
- }
-#else
- (void)strong;
-#endif /* HAVE_RAND_PRIV_BYTES */
-
- /* Returns -1 when not supported, 0 on error, 1 on success */
- return !!RAND_bytes(where, len);
-}
-
-SHACTX sha1_init(void)
-{
- int rc;
- SHACTX c = EVP_MD_CTX_new();
- if (c == NULL) {
- return NULL;
- }
- rc = EVP_DigestInit_ex(c, EVP_sha1(), NULL);
- if (rc == 0) {
- EVP_MD_CTX_free(c);
- c = NULL;
- }
- return c;
-}
-
-void sha1_update(SHACTX c, const void *data, unsigned long len)
-{
- EVP_DigestUpdate(c, data, len);
-}
+#ifndef WITH_PKCS11_PROVIDER
+static ENGINE *engine = NULL;
-void sha1_final(unsigned char *md, SHACTX c)
+ENGINE *pki_get_engine(void)
{
- unsigned int mdlen = 0;
-
- EVP_DigestFinal(c, md, &mdlen);
- EVP_MD_CTX_free(c);
-}
+ int ok;
-void sha1(const unsigned char *digest, int len, unsigned char *hash)
-{
- SHACTX c = sha1_init();
- if (c != NULL) {
- sha1_update(c, digest, len);
- sha1_final(hash, c);
- }
-}
+ if (engine == NULL) {
+ ENGINE_load_builtin_engines();
-#ifdef HAVE_OPENSSL_ECC
-static const EVP_MD *nid_to_evpmd(int nid)
-{
- switch (nid) {
- case NID_X9_62_prime256v1:
- return EVP_sha256();
- case NID_secp384r1:
- return EVP_sha384();
- case NID_secp521r1:
- return EVP_sha512();
- default:
+ engine = ENGINE_by_id("pkcs11");
+ if (engine == NULL) {
+ SSH_LOG(SSH_LOG_TRACE,
+ "Could not load the engine: %s",
+ ERR_error_string(ERR_get_error(), NULL));
return NULL;
- }
-
- return NULL;
-}
-
-void evp(int nid, unsigned char *digest, int len, unsigned char *hash, unsigned int *hlen)
-{
- const EVP_MD *evp_md = nid_to_evpmd(nid);
- EVP_MD_CTX *md = EVP_MD_CTX_new();
-
- EVP_DigestInit(md, evp_md);
- EVP_DigestUpdate(md, digest, len);
- EVP_DigestFinal(md, hash, hlen);
- EVP_MD_CTX_free(md);
-}
-
-EVPCTX evp_init(int nid)
-{
- const EVP_MD *evp_md = nid_to_evpmd(nid);
-
- EVPCTX ctx = EVP_MD_CTX_new();
- if (ctx == NULL) {
- return NULL;
- }
-
- EVP_DigestInit(ctx, evp_md);
-
- return ctx;
-}
-
-void evp_update(EVPCTX ctx, const void *data, unsigned long len)
-{
- EVP_DigestUpdate(ctx, data, len);
-}
-
-void evp_final(EVPCTX ctx, unsigned char *md, unsigned int *mdlen)
-{
- EVP_DigestFinal(ctx, md, mdlen);
- EVP_MD_CTX_free(ctx);
-}
-#endif
-
-SHA256CTX sha256_init(void)
-{
- int rc;
- SHA256CTX c = EVP_MD_CTX_new();
- if (c == NULL) {
- return NULL;
- }
- rc = EVP_DigestInit_ex(c, EVP_sha256(), NULL);
- if (rc == 0) {
- EVP_MD_CTX_free(c);
- c = NULL;
- }
- return c;
-}
-
-void sha256_update(SHA256CTX c, const void *data, unsigned long len)
-{
- EVP_DigestUpdate(c, data, len);
-}
-
-void sha256_final(unsigned char *md, SHA256CTX c)
-{
- unsigned int mdlen = 0;
-
- EVP_DigestFinal(c, md, &mdlen);
- EVP_MD_CTX_free(c);
-}
-
-void sha256(const unsigned char *digest, int len, unsigned char *hash)
-{
- SHA256CTX c = sha256_init();
- if (c != NULL) {
- sha256_update(c, digest, len);
- sha256_final(hash, c);
- }
-}
-
-SHA384CTX sha384_init(void)
-{
- int rc;
- SHA384CTX c = EVP_MD_CTX_new();
- if (c == NULL) {
- return NULL;
- }
- rc = EVP_DigestInit_ex(c, EVP_sha384(), NULL);
- if (rc == 0) {
- EVP_MD_CTX_free(c);
- c = NULL;
- }
- return c;
-}
-
-void sha384_update(SHA384CTX c, const void *data, unsigned long len)
-{
- EVP_DigestUpdate(c, data, len);
-}
-
-void sha384_final(unsigned char *md, SHA384CTX c)
-{
- unsigned int mdlen = 0;
-
- EVP_DigestFinal(c, md, &mdlen);
- EVP_MD_CTX_free(c);
-}
-
-void sha384(const unsigned char *digest, int len, unsigned char *hash)
-{
- SHA384CTX c = sha384_init();
- if (c != NULL) {
- sha384_update(c, digest, len);
- sha384_final(hash, c);
- }
-}
-
-SHA512CTX sha512_init(void)
-{
- int rc = 0;
- SHA512CTX c = EVP_MD_CTX_new();
- if (c == NULL) {
- return NULL;
- }
- rc = EVP_DigestInit_ex(c, EVP_sha512(), NULL);
- if (rc == 0) {
- EVP_MD_CTX_free(c);
- c = NULL;
- }
- return c;
-}
-
-void sha512_update(SHA512CTX c, const void *data, unsigned long len)
-{
- EVP_DigestUpdate(c, data, len);
-}
-
-void sha512_final(unsigned char *md, SHA512CTX c)
-{
- unsigned int mdlen = 0;
-
- EVP_DigestFinal(c, md, &mdlen);
- EVP_MD_CTX_free(c);
-}
-
-void sha512(const unsigned char *digest, int len, unsigned char *hash)
-{
- SHA512CTX c = sha512_init();
- if (c != NULL) {
- sha512_update(c, digest, len);
- sha512_final(hash, c);
- }
-}
+ }
+ SSH_LOG(SSH_LOG_DEBUG, "Engine loaded successfully");
+
+ ok = ENGINE_init(engine);
+ if (!ok) {
+ SSH_LOG(SSH_LOG_TRACE,
+ "Could not initialize the engine: %s",
+ ERR_error_string(ERR_get_error(), NULL));
+ ENGINE_free(engine);
+ return NULL;
+ }
-MD5CTX md5_init(void)
-{
- int rc;
- MD5CTX c = EVP_MD_CTX_new();
- if (c == NULL) {
- return NULL;
- }
- rc = EVP_DigestInit_ex(c, EVP_md5(), NULL);
- if(rc == 0) {
- EVP_MD_CTX_free(c);
- c = NULL;
+ SSH_LOG(SSH_LOG_DEBUG, "Engine init success");
}
- return c;
-}
-
-void md5_update(MD5CTX c, const void *data, unsigned long len)
-{
- EVP_DigestUpdate(c, data, len);
+ return engine;
}
+#endif /* WITH_PKCS11_PROVIDER */
-void md5_final(unsigned char *md, MD5CTX c)
-{
- unsigned int mdlen = 0;
-
- EVP_DigestFinal(c, md, &mdlen);
- EVP_MD_CTX_free(c);
-}
-
-#ifdef HAVE_OPENSSL_EVP_KDF_CTX_NEW_ID
+#ifdef HAVE_OPENSSL_EVP_KDF_CTX
+#if OPENSSL_VERSION_NUMBER < 0x30000000L
static const EVP_MD *sshkdf_digest_to_md(enum ssh_kdf_digest digest_type)
{
switch (digest_type) {
@@ -356,19 +143,50 @@ static const EVP_MD *sshkdf_digest_to_md(enum ssh_kdf_digest digest_type)
}
return NULL;
}
+#else
+static const char *sshkdf_digest_to_md(enum ssh_kdf_digest digest_type)
+{
+ switch (digest_type) {
+ case SSH_KDF_SHA1:
+ return SN_sha1;
+ case SSH_KDF_SHA256:
+ return SN_sha256;
+ case SSH_KDF_SHA384:
+ return SN_sha384;
+ case SSH_KDF_SHA512:
+ return SN_sha512;
+ }
+ return NULL;
+}
+#endif /* OPENSSL_VERSION_NUMBER */
int ssh_kdf(struct ssh_crypto_struct *crypto,
unsigned char *key, size_t key_len,
- int key_type, unsigned char *output,
+ uint8_t key_type, unsigned char *output,
size_t requested_len)
{
+ int rc = -1;
+#if OPENSSL_VERSION_NUMBER < 0x30000000L
EVP_KDF_CTX *ctx = EVP_KDF_CTX_new_id(EVP_KDF_SSHKDF);
- int rc;
+#else
+ EVP_KDF *kdf = EVP_KDF_fetch(NULL, "SSHKDF", NULL);
+ EVP_KDF_CTX *ctx = EVP_KDF_CTX_new(kdf);
+ OSSL_PARAM_BLD *param_bld = OSSL_PARAM_BLD_new();
+ OSSL_PARAM *params = NULL;
+ const char *md = sshkdf_digest_to_md(crypto->digest_type);
+
+ EVP_KDF_free(kdf);
+ if (param_bld == NULL) {
+ EVP_KDF_CTX_free(ctx);
+ return -1;
+ }
+#endif /* OPENSSL_VERSION_NUMBER */
if (ctx == NULL) {
- return -1;
+ goto out;
}
+#if OPENSSL_VERSION_NUMBER < 0x30000000L
rc = EVP_KDF_ctrl(ctx, EVP_KDF_CTRL_SET_MD,
sshkdf_digest_to_md(crypto->digest_type));
if (rc != 1) {
@@ -388,7 +206,7 @@ int ssh_kdf(struct ssh_crypto_struct *crypto,
goto out;
}
rc = EVP_KDF_ctrl(ctx, EVP_KDF_CTRL_SET_SSHKDF_SESSION_ID,
- crypto->session_id, crypto->digest_len);
+ crypto->session_id, crypto->session_id_len);
if (rc != 1) {
goto out;
}
@@ -396,8 +214,60 @@ int ssh_kdf(struct ssh_crypto_struct *crypto,
if (rc != 1) {
goto out;
}
+#else
+ rc = OSSL_PARAM_BLD_push_utf8_string(param_bld, OSSL_KDF_PARAM_DIGEST,
+ md, strlen(md));
+ if (rc != 1) {
+ rc = -1;
+ goto out;
+ }
+ rc = OSSL_PARAM_BLD_push_octet_string(param_bld, OSSL_KDF_PARAM_KEY,
+ key, key_len);
+ if (rc != 1) {
+ rc = -1;
+ goto out;
+ }
+ rc = OSSL_PARAM_BLD_push_octet_string(param_bld,
+ OSSL_KDF_PARAM_SSHKDF_XCGHASH,
+ crypto->secret_hash,
+ crypto->digest_len);
+ if (rc != 1) {
+ rc = -1;
+ goto out;
+ }
+ rc = OSSL_PARAM_BLD_push_octet_string(param_bld,
+ OSSL_KDF_PARAM_SSHKDF_SESSION_ID,
+ crypto->session_id,
+ crypto->session_id_len);
+ if (rc != 1) {
+ rc = -1;
+ goto out;
+ }
+ rc = OSSL_PARAM_BLD_push_utf8_string(param_bld, OSSL_KDF_PARAM_SSHKDF_TYPE,
+ (const char*)&key_type, 1);
+ if (rc != 1) {
+ rc = -1;
+ goto out;
+ }
+
+ params = OSSL_PARAM_BLD_to_param(param_bld);
+ if (params == NULL) {
+ rc = -1;
+ goto out;
+ }
+
+ rc = EVP_KDF_derive(ctx, output, requested_len, params);
+ if (rc != 1) {
+ rc = -1;
+ goto out;
+ }
+#endif /* OPENSSL_VERSION_NUMBER */
out:
+#if OPENSSL_VERSION_NUMBER >= 0x30000000L
+ OSSL_PARAM_BLD_free(param_bld);
+ OSSL_PARAM_free(params);
+#endif
EVP_KDF_CTX_free(ctx);
if (rc < 0) {
return rc;
@@ -408,15 +278,15 @@ out:
#else
int ssh_kdf(struct ssh_crypto_struct *crypto,
unsigned char *key, size_t key_len,
- int key_type, unsigned char *output,
+ uint8_t key_type, unsigned char *output,
size_t requested_len)
{
return sshkdf_derive_key(crypto, key, key_len,
key_type, output, requested_len);
}
-#endif
+#endif /* HAVE_OPENSSL_EVP_KDF_CTX */
-HMACCTX hmac_init(const void *key, int len, enum ssh_hmac_e type)
+HMACCTX hmac_init(const void *key, size_t len, enum ssh_hmac_e type)
{
HMACCTX ctx = NULL;
EVP_PKEY *pkey = NULL;
@@ -461,17 +331,22 @@ error:
return NULL;
}
-void hmac_update(HMACCTX ctx, const void *data, unsigned long len)
+int hmac_update(HMACCTX ctx, const void *data, size_t len)
{
- EVP_DigestSignUpdate(ctx, data, len);
+ return EVP_DigestSignUpdate(ctx, data, len);
}
-void hmac_final(HMACCTX ctx, unsigned char *hashmacbuf, unsigned int *len)
+int hmac_final(HMACCTX ctx, unsigned char *hashmacbuf, size_t *len)
{
- size_t res;
- EVP_DigestSignFinal(ctx, hashmacbuf, &res);
+ size_t res = *len;
+ int rc;
+ rc = EVP_DigestSignFinal(ctx, hashmacbuf, &res);
EVP_MD_CTX_free(ctx);
- *len = res;
+ if (rc == 1) {
+ *len = res;
+ }
+
+ return rc;
}
static void evp_cipher_init(struct ssh_cipher_struct *cipher)
@@ -515,12 +390,12 @@ static void evp_cipher_init(struct ssh_cipher_struct *cipher)
cipher->cipher = EVP_bf_cbc();
break;
/* ciphers not using EVP */
-#endif
+#endif /* WITH_BLOWFISH_CIPHER */
case SSH_AEAD_CHACHA20_POLY1305:
- SSH_LOG(SSH_LOG_WARNING, "The ChaCha cipher cannot be handled here");
+ SSH_LOG(SSH_LOG_TRACE, "The ChaCha cipher cannot be handled here");
break;
case SSH_NO_CIPHER:
- SSH_LOG(SSH_LOG_WARNING, "No valid ciphertype found");
+ SSH_LOG(SSH_LOG_TRACE, "No valid ciphertype found");
break;
}
}
@@ -534,7 +409,7 @@ static int evp_cipher_set_encrypt_key(struct ssh_cipher_struct *cipher,
rc = EVP_EncryptInit_ex(cipher->ctx, cipher->cipher, NULL, key, IV);
if (rc != 1){
- SSH_LOG(SSH_LOG_WARNING, "EVP_EncryptInit_ex failed");
+ SSH_LOG(SSH_LOG_TRACE, "EVP_EncryptInit_ex failed");
return SSH_ERROR;
}
@@ -546,7 +421,7 @@ static int evp_cipher_set_encrypt_key(struct ssh_cipher_struct *cipher,
-1,
(uint8_t *)IV);
if (rc != 1) {
- SSH_LOG(SSH_LOG_WARNING, "EVP_CTRL_GCM_SET_IV_FIXED failed");
+ SSH_LOG(SSH_LOG_TRACE, "EVP_CTRL_GCM_SET_IV_FIXED failed");
return SSH_ERROR;
}
}
@@ -564,7 +439,7 @@ static int evp_cipher_set_decrypt_key(struct ssh_cipher_struct *cipher,
rc = EVP_DecryptInit_ex(cipher->ctx, cipher->cipher, NULL, key, IV);
if (rc != 1){
- SSH_LOG(SSH_LOG_WARNING, "EVP_DecryptInit_ex failed");
+ SSH_LOG(SSH_LOG_TRACE, "EVP_DecryptInit_ex failed");
return SSH_ERROR;
}
@@ -576,7 +451,7 @@ static int evp_cipher_set_decrypt_key(struct ssh_cipher_struct *cipher,
-1,
(uint8_t *)IV);
if (rc != 1) {
- SSH_LOG(SSH_LOG_WARNING, "EVP_CTRL_GCM_SET_IV_FIXED failed");
+ SSH_LOG(SSH_LOG_TRACE, "EVP_CTRL_GCM_SET_IV_FIXED failed");
return SSH_ERROR;
}
}
@@ -601,11 +476,11 @@ static void evp_cipher_encrypt(struct ssh_cipher_struct *cipher,
(unsigned char *)in,
(int)len);
if (rc != 1){
- SSH_LOG(SSH_LOG_WARNING, "EVP_EncryptUpdate failed");
+ SSH_LOG(SSH_LOG_TRACE, "EVP_EncryptUpdate failed");
return;
}
if (outlen != (int)len){
- SSH_LOG(SSH_LOG_WARNING,
+ SSH_LOG(SSH_LOG_DEBUG,
"EVP_EncryptUpdate: output size %d for %zu in",
outlen,
len);
@@ -627,11 +502,11 @@ static void evp_cipher_decrypt(struct ssh_cipher_struct *cipher,
(unsigned char *)in,
(int)len);
if (rc != 1){
- SSH_LOG(SSH_LOG_WARNING, "EVP_DecryptUpdate failed");
+ SSH_LOG(SSH_LOG_TRACE, "EVP_DecryptUpdate failed");
return;
}
if (outlen != (int)len){
- SSH_LOG(SSH_LOG_WARNING,
+ SSH_LOG(SSH_LOG_DEBUG,
"EVP_DecryptUpdate: output size %d for %zu in",
outlen,
len);
@@ -686,7 +561,7 @@ evp_cipher_aead_encrypt(struct ssh_cipher_struct *cipher,
1,
lastiv);
if (rc == 0) {
- SSH_LOG(SSH_LOG_WARNING, "EVP_CTRL_GCM_IV_GEN failed");
+ SSH_LOG(SSH_LOG_TRACE, "EVP_CTRL_GCM_IV_GEN failed");
return;
}
@@ -698,7 +573,7 @@ evp_cipher_aead_encrypt(struct ssh_cipher_struct *cipher,
(int)aadlen);
outlen = tmplen;
if (rc == 0 || outlen != aadlen) {
- SSH_LOG(SSH_LOG_WARNING, "Failed to pass authenticated data");
+ SSH_LOG(SSH_LOG_TRACE, "Failed to pass authenticated data");
return;
}
memcpy(out, in, aadlen);
@@ -711,7 +586,7 @@ evp_cipher_aead_encrypt(struct ssh_cipher_struct *cipher,
(int)len - aadlen);
outlen = tmplen;
if (rc != 1 || outlen != (int)len - aadlen) {
- SSH_LOG(SSH_LOG_WARNING, "EVP_EncryptUpdate failed");
+ SSH_LOG(SSH_LOG_TRACE, "EVP_EncryptUpdate failed");
return;
}
@@ -720,7 +595,7 @@ evp_cipher_aead_encrypt(struct ssh_cipher_struct *cipher,
NULL,
&tmplen);
if (rc < 0) {
- SSH_LOG(SSH_LOG_WARNING, "EVP_EncryptFinal failed: Failed to create a tag");
+ SSH_LOG(SSH_LOG_TRACE, "EVP_EncryptFinal failed: Failed to create a tag");
return;
}
@@ -729,7 +604,7 @@ evp_cipher_aead_encrypt(struct ssh_cipher_struct *cipher,
authlen,
(unsigned char *)tag);
if (rc != 1) {
- SSH_LOG(SSH_LOG_WARNING, "EVP_CTRL_GCM_GET_TAG failed");
+ SSH_LOG(SSH_LOG_TRACE, "EVP_CTRL_GCM_GET_TAG failed");
return;
}
}
@@ -757,7 +632,7 @@ evp_cipher_aead_decrypt(struct ssh_cipher_struct *cipher,
1,
lastiv);
if (rc == 0) {
- SSH_LOG(SSH_LOG_WARNING, "EVP_CTRL_GCM_IV_GEN failed");
+ SSH_LOG(SSH_LOG_TRACE, "EVP_CTRL_GCM_IV_GEN failed");
return SSH_ERROR;
}
@@ -767,7 +642,7 @@ evp_cipher_aead_decrypt(struct ssh_cipher_struct *cipher,
authlen,
(unsigned char *)complete_packet + aadlen + encrypted_size);
if (rc == 0) {
- SSH_LOG(SSH_LOG_WARNING, "EVP_CTRL_GCM_SET_TAG failed");
+ SSH_LOG(SSH_LOG_TRACE, "EVP_CTRL_GCM_SET_TAG failed");
return SSH_ERROR;
}
@@ -778,7 +653,7 @@ evp_cipher_aead_decrypt(struct ssh_cipher_struct *cipher,
(unsigned char *)complete_packet,
(int)aadlen);
if (rc == 0) {
- SSH_LOG(SSH_LOG_WARNING, "Failed to pass authenticated data");
+ SSH_LOG(SSH_LOG_TRACE, "Failed to pass authenticated data");
return SSH_ERROR;
}
/* Do not copy the length to the target buffer, because it is already processed */
@@ -789,14 +664,14 @@ evp_cipher_aead_decrypt(struct ssh_cipher_struct *cipher,
(unsigned char *)out,
&outlen,
(unsigned char *)complete_packet + aadlen,
- encrypted_size /* already substracted aadlen*/);
+ encrypted_size /* already subtracted aadlen */);
if (rc != 1) {
- SSH_LOG(SSH_LOG_WARNING, "EVP_DecryptUpdate failed");
+ SSH_LOG(SSH_LOG_TRACE, "EVP_DecryptUpdate failed");
return SSH_ERROR;
}
if (outlen != (int)encrypted_size) {
- SSH_LOG(SSH_LOG_WARNING,
+ SSH_LOG(SSH_LOG_TRACE,
"EVP_DecryptUpdate: output size %d for %zd in",
outlen,
encrypted_size);
@@ -808,26 +683,31 @@ evp_cipher_aead_decrypt(struct ssh_cipher_struct *cipher,
NULL,
&outlen);
if (rc < 0) {
- SSH_LOG(SSH_LOG_WARNING, "EVP_DecryptFinal failed: Failed authentication");
+ SSH_LOG(SSH_LOG_TRACE, "EVP_DecryptFinal failed: Failed authentication");
return SSH_ERROR;
}
return SSH_OK;
}
-#if defined(HAVE_OPENSSL_EVP_CHACHA20) && defined(HAVE_OPENSSL_EVP_POLY1305)
+#ifdef HAVE_OPENSSL_EVP_CHACHA20
struct chacha20_poly1305_keysched {
/* cipher handle used for encrypting the packets */
EVP_CIPHER_CTX *main_evp;
/* cipher handle used for encrypting the length field */
EVP_CIPHER_CTX *header_evp;
+#if OPENSSL_VERSION_NUMBER < 0x30000000L
/* mac handle used for authenticating the packets */
EVP_PKEY_CTX *pctx;
/* Poly1305 key */
EVP_PKEY *key;
/* MD context for digesting data in poly1305 */
EVP_MD_CTX *mctx;
+#else
+ /* MAC context used to do poly1305 */
+ EVP_MAC_CTX *mctx;
+#endif /* OPENSSL_VERSION_NUMBER */
};
static void
@@ -845,11 +725,16 @@ chacha20_poly1305_cleanup(struct ssh_cipher_struct *cipher)
ctx->main_evp = NULL;
EVP_CIPHER_CTX_free(ctx->header_evp);
ctx->header_evp = NULL;
+#if OPENSSL_VERSION_NUMBER < 0x30000000L
/* ctx->pctx is freed as part of MD context */
EVP_PKEY_free(ctx->key);
ctx->key = NULL;
EVP_MD_CTX_free(ctx->mctx);
ctx->mctx = NULL;
+#else
+ EVP_MAC_CTX_free(ctx->mctx);
+ ctx->mctx = NULL;
+#endif /* OPENSSL_VERSION_NUMBER */
SAFE_FREE(cipher->chacha20_schedule);
}
@@ -862,6 +747,9 @@ chacha20_poly1305_set_key(struct ssh_cipher_struct *cipher,
struct chacha20_poly1305_keysched *ctx = NULL;
uint8_t *u8key = key;
int ret = SSH_ERROR, rv;
+#if OPENSSL_VERSION_NUMBER >= 0x30000000L
+ EVP_MAC *mac = NULL;
+#endif
if (cipher->chacha20_schedule == NULL) {
ctx = calloc(1, sizeof(*ctx));
@@ -877,38 +765,54 @@ chacha20_poly1305_set_key(struct ssh_cipher_struct *cipher,
/* K2 uses the first half of the key */
ctx->main_evp = EVP_CIPHER_CTX_new();
if (ctx->main_evp == NULL) {
- SSH_LOG(SSH_LOG_WARNING, "EVP_CIPHER_CTX_new failed");
+ SSH_LOG(SSH_LOG_TRACE, "EVP_CIPHER_CTX_new failed");
goto out;
}
rv = EVP_EncryptInit_ex(ctx->main_evp, EVP_chacha20(), NULL, u8key, NULL);
if (rv != 1) {
- SSH_LOG(SSH_LOG_WARNING, "EVP_CipherInit failed");
+ SSH_LOG(SSH_LOG_TRACE, "EVP_CipherInit failed");
goto out;
}
/* K1 uses the second half of the key */
ctx->header_evp = EVP_CIPHER_CTX_new();
if (ctx->header_evp == NULL) {
- SSH_LOG(SSH_LOG_WARNING, "EVP_CIPHER_CTX_new failed");
+ SSH_LOG(SSH_LOG_TRACE, "EVP_CIPHER_CTX_new failed");
goto out;
}
ret = EVP_EncryptInit_ex(ctx->header_evp, EVP_chacha20(), NULL,
u8key + CHACHA20_KEYLEN, NULL);
if (ret != 1) {
- SSH_LOG(SSH_LOG_WARNING, "EVP_CipherInit failed");
+ SSH_LOG(SSH_LOG_TRACE, "EVP_CipherInit failed");
goto out;
}
/* The Poly1305 key initialization is delayed to the time we know
* the actual key for packet so we do not need to create a bogus keys
*/
+#if OPENSSL_VERSION_NUMBER < 0x30000000L
ctx->mctx = EVP_MD_CTX_new();
if (ctx->mctx == NULL) {
- SSH_LOG(SSH_LOG_WARNING, "EVP_MD_CTX_new failed");
+ SSH_LOG(SSH_LOG_TRACE, "EVP_MD_CTX_new failed");
return SSH_ERROR;
}
+#else
+ mac = EVP_MAC_fetch(NULL, "poly1305", NULL);
+ if (mac == NULL) {
+ SSH_LOG(SSH_LOG_TRACE, "EVP_MAC_fetch failed");
+ goto out;
+ }
+ ctx->mctx = EVP_MAC_CTX_new(mac);
+ if (ctx->mctx == NULL) {
+ SSH_LOG(SSH_LOG_TRACE, "EVP_MAC_CTX_new failed");
+ goto out;
+ }
+#endif /* OPENSSL_VERSION_NUMBER */
ret = SSH_OK;
out:
+#if OPENSSL_VERSION_NUMBER >= 0x30000000L
+ EVP_MAC_free(mac);
+#endif
if (ret != SSH_OK) {
chacha20_poly1305_cleanup(cipher);
}
@@ -937,13 +841,13 @@ chacha20_poly1305_set_iv(struct ssh_cipher_struct *cipher,
ret = EVP_CipherInit_ex(ctx->header_evp, NULL, NULL, NULL, seqbuf, do_encrypt);
if (ret != 1) {
- SSH_LOG(SSH_LOG_WARNING, "EVP_CipherInit_ex(header_evp) failed");
+ SSH_LOG(SSH_LOG_TRACE, "EVP_CipherInit_ex(header_evp) failed");
return SSH_ERROR;
}
ret = EVP_CipherInit_ex(ctx->main_evp, NULL, NULL, NULL, seqbuf, do_encrypt);
if (ret != 1) {
- SSH_LOG(SSH_LOG_WARNING, "EVP_CipherInit_ex(main_evp) failed");
+ SSH_LOG(SSH_LOG_TRACE, "EVP_CipherInit_ex(main_evp) failed");
return SSH_ERROR;
}
@@ -972,7 +876,7 @@ chacha20_poly1305_packet_setup(struct ssh_cipher_struct *cipher,
rv = EVP_CipherUpdate(ctx->main_evp, poly_key, &len,
(unsigned char *)zero_block, sizeof(zero_block));
if (rv != 1 || len != CHACHA20_BLOCKSIZE) {
- SSH_LOG(SSH_LOG_WARNING, "EVP_EncryptUpdate failed");
+ SSH_LOG(SSH_LOG_TRACE, "EVP_EncryptUpdate failed");
goto out;
}
#ifdef DEBUG_CRYPTO
@@ -980,17 +884,18 @@ chacha20_poly1305_packet_setup(struct ssh_cipher_struct *cipher,
#endif /* DEBUG_CRYPTO */
/* Set the Poly1305 key */
+#if OPENSSL_VERSION_NUMBER < 0x30000000L
if (ctx->key == NULL) {
/* Poly1305 Initialization needs to know the actual key */
ctx->key = EVP_PKEY_new_mac_key(EVP_PKEY_POLY1305, NULL,
poly_key, POLY1305_KEYLEN);
if (ctx->key == NULL) {
- SSH_LOG(SSH_LOG_WARNING, "EVP_PKEY_new_mac_key failed");
+ SSH_LOG(SSH_LOG_TRACE, "EVP_PKEY_new_mac_key failed");
goto out;
}
rv = EVP_DigestSignInit(ctx->mctx, &ctx->pctx, NULL, NULL, ctx->key);
if (rv != 1) {
- SSH_LOG(SSH_LOG_WARNING, "EVP_DigestSignInit failed");
+ SSH_LOG(SSH_LOG_TRACE, "EVP_DigestSignInit failed");
goto out;
}
} else {
@@ -999,10 +904,17 @@ chacha20_poly1305_packet_setup(struct ssh_cipher_struct *cipher,
EVP_PKEY_CTRL_SET_MAC_KEY,
POLY1305_KEYLEN, (void *)poly_key);
if (rv <= 0) {
- SSH_LOG(SSH_LOG_WARNING, "EVP_PKEY_CTX_ctrl failed");
+ SSH_LOG(SSH_LOG_TRACE, "EVP_PKEY_CTX_ctrl failed");
goto out;
}
}
+#else
+ rv = EVP_MAC_init(ctx->mctx, poly_key, POLY1305_KEYLEN, NULL);
+ if (rv != 1) {
+ SSH_LOG(SSH_LOG_TRACE, "EVP_MAC_init failed");
+ goto out;
+ }
+#endif /* OPENSSL_VERSION_NUMBER */
ret = SSH_OK;
out:
@@ -1036,7 +948,7 @@ chacha20_poly1305_aead_decrypt_length(struct ssh_cipher_struct *cipher,
rv = EVP_CipherUpdate(ctx->header_evp, out, &outlen, in, len);
if (rv != 1 || outlen != sizeof(uint32_t)) {
- SSH_LOG(SSH_LOG_WARNING, "EVP_CipherUpdate failed");
+ SSH_LOG(SSH_LOG_TRACE, "EVP_CipherUpdate failed");
return SSH_ERROR;
}
@@ -1046,7 +958,7 @@ chacha20_poly1305_aead_decrypt_length(struct ssh_cipher_struct *cipher,
rv = EVP_CipherFinal_ex(ctx->header_evp, out + outlen, &outlen);
if (rv != 1 || outlen != 0) {
- SSH_LOG(SSH_LOG_WARNING, "EVP_CipherFinal_ex failed");
+ SSH_LOG(SSH_LOG_TRACE, "EVP_CipherFinal_ex failed");
return SSH_ERROR;
}
@@ -1071,7 +983,7 @@ chacha20_poly1305_aead_decrypt(struct ssh_cipher_struct *cipher,
/* Prepare the Poly1305 key */
rv = chacha20_poly1305_packet_setup(cipher, seq, 0);
if (rv != SSH_OK) {
- SSH_LOG(SSH_LOG_WARNING, "Failed to setup packet");
+ SSH_LOG(SSH_LOG_TRACE, "Failed to setup packet");
goto out;
}
@@ -1080,19 +992,34 @@ chacha20_poly1305_aead_decrypt(struct ssh_cipher_struct *cipher,
#endif /* DEBUG_CRYPTO */
/* Calculate MAC of received data */
+#if OPENSSL_VERSION_NUMBER < 0x30000000L
rv = EVP_DigestSignUpdate(ctx->mctx, complete_packet,
encrypted_size + sizeof(uint32_t));
if (rv != 1) {
- SSH_LOG(SSH_LOG_WARNING, "EVP_DigestSignUpdate failed");
+ SSH_LOG(SSH_LOG_TRACE, "EVP_DigestSignUpdate failed");
goto out;
}
rv = EVP_DigestSignFinal(ctx->mctx, tag, &taglen);
if (rv != 1) {
- SSH_LOG(SSH_LOG_WARNING, "poly1305 verify error");
+ SSH_LOG(SSH_LOG_TRACE, "poly1305 verify error");
+ goto out;
+ }
+#else
+ rv = EVP_MAC_update(ctx->mctx, complete_packet,
+ encrypted_size + sizeof(uint32_t));
+ if (rv != 1) {
+ SSH_LOG(SSH_LOG_TRACE, "EVP_MAC_update failed");
goto out;
}
+ rv = EVP_MAC_final(ctx->mctx, tag, &taglen, POLY1305_TAGLEN);
+ if (rv != 1) {
+ SSH_LOG(SSH_LOG_TRACE, "EVP_MAC_final failed");
+ goto out;
+ }
+#endif /* OPENSSL_VERSION_NUMBER */
+
#ifdef DEBUG_CRYPTO
ssh_log_hexdump("calculated mac", tag, POLY1305_TAGLEN);
#endif /* DEBUG_CRYPTO */
@@ -1110,13 +1037,13 @@ chacha20_poly1305_aead_decrypt(struct ssh_cipher_struct *cipher,
(uint8_t *)complete_packet + sizeof(uint32_t),
encrypted_size);
if (rv != 1) {
- SSH_LOG(SSH_LOG_WARNING, "EVP_CipherUpdate failed");
+ SSH_LOG(SSH_LOG_TRACE, "EVP_CipherUpdate failed");
goto out;
}
rv = EVP_CipherFinal_ex(ctx->main_evp, out + len, &len);
if (rv != 1 || len != 0) {
- SSH_LOG(SSH_LOG_WARNING, "EVP_CipherFinal_ex failed");
+ SSH_LOG(SSH_LOG_TRACE, "EVP_CipherFinal_ex failed");
goto out;
}
@@ -1141,7 +1068,7 @@ chacha20_poly1305_aead_encrypt(struct ssh_cipher_struct *cipher,
/* Prepare the Poly1305 key */
ret = chacha20_poly1305_packet_setup(cipher, seq, 1);
if (ret != SSH_OK) {
- SSH_LOG(SSH_LOG_WARNING, "Failed to setup packet");
+ SSH_LOG(SSH_LOG_TRACE, "Failed to setup packet");
return;
}
@@ -1156,7 +1083,7 @@ chacha20_poly1305_aead_encrypt(struct ssh_cipher_struct *cipher,
(unsigned char *)&in_packet->length,
sizeof(uint32_t));
if (ret != 1 || outlen != sizeof(uint32_t)) {
- SSH_LOG(SSH_LOG_WARNING, "EVP_CipherUpdate failed");
+ SSH_LOG(SSH_LOG_TRACE, "EVP_CipherUpdate failed");
return;
}
#ifdef DEBUG_CRYPTO
@@ -1165,7 +1092,7 @@ chacha20_poly1305_aead_encrypt(struct ssh_cipher_struct *cipher,
#endif /* DEBUG_CRYPTO */
ret = EVP_CipherFinal_ex(ctx->header_evp, (uint8_t *)out + outlen, &outlen);
if (ret != 1 || outlen != 0) {
- SSH_LOG(SSH_LOG_PACKET, "EVP_EncryptFinal_ex failed");
+ SSH_LOG(SSH_LOG_TRACE, "EVP_EncryptFinal_ex failed");
return;
}
@@ -1177,23 +1104,37 @@ chacha20_poly1305_aead_encrypt(struct ssh_cipher_struct *cipher,
in_packet->payload,
len - sizeof(uint32_t));
if (ret != 1) {
- SSH_LOG(SSH_LOG_WARNING, "EVP_CipherUpdate failed");
+ SSH_LOG(SSH_LOG_TRACE, "EVP_CipherUpdate failed");
return;
}
/* step 4, compute the MAC */
+#if OPENSSL_VERSION_NUMBER < 0x30000000L
ret = EVP_DigestSignUpdate(ctx->mctx, out_packet, len);
if (ret <= 0) {
- SSH_LOG(SSH_LOG_WARNING, "EVP_DigestSignUpdate failed");
+ SSH_LOG(SSH_LOG_TRACE, "EVP_DigestSignUpdate failed");
return;
}
ret = EVP_DigestSignFinal(ctx->mctx, tag, &taglen);
if (ret <= 0) {
- SSH_LOG(SSH_LOG_WARNING, "EVP_DigestSignFinal failed");
+ SSH_LOG(SSH_LOG_TRACE, "EVP_DigestSignFinal failed");
+ return;
+ }
+#else
+ ret = EVP_MAC_update(ctx->mctx, (void*)out_packet, len);
+ if (ret != 1) {
+ SSH_LOG(SSH_LOG_TRACE, "EVP_MAC_update failed");
return;
}
+
+ ret = EVP_MAC_final(ctx->mctx, tag, &taglen, POLY1305_TAGLEN);
+ if (ret != 1) {
+ SSH_LOG(SSH_LOG_TRACE, "EVP_MAC_final failed");
+ return;
+ }
+#endif /* OPENSSL_VERSION_NUMBER */
}
-#endif /* defined(HAVE_OPENSSL_EVP_CHACHA20) && defined(HAVE_OPENSSL_EVP_POLY1305) */
+#endif /* HAVE_OPENSSL_EVP_CHACHA20 */
#ifdef WITH_INSECURE_NONE
static void
@@ -1222,7 +1163,7 @@ static struct ssh_cipher_struct ssh_ciphertab[] = {
.decrypt = evp_cipher_decrypt,
.cleanup = evp_cipher_cleanup
},
-#endif
+#endif /* WITH_BLOWFISH_CIPHER */
#ifdef HAS_AES
{
.name = "aes128-ctr",
@@ -1333,7 +1274,7 @@ static struct ssh_cipher_struct ssh_ciphertab[] = {
},
#endif /* HAS_DES */
{
-#if defined(HAVE_OPENSSL_EVP_CHACHA20) && defined(HAVE_OPENSSL_EVP_POLY1305)
+#ifdef HAVE_OPENSSL_EVP_CHACHA20
.ciphertype = SSH_AEAD_CHACHA20_POLY1305,
.name = "chacha20-poly1305@openssh.com",
.blocksize = CHACHA20_BLOCKSIZE/8,
@@ -1349,7 +1290,7 @@ static struct ssh_cipher_struct ssh_ciphertab[] = {
.cleanup = chacha20_poly1305_cleanup
#else
.name = "chacha20-poly1305@openssh.com"
-#endif /* defined(HAVE_OPENSSL_EVP_CHACHA20) && defined(HAVE_OPENSSL_EVP_POLY1305) */
+#endif /* HAVE_OPENSSL_EVP_CHACHA20 */
},
#ifdef WITH_INSECURE_NONE
{
@@ -1376,13 +1317,15 @@ struct ssh_cipher_struct *ssh_get_ciphertab(void)
*/
int ssh_crypto_init(void)
{
- UNUSED_VAR(size_t i);
+#ifndef HAVE_OPENSSL_EVP_CHACHA20
+ size_t i;
+#endif
if (libcrypto_initialized) {
return SSH_OK;
}
if (OpenSSL_version_num() != OPENSSL_VERSION_NUMBER){
- SSH_LOG(SSH_LOG_WARNING, "libssh compiled with %s "
+ SSH_LOG(SSH_LOG_DEBUG, "libssh compiled with %s "
"headers, currently running with %s.",
OPENSSL_VERSION_TEXT,
OpenSSL_version(OpenSSL_version_num())
@@ -1398,12 +1341,9 @@ int ssh_crypto_init(void)
/* Bit #57 denotes AES-NI instruction set extension */
OPENSSL_ia32cap &= ~(1LL << 57);
}
-#endif
-#if OPENSSL_VERSION_NUMBER < 0x10100000L
- OpenSSL_add_all_algorithms();
-#endif
+#endif /* CAN_DISABLE_AESNI */
-#if !defined(HAVE_OPENSSL_EVP_CHACHA20) || !defined(HAVE_OPENSSL_EVP_POLY1305)
+#ifndef HAVE_OPENSSL_EVP_CHACHA20
for (i = 0; ssh_ciphertab[i].name != NULL; i++) {
int cmp;
@@ -1415,7 +1355,7 @@ int ssh_crypto_init(void)
break;
}
}
-#endif /* !defined(HAVE_OPENSSL_EVP_CHACHA20) || !defined(HAVE_OPENSSL_EVP_POLY1305) */
+#endif /* HAVE_OPENSSL_EVP_CHACHA20 */
libcrypto_initialized = 1;
@@ -1432,13 +1372,210 @@ void ssh_crypto_finalize(void)
return;
}
- ENGINE_cleanup();
-#if OPENSSL_VERSION_NUMBER < 0x10100000L
- EVP_cleanup();
- CRYPTO_cleanup_all_ex_data();
+/* TODO this should finalize engine if it was started, but during atexit calls,
+ * we are crashing. AFAIK this is related to the dlopened pkcs11 modules calling
+ * the crypto cleanups earlier. */
+#if 0
+ if (engine != NULL) {
+ ENGINE_finish(engine);
+ ENGINE_free(engine);
+ engine = NULL;
+ }
#endif
libcrypto_initialized = 0;
}
+#if OPENSSL_VERSION_NUMBER >= 0x30000000L
+/**
+ * @internal
+ * @brief Create EVP_PKEY from parameters
+ *
+ * @param[in] name Algorithm to use. For more info see manpage of EVP_PKEY_CTX_new_from_name
+ *
+ * @param[in] param_bld Constructed param builder for the pkey
+ *
+ * @param[out] pkey Created EVP_PKEY variable
+ *
+ * @param[in] selection Reference selections at man EVP_PKEY_FROMDATA
+ *
+ * @return 0 on success, -1 on error
+ */
+int evp_build_pkey(const char* name, OSSL_PARAM_BLD *param_bld,
+ EVP_PKEY **pkey, int selection)
+{
+ int rc;
+ EVP_PKEY_CTX *ctx = EVP_PKEY_CTX_new_from_name(NULL, name, NULL);
+ OSSL_PARAM *params = NULL;
+
+ if (ctx == NULL) {
+ return -1;
+ }
+
+ params = OSSL_PARAM_BLD_to_param(param_bld);
+ if (params == NULL) {
+ EVP_PKEY_CTX_free(ctx);
+ return -1;
+ }
+
+ rc = EVP_PKEY_fromdata_init(ctx);
+ if (rc != 1) {
+ OSSL_PARAM_free(params);
+ EVP_PKEY_CTX_free(ctx);
+ return -1;
+ }
+
+ rc = EVP_PKEY_fromdata(ctx, pkey, selection, params);
+ if (rc != 1) {
+ SSH_LOG(SSH_LOG_WARNING,
+ "Failed to import private key: %s\n",
+ ERR_error_string(ERR_get_error(), NULL));
+ OSSL_PARAM_free(params);
+ EVP_PKEY_CTX_free(ctx);
+ return -1;
+ }
+
+ OSSL_PARAM_free(params);
+ EVP_PKEY_CTX_free(ctx);
+
+ return SSH_OK;
+}
+
+/**
+ * @brief creates a copy of EVP_PKEY
+ *
+ * @param[in] name Algorithm to use. For more info see manpage of
+ * EVP_PKEY_CTX_new_from_name
+ *
+ * @param[in] key Key being duplicated from
+ *
+ * @param[in] demote Same as at pki_key_dup, only the public
+ * part of the key gets duplicated if true
+ *
+ * @param[out] new_key The key where the duplicate is saved
+ *
+ * @return 0 on success, -1 on error
+ */
+static int
+evp_dup_pkey(const char *name, const ssh_key key, int demote, ssh_key new_key)
+{
+ int rc;
+ EVP_PKEY_CTX *ctx = NULL;
+ OSSL_PARAM *params = NULL;
+
+ /* The simple case -- just reference the existing key */
+ if (!demote || (key->flags & SSH_KEY_FLAG_PRIVATE) == 0) {
+ rc = EVP_PKEY_up_ref(key->key);
+ if (rc != 1) {
+ return -1;
+ }
+ new_key->key = key->key;
+ return SSH_OK;
+ }
+
+ /* demote == 1 */
+ ctx = EVP_PKEY_CTX_new_from_name(NULL, name, NULL);
+ if (ctx == NULL) {
+ return -1;
+ }
+
+ rc = EVP_PKEY_todata(key->key, EVP_PKEY_PUBLIC_KEY, &params);
+ if (rc != 1) {
+ EVP_PKEY_CTX_free(ctx);
+ return -1;
+ }
+
+ if (strcmp(name, "EC") == 0) {
+ OSSL_PARAM *locate_param = NULL;
+ /* For ECC keys provided by engine or provider, we need to have the
+ * explicit public part available, otherwise the key will not be
+ * usable */
+ locate_param = OSSL_PARAM_locate(params, OSSL_PKEY_PARAM_PUB_KEY);
+ if (locate_param == NULL) {
+ EVP_PKEY_CTX_free(ctx);
+ OSSL_PARAM_free(params);
+ return -1;
+ }
+ }
+ rc = EVP_PKEY_fromdata_init(ctx);
+ if (rc != 1) {
+ EVP_PKEY_CTX_free(ctx);
+ OSSL_PARAM_free(params);
+ return -1;
+ }
+
+ rc = EVP_PKEY_fromdata(ctx, &(new_key->key), EVP_PKEY_PUBLIC_KEY, params);
+ if (rc != 1) {
+ EVP_PKEY_CTX_free(ctx);
+ OSSL_PARAM_free(params);
+ return -1;
+ }
+
+ OSSL_PARAM_free(params);
+ EVP_PKEY_CTX_free(ctx);
+
+ return SSH_OK;
+}
+
+int evp_dup_rsa_pkey(const ssh_key key, ssh_key new_key, int demote)
+{
+ return evp_dup_pkey("RSA", key, demote, new_key);
+}
+
+int evp_dup_ecdsa_pkey(const ssh_key key, ssh_key new_key, int demote)
+{
+ return evp_dup_pkey("EC", key, demote, new_key);
+}
+#endif /* OPENSSL_VERSION_NUMBER */
+
+ssh_string
+pki_key_make_ecpoint_string(const EC_GROUP *g, const EC_POINT *p)
+{
+ ssh_string s = NULL;
+ size_t len;
+
+ len = EC_POINT_point2oct(g,
+ p,
+ POINT_CONVERSION_UNCOMPRESSED,
+ NULL,
+ 0,
+ NULL);
+ if (len == 0) {
+ return NULL;
+ }
+
+ s = ssh_string_new(len);
+ if (s == NULL) {
+ return NULL;
+ }
+
+ len = EC_POINT_point2oct(g,
+ p,
+ POINT_CONVERSION_UNCOMPRESSED,
+ ssh_string_data(s),
+ ssh_string_len(s),
+ NULL);
+ if (len != ssh_string_len(s)) {
+ SSH_STRING_FREE(s);
+ return NULL;
+ }
+
+ return s;
+}
+
+int pki_key_ecgroup_name_to_nid(const char *group)
+{
+ if (strcmp(group, NISTP256) == 0 ||
+ strcmp(group, "secp256r1") == 0 ||
+ strcmp(group, "prime256v1") == 0) {
+ return NID_X9_62_prime256v1;
+ } else if (strcmp(group, NISTP384) == 0 ||
+ strcmp(group, "secp384r1") == 0) {
+ return NID_secp384r1;
+ } else if (strcmp(group, NISTP521) == 0 ||
+ strcmp(group, "secp521r1") == 0) {
+ return NID_secp521r1;
+ }
+ return -1;
+}
#endif /* LIBCRYPTO */