net_ssl: Use EVP API to create EVP_PKEYs when available

The following functions are deprecated in OpenSSL 3.0 and used in net_ssl.cpp: `RSA_free`, `EC_KEY_free`, `RSA_new`, `RSA_generate_key_ex`, `EC_KEY_set_group`, `EC_KEY_generate_key`.

Since EVP_RSA_gen was added in OpenSSL 3.0 and since the aforementioned functions were deprecated in OpenSSL 3.0, I check if the OpenSSL version >= 3.0, and use EVP_RSA_gen instead of everything else up to assigning the private key to the certificate in `create_rsa_ssl_certificate`.

I also deleted `create_ec_ssl_certificate` since it wasn't used.
This commit is contained in:
jeffro256
2022-05-16 13:19:17 -05:00
parent fb5b06bd3b
commit aa3abe2c03
2 changed files with 54 additions and 171 deletions
+1 -1
View File
@@ -39,6 +39,7 @@
#include <boost/asio/ssl.hpp>
#include <boost/filesystem/path.hpp>
#include <boost/system/error_code.hpp>
#include <openssl/evp.h>
#define SSL_FINGERPRINT_SIZE 32
@@ -151,7 +152,6 @@ namespace net_utils
bool is_ssl(const unsigned char *data, size_t len);
bool ssl_support_from_string(ssl_support_t &ssl, boost::string_ref s);
bool create_ec_ssl_certificate(EVP_PKEY *&pkey, X509 *&cert);
bool create_rsa_ssl_certificate(EVP_PKEY *&pkey, X509 *&cert);
/**
+53 -170
View File
@@ -65,14 +65,7 @@ static void add_windows_root_certs(SSL_CTX *ctx) noexcept;
namespace
{
struct openssl_bio_free
{
void operator()(BIO* ptr) const noexcept
{
BIO_free(ptr);
}
};
using openssl_bio = std::unique_ptr<BIO, openssl_bio_free>;
static constexpr unsigned int rsa_bits = 4096;
struct openssl_pkey_free
{
@@ -83,42 +76,6 @@ namespace
};
using openssl_pkey = std::unique_ptr<EVP_PKEY, openssl_pkey_free>;
struct openssl_rsa_free
{
void operator()(RSA* ptr) const noexcept
{
RSA_free(ptr);
}
};
using openssl_rsa = std::unique_ptr<RSA, openssl_rsa_free>;
struct openssl_bignum_free
{
void operator()(BIGNUM* ptr) const noexcept
{
BN_free(ptr);
}
};
using openssl_bignum = std::unique_ptr<BIGNUM, openssl_bignum_free>;
struct openssl_ec_key_free
{
void operator()(EC_KEY* ptr) const noexcept
{
EC_KEY_free(ptr);
}
};
using openssl_ec_key = std::unique_ptr<EC_KEY, openssl_ec_key_free>;
struct openssl_group_free
{
void operator()(EC_GROUP* ptr) const noexcept
{
EC_GROUP_free(ptr);
}
};
using openssl_group = std::unique_ptr<EC_GROUP, openssl_group_free>;
boost::system::error_code load_ca_file(boost::asio::ssl::context& ctx, const std::string& path)
{
SSL_CTX* const ssl_ctx = ctx.native_handle(); // could be moved from context
@@ -133,6 +90,55 @@ namespace
}
return boost::system::error_code{};
}
/**
* @brief Generate a new RSA private key. For OpenSSL >= 3.0, same as EVP_RSA_gen(rsa_bits)
*/
openssl_pkey gen_rsa_pkey_compat()
{
#if OPENSSL_VERSION_NUMBER >= 0x30000000L
return openssl_pkey{EVP_RSA_gen(rsa_bits)};
#else
openssl_pkey pkey{EVP_PKEY_new()};
if (!pkey) {
MERROR("Error allocating EVP private key");
return NULL;
}
std::unique_ptr<RSA, decltype(&RSA_free)> rsa(RSA_new(), &RSA_free);
if (!rsa)
{
MERROR("Error allocating RSA private key");
return NULL;
}
std::unique_ptr<BIGNUM, decltype(&BN_free)> exponent(BN_new(), &BN_free);
if (!exponent)
{
MERROR("Error allocating exponent");
return NULL;
}
BN_set_word(exponent.get(), RSA_F4);
if (RSA_generate_key_ex(rsa.get(), rsa_bits, exponent.get(), nullptr) != 1)
{
MERROR("Error generating RSA private key");
return NULL;
}
if (EVP_PKEY_assign_RSA(pkey.get(), rsa.get()) <= 0)
{
MERROR("Error assigning RSA private key");
return NULL;
}
// the RSA key is now managed by the EVP_PKEY structure
(void)rsa.release();
return pkey;
#endif
}
}
namespace epee
@@ -145,126 +151,14 @@ namespace net_utils
bool create_rsa_ssl_certificate(EVP_PKEY *&pkey, X509 *&cert)
{
MINFO("Generating SSL certificate");
pkey = EVP_PKEY_new();
openssl_pkey pkey_deleter = gen_rsa_pkey_compat();
pkey = pkey_deleter.get();
if (!pkey)
{
MERROR("Failed to create new private key");
MERROR("Failed to create new private key with gen_rsa_pkey_compat()");
return false;
}
openssl_pkey pkey_deleter{pkey};
openssl_rsa rsa{RSA_new()};
if (!rsa)
{
MERROR("Error allocating RSA private key");
return false;
}
openssl_bignum exponent{BN_new()};
if (!exponent)
{
MERROR("Error allocating exponent");
return false;
}
BN_set_word(exponent.get(), RSA_F4);
if (RSA_generate_key_ex(rsa.get(), 4096, exponent.get(), nullptr) != 1)
{
MERROR("Error generating RSA private key");
return false;
}
if (EVP_PKEY_assign_RSA(pkey, rsa.get()) <= 0)
{
MERROR("Error assigning RSA private key");
return false;
}
// the RSA key is now managed by the EVP_PKEY structure
(void)rsa.release();
cert = X509_new();
if (!cert)
{
MERROR("Failed to create new X509 certificate");
return false;
}
ASN1_INTEGER_set(X509_get_serialNumber(cert), 1);
X509_gmtime_adj(X509_get_notBefore(cert), 0);
X509_gmtime_adj(X509_get_notAfter(cert), 3600 * 24 * 182); // half a year
if (!X509_set_pubkey(cert, pkey))
{
MERROR("Error setting pubkey on certificate");
X509_free(cert);
return false;
}
X509_NAME *name = X509_get_subject_name(cert);
X509_set_issuer_name(cert, name);
if (X509_sign(cert, pkey, EVP_sha256()) == 0)
{
MERROR("Error signing certificate");
X509_free(cert);
return false;
}
(void)pkey_deleter.release();
return true;
}
bool create_ec_ssl_certificate(EVP_PKEY *&pkey, X509 *&cert, int type)
{
MINFO("Generating SSL certificate");
pkey = EVP_PKEY_new();
if (!pkey)
{
MERROR("Failed to create new private key");
return false;
}
openssl_pkey pkey_deleter{pkey};
openssl_ec_key ec_key{EC_KEY_new()};
if (!ec_key)
{
MERROR("Error allocating EC private key");
return false;
}
EC_GROUP *group = EC_GROUP_new_by_curve_name(type);
if (!group)
{
MERROR("Error getting EC group " << type);
return false;
}
openssl_group group_deleter{group};
EC_GROUP_set_asn1_flag(group, OPENSSL_EC_NAMED_CURVE);
EC_GROUP_set_point_conversion_form(group, POINT_CONVERSION_UNCOMPRESSED);
if (!EC_GROUP_check(group, NULL))
{
MERROR("Group failed check: " << ERR_reason_error_string(ERR_get_error()));
return false;
}
if (EC_KEY_set_group(ec_key.get(), group) != 1)
{
MERROR("Error setting EC group");
return false;
}
if (EC_KEY_generate_key(ec_key.get()) != 1)
{
MERROR("Error generating EC private key");
return false;
}
if (EVP_PKEY_assign_EC_KEY(pkey, ec_key.get()) <= 0)
{
MERROR("Error assigning EC private key");
return false;
}
// the key is now managed by the EVP_PKEY structure
(void)ec_key.release();
cert = X509_new();
if (!cert)
{
@@ -384,17 +278,6 @@ boost::asio::ssl::context ssl_options_t::create_context() const
X509 *cert;
bool ok = false;
#ifdef USE_EXTRA_EC_CERT
CHECK_AND_ASSERT_THROW_MES(create_ec_ssl_certificate(pkey, cert, NID_secp256k1), "Failed to create certificate");
CHECK_AND_ASSERT_THROW_MES(SSL_CTX_use_certificate(ctx, cert), "Failed to use generated certificate");
if (!SSL_CTX_use_PrivateKey(ctx, pkey))
MERROR("Failed to use generated EC private key for " << NID_secp256k1);
else
ok = true;
X509_free(cert);
EVP_PKEY_free(pkey);
#endif
CHECK_AND_ASSERT_THROW_MES(create_rsa_ssl_certificate(pkey, cert), "Failed to create certificate");
CHECK_AND_ASSERT_THROW_MES(SSL_CTX_use_certificate(ctx, cert), "Failed to use generated certificate");
if (!SSL_CTX_use_PrivateKey(ctx, pkey))