security: reimplement RSA and EC key generation for OpenSSL 3.0
Also suppress deprecation warnings related to the RAND_METHOD API.
Refs: #5154
Change-Id: I977b902465f4e4cae663c21fbeda5ab808a6e66c
diff --git a/ndn-cxx/security/transform/private-key.cpp b/ndn-cxx/security/transform/private-key.cpp
index b2e2aad..831ab8a 100644
--- a/ndn-cxx/security/transform/private-key.cpp
+++ b/ndn-cxx/security/transform/private-key.cpp
@@ -30,7 +30,9 @@
#include "ndn-cxx/security/key-params.hpp"
#include "ndn-cxx/encoding/buffer-stream.hpp"
#include "ndn-cxx/util/random.hpp"
+#if OPENSSL_VERSION_NUMBER < 0x30000000L
#include "ndn-cxx/util/scope.hpp"
+#endif
#include <boost/lexical_cast.hpp>
#include <cstring>
@@ -417,17 +419,26 @@
unique_ptr<PrivateKey>
PrivateKey::generateRsaKey(uint32_t keySize)
{
+ auto privateKey = make_unique<PrivateKey>();
+ BOOST_ASSERT(privateKey->m_impl->key == nullptr);
+
+#if OPENSSL_VERSION_NUMBER >= 0x30000000L
+ privateKey->m_impl->key = EVP_RSA_gen(keySize);
+
+ if (privateKey->m_impl->key == nullptr)
+ NDN_THROW(Error("Failed to generate RSA key"));
+#else // OPENSSL_VERSION_NUMBER
detail::EvpPkeyCtx kctx(EVP_PKEY_RSA);
if (EVP_PKEY_keygen_init(kctx) <= 0)
- NDN_THROW(PrivateKey::Error("Failed to initialize RSA keygen context"));
+ NDN_THROW(Error("Failed to initialize RSA keygen context"));
if (EVP_PKEY_CTX_set_rsa_keygen_bits(kctx, static_cast<int>(keySize)) <= 0)
- NDN_THROW(PrivateKey::Error("Failed to set RSA key length"));
+ NDN_THROW(Error("Failed to set RSA key length"));
- auto privateKey = make_unique<PrivateKey>();
if (EVP_PKEY_keygen(kctx, &privateKey->m_impl->key) <= 0)
- NDN_THROW(PrivateKey::Error("Failed to generate RSA key"));
+ NDN_THROW(Error("Failed to generate RSA key"));
+#endif // OPENSSL_VERSION_NUMBER
return privateKey;
}
@@ -435,6 +446,24 @@
unique_ptr<PrivateKey>
PrivateKey::generateEcKey(uint32_t keySize)
{
+ auto privateKey = make_unique<PrivateKey>();
+ BOOST_ASSERT(privateKey->m_impl->key == nullptr);
+
+#if OPENSSL_VERSION_NUMBER >= 0x30000000L
+ switch (keySize) {
+ case 224:
+ case 256:
+ case 384:
+ case 521:
+ privateKey->m_impl->key = EVP_EC_gen(("P-" + to_string(keySize)).data());
+ break;
+ default:
+ NDN_THROW(std::invalid_argument("Unsupported EC key length " + to_string(keySize)));
+ }
+
+ if (privateKey->m_impl->key == nullptr)
+ NDN_THROW(Error("Failed to generate EC key"));
+#else // OPENSSL_VERSION_NUMBER
EC_KEY* eckey = nullptr;
switch (keySize) {
case 224:
@@ -461,12 +490,12 @@
NDN_THROW(Error("Failed to generate EC key"));
}
- auto privateKey = make_unique<PrivateKey>();
privateKey->m_impl->key = EVP_PKEY_new();
if (privateKey->m_impl->key == nullptr)
NDN_THROW(Error("Failed to create EVP_PKEY"));
if (EVP_PKEY_set1_EC_KEY(privateKey->m_impl->key, eckey) != 1)
NDN_THROW(Error("Failed to assign EC key"));
+#endif // OPENSSL_VERSION_NUMBER
return privateKey;
}
diff --git a/tests/unit/util/random.t.cpp b/tests/unit/util/random.t.cpp
index 73c3825..8875cce 100644
--- a/tests/unit/util/random.t.cpp
+++ b/tests/unit/util/random.t.cpp
@@ -46,6 +46,13 @@
BOOST_CHECK_EQUAL(r1, r3);
}
+// RAND_get_rand_method() and RAND_set_rand_method() are deprecated in OpenSSL 3.0
+// and there is no straightforward replacement. Suppress the warnings for now, but
+// we may have to drop this test case when OpenSSL removes the RAND_METHOD API.
+#if OPENSSL_VERSION_NUMBER >= 0x30000000L
+#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
+#endif
+
// This fixture uses OpenSSL routines to set a dummy random generator that always fails
class FailRandMethodFixture
{
@@ -110,7 +117,7 @@
BOOST_FIXTURE_TEST_CASE(Error, FailRandMethodFixture)
{
- std::array<uint8_t, 1024> buf;
+ std::array<uint8_t, 512> buf;
BOOST_CHECK_THROW(random::generateSecureBytes(buf), std::runtime_error);
}