29 #include "ndn-cxx/security/impl/openssl-helper.hpp"
33 #if OPENSSL_VERSION_NUMBER < 0x30000000L
37 #include <boost/lexical_cast.hpp>
40 #include <openssl/ec.h>
41 #include <openssl/pem.h>
42 #include <openssl/rsa.h>
43 #include <openssl/x509.h>
45 #define ENSURE_PRIVATE_KEY_LOADED(key) \
47 if ((key) == nullptr) \
48 NDN_THROW(Error("Private key has not been loaded yet")); \
51 #define ENSURE_PRIVATE_KEY_NOT_LOADED(key) \
53 if ((key) != nullptr) \
54 NDN_THROW(Error("Private key has already been loaded")); \
61 class PrivateKey::Impl : noncopyable
70 EVP_PKEY* key =
nullptr;
74 : m_impl(make_unique<Impl>())
86 switch (detail::getEvpPkeyType(m_impl->key)) {
104 return static_cast<size_t>(EVP_PKEY_bits(m_impl->key));
107 EVP_PKEY_get_raw_private_key(m_impl->key,
nullptr, &nBytes);
120 boost::lexical_cast<std::string>(
getKeyType())));
123 const uint8_t* buf = EVP_PKEY_get0_hmac(m_impl->key, &len);
142 pkeyType = EVP_PKEY_HMAC;
145 NDN_THROW(std::invalid_argument(
"Unsupported key type " + boost::lexical_cast<std::string>(type)));
148 m_impl->key = EVP_PKEY_new_raw_private_key(pkeyType,
nullptr, buf.data(), buf.size());
149 if (m_impl->key ==
nullptr)
158 auto ptr = buf.data();
159 if (d2i_AutoPrivateKey(&m_impl->key, &ptr,
static_cast<long>(buf.size())) ==
nullptr)
190 BOOST_ASSERT(std::strlen(pw) == pwLen);
193 detail::Bio membio(BIO_s_mem());
194 if (!membio.write(buf))
197 if (d2i_PKCS8PrivateKey_bio(membio, &m_impl->key,
nullptr,
const_cast<char*
>(pw)) ==
nullptr)
202 passwordCallbackWrapper(
char* buf,
int size,
int rwflag,
void* u)
204 BOOST_ASSERT(size >= 0);
206 return (*cb)(buf,
static_cast<size_t>(size), rwflag);
214 detail::Bio membio(BIO_s_mem());
215 if (!membio.write(buf))
219 m_impl->key = d2i_PKCS8PrivateKey_bio(membio,
nullptr, &passwordCallbackWrapper, &pwCallback);
221 m_impl->key = d2i_PKCS8PrivateKey_bio(membio,
nullptr,
nullptr,
nullptr);
223 if (m_impl->key ==
nullptr)
316 uint8_t* pkcs8 =
nullptr;
317 int len = i2d_PUBKEY(m_impl->key, &pkcs8);
321 auto result = make_shared<Buffer>(pkcs8, len);
332 int keyType = detail::getEvpPkeyType(m_impl->key);
337 return rsaDecrypt(cipherText);
344 PrivateKey::getEvpPkey()
const
350 PrivateKey::toPkcs1()
const
354 detail::Bio membio(BIO_s_mem());
355 if (!i2d_PrivateKey_bio(membio, m_impl->key))
356 NDN_THROW(Error(
"Cannot convert key to PKCS #1 format"));
358 auto buffer = make_shared<Buffer>(BIO_pending(membio));
359 if (!membio.read(*buffer))
360 NDN_THROW(Error(
"Read error during PKCS #1 conversion"));
366 PrivateKey::toPkcs8(
const char* pw,
size_t pwLen)
const
368 BOOST_ASSERT(std::strlen(pw) == pwLen);
371 detail::Bio membio(BIO_s_mem());
372 if (!i2d_PKCS8PrivateKey_bio(membio, m_impl->key, EVP_aes_256_cbc(),
nullptr, 0,
373 nullptr,
const_cast<char*
>(pw)))
374 NDN_THROW(Error(
"Cannot convert key to PKCS #8 format"));
376 auto buffer = make_shared<Buffer>(BIO_pending(membio));
377 if (!membio.read(*buffer))
378 NDN_THROW(Error(
"Read error during PKCS #8 conversion"));
384 PrivateKey::toPkcs8(PasswordCallback pwCallback)
const
388 detail::Bio membio(BIO_s_mem());
389 if (!i2d_PKCS8PrivateKey_bio(membio, m_impl->key, EVP_aes_256_cbc(),
nullptr, 0,
390 &passwordCallbackWrapper, &pwCallback))
391 NDN_THROW(Error(
"Cannot convert key to PKCS #8 format"));
393 auto buffer = make_shared<Buffer>(BIO_pending(membio));
394 if (!membio.read(*buffer))
395 NDN_THROW(Error(
"Read error during PKCS #8 conversion"));
401 PrivateKey::rsaDecrypt(span<const uint8_t> cipherText)
const
403 detail::EvpPkeyCtx ctx(m_impl->key);
405 if (EVP_PKEY_decrypt_init(ctx) <= 0)
406 NDN_THROW(Error(
"Failed to initialize decryption context"));
408 if (EVP_PKEY_CTX_set_rsa_padding(ctx, RSA_PKCS1_OAEP_PADDING) <= 0)
409 NDN_THROW(Error(
"Failed to set padding"));
413 if (EVP_PKEY_decrypt(ctx,
nullptr, &outlen, cipherText.data(), cipherText.size()) <= 0)
414 NDN_THROW(Error(
"Failed to estimate output length"));
416 auto out = make_shared<Buffer>(outlen);
417 if (EVP_PKEY_decrypt(ctx, out->data(), &outlen, cipherText.data(), cipherText.size()) <= 0)
418 NDN_THROW(Error(
"Failed to decrypt ciphertext"));
424 unique_ptr<PrivateKey>
425 PrivateKey::generateRsaKey(uint32_t keySize)
427 auto privateKey = make_unique<PrivateKey>();
428 BOOST_ASSERT(privateKey->m_impl->key ==
nullptr);
430 #if OPENSSL_VERSION_NUMBER >= 0x30000000L
431 privateKey->m_impl->key = EVP_RSA_gen(keySize);
433 if (privateKey->m_impl->key ==
nullptr)
434 NDN_THROW(Error(
"Failed to generate RSA key"));
436 detail::EvpPkeyCtx kctx(EVP_PKEY_RSA);
438 if (EVP_PKEY_keygen_init(kctx) <= 0)
439 NDN_THROW(Error(
"Failed to initialize RSA keygen context"));
441 if (EVP_PKEY_CTX_set_rsa_keygen_bits(kctx,
static_cast<int>(keySize)) <= 0)
442 NDN_THROW(Error(
"Failed to set RSA key length"));
444 if (EVP_PKEY_keygen(kctx, &privateKey->m_impl->key) <= 0)
445 NDN_THROW(Error(
"Failed to generate RSA key"));
451 unique_ptr<PrivateKey>
452 PrivateKey::generateEcKey(uint32_t keySize)
454 auto privateKey = make_unique<PrivateKey>();
455 BOOST_ASSERT(privateKey->m_impl->key ==
nullptr);
457 #if OPENSSL_VERSION_NUMBER >= 0x30000000L
463 privateKey->m_impl->key = EVP_EC_gen((
"P-" +
to_string(keySize)).data());
469 if (privateKey->m_impl->key ==
nullptr)
470 NDN_THROW(Error(
"Failed to generate EC key"));
472 EC_KEY* eckey =
nullptr;
475 eckey = EC_KEY_new_by_curve_name(NID_secp224r1);
478 eckey = EC_KEY_new_by_curve_name(NID_X9_62_prime256v1);
481 eckey = EC_KEY_new_by_curve_name(NID_secp384r1);
484 eckey = EC_KEY_new_by_curve_name(NID_secp521r1);
489 if (eckey ==
nullptr) {
490 NDN_THROW(Error(
"Failed to set EC curve"));
493 auto guard = make_scope_exit([eckey] { EC_KEY_free(eckey); });
494 if (EC_KEY_generate_key(eckey) != 1) {
495 NDN_THROW(Error(
"Failed to generate EC key"));
498 privateKey->m_impl->key = EVP_PKEY_new();
499 if (privateKey->m_impl->key ==
nullptr)
500 NDN_THROW(Error(
"Failed to create EVP_PKEY"));
501 if (EVP_PKEY_set1_EC_KEY(privateKey->m_impl->key, eckey) != 1)
502 NDN_THROW(Error(
"Failed to assign EC key"));
508 unique_ptr<PrivateKey>
509 PrivateKey::generateHmacKey(uint32_t keySize)
511 std::vector<uint8_t> rawKey(keySize / 8);
514 auto privateKey = make_unique<PrivateKey>();
518 catch (
const PrivateKey::Error&) {
519 NDN_THROW(PrivateKey::Error(
"Failed to generate HMAC key"));
525 unique_ptr<PrivateKey>
530 const auto& rsaParams =
static_cast<const RsaKeyParams&
>(keyParams);
531 return PrivateKey::generateRsaKey(rsaParams.getKeySize());
534 const auto& ecParams =
static_cast<const EcKeyParams&
>(keyParams);
535 return PrivateKey::generateEcKey(ecParams.getKeySize());
538 const auto& hmacParams =
static_cast<const HmacKeyParams&
>(keyParams);
539 return PrivateKey::generateHmacKey(hmacParams.getKeySize());
542 NDN_THROW(std::invalid_argument(
"Unsupported key type " +
543 boost::lexical_cast<std::string>(keyParams.
getKeyType())));
Base class for key parameters.
KeyType getKeyType() const
An output stream that writes to a Buffer.
shared_ptr< Buffer > buf()
Return a shared pointer to the underlying buffer.
SimplePublicKeyParams is a template for public keys with only one parameter: size.
SimpleSymmetricKeyParams is a template for symmetric keys with only one parameter: size.
std::string to_string(const errinfo_stacktrace &x)
void generateSecureBytes(span< uint8_t > buf)
Fill buffer with cryptographically secure random bytes.
shared_ptr< const Buffer > ConstBufferPtr
KeyType
The type of a cryptographic key.
@ EC
Elliptic Curve key (e.g. for ECDSA), supports sign/verify operations.
@ RSA
RSA key, supports sign/verify and encrypt/decrypt operations.
@ NONE
Unknown or unsupported key type.
@ HMAC
HMAC key, supports sign/verify operations.
#define ENSURE_PRIVATE_KEY_LOADED(key)
#define ENSURE_PRIVATE_KEY_NOT_LOADED(key)