Blob Blame History Raw
diff --git a/CMakeLists.txt b/CMakeLists.txt
index a64b7708..535c74a9 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -89,13 +89,6 @@ if (WITH_GSSAPI)
     find_package(GSSAPI)
 endif (WITH_GSSAPI)
 
-if (WITH_PKCS11_URI)
-    find_package(softhsm)
-    if (NOT SOFTHSM_FOUND)
-        message(SEND_ERROR "Could not find softhsm module!")
-     endif (NOT SOFTHSM_FOUND)
-endif (WITH_PKCS11_URI)
-
 if (WITH_NACL)
     find_package(NaCl)
     if (NOT NACL_FOUND)
@@ -239,6 +232,7 @@ message(STATUS "Unit testing: ${UNIT_TESTING}")
 message(STATUS "Client code testing: ${CLIENT_TESTING}")
 message(STATUS "Blowfish cipher support: ${WITH_BLOWFISH_CIPHER}")
 message(STATUS "PKCS #11 URI support: ${WITH_PKCS11_URI}")
+message(STATUS "With PKCS #11 provider support: ${WITH_PKCS11_PROVIDER}")
 message(STATUS "DSA support: ${WITH_DSA}")
 set(_SERVER_TESTING OFF)
 if (WITH_SERVER)
diff --git a/ConfigureChecks.cmake b/ConfigureChecks.cmake
index 9de10225..06ed23c8 100644
--- a/ConfigureChecks.cmake
+++ b/ConfigureChecks.cmake
@@ -489,12 +489,21 @@ if (WITH_PKCS11_URI)
     if (WITH_GCRYPT)
         message(FATAL_ERROR "PKCS #11 is not supported for gcrypt.")
         set(WITH_PKCS11_URI 0)
-    endif()
-    if (WITH_MBEDTLS)
+    elseif (WITH_MBEDTLS)
         message(FATAL_ERROR "PKCS #11 is not supported for mbedcrypto")
         set(WITH_PKCS11_URI 0)
-    endif()
-    if (HAVE_OPENSSL AND NOT OPENSSL_VERSION VERSION_GREATER_EQUAL "1.1.1")
+    elseif (OPENSSL_FOUND AND OPENSSL_VERSION VERSION_GREATER_EQUAL "3.0.0")
+        find_library(PKCS11_PROVIDER
+            NAMES
+                pkcs11.so
+            PATH_SUFFIXES
+                ossl-modules
+        )
+        if (NOT PKCS11_PROVIDER)
+            set(WITH_PKCS11_PROVIDER 0)
+            message(WARNING "Could not find pkcs11 provider! Falling back to engines")
+        endif (NOT PKCS11_PROVIDER)
+    elseif (HAVE_OPENSSL AND NOT OPENSSL_VERSION VERSION_GREATER_EQUAL "1.1.1")
         message(FATAL_ERROR "PKCS #11 requires at least OpenSSL 1.1.1")
         set(WITH_PKCS11_URI 0)
     endif()
diff --git a/DefineOptions.cmake b/DefineOptions.cmake
index 6881b9a2..bc32abe5 100644
--- a/DefineOptions.cmake
+++ b/DefineOptions.cmake
@@ -13,6 +13,7 @@ option(WITH_PCAP "Compile with Pcap generation support" ON)
 option(WITH_INTERNAL_DOC "Compile doxygen internal documentation" OFF)
 option(BUILD_SHARED_LIBS "Build shared libraries" ON)
 option(WITH_PKCS11_URI "Build with PKCS#11 URI support" OFF)
+option(WITH_PKCS11_PROVIDER "Use the PKCS#11 provider for accessing pkcs11 objects" OFF)
 option(UNIT_TESTING "Build with unit tests" OFF)
 option(CLIENT_TESTING "Build with client tests; requires openssh" OFF)
 option(SERVER_TESTING "Build with server tests; requires openssh and dropbear" OFF)
diff --git a/config.h.cmake b/config.h.cmake
index cc83734d..409f5d0d 100644
--- a/config.h.cmake
+++ b/config.h.cmake
@@ -276,6 +276,9 @@
 /* Define to 1 if you want to enable PKCS #11 URI support */
 #cmakedefine WITH_PKCS11_URI 1
 
+/* Define to 1 if we want to build a support for PKCS #11 provider. */
+#cmakedefine WITH_PKCS11_PROVIDER 1
+
 /*************************** ENDIAN *****************************/
 
 /* Define WORDS_BIGENDIAN to 1 if your processor stores words with the most
diff --git a/doc/pkcs11.dox b/doc/pkcs11.dox
index 0bdfc6dc..c2732a81 100644
--- a/doc/pkcs11.dox
+++ b/doc/pkcs11.dox
@@ -9,11 +9,11 @@ objects stored on the tokens can be uniquely identified is called PKCS #11 URI
 (Uniform Resource Identifier) and is defined in RFC 7512
 (https://tools.ietf.org/html/rfc7512).
 
-Pre-requisites:
+# Pre-requisites (OpenSSL < 3.0):
 
-OpenSSL defines an abstract layer called the "engine" to achieve cryptographic
-acceleration. The engine_pkcs11 module acts like an interface between the PKCS #11
-modules and the OpenSSL engine.
+OpenSSL 1.x defines an abstract layer called the "engine" to achieve
+cryptographic acceleration. The engine_pkcs11 module acts like an interface
+between the PKCS #11 modules and the OpenSSL application.
 
 To build and use libssh with PKCS #11 support:
 1. Enable the cmake option: $ cmake -DWITH_PKCS11_URI=ON
@@ -21,6 +21,20 @@ To build and use libssh with PKCS #11 support:
 3. Install and configure engine_pkcs11 (https://github.com/OpenSC/libp11).
 4. Plug in a working smart card or configure softhsm (https://www.opendnssec.org/softhsm).
 
+# Pre-requisites (OpenSSL 3.0.8+)
+
+The OpenSSL 3.0 is deprecating usage of low-level engines in favor of high-level
+"providers" to provide alternative implementation of cryptographic operations
+or acceleration.
+
+To build and use libssh with PKCS #11 support using OpenSSL providers:
+1. Install and configure pkcs11 provider (https://github.com/latchset/pkcs11-provider).
+2. Enable the cmake options: $ cmake -DWITH_PKCS11_URI=ON -DWITH_PKCS11_PROVIDER=ON
+3. Build with OpenSSL.
+4. Plug in a working smart card or configure softhsm (https://www.opendnssec.org/softhsm).
+
+# New API functions
+
 The functions  ssh_pki_import_pubkey_file() and ssh_pki_import_privkey_file() that
 import the public and private keys from files respectively are now modified to support
 PKCS #11 URIs. These functions automatically detect if the provided filename is a file path
@@ -31,7 +45,7 @@ corresponding to the PKCS #11 URI are loaded from the PKCS #11 device.
 If you wish to authenticate using public keys on your own, follow the steps mentioned under
 "Authentication with public keys" in Chapter 2 - A deeper insight into authentication.
 
-The function pki_uri_import() is used to populate the public/private ssh_key from the 
+The function pki_uri_import() is used to populate the public/private ssh_key from the
 engine with PKCS #11 URIs as the look up.
 
 Here is a minimalistic example of public key authentication using PKCS #11 URIs:
@@ -64,4 +78,10 @@ We recommend the users to provide a specific PKCS #11 URI so that it matches onl
 If the engine discovers multiple slots that could potentially contain the private keys referenced
 by the provided PKCS #11 URI, the engine will not try to authenticate.
 
+For testing, the SoftHSM PKCS#11 library is used. But it has some issues with
+OpenSSL initialization/cleanup when used with OpenSSL 3.0 so we are using it
+indirectly through a p11-kit remoting as described in the following article:
+
+https://p11-glue.github.io/p11-glue/p11-kit/manual/remoting.html
+
 */
diff --git a/include/libssh/crypto.h b/include/libssh/crypto.h
index 3dba18d0..32016827 100644
--- a/include/libssh/crypto.h
+++ b/include/libssh/crypto.h
@@ -111,11 +111,7 @@ struct ssh_crypto_struct {
 #endif /* WITH_GEX */
 #ifdef HAVE_ECDH
 #ifdef HAVE_OPENSSL_ECC
-/* TODO Change to new API when the OpenSSL will support export of uncompressed EC keys
- * https://github.com/openssl/openssl/pull/16624
- * #if OPENSSL_VERSION_NUMBER < 0x30000000L
- */
-#if 1
+#if OPENSSL_VERSION_NUMBER < 0x30000000L
     EC_KEY *ecdh_privkey;
 #else
     EVP_PKEY *ecdh_privkey;
@@ -227,7 +223,7 @@ int sshkdf_derive_key(struct ssh_crypto_struct *crypto,
                       size_t requested_len);
 
 int secure_memcmp(const void *s1, const void *s2, size_t n);
-#ifdef HAVE_LIBCRYPTO
+#if defined(HAVE_LIBCRYPTO) && !defined(WITH_PKCS11_PROVIDER)
 ENGINE *pki_get_engine(void);
 #endif /* HAVE_LIBCRYPTO */
 
diff --git a/include/libssh/keys.h b/include/libssh/keys.h
index 615f1eae..79bba747 100644
--- a/include/libssh/keys.h
+++ b/include/libssh/keys.h
@@ -32,12 +32,7 @@ struct ssh_public_key_struct {
     gcry_sexp_t dsa_pub;
     gcry_sexp_t rsa_pub;
 #elif defined(HAVE_LIBCRYPTO)
-#if OPENSSL_VERSION_NUMBER < 0x30000000L
-    DSA *dsa_pub;
-    RSA *rsa_pub;
-#else /* OPENSSL_VERSION_NUMBER */
     EVP_PKEY *key_pub;
-#endif
 #elif defined(HAVE_LIBMBEDCRYPTO)
     mbedtls_pk_context *rsa_pub;
     void *dsa_pub;
@@ -50,12 +45,7 @@ struct ssh_private_key_struct {
     gcry_sexp_t dsa_priv;
     gcry_sexp_t rsa_priv;
 #elif defined(HAVE_LIBCRYPTO)
-#if OPENSSL_VERSION_NUMBER < 0x30000000L
-    DSA *dsa_priv;
-    RSA *rsa_priv;
-#else
     EVP_PKEY *key_priv;
-#endif /* OPENSSL_VERSION_NUMBER */
 #elif defined(HAVE_LIBMBEDCRYPTO)
     mbedtls_pk_context *rsa_priv;
     void *dsa_priv;
diff --git a/include/libssh/libcrypto.h b/include/libssh/libcrypto.h
index 87f30a4d..3abfa814 100644
--- a/include/libssh/libcrypto.h
+++ b/include/libssh/libcrypto.h
@@ -25,6 +25,7 @@
 
 #ifdef HAVE_LIBCRYPTO
 
+#include "libssh/libssh.h"
 #include <openssl/dsa.h>
 #include <openssl/rsa.h>
 #include <openssl/sha.h>
@@ -32,6 +33,7 @@
 #include <openssl/hmac.h>
 #include <openssl/evp.h>
 #include <openssl/crypto.h>
+#include <openssl/ec.h>
 
 typedef EVP_MD_CTX* SHACTX;
 typedef EVP_MD_CTX* SHA256CTX;
@@ -111,6 +113,8 @@ typedef BN_CTX* bignum_CTX;
 #define ssh_fips_mode() false
 #endif
 
+ssh_string pki_key_make_ecpoint_string(const EC_GROUP *g, const EC_POINT *p);
+int pki_key_ecgroup_name_to_nid(const char *group);
 #endif /* HAVE_LIBCRYPTO */
 
 #endif /* LIBCRYPTO_H_ */
diff --git a/include/libssh/pki.h b/include/libssh/pki.h
index 879a1d5c..10814f5b 100644
--- a/include/libssh/pki.h
+++ b/include/libssh/pki.h
@@ -65,21 +65,8 @@ struct ssh_key_struct {
     mbedtls_ecdsa_context *ecdsa;
     void *dsa;
 #elif defined(HAVE_LIBCRYPTO)
-#if OPENSSL_VERSION_NUMBER < 0x30000000L
-    DSA *dsa;
-    RSA *rsa;
-#endif /* OPENSSL_VERSION_NUMBER */
-/* TODO Change to new API when the OpenSSL will support export of uncompressed EC keys
- * https://github.com/openssl/openssl/pull/16624
- * Move into the #if above
- */
-# if defined(HAVE_OPENSSL_ECC)
-    EC_KEY *ecdsa;
-# else
-    void *ecdsa;
-# endif /* HAVE_OPENSSL_EC_H */
     /* This holds either ENGINE key for PKCS#11 support or just key in
-     * high-level format required by OpenSSL 3.0 */
+     * high-level format */
     EVP_PKEY *key;
 #endif /* HAVE_LIBGCRYPT */
 #if defined(HAVE_LIBCRYPTO) && defined(HAVE_OPENSSL_ED25519)
@@ -108,7 +95,7 @@ struct ssh_signature_struct {
 #endif /* HAVE_LIBGCRYPT */
 #if !defined(HAVE_LIBCRYPTO) || !defined(HAVE_OPENSSL_ED25519)
     ed25519_signature *ed25519_sig;
-#endif
+#endif /* HAVE_LIBGCRYPT */
     ssh_string raw_sig;
 
     /* Security Key specific additions */
diff --git a/src/auth.c b/src/auth.c
index 4feb6558..c48eea5e 100644
--- a/src/auth.c
+++ b/src/auth.c
@@ -1409,21 +1409,21 @@ int ssh_userauth_agent_pubkey(ssh_session session,
     key->type = publickey->type;
     key->type_c = ssh_key_type_to_char(key->type);
     key->flags = SSH_KEY_FLAG_PUBLIC;
-#if !defined(HAVE_LIBCRYPTO) || OPENSSL_VERSION_NUMBER < 0x30000000L
+#ifndef HAVE_LIBCRYPTO
     key->dsa = publickey->dsa_pub;
     key->rsa = publickey->rsa_pub;
 #else
     key->key = publickey->key_pub;
-#endif /* OPENSSL_VERSION_NUMBER */
+#endif /* HAVE_LIBCRYPTO */
 
     rc = ssh_userauth_agent_publickey(session, username, key);
 
-#if !defined(HAVE_LIBCRYPTO) || OPENSSL_VERSION_NUMBER < 0x30000000L
+#ifndef HAVE_LIBCRYPTO
     key->dsa = NULL;
     key->rsa = NULL;
 #else
     key->key = NULL;
-#endif /* OPENSSL_VERSION_NUMBER */
+#endif /* HAVE_LIBCRYPTO */
     ssh_key_free(key);
 
     return rc;
diff --git a/src/ecdh_crypto.c b/src/ecdh_crypto.c
index 069b1372..a8bce894 100644
--- a/src/ecdh_crypto.c
+++ b/src/ecdh_crypto.c
@@ -30,11 +30,7 @@
 
 #ifdef HAVE_ECDH
 #include <openssl/ecdh.h>
-/* TODO Change to new API when the OpenSSL will support export of uncompressed EC keys
- * https://github.com/openssl/openssl/pull/16624
- * #if OPENSSL_VERSION_NUMBER < 0x30000000L
- */
-#if 1
+#if OPENSSL_VERSION_NUMBER < 0x30000000L
 #define NISTP256 NID_X9_62_prime256v1
 #define NISTP384 NID_secp384r1
 #define NISTP521 NID_secp521r1
@@ -48,11 +44,7 @@
 /** @internal
  * @brief Map the given key exchange enum value to its curve name.
  */
-/* TODO Change to new API when the OpenSSL will support export of uncompressed EC keys
- * https://github.com/openssl/openssl/pull/16624
- * #if OPENSSL_VERSION_NUMBER < 0x30000000L
- */
-#if 1
+#if OPENSSL_VERSION_NUMBER < 0x30000000L
 static int ecdh_kex_type_to_curve(enum ssh_key_exchange_e kex_type) {
 #else
 static const char *ecdh_kex_type_to_curve(enum ssh_key_exchange_e kex_type) {
@@ -64,183 +56,156 @@ static const char *ecdh_kex_type_to_curve(enum ssh_key_exchange_e kex_type) {
     } else if (kex_type == SSH_KEX_ECDH_SHA2_NISTP521) {
         return NISTP521;
     }
-/* TODO Change to new API when the OpenSSL will support export of uncompressed EC keys
- * https://github.com/openssl/openssl/pull/16624
- * #if OPENSSL_VERSION_NUMBER < 0x30000000L
- */
-#if 1
+#if OPENSSL_VERSION_NUMBER < 0x30000000L
     return SSH_ERROR;
 #else
     return NULL;
 #endif
 }
 
-/** @internal
- * @brief Starts ecdh-sha2-nistp256 key exchange
- */
-int ssh_client_ecdh_init(ssh_session session){
-  int rc;
-  ssh_string client_pubkey;
-/* TODO Change to new API when the OpenSSL will support export of uncompressed EC keys
- * https://github.com/openssl/openssl/pull/16624
- * #if OPENSSL_VERSION_NUMBER < 0x30000000L
+/* @internal
+ * @brief Generate ECDH key pair for ecdh key exchange and store it in the
+ * session->next_crypto structure
  */
-#if 1
-  EC_KEY *key;
-  const EC_GROUP *group;
-  const EC_POINT *pubkey;
-  int curve;
-  int len;
-  bignum_CTX ctx = BN_CTX_new();
-  if (ctx == NULL) {
-      return SSH_ERROR;
-  }
+static ssh_string ssh_ecdh_generate(ssh_session session)
+{
+    ssh_string pubkey_string = NULL;
+    const EC_GROUP *group = NULL;
+    const EC_POINT *point = NULL;
+    int rc;
+#if OPENSSL_VERSION_NUMBER < 0x30000000L
+    EC_KEY *key = NULL;
+    int curve;
 #else
-  const char *curve = NULL;
-  EVP_PKEY *key = NULL;
-  OSSL_PARAM *out_params = NULL;
-  const OSSL_PARAM *pubkey_param = NULL;
-  const uint8_t *pubkey = NULL;
-  size_t pubkey_len;
-#endif /* OPENSSL_VERSION_NUMBER */
-
-  rc = ssh_buffer_add_u8(session->out_buffer, SSH2_MSG_KEX_ECDH_INIT);
-  if (rc < 0) {
-/* TODO Change to new API when the OpenSSL will support export of uncompressed EC keys
- * https://github.com/openssl/openssl/pull/16624
- * #if OPENSSL_VERSION_NUMBER < 0x30000000L
- */
-#if 1
-      BN_CTX_free(ctx);
+    const char *curve = NULL;
+    EVP_PKEY *key = NULL;
+    OSSL_PARAM *out_params = NULL;
+    const OSSL_PARAM *pubkey_param = NULL;
+    const void *pubkey = NULL;
+    size_t pubkey_len;
+    int nid;
 #endif /* OPENSSL_VERSION_NUMBER */
-      return SSH_ERROR;
-  }
 
-  curve = ecdh_kex_type_to_curve(session->next_crypto->kex_type);
-/* TODO Change to new API when the OpenSSL will support export of uncompressed EC keys
- * https://github.com/openssl/openssl/pull/16624
- * #if OPENSSL_VERSION_NUMBER < 0x30000000L
- */
-#if 1
-  if (curve == SSH_ERROR) {
-      BN_CTX_free(ctx);
-      return SSH_ERROR;
-  }
+    curve = ecdh_kex_type_to_curve(session->next_crypto->kex_type);
+#if OPENSSL_VERSION_NUMBER < 0x30000000L
+    if (curve == SSH_ERROR) {
+        SSH_LOG(SSH_LOG_TRACE, "Failed to get curve name");
+        return NULL;
+    }
 
-  key = EC_KEY_new_by_curve_name(curve);
+    key = EC_KEY_new_by_curve_name(curve);
 #else
-  if (curve == NULL) {
-      return SSH_ERROR;
-  }
-
-  key = EVP_EC_gen(curve);
-#endif /* OPENSSL_VERSION_NUMBER */
+    if (curve == NULL) {
+        SSH_LOG(SSH_LOG_TRACE, "Failed to get curve name");
+        return NULL;
+    }
 
-  if (key == NULL) {
-/* TODO Change to new API when the OpenSSL will support export of uncompressed EC keys
- * https://github.com/openssl/openssl/pull/16624
- * #if OPENSSL_VERSION_NUMBER < 0x30000000L
- */
-#if 1
-      BN_CTX_free(ctx);
+    key = EVP_EC_gen(curve);
 #endif /* OPENSSL_VERSION_NUMBER */
-      return SSH_ERROR;
-  }
-
-/* TODO Change to new API when the OpenSSL will support export of uncompressed EC keys
- * https://github.com/openssl/openssl/pull/16624
- * #if OPENSSL_VERSION_NUMBER < 0x30000000L
- */
-#if 1
-  group = EC_KEY_get0_group(key);
-
-  EC_KEY_generate_key(key);
+    if (key == NULL) {
+        SSH_LOG(SSH_LOG_TRACE, "Failed to generate key");
+        return NULL;
+    }
 
-  pubkey=EC_KEY_get0_public_key(key);
-  len = EC_POINT_point2oct(group,pubkey,POINT_CONVERSION_UNCOMPRESSED,
-      NULL,0,ctx);
+#if OPENSSL_VERSION_NUMBER < 0x30000000L
+    group = EC_KEY_get0_group(key);
 
-  client_pubkey = ssh_string_new(len);
-  if (client_pubkey == NULL) {
-      BN_CTX_free(ctx);
-      EC_KEY_free(key);
-      return SSH_ERROR;
-  }
+    EC_KEY_generate_key(key);
 
-  EC_POINT_point2oct(group,pubkey,POINT_CONVERSION_UNCOMPRESSED,
-      ssh_string_data(client_pubkey),len,ctx);
-  BN_CTX_free(ctx);
+    point = EC_KEY_get0_public_key(key);
 #else
-  rc = EVP_PKEY_todata(key, EVP_PKEY_PUBLIC_KEY, &out_params);
-  if (rc != 1) {
-      EVP_PKEY_free(key);
-      return SSH_ERROR;
-  }
+    rc = EVP_PKEY_todata(key, EVP_PKEY_PUBLIC_KEY, &out_params);
+    if (rc != 1) {
+        SSH_LOG(SSH_LOG_TRACE, "Failed to export public key");
+        EVP_PKEY_free(key);
+        return NULL;
+    }
 
-  pubkey_param = OSSL_PARAM_locate_const(out_params, OSSL_PKEY_PARAM_PUB_KEY);
-  if (pubkey_param == NULL) {
-      EVP_PKEY_free(key);
-      OSSL_PARAM_free(out_params);
-      return SSH_ERROR;
-  }
+    pubkey_param = OSSL_PARAM_locate_const(out_params, OSSL_PKEY_PARAM_PUB_KEY);
+    if (pubkey_param == NULL) {
+        SSH_LOG(SSH_LOG_TRACE, "Failed to find public key");
+        EVP_PKEY_free(key);
+        OSSL_PARAM_free(out_params);
+        return NULL;
+    }
 
-  rc = OSSL_PARAM_get_octet_string_ptr(pubkey_param,
-                                       (const void**)&pubkey,
-                                       &pubkey_len);
-  if (rc != 1) {
-      OSSL_PARAM_free(out_params);
-      EVP_PKEY_free(key);
-      return SSH_ERROR;
-  }
+    rc = OSSL_PARAM_get_octet_string_ptr(pubkey_param,
+                                         (const void**)&pubkey,
+                                         &pubkey_len);
+    OSSL_PARAM_free(out_params);
+    if (rc != 1) {
+        SSH_LOG(SSH_LOG_TRACE, "Failed to read public key");
+        EVP_PKEY_free(key);
+        return NULL;
+    }
 
-  client_pubkey = ssh_string_new(pubkey_len);
-  if (client_pubkey == NULL) {
-      OSSL_PARAM_free(out_params);
-      EVP_PKEY_free(key);
-      return SSH_ERROR;
-  }
+    /* Convert the data to low-level representation */
+    nid = pki_key_ecgroup_name_to_nid(curve);
+    group = EC_GROUP_new_by_curve_name_ex(NULL, NULL, nid);
+    point = EC_POINT_new(group);
+    rc = EC_POINT_oct2point(group, (EC_POINT *)point, pubkey, pubkey_len, NULL);
+    if (group == NULL || point == NULL || rc != 1) {
+        SSH_LOG(SSH_LOG_TRACE, "Failed to export public key");
+        EVP_PKEY_free(key);
+        return NULL;
+    }
 
-  memcpy(ssh_string_data(client_pubkey), pubkey, pubkey_len);
-  OSSL_PARAM_free(out_params);
 #endif /* OPENSSL_VERSION_NUMBER */
-
-  rc = ssh_buffer_add_ssh_string(session->out_buffer,client_pubkey);
-  if (rc < 0) {
-/* TODO Change to new API when the OpenSSL will support export of uncompressed EC keys
- * https://github.com/openssl/openssl/pull/16624
- * #if OPENSSL_VERSION_NUMBER < 0x30000000L
- */
-#if 1
-      EC_KEY_free(key);
+    pubkey_string = pki_key_make_ecpoint_string(group, point);
+    if (pubkey_string == NULL) {
+        SSH_LOG(SSH_LOG_TRACE, "Failed to convert public key");
+#if OPENSSL_VERSION_NUMBER < 0x30000000L
+        EC_KEY_free(key);
 #else
-      EVP_PKEY_free(key);
+        EVP_PKEY_free(key);
 #endif /* OPENSSL_VERSION_NUMBER */
-      SSH_STRING_FREE(client_pubkey);
-      return SSH_ERROR;
-  }
+        return NULL;
+    }
+    session->next_crypto->ecdh_privkey = key;
+    return pubkey_string;
+}
 
-  session->next_crypto->ecdh_privkey = key;
-  session->next_crypto->ecdh_client_pubkey = client_pubkey;
+/** @internal
+ * @brief Starts ecdh-sha2-nistp256 key exchange
+ */
+int ssh_client_ecdh_init(ssh_session session)
+{
+    ssh_string client_pubkey = NULL;
+    int rc;
 
-  /* register the packet callbacks */
-  ssh_packet_set_callbacks(session, &ssh_ecdh_client_callbacks);
-  session->dh_handshake_state = DH_STATE_INIT_SENT;
+    rc = ssh_buffer_add_u8(session->out_buffer, SSH2_MSG_KEX_ECDH_INIT);
+    if (rc < 0) {
+        return SSH_ERROR;
+    }
 
-  rc = ssh_packet_send(session);
+    client_pubkey = ssh_ecdh_generate(session);
+    if (client_pubkey == NULL) {
+        return SSH_ERROR;
+    }
 
-  return rc;
+    rc = ssh_buffer_add_ssh_string(session->out_buffer, client_pubkey);
+    if (rc < 0) {
+        return SSH_ERROR;
+    }
+
+    session->next_crypto->ecdh_client_pubkey = client_pubkey;
+
+    /* register the packet callbacks */
+    ssh_packet_set_callbacks(session, &ssh_ecdh_client_callbacks);
+    session->dh_handshake_state = DH_STATE_INIT_SENT;
+
+    rc = ssh_packet_send(session);
+
+    return rc;
 }
 
-int ecdh_build_k(ssh_session session) {
+int ecdh_build_k(ssh_session session)
+{
   struct ssh_crypto_struct *next_crypto = session->next_crypto;
-/* TODO Change to new API when the OpenSSL will support export of uncompressed EC keys
- * https://github.com/openssl/openssl/pull/16624
- * #if OPENSSL_VERSION_NUMBER < 0x30000000L
- */
- #if 1
+#if OPENSSL_VERSION_NUMBER < 0x30000000L
   const EC_GROUP *group = EC_KEY_get0_group(next_crypto->ecdh_privkey);
-  EC_POINT *pubkey;
-  void *buffer;
+  EC_POINT *pubkey = NULL;
+  void *buffer = NULL;
   int rc;
   int len = (EC_GROUP_get_degree(group) + 7) / 8;
   bignum_CTX ctx = bignum_ctx_new();
@@ -292,11 +257,13 @@ int ecdh_build_k(ssh_session session) {
   bignum_bin2bn(buffer, len, &next_crypto->shared_secret);
   free(buffer);
 #else
+  const char *curve = NULL;
   EVP_PKEY *pubkey = NULL;
   void *secret = NULL;
   size_t secret_len;
   int rc;
-  OSSL_PARAM params[2];
+  OSSL_PARAM params[3];
+  ssh_string peer_pubkey = NULL;
   EVP_PKEY_CTX *dh_ctx = EVP_PKEY_CTX_new_from_pkey(NULL,
                                                     next_crypto->ecdh_privkey,
                                                     NULL);
@@ -324,15 +291,18 @@ int ecdh_build_k(ssh_session session) {
   }
 
   if (session->server) {
-      params[0] = OSSL_PARAM_construct_octet_string(OSSL_PKEY_PARAM_PUB_KEY,
-                              ssh_string_data(next_crypto->ecdh_client_pubkey),
-                              ssh_string_len(next_crypto->ecdh_client_pubkey));
+      peer_pubkey = next_crypto->ecdh_client_pubkey;
   } else {
-      params[0] = OSSL_PARAM_construct_octet_string(OSSL_PKEY_PARAM_PUB_KEY,
-                              ssh_string_data(next_crypto->ecdh_server_pubkey),
-                              ssh_string_len(next_crypto->ecdh_server_pubkey));
+      peer_pubkey = next_crypto->ecdh_server_pubkey;
   }
-  params[1] = OSSL_PARAM_construct_end();
+  params[0] = OSSL_PARAM_construct_octet_string(OSSL_PKEY_PARAM_PUB_KEY,
+                                                ssh_string_data(peer_pubkey),
+                                                ssh_string_len(peer_pubkey));
+  curve = ecdh_kex_type_to_curve(next_crypto->kex_type);
+  params[1] = OSSL_PARAM_construct_utf8_string(OSSL_PKEY_PARAM_GROUP_NAME,
+                                               (char *)curve,
+                                               strlen(curve));
+  params[2] = OSSL_PARAM_construct_end();
 
   rc = EVP_PKEY_fromdata(pubkey_ctx, &pubkey, EVP_PKEY_PUBLIC_KEY, params);
   if (rc != 1) {
@@ -374,11 +344,7 @@ int ecdh_build_k(ssh_session session) {
   free(secret);
 #endif /* OPENSSL_VERSION_NUMBER */
   if (next_crypto->shared_secret == NULL) {
-/* TODO Change to new API when the OpenSSL will support export of uncompressed EC keys
- * https://github.com/openssl/openssl/pull/16624
- * #if OPENSSL_VERSION_NUMBER < 0x30000000L
- */
-#if 1
+#if OPENSSL_VERSION_NUMBER < 0x30000000L
       EC_KEY_free(next_crypto->ecdh_privkey);
 #else
       EVP_PKEY_free(next_crypto->ecdh_privkey);
@@ -386,11 +352,7 @@ int ecdh_build_k(ssh_session session) {
       next_crypto->ecdh_privkey = NULL;
       return -1;
   }
-/* TODO Change to new API when the OpenSSL will support export of uncompressed EC keys
- * https://github.com/openssl/openssl/pull/16624
- * #if OPENSSL_VERSION_NUMBER < 0x30000000L
- */
-#if 1
+#if OPENSSL_VERSION_NUMBER < 0x30000000L
   EC_KEY_free(next_crypto->ecdh_privkey);
 #else
   EVP_PKEY_free(next_crypto->ecdh_privkey);
@@ -413,29 +375,11 @@ int ecdh_build_k(ssh_session session) {
 /** @brief Handle a SSH_MSG_KEXDH_INIT packet (server) and send a
  * SSH_MSG_KEXDH_REPLY
  */
-SSH_PACKET_CALLBACK(ssh_packet_server_ecdh_init){
+SSH_PACKET_CALLBACK(ssh_packet_server_ecdh_init)
+{
     /* ECDH keys */
-    ssh_string q_c_string;
-    ssh_string q_s_string;
-/* TODO Change to new API when the OpenSSL will support export of uncompressed EC keys
- * https://github.com/openssl/openssl/pull/16624
- * #if OPENSSL_VERSION_NUMBER < 0x30000000L
- */
-#if 1
-    EC_KEY *ecdh_key;
-    const EC_GROUP *group;
-    const EC_POINT *ecdh_pubkey;
-    bignum_CTX ctx;
-    int curve;
-    int len;
-#else
-    EVP_PKEY *ecdh_key = NULL;
-    const void *pubkey_ptr = NULL;
-    size_t len;
-    OSSL_PARAM *params = NULL;
-    const OSSL_PARAM *pubkey = NULL;
-    const char *curve = NULL;
-#endif /* OPENSSL_VERSION_NUMBER */
+    ssh_string q_c_string = NULL;
+    ssh_string q_s_string = NULL;
     /* SSH host keys (rsa,dsa,ecdsa) */
     ssh_key privkey;
     enum ssh_digest_e digest = SSH_DIGEST_AUTO;
@@ -445,125 +389,22 @@ SSH_PACKET_CALLBACK(ssh_packet_server_ecdh_init){
     (void)type;
     (void)user;
 
+    SSH_LOG(SSH_LOG_TRACE, "Processing SSH_MSG_KEXDH_INIT");
+
     ssh_packet_remove_callbacks(session, &ssh_ecdh_server_callbacks);
     /* Extract the client pubkey from the init packet */
     q_c_string = ssh_buffer_get_ssh_string(packet);
     if (q_c_string == NULL) {
-        ssh_set_error(session,SSH_FATAL, "No Q_C ECC point in packet");
+        ssh_set_error(session, SSH_FATAL, "No Q_C ECC point in packet");
         goto error;
     }
     session->next_crypto->ecdh_client_pubkey = q_c_string;
 
-    curve = ecdh_kex_type_to_curve(session->next_crypto->kex_type);
-/* TODO Change to new API when the OpenSSL will support export of uncompressed EC keys
- * https://github.com/openssl/openssl/pull/16624
- * #if OPENSSL_VERSION_NUMBER < 0x30000000L
- */
-#if 1
-    if (curve == SSH_ERROR) {
-        return SSH_ERROR;
-    }
-#else
-    if (curve == NULL) {
-        return SSH_ERROR;
-    }
-#endif /* OPENSSL_VERSION_NUMBER */
-
-/* TODO Change to new API when the OpenSSL will support export of uncompressed EC keys
- * https://github.com/openssl/openssl/pull/16624
- * #if OPENSSL_VERSION_NUMBER < 0x30000000L
- */
-#if 1
-    ecdh_key = EC_KEY_new_by_curve_name(curve);
-#else
-    ecdh_key = EVP_EC_gen(curve);
-#endif /* OPENSSL_VERSION_NUMBER */
-    if (ecdh_key == NULL) {
-        ssh_set_error_oom(session);
-        goto error;
-    }
-
-/* TODO Change to new API when the OpenSSL will support export of uncompressed EC keys
- * https://github.com/openssl/openssl/pull/16624
- * #if OPENSSL_VERSION_NUMBER < 0x30000000L
- */
-#if 1
-    /* Build server's keypair */
-    ctx = BN_CTX_new();
-    if (ctx == NULL) {
-        EC_KEY_free(ecdh_key);
-        return SSH_ERROR;
-    }
-
-    group = EC_KEY_get0_group(ecdh_key);
-    EC_KEY_generate_key(ecdh_key);
-
-    ecdh_pubkey = EC_KEY_get0_public_key(ecdh_key);
-    len = EC_POINT_point2oct(group,
-                             ecdh_pubkey,
-                             POINT_CONVERSION_UNCOMPRESSED,
-                             NULL,
-                             0,
-                             ctx);
-#else
-    rc = EVP_PKEY_todata(ecdh_key, EVP_PKEY_PUBLIC_KEY, &params);
-    if (rc != 1) {
-        EVP_PKEY_free(ecdh_key);
-        return SSH_ERROR;
-    }
-
-    pubkey = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_PUB_KEY);
-    if (pubkey == NULL) {
-        OSSL_PARAM_free(params);
-        EVP_PKEY_free(ecdh_key);
-        return SSH_ERROR;
-    }
-
-    rc = OSSL_PARAM_get_octet_string_ptr(pubkey, &pubkey_ptr, &len);
-    if (rc != 1) {
-        OSSL_PARAM_free(params);
-        EVP_PKEY_free(ecdh_key);
-        return SSH_ERROR;
-    }
-#endif /* OPENSSL_VERSION_NUMBER */
-    q_s_string = ssh_string_new(len);
+    q_s_string = ssh_ecdh_generate(session);
     if (q_s_string == NULL) {
-/* TODO Change to new API when the OpenSSL will support export of uncompressed EC keys
- * https://github.com/openssl/openssl/pull/16624
- * #if OPENSSL_VERSION_NUMBER < 0x30000000L
- */
-#if 1
-        EC_KEY_free(ecdh_key);
-        BN_CTX_free(ctx);
-#else
-        EVP_PKEY_free(ecdh_key);
-#endif /* OPENSSL_VERSION_NUMBER */
         goto error;
     }
 
-/* TODO Change to new API when the OpenSSL will support export of uncompressed EC keys
- * https://github.com/openssl/openssl/pull/16624
- * #if OPENSSL_VERSION_NUMBER < 0x30000000L
- */
-#if 1
-    EC_POINT_point2oct(group,
-                       ecdh_pubkey,
-                       POINT_CONVERSION_UNCOMPRESSED,
-                       ssh_string_data(q_s_string),
-                       len,
-                       ctx);
-    BN_CTX_free(ctx);
-#else
-    if (memcpy(ssh_string_data(q_s_string), pubkey_ptr, len)) {
-        OSSL_PARAM_free(params);
-        EVP_PKEY_free(ecdh_key);
-        return SSH_ERROR;
-    }
-
-    OSSL_PARAM_free(params);
-#endif /* OPENSSL_VERSION_NUMBER */
-
-    session->next_crypto->ecdh_privkey = ecdh_key;
     session->next_crypto->ecdh_server_pubkey = q_s_string;
 
     /* build k and session_id */
diff --git a/src/legacy.c b/src/legacy.c
index 7b165dbe..4c2c0052 100644
--- a/src/legacy.c
+++ b/src/legacy.c
@@ -83,20 +83,20 @@ int ssh_userauth_pubkey(ssh_session session,
     key->type = privatekey->type;
     key->type_c = ssh_key_type_to_char(key->type);
     key->flags = SSH_KEY_FLAG_PRIVATE|SSH_KEY_FLAG_PUBLIC;
-#if !defined(HAVE_LIBCRYPTO) || OPENSSL_VERSION_NUMBER < 0x30000000L
+#ifndef HAVE_LIBCRYPTO
     key->dsa = privatekey->dsa_priv;
     key->rsa = privatekey->rsa_priv;
 #else
     key->key = privatekey->key_priv;
-#endif /* OPENSSL_VERSION_NUMBER */
+#endif /* HAVE_LIBCRYPTO */
 
     rc = ssh_userauth_publickey(session, username, key);
-#if !defined(HAVE_LIBCRYPTO) || OPENSSL_VERSION_NUMBER < 0x30000000L
+#ifndef HAVE_LIBCRYPTO
     key->dsa = NULL;
     key->rsa = NULL;
 #else
     key->key = NULL;
-#endif /* OPENSSL_VERSION_NUMBER */
+#endif /* HAVE_LIBCRYPTO */
     ssh_key_free(key);
 
     return rc;
@@ -362,22 +362,14 @@ void publickey_free(ssh_public_key key) {
 #ifdef HAVE_LIBGCRYPT
       gcry_sexp_release(key->dsa_pub);
 #elif defined HAVE_LIBCRYPTO
-#if OPENSSL_VERSION_NUMBER < 0x30000000L
-      DSA_free(key->dsa_pub);
-#else
       EVP_PKEY_free(key->key_pub);
-#endif /* OPENSSL_VERSION_NUMBER */
 #endif /* HAVE_LIBGCRYPT */
       break;
     case SSH_KEYTYPE_RSA:
 #ifdef HAVE_LIBGCRYPT
       gcry_sexp_release(key->rsa_pub);
 #elif defined HAVE_LIBCRYPTO
-#if OPENSSL_VERSION_NUMBER < 0x30000000L
-      RSA_free(key->rsa_pub);
-#else
       EVP_PKEY_free(key->key_pub);
-#endif /* OPENSSL_VERSION_NUMBER */
 #elif defined HAVE_LIBMBEDCRYPTO
       mbedtls_pk_free(key->rsa_pub);
       SAFE_FREE(key->rsa_pub);
@@ -403,20 +395,20 @@ ssh_public_key publickey_from_privatekey(ssh_private_key prv) {
     privkey->type = prv->type;
     privkey->type_c = ssh_key_type_to_char(privkey->type);
     privkey->flags = SSH_KEY_FLAG_PRIVATE | SSH_KEY_FLAG_PUBLIC;
-#if !defined(HAVE_LIBCRYPTO) || OPENSSL_VERSION_NUMBER < 0x30000000L
+#ifndef HAVE_LIBCRYPTO
     privkey->dsa = prv->dsa_priv;
     privkey->rsa = prv->rsa_priv;
 #else
     privkey->key = prv->key_priv;
-#endif /* OPENSSL_VERSION_NUMBER */
+#endif /* HAVE_LIBCRYPTO */
 
     rc = ssh_pki_export_privkey_to_pubkey(privkey, &pubkey);
-#if !defined(HAVE_LIBCRYPTO) || OPENSSL_VERSION_NUMBER < 0x30000000L
+#ifndef HAVE_LIBCRYPTO
     privkey->dsa = NULL;
     privkey->rsa = NULL;
 #else
     privkey->key = NULL;
-#endif /* OPENSSL_VERSION_NUMBER */
+#endif /* HAVE_LIBCRYPTO */
     ssh_key_free(privkey);
     if (rc < 0) {
         return NULL;
@@ -462,7 +454,7 @@ ssh_private_key privatekey_from_file(ssh_session session,
     }
 
     privkey->type = key->type;
-#if !defined(HAVE_LIBCRYPTO) || OPENSSL_VERSION_NUMBER < 0x30000000L
+#ifndef HAVE_LIBCRYPTO
     privkey->dsa_priv = key->dsa;
     privkey->rsa_priv = key->rsa;
 
@@ -472,7 +464,7 @@ ssh_private_key privatekey_from_file(ssh_session session,
     privkey->key_priv = key->key;
 
     key->key = NULL;
-#endif /* OPENSSL_VERSION_NUMBER */
+#endif /* HAVE_LIBCRYPTO */
 
     ssh_key_free(key);
 
@@ -494,12 +486,7 @@ void privatekey_free(ssh_private_key prv) {
   gcry_sexp_release(prv->dsa_priv);
   gcry_sexp_release(prv->rsa_priv);
 #elif defined HAVE_LIBCRYPTO
-#if OPENSSL_VERSION_NUMBER < 0x30000000L
-  DSA_free(prv->dsa_priv);
-  RSA_free(prv->rsa_priv);
-#else
   EVP_PKEY_free(prv->key_priv);
-#endif /* OPENSSL_VERSION_NUMBER */
 #elif defined HAVE_LIBMBEDCRYPTO
   mbedtls_pk_free(prv->rsa_priv);
   SAFE_FREE(prv->rsa_priv);
@@ -564,7 +551,7 @@ ssh_public_key publickey_from_string(ssh_session session, ssh_string pubkey_s) {
     pubkey->type = key->type;
     pubkey->type_c = key->type_c;
 
-#if !defined(HAVE_LIBCRYPTO) || OPENSSL_VERSION_NUMBER < 0x30000000L
+#ifndef HAVE_LIBCRYPTO
     pubkey->dsa_pub = key->dsa;
     key->dsa = NULL;
     pubkey->rsa_pub = key->rsa;
@@ -572,7 +559,7 @@ ssh_public_key publickey_from_string(ssh_session session, ssh_string pubkey_s) {
 #else
     pubkey->key_pub = key->key;
     key->key = NULL;
-#endif /* OPENSSL_VERSION_NUMBER */
+#endif /* HAVE_LIBCRYPTO */
 
     ssh_key_free(key);
 
@@ -596,24 +583,24 @@ ssh_string publickey_to_string(ssh_public_key pubkey) {
     key->type = pubkey->type;
     key->type_c = pubkey->type_c;
 
-#if !defined(HAVE_LIBCRYPTO) || OPENSSL_VERSION_NUMBER < 0x30000000L
+#ifndef HAVE_LIBCRYPTO
     key->dsa = pubkey->dsa_pub;
     key->rsa = pubkey->rsa_pub;
 #else
     key->key = pubkey->key_pub;
-#endif /* OPENSSL_VERSION_NUMBER */
+#endif /* HAVE_LIBCRYPTO */
 
     rc = ssh_pki_export_pubkey_blob(key, &key_blob);
     if (rc < 0) {
         key_blob = NULL;
     }
 
-#if !defined(HAVE_LIBCRYPTO) || OPENSSL_VERSION_NUMBER < 0x30000000L
+#ifndef HAVE_LIBCRYPTO
     key->dsa = NULL;
     key->rsa = NULL;
 #else
     key->key = NULL;
-#endif /* OPENSSL_VERSION_NUMBER */
+#endif /* HAVE_LIBCRYPTO */
     ssh_key_free(key);
 
     return key_blob;
diff --git a/src/libcrypto-compat.c b/src/libcrypto-compat.c
deleted file mode 100644
index 33b8dffd..00000000
--- a/src/libcrypto-compat.c
+++ /dev/null
@@ -1,305 +0,0 @@
-/*
- * Copyright 2016 The OpenSSL Project Authors. All Rights Reserved.
- *
- * Licensed under the OpenSSL license (the "License").  You may not use
- * this file except in compliance with the License.  You can obtain a copy
- * in the file LICENSE in the source distribution or at
- * https://www.openssl.org/source/license.html
- */
-
-#include "config.h"
-
-#include <string.h>
-#include "libcrypto-compat.h"
-
-int RSA_set0_key(RSA *r, BIGNUM *n, BIGNUM *e, BIGNUM *d)
-{
-    /* If the fields n and e in r are NULL, the corresponding input
-     * parameters MUST be non-NULL for n and e.  d may be
-     * left NULL (in case only the public key is used).
-     */
-    if ((r->n == NULL && n == NULL)
-        || (r->e == NULL && e == NULL))
-        return 0;
-
-    if (n != NULL) {
-        BN_free(r->n);
-        r->n = n;
-    }
-    if (e != NULL) {
-        BN_free(r->e);
-        r->e = e;
-    }
-    if (d != NULL) {
-        BN_free(r->d);
-        r->d = d;
-    }
-
-    return 1;
-}
-
-int RSA_set0_factors(RSA *r, BIGNUM *p, BIGNUM *q)
-{
-    /* If the fields p and q in r are NULL, the corresponding input
-     * parameters MUST be non-NULL.
-     */
-    if ((r->p == NULL && p == NULL)
-        || (r->q == NULL && q == NULL))
-        return 0;
-
-    if (p != NULL) {
-        BN_free(r->p);
-        r->p = p;
-    }
-    if (q != NULL) {
-        BN_free(r->q);
-        r->q = q;
-    }
-
-    return 1;
-}
-
-int RSA_set0_crt_params(RSA *r, BIGNUM *dmp1, BIGNUM *dmq1, BIGNUM *iqmp)
-{
-    /* If the fields dmp1, dmq1 and iqmp in r are NULL, the corresponding input
-     * parameters MUST be non-NULL.
-     */
-    if ((r->dmp1 == NULL && dmp1 == NULL)
-        || (r->dmq1 == NULL && dmq1 == NULL)
-        || (r->iqmp == NULL && iqmp == NULL))
-        return 0;
-
-    if (dmp1 != NULL) {
-        BN_free(r->dmp1);
-        r->dmp1 = dmp1;
-    }
-    if (dmq1 != NULL) {
-        BN_free(r->dmq1);
-        r->dmq1 = dmq1;
-    }
-    if (iqmp != NULL) {
-        BN_free(r->iqmp);
-        r->iqmp = iqmp;
-    }
-
-    return 1;
-}
-
-void RSA_get0_key(const RSA *r,
-                  const BIGNUM **n, const BIGNUM **e, const BIGNUM **d)
-{
-    if (n != NULL)
-        *n = r->n;
-    if (e != NULL)
-        *e = r->e;
-    if (d != NULL)
-        *d = r->d;
-}
-
-void RSA_get0_factors(const RSA *r, const BIGNUM **p, const BIGNUM **q)
-{
-    if (p != NULL)
-        *p = r->p;
-    if (q != NULL)
-        *q = r->q;
-}
-
-void RSA_get0_crt_params(const RSA *r,
-                         const BIGNUM **dmp1, const BIGNUM **dmq1,
-                         const BIGNUM **iqmp)
-{
-    if (dmp1 != NULL)
-        *dmp1 = r->dmp1;
-    if (dmq1 != NULL)
-        *dmq1 = r->dmq1;
-    if (iqmp != NULL)
-        *iqmp = r->iqmp;
-}
-
-void DSA_get0_pqg(const DSA *d,
-                  const BIGNUM **p, const BIGNUM **q, const BIGNUM **g)
-{
-    if (p != NULL)
-        *p = d->p;
-    if (q != NULL)
-        *q = d->q;
-    if (g != NULL)
-        *g = d->g;
-}
-
-int DSA_set0_pqg(DSA *d, BIGNUM *p, BIGNUM *q, BIGNUM *g)
-{
-    /* If the fields p, q and g in d are NULL, the corresponding input
-     * parameters MUST be non-NULL.
-     */
-    if ((d->p == NULL && p == NULL)
-        || (d->q == NULL && q == NULL)
-        || (d->g == NULL && g == NULL))
-        return 0;
-
-    if (p != NULL) {
-        BN_free(d->p);
-        d->p = p;
-    }
-    if (q != NULL) {
-        BN_free(d->q);
-        d->q = q;
-    }
-    if (g != NULL) {
-        BN_free(d->g);
-        d->g = g;
-    }
-
-    return 1;
-}
-
-void DSA_get0_key(const DSA *d,
-                  const BIGNUM **pub_key, const BIGNUM **priv_key)
-{
-    if (pub_key != NULL)
-        *pub_key = d->pub_key;
-    if (priv_key != NULL)
-        *priv_key = d->priv_key;
-}
-
-int DSA_set0_key(DSA *d, BIGNUM *pub_key, BIGNUM *priv_key)
-{
-    /* If the field pub_key in d is NULL, the corresponding input
-     * parameters MUST be non-NULL.  The priv_key field may
-     * be left NULL.
-     */
-    if (d->pub_key == NULL && pub_key == NULL)
-        return 0;
-
-    if (pub_key != NULL) {
-        BN_free(d->pub_key);
-        d->pub_key = pub_key;
-    }
-    if (priv_key != NULL) {
-        BN_free(d->priv_key);
-        d->priv_key = priv_key;
-    }
-
-    return 1;
-}
-
-void DSA_SIG_get0(const DSA_SIG *sig, const BIGNUM **pr, const BIGNUM **ps)
-{
-    if (pr != NULL)
-        *pr = sig->r;
-    if (ps != NULL)
-        *ps = sig->s;
-}
-
-int DSA_SIG_set0(DSA_SIG *sig, BIGNUM *r, BIGNUM *s)
-{
-    if (r == NULL || s == NULL)
-        return 0;
-    BN_clear_free(sig->r);
-    BN_clear_free(sig->s);
-    sig->r = r;
-    sig->s = s;
-    return 1;
-}
-
-void ECDSA_SIG_get0(const ECDSA_SIG *sig, const BIGNUM **pr, const BIGNUM **ps)
-{
-    if (pr != NULL)
-        *pr = sig->r;
-    if (ps != NULL)
-        *ps = sig->s;
-}
-
-int ECDSA_SIG_set0(ECDSA_SIG *sig, BIGNUM *r, BIGNUM *s)
-{
-    if (r == NULL || s == NULL)
-        return 0;
-    BN_clear_free(sig->r);
-    BN_clear_free(sig->s);
-    sig->r = r;
-    sig->s = s;
-    return 1;
-}
-
-EVP_MD_CTX *EVP_MD_CTX_new(void)
-{
-    EVP_MD_CTX *ctx = OPENSSL_malloc(sizeof(EVP_MD_CTX));
-    if (ctx != NULL) {
-        EVP_MD_CTX_init(ctx);
-    }
-    return ctx;
-}
-
-void EVP_MD_CTX_free(EVP_MD_CTX *ctx)
-{
-    EVP_MD_CTX_cleanup(ctx);
-    OPENSSL_free(ctx);
-}
-
-void DH_get0_pqg(const DH *dh,
-                 const BIGNUM **p, const BIGNUM **q, const BIGNUM **g)
-{
-    if (p) {
-        *p = dh->p;
-    }
-    if (q) {
-        *q = NULL;
-    }
-    if (g) {
-        *g = dh->g;
-    }
-}
-
-int DH_set0_pqg(DH *dh, BIGNUM *p, BIGNUM *q, BIGNUM *g)
-{
-    if (p) {
-        if (dh->p) {
-            BN_free(dh->p);
-        }
-        dh->p = p;
-    }
-    if (g) {
-        if (dh->g) {
-            BN_free(dh->g);
-        }
-        dh->g = g;
-    }
-    return 1;
-}
-
-void DH_get0_key(const DH *dh,
-                 const BIGNUM **pub_key, const BIGNUM **priv_key)
-{
-    if (pub_key) {
-        *pub_key = dh->pub_key;
-    }
-    if (priv_key) {
-        *priv_key = dh->priv_key;
-    }
-}
-
-int DH_set0_key(DH *dh, BIGNUM *pub_key, BIGNUM *priv_key)
-{
-    if (pub_key) {
-        if (dh->pub_key) {
-            BN_free(dh->pub_key);
-        }
-        dh->pub_key = pub_key;
-    }
-    if (priv_key) {
-        if (dh->priv_key) {
-            BN_free(dh->priv_key);
-        }
-        dh->priv_key = priv_key;
-    }
-    return 1;
-}
-
-const char *OpenSSL_version(int type)
-{
-    return SSLeay_version(type);
-}
-unsigned long OpenSSL_version_num(void)
-{
-    return SSLeay();
-}
diff --git a/src/libcrypto-compat.h b/src/libcrypto-compat.h
index 48e30bd1..0f2dc184 100644
--- a/src/libcrypto-compat.h
+++ b/src/libcrypto-compat.h
@@ -7,47 +7,8 @@
 #define NISTP384 "P-384"
 #define NISTP521 "P-521"
 
-#if OPENSSL_VERSION_NUMBER < 0x10100000L
-
-#include <openssl/rsa.h>
-#include <openssl/dsa.h>
-#include <openssl/ecdsa.h>
-#include <openssl/dh.h>
-#include <openssl/evp.h>
-#include <openssl/hmac.h>
-#include <openssl/bn.h>
-
-int RSA_set0_key(RSA *r, BIGNUM *n, BIGNUM *e, BIGNUM *d);
-int RSA_set0_factors(RSA *r, BIGNUM *p, BIGNUM *q);
-int RSA_set0_crt_params(RSA *r, BIGNUM *dmp1, BIGNUM *dmq1, BIGNUM *iqmp);
-void RSA_get0_key(const RSA *r, const BIGNUM **n, const BIGNUM **e, const BIGNUM **d);
-void RSA_get0_factors(const RSA *r, const BIGNUM **p, const BIGNUM **q);
-void RSA_get0_crt_params(const RSA *r, const BIGNUM **dmp1, const BIGNUM **dmq1, const BIGNUM **iqmp);
-
-void DSA_get0_pqg(const DSA *d, const BIGNUM **p, const BIGNUM **q, const BIGNUM **g);
-int DSA_set0_pqg(DSA *d, BIGNUM *p, BIGNUM *q, BIGNUM *g);
-void DSA_get0_key(const DSA *d, const BIGNUM **pub_key, const BIGNUM **priv_key);
-int DSA_set0_key(DSA *d, BIGNUM *pub_key, BIGNUM *priv_key);
-
-void DSA_SIG_get0(const DSA_SIG *sig, const BIGNUM **pr, const BIGNUM **ps);
-int DSA_SIG_set0(DSA_SIG *sig, BIGNUM *r, BIGNUM *s);
-
-void ECDSA_SIG_get0(const ECDSA_SIG *sig, const BIGNUM **pr, const BIGNUM **ps);
-int ECDSA_SIG_set0(ECDSA_SIG *sig, BIGNUM *r, BIGNUM *s);
-
-EVP_MD_CTX *EVP_MD_CTX_new(void);
-void EVP_MD_CTX_free(EVP_MD_CTX *ctx);
-
-void DH_get0_pqg(const DH *dh,
-                 const BIGNUM **p, const BIGNUM **q, const BIGNUM **g);
-int DH_set0_pqg(DH *dh, BIGNUM *p, BIGNUM *q, BIGNUM *g);
-void DH_get0_key(const DH *dh,
-                 const BIGNUM **pub_key, const BIGNUM **priv_key);
-int DH_set0_key(DH *dh, BIGNUM *pub_key, BIGNUM *priv_key);
-
-const char *OpenSSL_version(int type);
-unsigned long OpenSSL_version_num(void);
-
+#if OPENSSL_VERSION_NUMBER < 0x30000000L
+#define EVP_PKEY_eq EVP_PKEY_cmp
 #endif /* OPENSSL_VERSION_NUMBER */
 
 #endif /* LIBCRYPTO_COMPAT_H */
diff --git a/src/libcrypto.c b/src/libcrypto.c
index 4f945d90..7b9ffc00 100644
--- a/src/libcrypto.c
+++ b/src/libcrypto.c
@@ -85,7 +85,6 @@
 
 static int libcrypto_initialized = 0;
 
-static ENGINE *engine = NULL;
 
 void ssh_reseed(void){
 #ifndef _WIN32
@@ -95,6 +94,9 @@ void ssh_reseed(void){
 #endif
 }
 
+#ifndef WITH_PKCS11_PROVIDER
+static ENGINE *engine = NULL;
+
 ENGINE *pki_get_engine(void)
 {
     int ok;
@@ -124,6 +126,7 @@ ENGINE *pki_get_engine(void)
     }
     return engine;
 }
+#endif /* WITH_PKCS11_PROVIDER */
 
 #ifdef HAVE_OPENSSL_EVP_KDF_CTX
 #if OPENSSL_VERSION_NUMBER < 0x30000000L
@@ -1460,57 +1463,59 @@ int evp_build_pkey(const char* name, OSSL_PARAM_BLD *param_bld,
  *
  * @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)
+static int
+evp_dup_pkey(const char *name, const ssh_key key, int demote, ssh_key new_key)
 {
     int rc;
-    EVP_PKEY_CTX *ctx = EVP_PKEY_CTX_new_from_name(NULL, name, NULL);
+    EVP_PKEY_CTX *ctx = NULL;
     OSSL_PARAM *params = NULL;
 
-    if (ctx == NULL) {
-        return -1;
-    }
-
-    if (!demote && (key->flags & SSH_KEY_FLAG_PRIVATE)) {
-        rc = EVP_PKEY_todata(key->key, EVP_PKEY_KEYPAIR, &params);
+    /* 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) {
-            EVP_PKEY_CTX_free(ctx);
             return -1;
         }
+        new_key->key = key->key;
+        return SSH_OK;
+    }
 
-        rc = EVP_PKEY_fromdata_init(ctx);
-        if (rc != 1) {
-            EVP_PKEY_CTX_free(ctx);
-            OSSL_PARAM_free(params);
-            return -1;
-        }
+    /* demote == 1 */
+    ctx = EVP_PKEY_CTX_new_from_name(NULL, name, NULL);
+    if (ctx == NULL) {
+        return -1;
+    }
 
-        rc = EVP_PKEY_fromdata(ctx, &(new_key->key), EVP_PKEY_KEYPAIR, params);
-        if (rc != 1) {
-            EVP_PKEY_CTX_free(ctx);
-            OSSL_PARAM_free(params);
-            return -1;
-        }
-    } else {
-        rc = EVP_PKEY_todata(key->key, EVP_PKEY_PUBLIC_KEY, &params);
-        if (rc != 1) {
-            EVP_PKEY_CTX_free(ctx);
-            return -1;
-        }
+    rc = EVP_PKEY_todata(key->key, EVP_PKEY_PUBLIC_KEY, &params);
+    if (rc != 1) {
+        EVP_PKEY_CTX_free(ctx);
+        return -1;
+    }
 
-        rc = EVP_PKEY_fromdata_init(ctx);
-        if (rc != 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;
-        }
+    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);
@@ -1535,4 +1540,54 @@ int evp_dup_ecdsa_pkey(const ssh_key key, ssh_key new_key, int demote)
 }
 #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 */
diff --git a/src/pki.c b/src/pki.c
index a7c84c5e..b606ae99 100644
--- a/src/pki.c
+++ b/src/pki.c
@@ -1114,7 +1114,7 @@ ssh_public_key ssh_pki_convert_key_to_publickey(const ssh_key key)
     pub->type = tmp->type;
     pub->type_c = tmp->type_c;
 
-#if !defined(HAVE_LIBCRYPTO) || OPENSSL_VERSION_NUMBER < 0x30000000L
+#ifndef HAVE_LIBCRYPTO
     pub->dsa_pub = tmp->dsa;
     tmp->dsa = NULL;
     pub->rsa_pub = tmp->rsa;
@@ -1122,7 +1122,7 @@ ssh_public_key ssh_pki_convert_key_to_publickey(const ssh_key key)
 #else
     pub->key_pub = tmp->key;
     tmp->key = NULL;
-#endif /* OPENSSL_VERSION_NUMBER */
+#endif /* HAVE_LIBCRYPTO */
 
     ssh_key_free(tmp);
 
@@ -1140,12 +1140,12 @@ ssh_private_key ssh_pki_convert_key_to_privatekey(const ssh_key key)
     }
 
     privkey->type = key->type;
-#if !defined(HAVE_LIBCRYPTO) || OPENSSL_VERSION_NUMBER < 0x30000000L
+#ifndef HAVE_LIBCRYPTO
     privkey->dsa_priv = key->dsa;
     privkey->rsa_priv = key->rsa;
 #else
     privkey->key_priv = key->key;
-#endif /* OPENSSL_VERSION_NUMBER */
+#endif /* HAVE_LIBCRYPTO */
 
     return privkey;
 }
diff --git a/src/pki_crypto.c b/src/pki_crypto.c
index 5b0d7ded..d3e98ba6 100644
--- a/src/pki_crypto.c
+++ b/src/pki_crypto.c
@@ -42,6 +42,10 @@
 #include <openssl/params.h>
 #include <openssl/core_names.h>
 #include <openssl/param_build.h>
+#if defined(WITH_PKCS11_URI) && defined(WITH_PKCS11_PROVIDER)
+#include <openssl/store.h>
+#include <openssl/provider.h>
+#endif
 #endif /* OPENSSL_VERSION_NUMBER */
 
 #ifdef HAVE_OPENSSL_EC_H
@@ -91,37 +95,20 @@ void pki_key_clean(ssh_key key)
 {
     if (key == NULL)
         return;
-#if OPENSSL_VERSION_NUMBER < 0x30000000L
-    DSA_free(key->dsa);
-    key->dsa = NULL;
-    RSA_free(key->rsa);
-    key->rsa = NULL;
-#endif /* OPENSSL_VERSION_NUMBER */
-#ifdef HAVE_OPENSSL_ECC
-/* TODO Change to new API when the OpenSSL will support export of uncompressed EC keys
- * https://github.com/openssl/openssl/pull/16624
- * Move whole HAVE_OPENSSL_ECC into #if < 0x3 above
- */
-#if 1
-    EC_KEY_free(key->ecdsa);
-    key->ecdsa = NULL;
-#endif
-#endif /* HAVE_OPENSSL_ECC */
     EVP_PKEY_free(key->key);
     key->key = NULL;
 }
 
 #ifdef HAVE_OPENSSL_ECC
-/* TODO Change to new API when the OpenSSL will support export of uncompressed EC keys
- * https://github.com/openssl/openssl/pull/16624
- * #if OPENSSL_VERSION_NUMBER < 0x30000000L
- */
-#if 1
+#if OPENSSL_VERSION_NUMBER < 0x30000000L
 static int pki_key_ecdsa_to_nid(EC_KEY *k)
 {
     const EC_GROUP *g = EC_KEY_get0_group(k);
     int nid;
 
+    if (g == NULL) {
+        return -1;
+    }
     nid = EC_GROUP_get_curve_name(g);
     if (nid) {
         return nid;
@@ -133,34 +120,22 @@ static int pki_key_ecdsa_to_nid(EC_KEY *k)
 static int pki_key_ecdsa_to_nid(EVP_PKEY *k)
 {
     char gname[25] = { 0 };
-    int nid, rc;
-
-    rc = EVP_PKEY_get_utf8_string_param(k, "group", gname, 25, NULL);
-    if (rc != 1)
-        return -1;
+    int rc;
 
-    if (strcmp(gname, NISTP256) == 0
-        || strcmp(gname, "secp256r1") == 0
-        || strcmp(gname, "prime256v1") == 0) {
-        nid = NID_X9_62_prime256v1;
-    } else if (strcmp(gname, NISTP384) == 0
-               || strcmp(gname, "secp384r1") == 0) {
-        nid = NID_secp384r1;
-    } else if (strcmp(gname, NISTP521) == 0
-               || strcmp(gname, "secp521r1") == 0) {
-        nid = NID_secp521r1;
-    } else
+    rc = EVP_PKEY_get_utf8_string_param(k,
+                                        OSSL_PKEY_PARAM_GROUP_NAME,
+                                        gname,
+                                        25,
+                                        NULL);
+    if (rc != 1) {
         return -1;
+    }
 
-    return nid;
+    return pki_key_ecgroup_name_to_nid(gname);
 }
 #endif /* OPENSSL_VERSION_NUMBER */
 
-/* TODO Change to new API when the OpenSSL will support export of uncompressed EC keys
- * https://github.com/openssl/openssl/pull/16624
- * #if OPENSSL_VERSION_NUMBER < 0x30000000L
- */
-#if 1
+#if OPENSSL_VERSION_NUMBER < 0x30000000L
 static enum ssh_keytypes_e pki_key_ecdsa_to_key_type(EC_KEY *k)
 #else
 static enum ssh_keytypes_e pki_key_ecdsa_to_key_type(EVP_PKEY *k)
@@ -227,160 +202,139 @@ int pki_key_ecdsa_nid_from_name(const char *name)
     return -1;
 }
 
-/* TODO Change to new API when the OpenSSL will support export of uncompressed EC keys
- * https://github.com/openssl/openssl/pull/16624
- * #if OPENSSL_VERSION_NUMBER < 0x30000000L
- */
-#if 1
-static ssh_string make_ecpoint_string(const EC_GROUP *g,
-                                      const EC_POINT *p)
-{
-    ssh_string s;
-    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;
-}
-#endif /* OPENSSL_VERSION_NUMBER */
-
 int pki_privkey_build_ecdsa(ssh_key key, int nid, ssh_string e, ssh_string exp)
 {
-/* TODO Change to new API when the OpenSSL will support export of uncompressed EC keys
- * https://github.com/openssl/openssl/pull/16624
- * #if OPENSSL_VERSION_NUMBER < 0x30000000L
- */
-#if 1
+    int rc = 0;
+    BIGNUM *bexp = NULL;
+
+#if OPENSSL_VERSION_NUMBER < 0x30000000L
     EC_POINT *p = NULL;
     const EC_GROUP *g = NULL;
-    int ok;
-    BIGNUM *bexp = NULL;
+    EC_KEY *ecdsa = NULL;
 #else
-    int rc;
-    const BIGNUM *expb;
     const char *group_name = OSSL_EC_curve_nid2name(nid);
     OSSL_PARAM_BLD *param_bld = NULL;
 
     if (group_name == NULL) {
         return -1;
     }
-    expb = ssh_make_string_bn(exp);
 #endif /* OPENSSL_VERSION_NUMBER */
 
+    bexp = ssh_make_string_bn(exp);
+    if (bexp == NULL) {
+        return -1;
+    }
+
     key->ecdsa_nid = nid;
     key->type_c = pki_key_ecdsa_nid_to_name(nid);
 
-/* TODO Change to new API when the OpenSSL will support export of uncompressed EC keys
- * https://github.com/openssl/openssl/pull/16624
- * #if OPENSSL_VERSION_NUMBER < 0x30000000L
- */
-#if 1
-    key->ecdsa = EC_KEY_new_by_curve_name(key->ecdsa_nid);
-    if (key->ecdsa == NULL) {
-        return -1;
+#if OPENSSL_VERSION_NUMBER < 0x30000000L
+    ecdsa = EC_KEY_new_by_curve_name(key->ecdsa_nid);
+    if (ecdsa == NULL) {
+        rc = -1;
+        goto cleanup;
     }
 
-    g = EC_KEY_get0_group(key->ecdsa);
+    g = EC_KEY_get0_group(ecdsa);
 
     p = EC_POINT_new(g);
     if (p == NULL) {
-        return -1;
+        rc = -1;
+        goto cleanup;
     }
 
-    ok = EC_POINT_oct2point(g,
+    rc = EC_POINT_oct2point(g,
                             p,
                             ssh_string_data(e),
                             ssh_string_len(e),
                             NULL);
-    if (!ok) {
-        EC_POINT_free(p);
-        return -1;
+    if (rc != 1) {
+        rc = -1;
+        goto cleanup;
     }
 
     /* EC_KEY_set_public_key duplicates p */
-    ok = EC_KEY_set_public_key(key->ecdsa, p);
-    EC_POINT_free(p);
-    if (!ok) {
-        return -1;
+    rc = EC_KEY_set_public_key(ecdsa, p);
+    if (rc != 1) {
+        rc = -1;
+        goto cleanup;
     }
 
-    bexp = ssh_make_string_bn(exp);
-    if (bexp == NULL) {
-        EC_KEY_free(key->ecdsa);
-        return -1;
-    }
     /* EC_KEY_set_private_key duplicates exp */
-    ok = EC_KEY_set_private_key(key->ecdsa, bexp);
-    BN_free(bexp);
-    if (!ok) {
-        EC_KEY_free(key->ecdsa);
-        return -1;
+    rc = EC_KEY_set_private_key(ecdsa, bexp);
+    if (rc != 1) {
+        rc = -1;
+        goto cleanup;
     }
 
-    return 0;
+    key->key = EVP_PKEY_new();
+    if (key->key == NULL) {
+        rc = -1;
+        goto cleanup;
+    }
+
+    /* ecdsa will be freed when the EVP_PKEY key->key is freed */
+    rc = EVP_PKEY_assign_EC_KEY(key->key, ecdsa);
+    if (rc != 1) {
+        rc = -1;
+        goto cleanup;
+    }
+    /* ssh_key is now the owner of this memory */
+    ecdsa = NULL;
+
+    /* set rc to 0 if everything went well */
+    rc = 0;
+
+cleanup:
+    EC_KEY_free(ecdsa);
+    EC_POINT_free(p);
+    BN_free(bexp);
+    return rc;
 #else
     param_bld = OSSL_PARAM_BLD_new();
-    if (param_bld == NULL)
-        goto err;
+    if (param_bld == NULL){
+        rc = -1;
+        goto cleanup;
+    }
 
     rc = OSSL_PARAM_BLD_push_utf8_string(param_bld, OSSL_PKEY_PARAM_GROUP_NAME,
                                          group_name, strlen(group_name));
-    if (rc != 1)
-        goto err;
+    if (rc != 1) {
+        rc = -1;
+        goto cleanup;
+    }
+
     rc = OSSL_PARAM_BLD_push_octet_string(param_bld, OSSL_PKEY_PARAM_PUB_KEY,
                                           ssh_string_data(e), ssh_string_len(e));
-    if (rc != 1)
-        goto err;
-    rc = OSSL_PARAM_BLD_push_BN(param_bld, OSSL_PKEY_PARAM_PRIV_KEY, expb);
-    if (rc != 1)
-        goto err;
+    if (rc != 1) {
+        rc = -1;
+        goto cleanup;
+    }
+
+    rc = OSSL_PARAM_BLD_push_BN(param_bld, OSSL_PKEY_PARAM_PRIV_KEY, bexp);
+    if (rc != 1) {
+        rc = -1;
+        goto cleanup;
+    }
 
     rc = evp_build_pkey("EC", param_bld, &(key->key), EVP_PKEY_KEYPAIR);
-    OSSL_PARAM_BLD_free(param_bld);
 
-    return rc;
-err:
+cleanup:
     OSSL_PARAM_BLD_free(param_bld);
-    return -1;
+    BN_free(bexp);
+    return rc;
 #endif /* OPENSSL_VERSION_NUMBER */
 }
 
 int pki_pubkey_build_ecdsa(ssh_key key, int nid, ssh_string e)
 {
-/* TODO Change to new API when the OpenSSL will support export of uncompressed EC keys
- * https://github.com/openssl/openssl/pull/16624
- * #if OPENSSL_VERSION_NUMBER < 0x30000000L
- */
-#if 1
+    int rc;
+#if OPENSSL_VERSION_NUMBER < 0x30000000L
     EC_POINT *p = NULL;
     const EC_GROUP *g = NULL;
+    EC_KEY *ecdsa = NULL;
     int ok;
 #else
-    int rc;
     const char *group_name = OSSL_EC_curve_nid2name(nid);
     OSSL_PARAM_BLD *param_bld;
 #endif /* OPENSSL_VERSION_NUMBER */
@@ -388,20 +342,17 @@ int pki_pubkey_build_ecdsa(ssh_key key, int nid, ssh_string e)
     key->ecdsa_nid = nid;
     key->type_c = pki_key_ecdsa_nid_to_name(nid);
 
-/* TODO Change to new API when the OpenSSL will support export of uncompressed EC keys
- * https://github.com/openssl/openssl/pull/16624
- * #if OPENSSL_VERSION_NUMBER < 0x30000000L
- */
- #if 1
-    key->ecdsa = EC_KEY_new_by_curve_name(key->ecdsa_nid);
-    if (key->ecdsa == NULL) {
+#if OPENSSL_VERSION_NUMBER < 0x30000000L
+    ecdsa = EC_KEY_new_by_curve_name(key->ecdsa_nid);
+    if (ecdsa == NULL) {
         return -1;
     }
 
-    g = EC_KEY_get0_group(key->ecdsa);
+    g = EC_KEY_get0_group(ecdsa);
 
     p = EC_POINT_new(g);
     if (p == NULL) {
+        EC_KEY_free(ecdsa);
         return -1;
     }
 
@@ -411,14 +362,28 @@ int pki_pubkey_build_ecdsa(ssh_key key, int nid, ssh_string e)
                             ssh_string_len(e),
                             NULL);
     if (!ok) {
+        EC_KEY_free(ecdsa);
         EC_POINT_free(p);
         return -1;
     }
 
     /* EC_KEY_set_public_key duplicates p */
-    ok = EC_KEY_set_public_key(key->ecdsa, p);
+    ok = EC_KEY_set_public_key(ecdsa, p);
     EC_POINT_free(p);
     if (!ok) {
+        EC_KEY_free(ecdsa);
+        return -1;
+    }
+
+    key->key = EVP_PKEY_new();
+    if (key->key == NULL) {
+        EC_KEY_free(ecdsa);
+        return -1;
+    }
+
+    rc = EVP_PKEY_assign_EC_KEY(key->key, ecdsa);
+    if (rc != 1) {
+        EC_KEY_free(ecdsa);
         return -1;
     }
 
@@ -472,8 +437,9 @@ ssh_key pki_key_dup(const ssh_key key, int demote)
         const BIGNUM *p = NULL, *q = NULL, *g = NULL,
           *pub_key = NULL, *priv_key = NULL;
         BIGNUM *np, *nq, *ng, *npub_key, *npriv_key;
-        new->dsa = DSA_new();
-        if (new->dsa == NULL) {
+        DSA *new_dsa = DSA_new();
+        const DSA *key_dsa = EVP_PKEY_get0_DSA(key->key);
+        if (new_dsa == NULL) {
             goto fail;
         }
 
@@ -484,11 +450,12 @@ ssh_key pki_key_dup(const ssh_key key, int demote)
          * pub_key  = public key y = g^x
          * priv_key = private key x
          */
-        DSA_get0_pqg(key->dsa, &p, &q, &g);
+        DSA_get0_pqg(key_dsa, &p, &q, &g);
         np = BN_dup(p);
         nq = BN_dup(q);
         ng = BN_dup(g);
         if (np == NULL || nq == NULL || ng == NULL) {
+            DSA_free(new_dsa);
             BN_free(np);
             BN_free(nq);
             BN_free(ng);
@@ -496,38 +463,58 @@ ssh_key pki_key_dup(const ssh_key key, int demote)
         }
 
         /* Memory management of np, nq and ng is transferred to DSA object */
-        rc = DSA_set0_pqg(new->dsa, np, nq, ng);
+        rc = DSA_set0_pqg(new_dsa, np, nq, ng);
         if (rc == 0) {
+            DSA_free(new_dsa);
             BN_free(np);
             BN_free(nq);
             BN_free(ng);
             goto fail;
         }
 
-        DSA_get0_key(key->dsa, &pub_key, &priv_key);
+        DSA_get0_key(key_dsa, &pub_key, &priv_key);
         npub_key = BN_dup(pub_key);
         if (npub_key == NULL) {
+            DSA_free(new_dsa);
             goto fail;
         }
 
         /* Memory management of npubkey is transferred to DSA object */
-        rc = DSA_set0_key(new->dsa, npub_key, NULL);
+        rc = DSA_set0_key(new_dsa, npub_key, NULL);
         if (rc == 0) {
+            DSA_free(new_dsa);
             goto fail;
         }
 
         if (!demote && (key->flags & SSH_KEY_FLAG_PRIVATE)) {
             npriv_key = BN_dup(priv_key);
             if (npriv_key == NULL) {
+                DSA_free(new_dsa);
                 goto fail;
             }
 
             /* Memory management of npriv_key is transferred to DSA object */
-            rc = DSA_set0_key(new->dsa, NULL, npriv_key);
+            rc = DSA_set0_key(new_dsa, NULL, npriv_key);
             if (rc == 0) {
+                DSA_free(new_dsa);
                 goto fail;
             }
         }
+
+        new->key = EVP_PKEY_new();
+        if (new->key == NULL) {
+            DSA_free(new_dsa);
+            goto fail;
+        }
+
+        rc = EVP_PKEY_assign_DSA(new->key, new_dsa);
+        if (rc != 1) {
+            EVP_PKEY_free(new->key);
+            DSA_free(new_dsa);
+            goto fail;
+        }
+
+        new_dsa = NULL;
 #else
         rc = evp_dup_dsa_pkey(key, new, demote);
         if (rc != SSH_OK) {
@@ -541,6 +528,8 @@ ssh_key pki_key_dup(const ssh_key key, int demote)
 #if OPENSSL_VERSION_NUMBER < 0x30000000L
         const BIGNUM *n = NULL, *e = NULL, *d = NULL;
         BIGNUM *nn, *ne, *nd;
+        RSA *new_rsa = NULL;
+        const RSA *key_rsa = EVP_PKEY_get0_RSA(key->key);
 #endif /* OPENSSL_VERSION_NUMBER < 0x30000000L */
 #ifdef WITH_PKCS11_URI
         /* Take the PKCS#11 keys as they are */
@@ -554,8 +543,8 @@ ssh_key pki_key_dup(const ssh_key key, int demote)
         }
 #endif /* WITH_PKCS11_URI */
 #if OPENSSL_VERSION_NUMBER < 0x30000000L
-        new->rsa = RSA_new();
-        if (new->rsa == NULL) {
+        new_rsa = RSA_new();
+        if (new_rsa == NULL) {
             goto fail;
         }
 
@@ -569,18 +558,20 @@ ssh_key pki_key_dup(const ssh_key key, int demote)
          * dmq1 = d mod (q-1)
          * iqmp = q^-1 mod p
          */
-        RSA_get0_key(key->rsa, &n, &e, &d);
+        RSA_get0_key(key_rsa, &n, &e, &d);
         nn = BN_dup(n);
         ne = BN_dup(e);
         if (nn == NULL || ne == NULL) {
+            RSA_free(new_rsa);
             BN_free(nn);
             BN_free(ne);
             goto fail;
         }
 
         /* Memory management of nn and ne is transferred to RSA object */
-        rc = RSA_set0_key(new->rsa, nn, ne, NULL);
+        rc = RSA_set0_key(new_rsa, nn, ne, NULL);
         if (rc == 0) {
+            RSA_free(new_rsa);
             BN_free(nn);
             BN_free(ne);
             goto fail;
@@ -593,43 +584,48 @@ ssh_key pki_key_dup(const ssh_key key, int demote)
 
             nd = BN_dup(d);
             if (nd == NULL) {
+                RSA_free(new_rsa);
                 goto fail;
             }
 
             /* Memory management of nd is transferred to RSA object */
-            rc = RSA_set0_key(new->rsa, NULL, NULL, nd);
+            rc = RSA_set0_key(new_rsa, NULL, NULL, nd);
             if (rc == 0) {
+                RSA_free(new_rsa);
                 goto fail;
             }
 
             /* p, q, dmp1, dmq1 and iqmp may be NULL in private keys, but the
              * RSA operations are much faster when these values are available.
              */
-            RSA_get0_factors(key->rsa, &p, &q);
+            RSA_get0_factors(key_rsa, &p, &q);
             if (p != NULL && q != NULL) { /* need to set both of them */
                 np = BN_dup(p);
                 nq = BN_dup(q);
                 if (np == NULL || nq == NULL) {
+                    RSA_free(new_rsa);
                     BN_free(np);
                     BN_free(nq);
                     goto fail;
                 }
 
                 /* Memory management of np and nq is transferred to RSA object */
-                rc = RSA_set0_factors(new->rsa, np, nq);
+                rc = RSA_set0_factors(new_rsa, np, nq);
                 if (rc == 0) {
+                    RSA_free(new_rsa);
                     BN_free(np);
                     BN_free(nq);
                     goto fail;
                 }
             }
 
-            RSA_get0_crt_params(key->rsa, &dmp1, &dmq1, &iqmp);
+            RSA_get0_crt_params(key_rsa, &dmp1, &dmq1, &iqmp);
             if (dmp1 != NULL || dmq1 != NULL || iqmp != NULL) {
                 ndmp1 = BN_dup(dmp1);
                 ndmq1 = BN_dup(dmq1);
                 niqmp = BN_dup(iqmp);
                 if (ndmp1 == NULL || ndmq1 == NULL || niqmp == NULL) {
+                    RSA_free(new_rsa);
                     BN_free(ndmp1);
                     BN_free(ndmq1);
                     BN_free(niqmp);
@@ -638,8 +634,9 @@ ssh_key pki_key_dup(const ssh_key key, int demote)
 
                 /* Memory management of ndmp1, ndmq1 and niqmp is transferred
                  * to RSA object */
-                rc = RSA_set0_crt_params(new->rsa, ndmp1, ndmq1, niqmp);
+                rc = RSA_set0_crt_params(new_rsa, ndmp1, ndmq1, niqmp);
                 if (rc == 0) {
+                    RSA_free(new_rsa);
                     BN_free(ndmp1);
                     BN_free(ndmq1);
                     BN_free(niqmp);
@@ -647,6 +644,21 @@ ssh_key pki_key_dup(const ssh_key key, int demote)
                 }
             }
         }
+
+        new->key = EVP_PKEY_new();
+        if (new->key == NULL) {
+            RSA_free(new_rsa);
+            goto fail;
+        }
+
+        rc = EVP_PKEY_assign_RSA(new->key, new_rsa);
+        if (rc != 1) {
+            EVP_PKEY_free(new->key);
+            RSA_free(new_rsa);
+            goto fail;
+        }
+
+        new_rsa = NULL;
 #else
         rc = evp_dup_rsa_pkey(key, new, demote);
         if (rc != SSH_OK) {
@@ -668,44 +680,56 @@ ssh_key pki_key_dup(const ssh_key key, int demote)
                 goto fail;
             }
             new->key = key->key;
-            rc = EC_KEY_up_ref(key->ecdsa);
-            if (rc != 1) {
-                goto fail;
-            }
-            new->ecdsa = key->ecdsa;
             return new;
         }
 #endif /* WITH_PKCS11_URI */
-/* TODO Change to new API when the OpenSSL will support export of uncompressed EC keys
- * https://github.com/openssl/openssl/pull/16624
- * #if OPENSSL_VERSION_NUMBER < 0x30000000L
- */
-#if 1
+#if OPENSSL_VERSION_NUMBER < 0x30000000L
         /* privkey -> pubkey */
         if (demote && ssh_key_is_private(key)) {
-            const EC_POINT *p;
+            const EC_POINT *p = NULL;
+            EC_KEY *new_ecdsa = NULL, *old_ecdsa = NULL;
             int ok;
 
-            new->ecdsa = EC_KEY_new_by_curve_name(key->ecdsa_nid);
-            if (new->ecdsa == NULL) {
+            new_ecdsa = EC_KEY_new_by_curve_name(key->ecdsa_nid);
+            if (new_ecdsa == NULL) {
                 goto fail;
             }
 
-            p = EC_KEY_get0_public_key(key->ecdsa);
+            old_ecdsa = EVP_PKEY_get0_EC_KEY(key->key);
+            if (old_ecdsa == NULL) {
+                EC_KEY_free(new_ecdsa);
+                goto fail;
+            }
+
+            p = EC_KEY_get0_public_key(old_ecdsa);
             if (p == NULL) {
+                EC_KEY_free(new_ecdsa);
+                goto fail;
+            }
+
+            ok = EC_KEY_set_public_key(new_ecdsa, p);
+            if (ok != 1) {
+                EC_KEY_free(new_ecdsa);
                 goto fail;
             }
 
-            ok = EC_KEY_set_public_key(new->ecdsa, p);
-            if (!ok) {
+            new->key = EVP_PKEY_new();
+            if (new->key == NULL) {
+                EC_KEY_free(new_ecdsa);
+                goto fail;
+            }
+
+            ok = EVP_PKEY_assign_EC_KEY(new->key, new_ecdsa);
+            if (ok != 1) {
+                EC_KEY_free(new_ecdsa);
                 goto fail;
             }
         } else {
-            rc = EC_KEY_up_ref(key->ecdsa);
+            rc = EVP_PKEY_up_ref(key->key);
             if (rc != 1) {
                 goto fail;
             }
-            new->ecdsa = key->ecdsa;
+            new->key = key->key;
         }
 #else
         rc = evp_dup_ecdsa_pkey(key, new, demote);
@@ -736,7 +760,8 @@ fail:
 int pki_key_generate_rsa(ssh_key key, int parameter){
 	int rc;
 #if OPENSSL_VERSION_NUMBER < 0x30000000L
-    BIGNUM *e;
+    BIGNUM *e = NULL;
+    RSA *key_rsa = NULL;
 #else
     OSSL_PARAM params[3];
     EVP_PKEY_CTX *pctx = EVP_PKEY_CTX_new_from_name(NULL, "RSA", NULL);
@@ -745,15 +770,34 @@ int pki_key_generate_rsa(ssh_key key, int parameter){
 
 #if OPENSSL_VERSION_NUMBER < 0x30000000L
     e = BN_new();
-    key->rsa = RSA_new();
+    key_rsa = RSA_new();
+    if (key_rsa == NULL) {
+        return SSH_ERROR;
+    }
 
     BN_set_word(e, 65537);
-    rc = RSA_generate_key_ex(key->rsa, parameter, e, NULL);
+    rc = RSA_generate_key_ex(key_rsa, parameter, e, NULL);
 
     BN_free(e);
 
-    if (rc <= 0 || key->rsa == NULL)
+    if (rc <= 0 || key_rsa == NULL) {
+        return SSH_ERROR;
+    }
+
+    key->key = EVP_PKEY_new();
+    if (key->key == NULL) {
+        RSA_free(key_rsa);
+        return SSH_ERROR;
+    }
+
+    rc = EVP_PKEY_assign_RSA(key->key, key_rsa);
+    if (rc != 1) {
+        RSA_free(key_rsa);
+        EVP_PKEY_free(key->key);
         return SSH_ERROR;
+    }
+
+    key_rsa = NULL;
 #else
     key->key = NULL;
 
@@ -785,11 +829,11 @@ int pki_key_generate_rsa(ssh_key key, int parameter){
 int pki_key_generate_dss(ssh_key key, int parameter){
     int rc;
 #if OPENSSL_VERSION_NUMBER < 0x30000000L
-    key->dsa = DSA_new();
-    if (key->dsa == NULL) {
+    DSA *key_dsa = DSA_new();
+    if (key_dsa == NULL) {
         return SSH_ERROR;
     }
-    rc = DSA_generate_parameters_ex(key->dsa,
+    rc = DSA_generate_parameters_ex(key_dsa,
                                     parameter,
                                     NULL,  /* seed */
                                     0,     /* seed_len */
@@ -797,16 +841,29 @@ int pki_key_generate_dss(ssh_key key, int parameter){
                                     NULL,  /* h_ret */
                                     NULL); /* cb */
     if (rc != 1) {
-        DSA_free(key->dsa);
-        key->dsa = NULL;
+        DSA_free(key_dsa);
         return SSH_ERROR;
     }
-    rc = DSA_generate_key(key->dsa);
+    rc = DSA_generate_key(key_dsa);
     if (rc != 1) {
-        DSA_free(key->dsa);
-        key->dsa=NULL;
+        DSA_free(key_dsa);
+        return SSH_ERROR;
+    }
+
+    key->key = EVP_PKEY_new();
+    if (key->key == NULL) {
+        DSA_free(key_dsa);
         return SSH_ERROR;
     }
+
+    rc = EVP_PKEY_assign_DSA(key->key, key_dsa);
+    if (rc != 1) {
+        DSA_free(key_dsa);
+        EVP_PKEY_free(key->key);
+        return SSH_ERROR;
+    }
+
+    key_dsa = NULL;
 #else
     OSSL_PARAM params[3];
     EVP_PKEY *param_key = NULL;
@@ -871,12 +928,10 @@ int pki_key_generate_dss(ssh_key key, int parameter){
 }
 
 #ifdef HAVE_OPENSSL_ECC
-int pki_key_generate_ecdsa(ssh_key key, int parameter) {
-/* TODO Change to new API when the OpenSSL will support export of uncompressed EC keys
- * https://github.com/openssl/openssl/pull/16624
- * #if OPENSSL_VERSION_NUMBER < 0x30000000L
- */
-#if 1
+int pki_key_generate_ecdsa(ssh_key key, int parameter)
+{
+#if OPENSSL_VERSION_NUMBER < 0x30000000L
+    EC_KEY *ecdsa = NULL;
     int ok;
 #else
     const char *group_name = NULL;
@@ -885,33 +940,21 @@ int pki_key_generate_ecdsa(ssh_key key, int parameter) {
         case 256:
             key->ecdsa_nid = NID_X9_62_prime256v1;
             key->type = SSH_KEYTYPE_ECDSA_P256;
-/* TODO Change to new API when the OpenSSL will support export of uncompressed EC keys
- * https://github.com/openssl/openssl/pull/16624
- * #if OPENSSL_VERSION_NUMBER >= 0x30000000L
- */
-#if 0
+#if OPENSSL_VERSION_NUMBER >= 0x30000000L
             group_name = NISTP256;
 #endif /* OPENSSL_VERSION_NUMBER */
             break;
         case 384:
             key->ecdsa_nid = NID_secp384r1;
             key->type = SSH_KEYTYPE_ECDSA_P384;
-/* TODO Change to new API when the OpenSSL will support export of uncompressed EC keys
- * https://github.com/openssl/openssl/pull/16624
- * #if OPENSSL_VERSION_NUMBER >= 0x30000000L
- */
-#if 0
+#if OPENSSL_VERSION_NUMBER >= 0x30000000L
             group_name = NISTP384;
 #endif /* OPENSSL_VERSION_NUMBER */
             break;
         case 521:
             key->ecdsa_nid = NID_secp521r1;
             key->type = SSH_KEYTYPE_ECDSA_P521;
-/* TODO Change to new API when the OpenSSL will support export of uncompressed EC keys
- * https://github.com/openssl/openssl/pull/16624
- * #if OPENSSL_VERSION_NUMBER >= 0x30000000L
- */
-#if 0
+#if OPENSSL_VERSION_NUMBER >= 0x30000000L
             group_name = NISTP521;
 #endif /* OPENSSL_VERSION_NUMBER */
             break;
@@ -920,35 +963,37 @@ int pki_key_generate_ecdsa(ssh_key key, int parameter) {
                     "generation", parameter);
             return SSH_ERROR;
     }
-/* TODO Change to new API when the OpenSSL will support export of uncompressed EC keys
- * https://github.com/openssl/openssl/pull/16624
- * #if OPENSSL_VERSION_NUMBER < 0x30000000L
- */
-#if 1
-    key->ecdsa = EC_KEY_new_by_curve_name(key->ecdsa_nid);
-    if (key->ecdsa == NULL) {
+#if OPENSSL_VERSION_NUMBER < 0x30000000L
+    ecdsa = EC_KEY_new_by_curve_name(key->ecdsa_nid);
+    if (ecdsa == NULL) {
         return SSH_ERROR;
     }
-#else
-    key->key = EVP_EC_gen(group_name);
+    ok = EC_KEY_generate_key(ecdsa);
+    if (!ok) {
+        EC_KEY_free(ecdsa);
+        return SSH_ERROR;
+    }
+
+    EC_KEY_set_asn1_flag(ecdsa, OPENSSL_EC_NAMED_CURVE);
+
+    key->key = EVP_PKEY_new();
     if (key->key == NULL) {
+        EC_KEY_free(ecdsa);
         return SSH_ERROR;
     }
-#endif /* OPENSSL_VERSION_NUMBER */
 
-/* TODO Change to new API when the OpenSSL will support export of uncompressed EC keys
- * https://github.com/openssl/openssl/pull/16624
- * #if OPENSSL_VERSION_NUMBER < 0x30000000L
- */
-#if 1
-    ok = EC_KEY_generate_key(key->ecdsa);
-    if (!ok) {
-        EC_KEY_free(key->ecdsa);
+    ok = EVP_PKEY_assign_EC_KEY(key->key, ecdsa);
+    if (ok != 1) {
         return SSH_ERROR;
     }
 
-    EC_KEY_set_asn1_flag(key->ecdsa, OPENSSL_EC_NAMED_CURVE);
+#else
+    key->key = EVP_EC_gen(group_name);
+    if (key->key == NULL) {
+        return SSH_ERROR;
+    }
 #endif /* OPENSSL_VERSION_NUMBER */
+
     return SSH_OK;
 }
 #endif /* HAVE_OPENSSL_ECC */
@@ -960,104 +1005,34 @@ int pki_key_compare(const ssh_key k1,
                     const ssh_key k2,
                     enum ssh_keycmp_e what)
 {
-#if OPENSSL_VERSION_NUMBER >= 0x30000000L
     int rc;
     (void) what;
-#endif /* OPENSSL_VERSION_NUMBER */
 
     switch (k1->type) {
-        case SSH_KEYTYPE_DSS:
-#if OPENSSL_VERSION_NUMBER < 0x30000000L
-            {
-                const BIGNUM *p1, *p2, *q1, *q2, *g1, *g2,
-                    *pub_key1, *pub_key2, *priv_key1, *priv_key2;
-                if (DSA_size(k1->dsa) != DSA_size(k2->dsa)) {
-                    return 1;
-                }
-                DSA_get0_pqg(k1->dsa, &p1, &q1, &g1);
-                DSA_get0_pqg(k2->dsa, &p2, &q2, &g2);
-                if (bignum_cmp(p1, p2) != 0) {
-                    return 1;
-                }
-                if (bignum_cmp(q1, q2) != 0) {
-                    return 1;
-                }
-                if (bignum_cmp(g1, g2) != 0) {
-                    return 1;
-                }
-                DSA_get0_key(k1->dsa, &pub_key1, &priv_key1);
-                DSA_get0_key(k2->dsa, &pub_key2, &priv_key2);
-                if (bignum_cmp(pub_key1, pub_key2) != 0) {
-                    return 1;
-                }
-
-                if (what == SSH_KEY_CMP_PRIVATE) {
-                    if (bignum_cmp(priv_key1, priv_key2) != 0) {
-                        return 1;
-                    }
-                }
-                break;
-            }
-#endif /* OPENSSL_VERSION_NUMBER */
-        case SSH_KEYTYPE_RSA:
-        case SSH_KEYTYPE_RSA1:
-#if OPENSSL_VERSION_NUMBER < 0x30000000L
-            {
-                const BIGNUM *e1, *e2, *n1, *n2, *p1, *p2, *q1, *q2;
-                if (RSA_size(k1->rsa) != RSA_size(k2->rsa)) {
-                    return 1;
-                }
-                RSA_get0_key(k1->rsa, &n1, &e1, NULL);
-                RSA_get0_key(k2->rsa, &n2, &e2, NULL);
-                if (bignum_cmp(e1, e2) != 0) {
-                    return 1;
-                }
-                if (bignum_cmp(n1, n2) != 0) {
-                    return 1;
-                }
-
-                if (what == SSH_KEY_CMP_PRIVATE) {
-                    RSA_get0_factors(k1->rsa, &p1, &q1);
-                    RSA_get0_factors(k2->rsa, &p2, &q2);
-                    if (bignum_cmp(p1, p2) != 0) {
-                        return 1;
-                    }
-
-                    if (bignum_cmp(q1, q2) != 0) {
-                        return 1;
-                    }
-                }
-                break;
-            }
-#endif /* OPENSSL_VERSION_NUMBER */
-/* TODO Change to new API when the OpenSSL will support export of uncompressed EC keys
- * https://github.com/openssl/openssl/pull/16624
- * delete this part of #if because it gets done below EC
- */
-#if OPENSSL_VERSION_NUMBER >= 0x30000000L
-            rc = EVP_PKEY_eq(k1->key, k2->key);
-            if (rc != 1) {
-                return 1;
-            }
-            break;
-#endif /* OPENSSL_VERSION_NUMBER */
         case SSH_KEYTYPE_ECDSA_P256:
         case SSH_KEYTYPE_ECDSA_P384:
         case SSH_KEYTYPE_ECDSA_P521:
         case SSH_KEYTYPE_SK_ECDSA:
-/* TODO Change to new API when the OpenSSL will support export of uncompressed EC keys
- * https://github.com/openssl/openssl/pull/16624
- * #if OPENSSL_VERSION_NUMBER < 0x30000000L
- */
-#if 1
+#if OPENSSL_VERSION_NUMBER < 0x30000000L
 #ifdef HAVE_OPENSSL_ECC
             {
-                const EC_POINT *p1 = EC_KEY_get0_public_key(k1->ecdsa);
-                const EC_POINT *p2 = EC_KEY_get0_public_key(k2->ecdsa);
-                const EC_GROUP *g1 = EC_KEY_get0_group(k1->ecdsa);
-                const EC_GROUP *g2 = EC_KEY_get0_group(k2->ecdsa);
+                const EC_KEY *ec1 = EVP_PKEY_get0_EC_KEY(k1->key);
+                const EC_KEY *ec2 = EVP_PKEY_get0_EC_KEY(k2->key);
+                const EC_POINT *p1 = NULL;
+                const EC_POINT *p2 = NULL;
+                const EC_GROUP *g1 = NULL;
+                const EC_GROUP *g2 = NULL;
+
+                if (ec1 == NULL || ec2 == NULL) {
+                    return 1;
+                }
+
+                p1 = EC_KEY_get0_public_key(ec1);
+                p2 = EC_KEY_get0_public_key(ec2);
+                g1 = EC_KEY_get0_group(ec1);
+                g2 = EC_KEY_get0_group(ec2);
 
-                if (p1 == NULL || p2 == NULL) {
+                if (p1 == NULL || p2 == NULL || g1 == NULL || g2 == NULL) {
                     return 1;
                 }
 
@@ -1070,8 +1045,8 @@ int pki_key_compare(const ssh_key k1,
                 }
 
                 if (what == SSH_KEY_CMP_PRIVATE) {
-                    if (bignum_cmp(EC_KEY_get0_private_key(k1->ecdsa),
-                                   EC_KEY_get0_private_key(k2->ecdsa))) {
+                    if (bignum_cmp(EC_KEY_get0_private_key(ec1),
+                                   EC_KEY_get0_private_key(ec2))) {
                         return 1;
                     }
                 }
@@ -1079,17 +1054,14 @@ int pki_key_compare(const ssh_key k1,
             }
 #endif /* HAVE_OPENSSL_ECC */
 #endif /* OPENSSL_VERSION_NUMBER */
-/* TODO Change to new API when the OpenSSL will support export of uncompressed EC keys
- * https://github.com/openssl/openssl/pull/16624
- * else
- */
-#if 0
+        case SSH_KEYTYPE_DSS:
+        case SSH_KEYTYPE_RSA:
+        case SSH_KEYTYPE_RSA1:
             rc = EVP_PKEY_eq(k1->key, k2->key);
             if (rc != 1) {
                 return 1;
             }
             break;
-#endif /* OPENSSL_VERSION_NUMBER */
         case SSH_KEYTYPE_ED25519:
         case SSH_KEYTYPE_SK_ED25519:
             /* ed25519 keys handled globally */
@@ -1118,65 +1090,11 @@ ssh_string pki_private_key_to_pem(const ssh_key key,
 
     switch (key->type) {
         case SSH_KEYTYPE_DSS:
-#if OPENSSL_VERSION_NUMBER < 0x30000000L
-            pkey = EVP_PKEY_new();
-            if (pkey == NULL) {
-                goto err;
-            }
-
-            rc = EVP_PKEY_set1_DSA(pkey, key->dsa);
-            break;
-#endif /* OPENSSL_VERSION_NUMBER */
         case SSH_KEYTYPE_RSA:
         case SSH_KEYTYPE_RSA1:
-#if OPENSSL_VERSION_NUMBER < 0x30000000L
-            pkey = EVP_PKEY_new();
-            if (pkey == NULL) {
-                goto err;
-            }
-
-            rc = EVP_PKEY_set1_RSA(pkey, key->rsa);
-            break;
-#endif /* OPENSSL_VERSION_NUMBER */
-/* TODO Change to new API when the OpenSSL will support export of uncompressed EC keys
- * https://github.com/openssl/openssl/pull/16624
- * Delete this part, because it is done below HAVE_ECC
- */
-#if OPENSSL_VERSION_NUMBER >= 0x30000000L
-            rc = EVP_PKEY_up_ref(key->key);
-            if (rc != 1) {
-                goto err;
-            }
-            pkey = key->key;
-
-            /* Mark the operation as successful as for the other key types */
-            rc = 1;
-
-            break;
-#endif /* OPENSSL_VERSION_NUMBER */
-        case SSH_KEYTYPE_ECDSA_P256:
-        case SSH_KEYTYPE_ECDSA_P384:
-        case SSH_KEYTYPE_ECDSA_P521:
-#ifdef HAVE_ECC
-/* TODO Change to new API when the OpenSSL will support export of uncompressed EC keys
- * https://github.com/openssl/openssl/pull/16624
- * #if OPENSSL_VERSION_NUMBER < 0x30000000L
- */
-#if 1
-            pkey = EVP_PKEY_new();
-            if (pkey == NULL) {
-                goto err;
-            }
-
-            rc = EVP_PKEY_set1_EC_KEY(pkey, key->ecdsa);
-            break;
-#endif /* OPENSSL_VERSION_NUMBER */
-#endif /* HAVE_ECC */
-/* TODO Change to new API when the OpenSSL will support export of uncompressed EC keys
- * https://github.com/openssl/openssl/pull/16624
- * #if OPENSSL_VERSION_NUMBER >= 0x30000000L
- */
-#if 0
+        case SSH_KEYTYPE_ECDSA_P256:
+        case SSH_KEYTYPE_ECDSA_P384:
+        case SSH_KEYTYPE_ECDSA_P521:
             rc = EVP_PKEY_up_ref(key->key);
             if (rc != 1) {
                 goto err;
@@ -1187,7 +1105,6 @@ ssh_string pki_private_key_to_pem(const ssh_key key,
             rc = 1;
 
             break;
-#endif /* OPENSSL_VERSION_NUMBER */
         case SSH_KEYTYPE_ED25519:
 #ifdef HAVE_OPENSSL_ED25519
             /* In OpenSSL, the input is the private key seed only, which means
@@ -1282,14 +1199,8 @@ ssh_key pki_private_key_from_base64(const char *b64_key,
 {
     BIO *mem = NULL;
 #if OPENSSL_VERSION_NUMBER < 0x30000000L
-    DSA *dsa = NULL;
-    RSA *rsa = NULL;
-#endif /* OPENSSL_VERSION_NUMBER */
-#ifdef HAVE_OPENSSL_ECC
     EC_KEY *ecdsa = NULL;
-#else
-    void *ecdsa = NULL;
-#endif /* HAVE_OPENSSL_ECC */
+#endif /* OPENSSL_VERSION_NUMBER */
 #ifdef HAVE_OPENSSL_ED25519
     uint8_t *ed25519 = NULL;
 #else
@@ -1324,37 +1235,15 @@ ssh_key pki_private_key_from_base64(const char *b64_key,
     }
     switch (EVP_PKEY_base_id(pkey)) {
     case EVP_PKEY_DSA:
-#if OPENSSL_VERSION_NUMBER < 0x30000000L
-        dsa = EVP_PKEY_get1_DSA(pkey);
-        if (dsa == NULL) {
-            SSH_LOG(SSH_LOG_WARN,
-                    "Parsing private key: %s",
-                    ERR_error_string(ERR_get_error(),NULL));
-            goto fail;
-        }
-#endif
         type = SSH_KEYTYPE_DSS;
         break;
     case EVP_PKEY_RSA:
-#if OPENSSL_VERSION_NUMBER < 0x30000000L
-        rsa = EVP_PKEY_get1_RSA(pkey);
-        if (rsa == NULL) {
-            SSH_LOG(SSH_LOG_WARN,
-                    "Parsing private key: %s",
-                    ERR_error_string(ERR_get_error(),NULL));
-            goto fail;
-        }
-#endif /* OPENSSL_VERSION_NUMBER */
         type = SSH_KEYTYPE_RSA;
         break;
     case EVP_PKEY_EC:
 #ifdef HAVE_OPENSSL_ECC
-/* TODO Change to new API when the OpenSSL will support export of uncompressed EC keys
- * https://github.com/openssl/openssl/pull/16624
- * #if OPENSSL_VERSION_NUMBER < 0x30000000L
- */
-#if 1
-        ecdsa = EVP_PKEY_get1_EC_KEY(pkey);
+#if OPENSSL_VERSION_NUMBER < 0x30000000L
+        ecdsa = EVP_PKEY_get0_EC_KEY(pkey);
         if (ecdsa == NULL) {
             SSH_LOG(SSH_LOG_WARN,
                     "Parsing private key: %s",
@@ -1365,11 +1254,7 @@ ssh_key pki_private_key_from_base64(const char *b64_key,
 
         /* pki_privatekey_type_from_string always returns P256 for ECDSA
          * keys, so we need to figure out the correct type here */
-/* TODO Change to new API when the OpenSSL will support export of uncompressed EC keys
- * https://github.com/openssl/openssl/pull/16624
- * #if OPENSSL_VERSION_NUMBER < 0x30000000L
- */
-#if 1
+#if OPENSSL_VERSION_NUMBER < 0x30000000L
         type = pki_key_ecdsa_to_key_type(ecdsa);
 #else
         type = pki_key_ecdsa_to_key_type(pkey);
@@ -1379,10 +1264,6 @@ ssh_key pki_private_key_from_base64(const char *b64_key,
             goto fail;
         }
 
-/* TODO Change to new API when the OpenSSL will support export of uncompressed EC keys
- * https://github.com/openssl/openssl/pull/16624
- * Remove these three lines
- */
         break;
 #endif /* HAVE_OPENSSL_ECC */
 #ifdef HAVE_OPENSSL_ED25519
@@ -1438,25 +1319,12 @@ ssh_key pki_private_key_from_base64(const char *b64_key,
     key->type = type;
     key->type_c = ssh_key_type_to_char(type);
     key->flags = SSH_KEY_FLAG_PRIVATE | SSH_KEY_FLAG_PUBLIC;
-#if OPENSSL_VERSION_NUMBER < 0x30000000L
-    key->dsa = dsa;
-    key->rsa = rsa;
-#endif /* OPENSSL_VERSION_NUMBER */
     key->key = pkey;
-/* TODO Change to new API when the OpenSSL will support export of uncompressed EC keys
- * https://github.com/openssl/openssl/pull/16624
- * Move key->ecdsa line into the #if above this
- */
-    key->ecdsa = ecdsa;
     key->ed25519_privkey = ed25519;
 #ifdef HAVE_OPENSSL_ECC
     if (is_ecdsa_key_type(key->type)) {
-/* TODO Change to new API when the OpenSSL will support export of uncompressed EC keys
- * https://github.com/openssl/openssl/pull/16624
- * #if OPENSSL_VERSION_NUMBER < 0x30000000L
- */
-#if 1
-        key->ecdsa_nid = pki_key_ecdsa_to_nid(key->ecdsa);
+#if OPENSSL_VERSION_NUMBER < 0x30000000L
+        key->ecdsa_nid = pki_key_ecdsa_to_nid(ecdsa);
 #else
         key->ecdsa_nid = pki_key_ecdsa_to_nid(key->key);
 #endif /* OPENSSL_VERSION_NUMBER */
@@ -1467,17 +1335,6 @@ ssh_key pki_private_key_from_base64(const char *b64_key,
 fail:
     EVP_PKEY_free(pkey);
     ssh_key_free(key);
-#if OPENSSL_VERSION_NUMBER < 0x30000000L
-    DSA_free(dsa);
-    RSA_free(rsa);
-#endif /* OPENSSL_VERSION_NUMBER */
-/* TODO Change to new API when the OpenSSL will support export of uncompressed EC keys
- * https://github.com/openssl/openssl/pull/16624
- * Move HAVE_OPENSSL_ECC #ifdef inside the #if above
- */
-#ifdef HAVE_OPENSSL_ECC
-    EC_KEY_free(ecdsa);
-#endif
 #ifdef HAVE_OPENSSL_ED25519
     SAFE_FREE(ed25519);
 #endif
@@ -1499,8 +1356,8 @@ int pki_privkey_build_dss(ssh_key key,
         return SSH_ERROR;
     }
 #else
-    key->dsa = DSA_new();
-    if (key->dsa == NULL) {
+    DSA *key_dsa = DSA_new();
+    if (key_dsa == NULL) {
         return SSH_ERROR;
     }
 #endif /* OPENSSL_VERSION_NUMBER */
@@ -1518,20 +1375,31 @@ int pki_privkey_build_dss(ssh_key key,
 
 #if OPENSSL_VERSION_NUMBER < 0x30000000L
     /* Memory management of bp, qq and bg is transferred to DSA object */
-    rc = DSA_set0_pqg(key->dsa, bp, bq, bg);
+    rc = DSA_set0_pqg(key_dsa, bp, bq, bg);
     if (rc == 0) {
         goto fail;
     }
 
     /* Memory management of bpub_key and bpriv_key is transferred to DSA object */
-    rc = DSA_set0_key(key->dsa, bpub_key, bpriv_key);
+    rc = DSA_set0_key(key_dsa, bpub_key, bpriv_key);
     if (rc == 0) {
         goto fail;
     }
 
+    key->key = EVP_PKEY_new();
+    if (key->key == NULL) {
+        goto fail;
+    }
+
+    rc = EVP_PKEY_assign_DSA(key->key, key_dsa);
+    if (rc != 1) {
+        goto fail;
+    }
+
     return SSH_OK;
 fail:
-    DSA_free(key->dsa);
+    EVP_PKEY_free(key->key);
+    DSA_free(key_dsa);
     return SSH_ERROR;
 #else
     rc = OSSL_PARAM_BLD_push_BN(param_bld, OSSL_PKEY_PARAM_FFC_P, bp);
@@ -1587,8 +1455,8 @@ int pki_pubkey_build_dss(ssh_key key,
         return SSH_ERROR;
     }
 #else
-    key->dsa = DSA_new();
-    if (key->dsa == NULL) {
+    DSA *key_dsa = DSA_new();
+    if (key_dsa == NULL) {
         return SSH_ERROR;
     }
 #endif /* OPENSSL_VERSION_NUMBER */
@@ -1605,20 +1473,31 @@ int pki_pubkey_build_dss(ssh_key key,
 
 #if OPENSSL_VERSION_NUMBER < 0x30000000L
     /* Memory management of bp, bq and bg is transferred to DSA object */
-    rc = DSA_set0_pqg(key->dsa, bp, bq, bg);
+    rc = DSA_set0_pqg(key_dsa, bp, bq, bg);
     if (rc == 0) {
         goto fail;
     }
 
     /* Memory management of npub_key is transferred to DSA object */
-    rc = DSA_set0_key(key->dsa, bpub_key, NULL);
+    rc = DSA_set0_key(key_dsa, bpub_key, NULL);
     if (rc == 0) {
         goto fail;
     }
 
+    key->key = EVP_PKEY_new();
+    if (key->key == NULL) {
+        goto fail;
+    }
+
+    rc = EVP_PKEY_assign_DSA(key->key, key_dsa);
+    if (rc != 1) {
+        goto fail;
+    }
+
     return SSH_OK;
 fail:
-    DSA_free(key->dsa);
+    EVP_PKEY_free(key->key);
+    DSA_free(key_dsa);
     return SSH_ERROR;
 #else
     rc = OSSL_PARAM_BLD_push_BN(param_bld, OSSL_PKEY_PARAM_FFC_P, bp);
@@ -1659,20 +1538,25 @@ int pki_privkey_build_rsa(ssh_key key,
                           ssh_string n,
                           ssh_string e,
                           ssh_string d,
-                          UNUSED_PARAM(ssh_string iqmp),
+                          ssh_string iqmp,
                           ssh_string p,
                           ssh_string q)
 {
     int rc;
-    BIGNUM *be, *bn, *bd/*, *biqmp*/, *bp, *bq;
+    BIGNUM *be = NULL, *bn = NULL, *bd = NULL;
+    BIGNUM *biqmp = NULL, *bp = NULL, *bq = NULL;
+    BIGNUM *aux = NULL, *d_consttime = NULL;
+    BIGNUM *bdmq1 = NULL, *bdmp1 = NULL;
+    BN_CTX *ctx = NULL;
+
 #if OPENSSL_VERSION_NUMBER >= 0x30000000L
     OSSL_PARAM_BLD *param_bld = OSSL_PARAM_BLD_new();
     if (param_bld == NULL) {
         return SSH_ERROR;
     }
 #else
-    key->rsa = RSA_new();
-    if (key->rsa == NULL) {
+    RSA *key_rsa = RSA_new();
+    if (key_rsa == NULL) {
         return SSH_ERROR;
     }
 #endif /* OPENSSL_VERSION_NUMBER */
@@ -1680,7 +1564,7 @@ int pki_privkey_build_rsa(ssh_key key,
     bn = ssh_make_string_bn(n);
     be = ssh_make_string_bn(e);
     bd = ssh_make_string_bn(d);
-    /*biqmp = ssh_make_string_bn(iqmp);*/
+    biqmp = ssh_make_string_bn(iqmp);
     bp = ssh_make_string_bn(p);
     bq = ssh_make_string_bn(q);
     if (be == NULL || bn == NULL || bd == NULL ||
@@ -1689,15 +1573,42 @@ int pki_privkey_build_rsa(ssh_key key,
         goto fail;
     }
 
+    /* Calculate remaining CRT parameters for OpenSSL to be happy
+     * taken from OpenSSH */
+    if ((ctx = BN_CTX_new()) == NULL) {
+        rc = SSH_ERROR;
+        goto fail;
+    }
+    if ((aux = BN_new()) == NULL ||
+        (bdmq1 = BN_new()) == NULL ||
+        (bdmp1 = BN_new()) == NULL) {
+        rc = SSH_ERROR;
+        goto fail;
+    }
+    if ((d_consttime = BN_dup(bd)) == NULL) {
+        rc = SSH_ERROR;
+        goto fail;
+    }
+    BN_set_flags(aux, BN_FLG_CONSTTIME);
+    BN_set_flags(d_consttime, BN_FLG_CONSTTIME);
+
+    if ((BN_sub(aux, bq, BN_value_one()) == 0) ||
+        (BN_mod(bdmq1, d_consttime, aux, ctx) == 0) ||
+        (BN_sub(aux, bp, BN_value_one()) == 0) ||
+        (BN_mod(bdmp1, d_consttime, aux, ctx) == 0)) {
+        rc = SSH_ERROR;
+        goto fail;
+    }
+
 #if OPENSSL_VERSION_NUMBER < 0x30000000L
     /* Memory management of be, bn and bd is transferred to RSA object */
-    rc = RSA_set0_key(key->rsa, bn, be, bd);
+    rc = RSA_set0_key(key_rsa, bn, be, bd);
     if (rc == 0) {
         goto fail;
     }
 
     /* Memory management of bp and bq is transferred to RSA object */
-    rc = RSA_set0_factors(key->rsa, bp, bq);
+    rc = RSA_set0_factors(key_rsa, bp, bq);
     if (rc == 0) {
         goto fail;
     }
@@ -1705,13 +1616,30 @@ int pki_privkey_build_rsa(ssh_key key,
     /* p, q, dmp1, dmq1 and iqmp may be NULL in private keys, but the RSA
      * operations are much faster when these values are available.
      * https://www.openssl.org/docs/man1.0.2/crypto/rsa.html
+     * And OpenSSL fails to export these keys to PEM if these are missing:
+     * https://github.com/openssl/openssl/issues/21826
      */
-    /* RSA_set0_crt_params(key->rsa, biqmp, NULL, NULL);
-    TODO calculate missing crt_params */
+    rc = RSA_set0_crt_params(key_rsa, bdmp1, bdmq1, biqmp);
+    if (rc == 0) {
+        goto fail;
+    }
+    bignum_safe_free(aux);
+    bignum_safe_free(d_consttime);
+
+    key->key = EVP_PKEY_new();
+    if (key->key == NULL) {
+        goto fail;
+    }
+
+    rc = EVP_PKEY_assign_RSA(key->key, key_rsa);
+    if (rc != 1) {
+        goto fail;
+    }
 
     return SSH_OK;
 fail:
-    RSA_free(key->rsa);
+    RSA_free(key_rsa);
+    EVP_PKEY_free(key->key);
     return SSH_ERROR;
 #else
     rc = OSSL_PARAM_BLD_push_BN(param_bld, OSSL_PKEY_PARAM_RSA_N, bn);
@@ -1730,6 +1658,36 @@ fail:
         goto fail;
     }
 
+    rc = OSSL_PARAM_BLD_push_BN(param_bld, OSSL_PKEY_PARAM_RSA_FACTOR1, bp);
+    if (rc != 1) {
+        rc = SSH_ERROR;
+        goto fail;
+    }
+
+    rc = OSSL_PARAM_BLD_push_BN(param_bld, OSSL_PKEY_PARAM_RSA_FACTOR2, bq);
+    if (rc != 1) {
+        rc = SSH_ERROR;
+        goto fail;
+    }
+
+    rc = OSSL_PARAM_BLD_push_BN(param_bld, OSSL_PKEY_PARAM_RSA_EXPONENT1, bdmp1);
+    if (rc != 1) {
+        rc = SSH_ERROR;
+        goto fail;
+    }
+
+    rc = OSSL_PARAM_BLD_push_BN(param_bld, OSSL_PKEY_PARAM_RSA_EXPONENT2, bdmq1);
+    if (rc != 1) {
+        rc = SSH_ERROR;
+        goto fail;
+    }
+
+    rc = OSSL_PARAM_BLD_push_BN(param_bld, OSSL_PKEY_PARAM_RSA_COEFFICIENT1, biqmp);
+    if (rc != 1) {
+        rc = SSH_ERROR;
+        goto fail;
+    }
+
     rc = evp_build_pkey("RSA", param_bld, &(key->key), EVP_PKEY_KEYPAIR);
     if (rc != SSH_OK) {
         rc = SSH_ERROR;
@@ -1755,7 +1713,13 @@ fail:
     bignum_safe_free(bd);
     bignum_safe_free(bp);
     bignum_safe_free(bq);
+    bignum_safe_free(biqmp);
 
+    bignum_safe_free(aux);
+    bignum_safe_free(d_consttime);
+    bignum_safe_free(bdmp1);
+    bignum_safe_free(bdmq1);
+    BN_CTX_free(ctx);
     return rc;
 #endif /* OPENSSL_VERSION_NUMBER */
 }
@@ -1771,8 +1735,8 @@ int pki_pubkey_build_rsa(ssh_key key,
         return SSH_ERROR;
     }
 #else
-    key->rsa = RSA_new();
-    if (key->rsa == NULL) {
+    RSA *key_rsa = RSA_new();
+    if (key_rsa == NULL) {
         return SSH_ERROR;
     }
 #endif /* OPENSSL_VERSION_NUMBER */
@@ -1786,14 +1750,25 @@ int pki_pubkey_build_rsa(ssh_key key,
 
 #if OPENSSL_VERSION_NUMBER < 0x30000000L
     /* Memory management of bn and be is transferred to RSA object */
-    rc = RSA_set0_key(key->rsa, bn, be, NULL);
+    rc = RSA_set0_key(key_rsa, bn, be, NULL);
     if (rc == 0) {
         goto fail;
     }
 
+    key->key = EVP_PKEY_new();
+    if (key->key == NULL) {
+        goto fail;
+    }
+
+    rc = EVP_PKEY_assign_RSA(key->key, key_rsa);
+    if (rc != 1) {
+        goto fail;
+    }
+
     return SSH_OK;
 fail:
-    RSA_free(key->rsa);
+    EVP_PKEY_free(key->key);
+    RSA_free(key_rsa);
     return SSH_ERROR;
 #else
     rc = OSSL_PARAM_BLD_push_BN(param_bld, OSSL_PKEY_PARAM_RSA_N, bn);
@@ -1866,8 +1841,9 @@ ssh_string pki_publickey_to_blob(const ssh_key key)
         case SSH_KEYTYPE_DSS: {
 #if OPENSSL_VERSION_NUMBER < 0x30000000L
             const BIGNUM *bp, *bq, *bg, *bpub_key;
-            DSA_get0_pqg(key->dsa, &bp, &bq, &bg);
-            DSA_get0_key(key->dsa, &bpub_key, NULL);
+            const DSA *key_dsa = EVP_PKEY_get0_DSA(key->key);
+            DSA_get0_pqg(key_dsa, &bp, &bq, &bg);
+            DSA_get0_key(key_dsa, &bpub_key, NULL);
 #else
             const OSSL_PARAM *out_param = NULL;
             rc = EVP_PKEY_todata(key->key, EVP_PKEY_PUBLIC_KEY, &params);
@@ -1970,7 +1946,8 @@ ssh_string pki_publickey_to_blob(const ssh_key key)
         case SSH_KEYTYPE_RSA1: {
 #if OPENSSL_VERSION_NUMBER < 0x30000000L
             const BIGNUM *be, *bn;
-            RSA_get0_key(key->rsa, &bn, &be, NULL);
+            const RSA *key_rsa = EVP_PKEY_get0_RSA(key->key);
+            RSA_get0_key(key_rsa, &bn, &be, NULL);
 #else
             const OSSL_PARAM *out_param = NULL;
             rc = EVP_PKEY_todata(key->key, EVP_PKEY_PUBLIC_KEY, &params);
@@ -2043,14 +2020,16 @@ ssh_string pki_publickey_to_blob(const ssh_key key)
         case SSH_KEYTYPE_SK_ECDSA:
 #ifdef HAVE_OPENSSL_ECC
             {
-/* TODO Change to new API when the OpenSSL will support export of uncompressed EC keys
- * https://github.com/openssl/openssl/pull/16624
- * #if OPENSSL_VERSION_NUMBER >= 0x30000000L
- */
-#if 0
+#if OPENSSL_VERSION_NUMBER >= 0x30000000L
+                EC_GROUP *group = NULL;
+                EC_POINT *point = NULL;
                 const void *pubkey;
                 size_t pubkey_len;
-                OSSL_PARAM *params = NULL, *locate_param = NULL;
+                OSSL_PARAM *locate_param = NULL;
+#else
+                const EC_GROUP *group = NULL;
+                const EC_POINT *point = NULL;
+                EC_KEY *ec = NULL;
 #endif /* OPENSSL_VERSION_NUMBER */
 
                 type_s = ssh_string_from_char(pki_key_ecdsa_nid_to_char(key->ecdsa_nid));
@@ -2066,25 +2045,29 @@ ssh_string pki_publickey_to_blob(const ssh_key key)
                     return NULL;
                 }
 
-/* TODO Change to new API when the OpenSSL will support export of uncompressed EC keys
- * https://github.com/openssl/openssl/pull/16624
- * #if OPENSSL_VERSION_NUMBER < 0x30000000L
- */
-#if 1
+#if OPENSSL_VERSION_NUMBER < 0x30000000L
+                ec = EVP_PKEY_get0_EC_KEY(key->key);
+                if (ec == NULL) {
+                    goto fail;
+                }
 #ifdef WITH_PKCS11_URI
-            if (ssh_key_is_private(key) && !EC_KEY_get0_public_key(key->ecdsa)) {
-                SSH_LOG(SSH_LOG_INFO, "It is mandatory to have separate public"
-                        " ECDSA key objects in the PKCS #11 device. Unlike RSA,"
-                        " ECDSA public keys cannot be derived from their private keys.");
-                goto fail;
-            }
+                if (ssh_key_is_private(key) && !EC_KEY_get0_public_key(ec)) {
+                    SSH_LOG(SSH_LOG_TRACE, "It is mandatory to have separate"
+                            " public ECDSA key objects in the PKCS #11 device."
+                            " Unlike RSA, ECDSA public keys cannot be derived"
+                            " from their private keys.");
+                    goto fail;
+                }
 #endif /* WITH_PKCS11_URI */
-                e = make_ecpoint_string(EC_KEY_get0_group(key->ecdsa),
-                                        EC_KEY_get0_public_key(key->ecdsa));
+                group = EC_KEY_get0_group(ec);
+                point = EC_KEY_get0_public_key(ec);
+                if (group == NULL || point == NULL) {
+                    goto fail;
+                }
+                e = pki_key_make_ecpoint_string(group, point);
 #else
                 rc = EVP_PKEY_todata(key->key, EVP_PKEY_PUBLIC_KEY, &params);
                 if (rc < 0) {
-                    OSSL_PARAM_free(params);
                     goto fail;
                 }
 
@@ -2101,47 +2084,36 @@ ssh_string pki_publickey_to_blob(const ssh_key key)
 
                 rc = OSSL_PARAM_get_octet_string_ptr(locate_param, &pubkey, &pubkey_len);
                 if (rc != 1) {
-                    OSSL_PARAM_free(params);
+                    goto fail;
+                }
+                /* Convert the data to low-level representation */
+                group = EC_GROUP_new_by_curve_name_ex(NULL, NULL, key->ecdsa_nid);
+                point = EC_POINT_new(group);
+                rc = EC_POINT_oct2point(group, point, pubkey, pubkey_len, NULL);
+                if (group == NULL || point == NULL || rc != 1) {
+                    EC_GROUP_free(group);
+                    EC_POINT_free(point);
                     goto fail;
                 }
 
-                e = ssh_string_new(pubkey_len);
+                e = pki_key_make_ecpoint_string(group, point);
+                EC_GROUP_free(group);
+                EC_POINT_free(point);
 #endif /* OPENSSL_VERSION_NUMBER */
                 if (e == NULL) {
                     SSH_BUFFER_FREE(buffer);
                     return NULL;
                 }
 
-/* TODO Change to new API when the OpenSSL will support export of uncompressed EC keys
- * https://github.com/openssl/openssl/pull/16624
- * #if OPENSSL_VERSION_NUMBER >= 0x30000000L
- */
-#if 0
-                if (memcpy(ssh_string_data(e), pubkey, pubkey_len) == NULL) {
-                    OSSL_PARAM_free(params);
-                    goto fail;
-                }
-#endif /* OPENSSL_VERSION_NUMBER */
                 rc = ssh_buffer_add_ssh_string(buffer, e);
                 if (rc < 0) {
-/* TODO Change to new API when the OpenSSL will support export of uncompressed EC keys
- * https://github.com/openssl/openssl/pull/16624
- * #if OPENSSL_VERSION_NUMBER >= 0x30000000L
- */
-#if 0
-                    OSSL_PARAM_free(params);
-#endif /* OPENSSL_VERSION_NUMBER */
                     goto fail;
                 }
 
                 ssh_string_burn(e);
                 SSH_STRING_FREE(e);
                 e = NULL;
-/* TODO Change to new API when the OpenSSL will support export of uncompressed EC keys
- * https://github.com/openssl/openssl/pull/16624
- * #if OPENSSL_VERSION_NUMBER >= 0x30000000L
- */
-#if 0
+#if OPENSSL_VERSION_NUMBER >= 0x30000000L
                 OSSL_PARAM_free(params);
 #endif /* OPENSSL_VERSION_NUMBER */
 
@@ -2415,12 +2387,14 @@ static int pki_signature_from_rsa_blob(const ssh_key pubkey,
     size_t len = ssh_string_len(sig_blob);
 
 #if OPENSSL_VERSION_NUMBER < 0x30000000L
-    if (pubkey->rsa == NULL) {
-        SSH_LOG(SSH_LOG_WARN, "Pubkey RSA field NULL");
+    const RSA *rsa = EVP_PKEY_get0_RSA(pubkey->key);
+
+    if (rsa == NULL) {
+        SSH_LOG(SSH_LOG_TRACE, "RSA field NULL");
         goto errout;
     }
 
-    rsalen = RSA_size(pubkey->rsa);
+    rsalen = RSA_size(rsa);
 #else
     if (EVP_PKEY_get_base_id(pubkey->key) != EVP_PKEY_RSA) {
         SSH_LOG(SSH_LOG_WARN, "Key has no RSA pubkey");
@@ -2851,60 +2825,14 @@ static const EVP_MD *pki_digest_to_md(enum ssh_digest_e hash_type)
 static EVP_PKEY *pki_key_to_pkey(ssh_key key)
 {
     EVP_PKEY *pkey = NULL;
-#if OPENSSL_VERSION_NUMBER >= 0x30000000L
     int rc = 0;
-#endif
 
     switch (key->type) {
     case SSH_KEYTYPE_DSS:
     case SSH_KEYTYPE_DSS_CERT01:
-#if OPENSSL_VERSION_NUMBER < 0x30000000L
-        if (key->dsa == NULL) {
-            SSH_LOG(SSH_LOG_TRACE, "NULL key->dsa");
-            goto error;
-        }
-        pkey = EVP_PKEY_new();
-        if (pkey == NULL) {
-            SSH_LOG(SSH_LOG_TRACE, "Out of memory");
-            return NULL;
-        }
-
-        EVP_PKEY_set1_DSA(pkey, key->dsa);
-        break;
-#endif /* OPENSSL_VERSION_NUMBER */
     case SSH_KEYTYPE_RSA:
     case SSH_KEYTYPE_RSA1:
     case SSH_KEYTYPE_RSA_CERT01:
-#if OPENSSL_VERSION_NUMBER < 0x30000000L
-        if (key->rsa == NULL) {
-            SSH_LOG(SSH_LOG_TRACE, "NULL key->rsa");
-            goto error;
-        }
-        pkey = EVP_PKEY_new();
-        if (pkey == NULL) {
-            SSH_LOG(SSH_LOG_TRACE, "Out of memory");
-            return NULL;
-        }
-
-        EVP_PKEY_set1_RSA(pkey, key->rsa);
-        break;
-/* TODO Change to new API when the OpenSSL will support export of uncompressed EC keys
- * https://github.com/openssl/openssl/pull/16624
- * Remove this #else part from here
- */
-#else
-        if (key->key == NULL) {
-            SSH_LOG(SSH_LOG_TRACE, "NULL key->key");
-            goto error;
-        }
-        rc = EVP_PKEY_up_ref(key->key);
-        if (rc != 1) {
-            SSH_LOG(SSH_LOG_TRACE, "Failed to reference EVP_PKEY");
-            return NULL;
-        }
-        pkey = key->key;
-        break;
-#endif /* OPENSSL_VERSION_NUMBER */
     case SSH_KEYTYPE_ECDSA_P256:
     case SSH_KEYTYPE_ECDSA_P384:
     case SSH_KEYTYPE_ECDSA_P521:
@@ -2913,43 +2841,17 @@ static EVP_PKEY *pki_key_to_pkey(ssh_key key)
     case SSH_KEYTYPE_ECDSA_P521_CERT01:
     case SSH_KEYTYPE_SK_ECDSA:
     case SSH_KEYTYPE_SK_ECDSA_CERT01:
-# if defined(HAVE_OPENSSL_ECC)
-/* TODO Change to new API when the OpenSSL will support export of uncompressed EC keys
- * https://github.com/openssl/openssl/pull/16624
- * #if OPENSSL_VERSION_NUMBER < 0x30000000L
- */
-#if 1
-        if (key->ecdsa == NULL) {
-            SSH_LOG(SSH_LOG_TRACE, "NULL key->ecdsa");
-            goto error;
-        }
-        pkey = EVP_PKEY_new();
-        if (pkey == NULL) {
-            SSH_LOG(SSH_LOG_TRACE, "Out of memory");
-            return NULL;
-        }
-
-        EVP_PKEY_set1_EC_KEY(pkey, key->ecdsa);
-        break;
-#endif /* OPENSSL_VERSION_NUMBER */
-# endif
-/* TODO Change to new API when the OpenSSL will support export of uncompressed EC keys
- * https://github.com/openssl/openssl/pull/16624
- * #if OPENSSL_VERSION_NUMBER >= 0x30000000L
- */
-#if 0
         if (key->key == NULL) {
             SSH_LOG(SSH_LOG_TRACE, "NULL key->key");
             goto error;
         }
-        rc = EVP_PKEY_uo_ref(key->key);
+        rc = EVP_PKEY_up_ref(key->key);
         if (rc != 1) {
             SSH_LOG(SSH_LOG_TRACE, "Failed to reference EVP_PKEY");
             return NULL;
         }
         pkey = key->key;
         break;
-#endif /* OPENSSL_VERSION_NUMBER */
     case SSH_KEYTYPE_ED25519:
     case SSH_KEYTYPE_ED25519_CERT01:
     case SSH_KEYTYPE_SK_ED25519:
@@ -3437,15 +3339,19 @@ ssh_signature pki_do_sign_hash(const ssh_key privkey,
 #endif /* HAVE_OPENSSL_ED25519 */
 
 #ifdef WITH_PKCS11_URI
+#ifdef WITH_PKCS11_PROVIDER
+static bool pkcs11_provider_failed = false;
+#endif
+
 /**
  * @internal
  *
- * @brief Populate the public/private ssh_key from the engine with
+ * @brief Populate the public/private ssh_key from the engine/provider with
  * PKCS#11 URIs as the look up.
  *
  * @param[in]   uri_name    The PKCS#11 URI
  * @param[in]   nkey        The ssh-key context for
- *                          the key loaded from the engine.
+ *                          the key loaded from the engine/provider.
  * @param[in]   key_type    The type of the key used. Public/Private.
  *
  * @return  SSH_OK if ssh-key is valid; SSH_ERROR otherwise.
@@ -3454,22 +3360,14 @@ int pki_uri_import(const char *uri_name,
                      ssh_key *nkey,
                      enum ssh_key_e key_type)
 {
-    ENGINE *engine = NULL;
     EVP_PKEY *pkey = NULL;
-#if OPENSSL_VERSION_NUMBER < 0x30000000L
-    RSA *rsa = NULL;
-#endif
-/* TODO Change to new API when the OpenSSL will support export of uncompressed EC keys
- * https://github.com/openssl/openssl/pull/16624
- * Move HAVE_OPENSSL_ECC #ifdef into #if above
- */
-#ifdef HAVE_OPENSSL_ECC
-    EC_KEY *ecdsa = NULL;
-#else
-    void *ecdsa = NULL;
-#endif
     ssh_key key = NULL;
     enum ssh_keytypes_e type = SSH_KEYTYPE_UNKNOWN;
+#if OPENSSL_VERSION_NUMBER < 0x30000000L && HAVE_OPENSSL_ECC
+    EC_KEY *ecdsa = NULL;
+#endif
+#ifndef WITH_PKCS11_PROVIDER
+    ENGINE *engine = NULL;
 
     /* Do the init only once */
     engine = pki_get_engine();
@@ -3484,7 +3382,7 @@ int pki_uri_import(const char *uri_name,
         if (pkey == NULL) {
             SSH_LOG(SSH_LOG_WARN,
                     "Could not load key: %s",
-                    ERR_error_string(ERR_get_error(),NULL));
+                    ERR_error_string(ERR_get_error(), NULL));
             goto fail;
         }
         break;
@@ -3493,7 +3391,7 @@ int pki_uri_import(const char *uri_name,
         if (pkey == NULL) {
             SSH_LOG(SSH_LOG_WARN,
                     "Could not load key: %s",
-                    ERR_error_string(ERR_get_error(),NULL));
+                    ERR_error_string(ERR_get_error(), NULL));
             goto fail;
         }
         break;
@@ -3502,6 +3400,72 @@ int pki_uri_import(const char *uri_name,
                 "Invalid key type: %d", key_type);
         goto fail;
     }
+#else /* WITH_PKCS11_PROVIDER */
+    OSSL_STORE_CTX *store = NULL;
+    OSSL_STORE_INFO *info = NULL;
+    int rv, expect_type = OSSL_STORE_INFO_PKEY;
+
+    /* The provider can be either configured in openssl.cnf or dynamically
+     * loaded, assuming it does not need any special configuration */
+    if (OSSL_PROVIDER_available(NULL, "pkcs11") == 0 &&
+        !pkcs11_provider_failed) {
+        OSSL_PROVIDER *pkcs11_provider = NULL;
+
+        pkcs11_provider = OSSL_PROVIDER_try_load(NULL, "pkcs11", 1);
+        if (pkcs11_provider == NULL) {
+            SSH_LOG(SSH_LOG_TRACE,
+                    "Failed to initialize provider: %s",
+                    ERR_error_string(ERR_get_error(), NULL));
+            /* Do not attempt to load it again */
+            pkcs11_provider_failed = true;
+            goto fail;
+        }
+    }
+
+    store = OSSL_STORE_open(uri_name, NULL, NULL, NULL, NULL);
+    if (store == NULL) {
+        SSH_LOG(SSH_LOG_TRACE,
+                "Failed to open OpenSSL store: %s",
+                ERR_error_string(ERR_get_error(), NULL));
+        goto fail;
+    }
+    if (key_type == SSH_KEY_PUBLIC) {
+        expect_type = OSSL_STORE_INFO_PUBKEY;
+    }
+    rv = OSSL_STORE_expect(store, expect_type);
+    if (rv != 1) {
+        SSH_LOG(SSH_LOG_TRACE,
+                "Failed to set the store preference. Ignoring the error: %s",
+                ERR_error_string(ERR_get_error(), NULL));
+    }
+
+    for (info = OSSL_STORE_load(store);
+         info != NULL;
+         info = OSSL_STORE_load(store)) {
+        int ossl_type = OSSL_STORE_INFO_get_type(info);
+
+        if (ossl_type == OSSL_STORE_INFO_PUBKEY && key_type == SSH_KEY_PUBLIC) {
+            pkey = OSSL_STORE_INFO_get1_PUBKEY(info);
+            break;
+        } else if (ossl_type == OSSL_STORE_INFO_PKEY &&
+                   key_type == SSH_KEY_PRIVATE) {
+            pkey = OSSL_STORE_INFO_get1_PKEY(info);
+            break;
+        } else {
+            SSH_LOG(SSH_LOG_TRACE,
+                    "Ignoring object not matching our type: %d",
+                    ossl_type);
+        }
+    }
+    OSSL_STORE_close(store);
+    if (pkey == NULL) {
+        SSH_LOG(SSH_LOG_TRACE,
+                "No key found in the pkcs11 store: %s",
+                ERR_error_string(ERR_get_error(), NULL));
+        goto fail;
+    }
+
+#endif /* WITH_PKCS11_PROVIDER */
 
     key = ssh_key_new();
     if (key == NULL) {
@@ -3510,25 +3474,12 @@ int pki_uri_import(const char *uri_name,
 
     switch (EVP_PKEY_base_id(pkey)) {
     case EVP_PKEY_RSA:
-#if OPENSSL_VERSION_NUMBER < 0x30000000L
-        rsa = EVP_PKEY_get1_RSA(pkey);
-        if (rsa == NULL) {
-            SSH_LOG(SSH_LOG_WARN,
-                    "Parsing pub key: %s",
-                    ERR_error_string(ERR_get_error(),NULL));
-            goto fail;
-        }
-#endif /* OPENSSL_VERSION_NUMBER */
         type = SSH_KEYTYPE_RSA;
         break;
     case EVP_PKEY_EC:
 #ifdef HAVE_OPENSSL_ECC
-/* TODO Change to new API when the OpenSSL will support export of uncompressed EC keys
- * https://github.com/openssl/openssl/pull/16624
- * #if OPENSSL_VERSION_NUMBER < 0x30000000L
- */
-#if 1
-        ecdsa = EVP_PKEY_get1_EC_KEY(pkey);
+#if OPENSSL_VERSION_NUMBER < 0x30000000L
+        ecdsa = EVP_PKEY_get0_EC_KEY(pkey);
         if (ecdsa == NULL) {
             SSH_LOG(SSH_LOG_WARN,
                     "Parsing pub key: %s",
@@ -3562,22 +3513,10 @@ int pki_uri_import(const char *uri_name,
     if (key_type == SSH_KEY_PRIVATE) {
         key->flags |= SSH_KEY_FLAG_PRIVATE;
     }
-#if OPENSSL_VERSION_NUMBER < 0x30000000L
-    key->rsa = rsa;
-#endif
-/* TODO Change to new API when the OpenSSL will support export of uncompressed EC keys
- * https://github.com/openssl/openssl/pull/16624
- * Move line key->ecdsa into #if above
- */
-    key->ecdsa = ecdsa;
 #ifdef HAVE_OPENSSL_ECC
     if (is_ecdsa_key_type(key->type)) {
-/* TODO Change to new API when the OpenSSL will support export of uncompressed EC keys
- * https://github.com/openssl/openssl/pull/16624
- * #if OPENSSL_VERSION_NUMBER < 0x30000000L
- */
-#if 1
-        key->ecdsa_nid = pki_key_ecdsa_to_nid(key->ecdsa);
+#if OPENSSL_VERSION_NUMBER < 0x30000000L
+        key->ecdsa_nid = pki_key_ecdsa_to_nid(ecdsa);
 #else
         key->ecdsa_nid = pki_key_ecdsa_to_nid(key->key);
 #endif /* OPENSSL_VERSION_NUMBER */
@@ -3591,16 +3530,6 @@ int pki_uri_import(const char *uri_name,
 fail:
     EVP_PKEY_free(pkey);
     ssh_key_free(key);
-#if OPENSSL_VERSION_NUMBER < 0x30000000L
-    RSA_free(rsa);
-#endif
-/* TODO Change to new API when the OpenSSL will support export of uncompressed EC keys
- * https://github.com/openssl/openssl/pull/16624
- * Move HAVE_OPENSSL_ECC #ifdef into #if above
- */
-#ifdef HAVE_OPENSSL_ECC
-    EC_KEY_free(ecdsa);
-#endif
 
     return SSH_ERROR;
 }
diff --git a/src/wrapper.c b/src/wrapper.c
index d317dc4c..bf949ea9 100644
--- a/src/wrapper.c
+++ b/src/wrapper.c
@@ -177,13 +177,9 @@ void crypto_free(struct ssh_crypto_struct *crypto)
 #ifdef HAVE_ECDH
     SAFE_FREE(crypto->ecdh_client_pubkey);
     SAFE_FREE(crypto->ecdh_server_pubkey);
-    if(crypto->ecdh_privkey != NULL){
+    if (crypto->ecdh_privkey != NULL) {
 #ifdef HAVE_OPENSSL_ECC
-/* TODO Change to new API when the OpenSSL will support export of uncompressed EC keys
- * https://github.com/openssl/openssl/pull/16624
- * #if OPENSSL_VERSION_NUMBER < 0x30000000L
- */
-#if 1
+#if OPENSSL_VERSION_NUMBER < 0x30000000L
         EC_KEY_free(crypto->ecdh_privkey);
 #else
         EVP_PKEY_free(crypto->ecdh_privkey);
diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt
index f5c30061..93d1250f 100644
--- a/tests/CMakeLists.txt
+++ b/tests/CMakeLists.txt
@@ -183,6 +183,16 @@ if (CLIENT_TESTING OR SERVER_TESTING)
         if (NOT SOFTHSM_FOUND)
             message(SEND_ERROR "Could not find softhsm module!")
         endif (NOT SOFTHSM_FOUND)
+        if (WITH_PKCS11_PROVIDER)
+            find_package(PkgConfig)
+            if (PKG_CONFIG_FOUND)
+                pkg_check_modules(P11_KIT p11-kit-1)
+                if (P11_KIT_FOUND)
+                    pkg_get_variable(P11_MODULE_PATH p11-kit-1 p11_module_path)
+                    set(P11_KIT_CLIENT ${P11_MODULE_PATH}/p11-kit-client.so)
+                endif (P11_KIT_FOUND)
+            endif (PKG_CONFIG_FOUND)
+        endif (WITH_PKCS11_PROVIDER)
     endif (WITH_PKCS11_URI)
 
     find_program(SSH_EXECUTABLE NAMES ssh)
@@ -296,12 +306,14 @@ if (CLIENT_TESTING OR SERVER_TESTING)
     file(COPY keys/certauth/id_rsa DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/home/bob/.ssh_cert/ FILE_PERMISSIONS OWNER_READ OWNER_WRITE)
     file(COPY keys/certauth/id_rsa.pub DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/home/bob/.ssh_cert/ FILE_PERMISSIONS OWNER_READ OWNER_WRITE)
     file(COPY keys/certauth/id_rsa-cert.pub DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/home/bob/.ssh_cert/ FILE_PERMISSIONS OWNER_READ OWNER_WRITE)
+endif ()
 
+if (WITH_PKCS11_URI)
     #Copy the script to setup PKCS11 tokens
     file(COPY pkcs11/setup-softhsm-tokens.sh DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/pkcs11 FILE_PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE)
+endif (WITH_PKCS11_URI)
 
-    message(STATUS "TORTURE_ENVIRONMENT=${TORTURE_ENVIRONMENT}")
-endif ()
+message(STATUS "TORTURE_ENVIRONMENT=${TORTURE_ENVIRONMENT}")
 
 configure_file(tests_config.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/tests_config.h)
 
diff --git a/tests/client/torture_auth_pkcs11.c b/tests/client/torture_auth_pkcs11.c
index e75fea0e..2537d2d8 100644
--- a/tests/client/torture_auth_pkcs11.c
+++ b/tests/client/torture_auth_pkcs11.c
@@ -39,9 +39,8 @@
 #define LIBSSH_ECDSA_256_TESTKEY  "id_pkcs11_ecdsa_256"
 #define LIBSSH_ECDSA_384_TESTKEY  "id_pkcs11_ecdsa_384"
 #define LIBSSH_ECDSA_521_TESTKEY  "id_pkcs11_ecdsa_521"
-#define SOFTHSM_CONF "softhsm.conf"
 
-const char template[] = "temp_dir_XXXXXX";
+const char template[] = "/tmp/temp_dir_XXXXXX";
 
 struct pki_st {
     char *temp_dir;
@@ -109,7 +108,6 @@ static int setup_session(void **state)
     struct torture_state *s = *state;
     struct pki_st *test_state = NULL;
     int rc;
-    char conf_path[1024] = {0};
     char keys_dir[1024] = {0};
     char *temp_dir;
 
@@ -134,9 +132,6 @@ static int setup_session(void **state)
 
     test_state->keys_dir = strdup(keys_dir);
 
-    snprintf(conf_path, sizeof(conf_path), "%s/softhsm.conf", test_state->temp_dir);
-    setenv("SOFTHSM2_CONF", conf_path, 1);
-
     setup_tokens(state, LIBSSH_RSA_TESTKEY, "rsa");
     setup_tokens(state, LIBSSH_ECDSA_256_TESTKEY, "ecdsa256");
     setup_tokens(state, LIBSSH_ECDSA_384_TESTKEY, "ecdsa384");
@@ -160,7 +155,7 @@ static int sshd_teardown(void **state) {
     struct pki_st *test_state = s->private_data;
     int rc;
 
-    unsetenv("SOFTHSM2_CONF");
+    torture_cleanup_tokens(test_state->temp_dir);
 
     rc = torture_change_dir(test_state->orig_dir);
     assert_int_equal(rc, 0);
diff --git a/tests/pkcs11/setup-softhsm-tokens.sh b/tests/pkcs11/setup-softhsm-tokens.sh
index ae316c7a..bd8e0944 100755
--- a/tests/pkcs11/setup-softhsm-tokens.sh
+++ b/tests/pkcs11/setup-softhsm-tokens.sh
@@ -5,8 +5,10 @@
 TESTDIR=$1
 PRIVKEY=$2
 OBJNAME=$3
+TOKENLABEL=$3 # yeah. The same as object label
 LOADPUBLIC=$4
 LIBSOFTHSM_PATH=$5
+P11_KIT_CLIENT=$6
 shift 5
 
 PUBKEY="$PRIVKEY.pub"
@@ -15,24 +17,27 @@ echo "TESTDIR: $TESTDIR"
 echo "PRIVKEY: $PRIVKEY"
 echo "PUBKEY: $PUBKEY"
 echo "OBJNAME: $OBJNAME"
+echo "TOKENLABEL: $TOKENLABEL"
 echo "LOADPUBLIC: $LOADPUBLIC"
 
-# Create temporary directory for tokens
-install -d -m 0755 "$TESTDIR/db"
+if [ ! -d "$TESTDIR/db" ]; then
+    # Create temporary directory for tokens
+    install -d -m 0755 "$TESTDIR/db"
 
-# Create SoftHSM configuration file
-cat >"$TESTDIR/softhsm.conf" <<EOF
+    # Create SoftHSM configuration file
+    cat >"$TESTDIR/softhsm.conf" <<EOF
 directories.tokendir = $TESTDIR/db
 objectstore.backend = file
 log.level = DEBUG
 EOF
 
-export SOFTHSM2_CONF=$TESTDIR/softhsm.conf
+    cat "$TESTDIR/softhsm.conf"
+fi
 
-cat "$TESTDIR/softhsm.conf"
+export SOFTHSM2_CONF=$TESTDIR/softhsm.conf
 
-#init
-cmd="softhsm2-util --init-token --label $OBJNAME --free --pin 1234 --so-pin 1234"
+#init -- each object will have its own token
+cmd="softhsm2-util --init-token --label $TOKENLABEL --free --pin 1234 --so-pin 1234"
 eval echo "$cmd"
 out=$(eval "$cmd")
 ret=$?
@@ -43,7 +48,7 @@ if [ $ret -ne 0 ]; then
 fi
 
 #load private key
-cmd="p11tool --provider $LIBSOFTHSM_PATH --write --load-privkey $PRIVKEY --label $OBJNAME --login --set-pin=1234 \"pkcs11:token=$OBJNAME\""
+cmd="p11tool --provider $LIBSOFTHSM_PATH --write --load-privkey $PRIVKEY --label $OBJNAME --login --set-pin=1234 \"pkcs11:token=$TOKENLABEL\""
 eval echo "$cmd"
 out=$(eval "$cmd")
 ret=$?
@@ -59,7 +64,7 @@ ls -l "$TESTDIR"
 
 if [ "$LOADPUBLIC" -ne 0 ]; then
 #load public key
-    cmd="p11tool --provider $LIBSOFTHSM_PATH --write --load-pubkey $PUBKEY --label $OBJNAME --login --set-pin=1234 \"pkcs11:token=$OBJNAME\""
+    cmd="p11tool --provider $LIBSOFTHSM_PATH --write --load-pubkey $PUBKEY --label $OBJNAME --login --set-pin=1234 \"pkcs11:token=$TOKENLABEL\""
     eval echo "$cmd"
     out=$(eval "$cmd")
     ret=$?
@@ -70,7 +75,7 @@ if [ "$LOADPUBLIC" -ne 0 ]; then
     fi
 fi
 
-cmd="p11tool --list-all --login \"pkcs11:token=$OBJNAME\" --set-pin=1234"
+cmd="p11tool --list-all --login \"pkcs11:token=$TOKENLABEL\" --set-pin=1234"
 eval echo "$cmd"
 out=$(eval "$cmd")
 ret=$?
@@ -81,4 +86,55 @@ if [ $ret -ne 0 ]; then
 fi
 echo "$out"
 
+# Skip the p11-kit if not needed
+if [ -z "$P11_KIT_CLIENT" ]; then
+    exit 0
+fi
+
+# when creating more keys, we need to restart the p11-kit
+# so it can pick up the new keys
+if [ -h "$TESTDIR/p11-kit-server.socket" ]; then
+    kill -9 $(cat $TESTDIR/p11-kit-server.pid)
+    rm $TESTDIR/p11-kit-server.socket
+fi
+
+# p11-kit complains if there is no runtime directory
+if [ -z "$XDG_RUNTIME_DIR" ]; then
+    export XDG_RUNTIME_DIR=$PWD
+fi
+
+# Start the p11-kit server
+cmd="p11-kit server --provider $LIBSOFTHSM_PATH pkcs11:"
+echo "$cmd"
+out=$(eval "$cmd")
+ret=$?
+if [ $ret -ne 0 ]; then
+    echo "Starting p11-kit server failed"
+    echo "$out"
+    exit 1
+fi
+eval $out
+
+# Symlink the p11-kit-server socket to "known place"
+P11_KIT_SERVER_ADDRESS_PATH=${P11_KIT_SERVER_ADDRESS:10}
+cmd="ln -s $P11_KIT_SERVER_ADDRESS_PATH $TESTDIR/p11-kit-server.socket"
+echo "$cmd"
+out=$(eval "$cmd")
+
+# Save the PID for the C code to clean up
+cmd="echo $P11_KIT_SERVER_PID > $TESTDIR/p11-kit-server.pid"
+echo "$cmd"
+out=$(eval "$cmd")
+
+cmd="pkcs11-tool -O --login --pin=1234 --module=$P11_KIT_CLIENT --token-label=$TOKENLABEL"
+echo "$cmd"
+out=$(eval "$cmd")
+ret=$?
+echo "$out"
+if [ $ret -ne 0 ]; then
+    echo "Failed to list keys through p11-kit remoting"
+    echo "$out"
+    exit 1
+fi
+
 exit 0
diff --git a/tests/tests_config.h.cmake b/tests/tests_config.h.cmake
index a8147c44..92a08781 100644
--- a/tests/tests_config.h.cmake
+++ b/tests/tests_config.h.cmake
@@ -70,3 +70,4 @@
 #cmakedefine WITH_TIMEOUT ${WITH_TIMEOUT}
 #cmakedefine TIMEOUT_EXECUTABLE "${TIMEOUT_EXECUTABLE}"
 #cmakedefine SOFTHSM2_LIBRARY "${SOFTHSM2_LIBRARY}"
+#cmakedefine P11_KIT_CLIENT "${P11_KIT_CLIENT}"
diff --git a/tests/torture.c b/tests/torture.c
index 6b2d5b7b..35f7d80b 100644
--- a/tests/torture.c
+++ b/tests/torture.c
@@ -1238,19 +1238,60 @@ void torture_setup_tokens(const char *temp_dir,
                           const char *load_public)
 {
     char token_setup_start_cmd[1024] = {0};
+    char socket_path[1204] = {0};
+    char conf_path[1024] = {0};
     int rc;
 
-    snprintf(token_setup_start_cmd, sizeof(token_setup_start_cmd),
-             "%s/tests/pkcs11/setup-softhsm-tokens.sh %s %s %s %s %s",
-             BINARYDIR,
-             temp_dir,
-             filename,
-             object_name,
-             load_public,
-             SOFTHSM2_LIBRARY);
+    rc = snprintf(token_setup_start_cmd,
+                  sizeof(token_setup_start_cmd),
+                  "%s/tests/pkcs11/setup-softhsm-tokens.sh %s %s %s %s %s %s",
+                  BINARYDIR,
+                  temp_dir,
+                  filename,
+                  object_name,
+                  load_public,
+                  SOFTHSM2_LIBRARY,
+#ifdef WITH_PKCS11_PROVIDER
+                  P11_KIT_CLIENT
+#else
+                  ""
+#endif
+                 );
+    assert_int_not_equal(rc, sizeof(token_setup_start_cmd));
 
     rc = system(token_setup_start_cmd);
     assert_return_code(rc, errno);
+
+#ifdef WITH_PKCS11_PROVIDER
+    rc = snprintf(socket_path,
+                  sizeof(socket_path),
+                  "unix:path=%s/p11-kit-server.socket",
+                  temp_dir);
+    assert_int_not_equal(rc, sizeof(socket_path));
+    setenv("P11_KIT_SERVER_ADDRESS", socket_path, 1);
+
+    setenv("PKCS11_PROVIDER_MODULE", P11_KIT_CLIENT, 1);
+    /* This is useful for debugging PKCS#11 calls */
+    // setenv("PKCS11SPY", P11_KIT_CLIENT, 1);
+    // setenv("PKCS11_PROVIDER_MODULE", "/usr/lib64/pkcs11-spy.so", 1);
+#else
+    snprintf(conf_path, sizeof(conf_path), "%s/softhsm.conf", temp_dir);
+    setenv("SOFTHSM2_CONF", conf_path, 1);
+#endif /* WITH_PKCS11_PROVIDER */
+}
+
+void torture_cleanup_tokens(const char *temp_dir)
+{
+    char pidfile[1024] = {0};
+    int rc;
+    pid_t pid;
+
+#ifdef WITH_PKCS11_PROVIDER
+    snprintf(pidfile, sizeof(pidfile), "%s/p11-kit-server.pid", temp_dir);
+    torture_terminate_process(pidfile);
+#else
+    unsetenv("SOFTHSM2_CONF");
+#endif /* WITH_PKCS11_PROVIDER */
 }
 #endif /* WITH_PKCS11_URI */
 
diff --git a/tests/torture.h b/tests/torture.h
index 498acf60..36f28f38 100644
--- a/tests/torture.h
+++ b/tests/torture.h
@@ -135,6 +135,7 @@ void torture_setup_tokens(const char *temp_dir,
                           const char *filename,
                           const char object_name[],
                           const char *load_public);
+void torture_cleanup_tokens(const char *temp_dir);
 #endif /* WITH_PKCS11_URI */
 
 void torture_reset_config(ssh_session session);
diff --git a/tests/unittests/CMakeLists.txt b/tests/unittests/CMakeLists.txt
index f85da72b..58c5b6d7 100644
--- a/tests/unittests/CMakeLists.txt
+++ b/tests/unittests/CMakeLists.txt
@@ -76,6 +76,7 @@ if (UNIX AND NOT WIN32)
             torture_pki_rsa_uri
             torture_pki_ecdsa_uri
         )
+        list(APPEND TORTURE_UNIT_ENVIRONMENT PKCS11_PROVIDER_DEBUG=file:/tmp/p11prov-debug.log)
     endif()
 
     if (HAVE_ECC)
diff --git a/tests/unittests/torture_pki_ecdsa_uri.c b/tests/unittests/torture_pki_ecdsa_uri.c
index 038780db..a2bdae8f 100644
--- a/tests/unittests/torture_pki_ecdsa_uri.c
+++ b/tests/unittests/torture_pki_ecdsa_uri.c
@@ -31,7 +31,7 @@
 #define PUB_URI_FMT_384_INVALID_TOKEN "pkcs11:token=ecdsa521;object=ecdsa384;type=public"
 #define PUB_URI_FMT_521_INVALID_OBJECT "pkcs11:token=ecdsa521;object=ecdsa384;type=public"
 
-const char template[] = "temp_dir_XXXXXX";
+const char template[] = "/tmp/temp_dir_XXXXXX";
 const unsigned char INPUT[] = "1234567890123456789012345678901234567890"
                               "123456789012345678901234";
 struct pki_st {
@@ -80,7 +80,6 @@ static int setup_directory_structure(void **state)
     struct pki_st *test_state = NULL;
     char *temp_dir;
     int rc;
-    char conf_path[1024] = {0};
 
     test_state = (struct pki_st *)malloc(sizeof(struct pki_st));
     assert_non_null(test_state);
@@ -100,9 +99,6 @@ static int setup_directory_structure(void **state)
 
     *state = test_state;
 
-    snprintf(conf_path, sizeof(conf_path), "%s/softhsm.conf", test_state->temp_dir);
-    setenv("SOFTHSM2_CONF", conf_path, 1);
-
     setup_tokens_ecdsa(state, 256, "ecdsa256", "1");
     setup_tokens_ecdsa(state, 384, "ecdsa384", "1");
     setup_tokens_ecdsa(state, 521, "ecdsa521", "1");
@@ -118,7 +114,7 @@ static int teardown_directory_structure(void **state)
     struct pki_st *test_state = *state;
     int rc;
 
-    unsetenv("SOFTHSM2_CONF");
+    torture_cleanup_tokens(test_state->temp_dir);
 
     rc = torture_change_dir(test_state->orig_dir);
     assert_int_equal(rc, 0);
diff --git a/tests/unittests/torture_pki_rsa_uri.c b/tests/unittests/torture_pki_rsa_uri.c
index 1d15db6d..d0325def 100644
--- a/tests/unittests/torture_pki_rsa_uri.c
+++ b/tests/unittests/torture_pki_rsa_uri.c
@@ -13,11 +13,10 @@
 
 #define LIBSSH_RSA_TESTKEY            "libssh_testkey.id_rsa"
 #define LIBSSH_RSA_TESTKEY_PASSPHRASE "libssh_testkey_passphrase.id_rsa"
-#define SOFTHSM_CONF "softhsm.conf"
 #define PUB_URI_FMT  "pkcs11:token=%s;object=%s;type=public"
 #define PRIV_URI_FMT "pkcs11:token=%s;object=%s;type=private?pin-value=%s"
 
-const char template[] = "temp_dir_XXXXXX";
+const char template[] = "/tmp/temp_dir_XXXXXX";
 const unsigned char INPUT[] = "1234567890123456789012345678901234567890"
                               "123456789012345678901234";
 struct pki_st {
@@ -33,7 +32,6 @@ struct pki_st {
 
 static int setup_tokens(void **state)
 {
-    char conf_path[1024] = {0};
     char keys_path[1024] = {0};
     char keys_path_pub[1024] = {0};
     char *cwd = NULL;
@@ -85,10 +83,6 @@ static int setup_tokens(void **state)
 
     torture_setup_tokens(cwd, keys_path, obj_tempname, "1");
 
-    snprintf(conf_path, sizeof(conf_path), "%s/softhsm.conf", cwd);
-
-    setenv("SOFTHSM2_CONF", conf_path, 1);
-
     return 0;
 }
 
@@ -126,6 +120,8 @@ static int teardown_directory_structure(void **state)
     struct pki_st *test_state = *state;
     int rc;
 
+    torture_cleanup_tokens(test_state->temp_dir);
+
     rc = torture_change_dir(test_state->orig_dir);
     assert_int_equal(rc, 0);
 
@@ -142,8 +138,6 @@ static int teardown_directory_structure(void **state)
     SAFE_FREE(test_state->pub_uri_invalid_token);
     SAFE_FREE(test_state);
 
-    unsetenv("SOFTHSM2_CONF");
-
     return 0;
 }