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 #include #include @@ -32,6 +33,7 @@ #include #include #include +#include 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 -/* 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, ¶ms); - 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 -#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 -#include -#include -#include -#include -#include -#include - -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, ¶ms); + /* 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, ¶ms); - if (rc != 1) { - EVP_PKEY_CTX_free(ctx); - return -1; - } + rc = EVP_PKEY_todata(key->key, EVP_PKEY_PUBLIC_KEY, ¶ms); + 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 #include #include +#if defined(WITH_PKCS11_URI) && defined(WITH_PKCS11_PROVIDER) +#include +#include +#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, ¶ms); @@ -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, ¶ms); @@ -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, ¶ms); 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" <"$TESTDIR/softhsm.conf" <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; }