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")); \
59 class PrivateKey::Impl : noncopyable
68 EVP_PKEY* key =
nullptr;
72 : m_impl(make_unique<Impl>())
84 switch (detail::getEvpPkeyType(m_impl->key)) {
102 return static_cast<size_t>(EVP_PKEY_bits(m_impl->key));
105 EVP_PKEY_get_raw_private_key(m_impl->key,
nullptr, &nBytes);
118 boost::lexical_cast<std::string>(
getKeyType())));
121 if (EVP_PKEY_get_raw_private_key(m_impl->key,
nullptr, &len) != 1)
124 if (EVP_PKEY_get_raw_private_key(m_impl->key, digest.data(), &len) != 1)
140 pkeyType = EVP_PKEY_HMAC;
143 NDN_THROW(std::invalid_argument(
"Unsupported key type " + boost::lexical_cast<std::string>(type)));
146 m_impl->key = EVP_PKEY_new_raw_private_key(pkeyType,
nullptr, buf.data(), buf.size());
147 if (m_impl->key ==
nullptr)
156 auto ptr = buf.data();
157 if (d2i_AutoPrivateKey(&m_impl->key, &ptr,
static_cast<long>(buf.size())) ==
nullptr)
188 BOOST_ASSERT(std::strlen(pw) == pwLen);
191 detail::Bio membio(BIO_s_mem());
192 if (!membio.write(buf))
195 if (d2i_PKCS8PrivateKey_bio(membio, &m_impl->key,
nullptr,
const_cast<char*
>(pw)) ==
nullptr)
200 passwordCallbackWrapper(
char* buf,
int size,
int rwflag,
void* u)
202 BOOST_ASSERT(size >= 0);
204 return (*cb)(buf,
static_cast<size_t>(size), rwflag);
212 detail::Bio membio(BIO_s_mem());
213 if (!membio.write(buf))
217 m_impl->key = d2i_PKCS8PrivateKey_bio(membio,
nullptr, &passwordCallbackWrapper, &pwCallback);
219 m_impl->key = d2i_PKCS8PrivateKey_bio(membio,
nullptr,
nullptr,
nullptr);
221 if (m_impl->key ==
nullptr)
314 uint8_t* pkcs8 =
nullptr;
315 int len = i2d_PUBKEY(m_impl->key, &pkcs8);
319 auto result = make_shared<Buffer>(pkcs8, len);
330 int keyType = detail::getEvpPkeyType(m_impl->key);
335 return rsaDecrypt(cipherText);
342 PrivateKey::getEvpPkey()
const
348 PrivateKey::toPkcs1()
const
352 detail::Bio membio(BIO_s_mem());
353 if (!i2d_PrivateKey_bio(membio, m_impl->key))
354 NDN_THROW(Error(
"Cannot convert key to PKCS #1 format"));
356 auto buffer = make_shared<Buffer>(BIO_pending(membio));
357 if (!membio.read(*buffer))
358 NDN_THROW(Error(
"Read error during PKCS #1 conversion"));
364 PrivateKey::toPkcs8(
const char* pw,
size_t pwLen)
const
366 BOOST_ASSERT(std::strlen(pw) == pwLen);
369 detail::Bio membio(BIO_s_mem());
370 if (!i2d_PKCS8PrivateKey_bio(membio, m_impl->key, EVP_aes_256_cbc(),
nullptr, 0,
371 nullptr,
const_cast<char*
>(pw)))
372 NDN_THROW(Error(
"Cannot convert key to PKCS #8 format"));
374 auto buffer = make_shared<Buffer>(BIO_pending(membio));
375 if (!membio.read(*buffer))
376 NDN_THROW(Error(
"Read error during PKCS #8 conversion"));
382 PrivateKey::toPkcs8(PasswordCallback pwCallback)
const
386 detail::Bio membio(BIO_s_mem());
387 if (!i2d_PKCS8PrivateKey_bio(membio, m_impl->key, EVP_aes_256_cbc(),
nullptr, 0,
388 &passwordCallbackWrapper, &pwCallback))
389 NDN_THROW(Error(
"Cannot convert key to PKCS #8 format"));
391 auto buffer = make_shared<Buffer>(BIO_pending(membio));
392 if (!membio.read(*buffer))
393 NDN_THROW(Error(
"Read error during PKCS #8 conversion"));
399 PrivateKey::rsaDecrypt(span<const uint8_t> cipherText)
const
401 detail::EvpPkeyCtx ctx(m_impl->key);
403 if (EVP_PKEY_decrypt_init(ctx) <= 0)
404 NDN_THROW(Error(
"Failed to initialize decryption context"));
406 if (EVP_PKEY_CTX_set_rsa_padding(ctx, RSA_PKCS1_OAEP_PADDING) <= 0)
407 NDN_THROW(Error(
"Failed to set padding"));
411 if (EVP_PKEY_decrypt(ctx,
nullptr, &outlen, cipherText.data(), cipherText.size()) <= 0)
412 NDN_THROW(Error(
"Failed to estimate output length"));
414 auto out = make_shared<Buffer>(outlen);
415 if (EVP_PKEY_decrypt(ctx, out->data(), &outlen, cipherText.data(), cipherText.size()) <= 0)
416 NDN_THROW(Error(
"Failed to decrypt ciphertext"));
422 unique_ptr<PrivateKey>
423 PrivateKey::generateRsaKey(uint32_t keySize)
425 auto privateKey = make_unique<PrivateKey>();
426 BOOST_ASSERT(privateKey->m_impl->key ==
nullptr);
428 #if OPENSSL_VERSION_NUMBER >= 0x30000000L
429 privateKey->m_impl->key = EVP_RSA_gen(keySize);
431 if (privateKey->m_impl->key ==
nullptr)
432 NDN_THROW(Error(
"Failed to generate RSA key"));
434 detail::EvpPkeyCtx kctx(EVP_PKEY_RSA);
436 if (EVP_PKEY_keygen_init(kctx) <= 0)
437 NDN_THROW(Error(
"Failed to initialize RSA keygen context"));
439 if (EVP_PKEY_CTX_set_rsa_keygen_bits(kctx,
static_cast<int>(keySize)) <= 0)
440 NDN_THROW(Error(
"Failed to set RSA key length"));
442 if (EVP_PKEY_keygen(kctx, &privateKey->m_impl->key) <= 0)
443 NDN_THROW(Error(
"Failed to generate RSA key"));
449 unique_ptr<PrivateKey>
450 PrivateKey::generateEcKey(uint32_t keySize)
452 auto privateKey = make_unique<PrivateKey>();
453 BOOST_ASSERT(privateKey->m_impl->key ==
nullptr);
455 #if OPENSSL_VERSION_NUMBER >= 0x30000000L
461 privateKey->m_impl->key = EVP_EC_gen((
"P-" +
to_string(keySize)).data());
467 if (privateKey->m_impl->key ==
nullptr)
468 NDN_THROW(Error(
"Failed to generate EC key"));
470 EC_KEY* eckey =
nullptr;
473 eckey = EC_KEY_new_by_curve_name(NID_secp224r1);
476 eckey = EC_KEY_new_by_curve_name(NID_X9_62_prime256v1);
479 eckey = EC_KEY_new_by_curve_name(NID_secp384r1);
482 eckey = EC_KEY_new_by_curve_name(NID_secp521r1);
487 if (eckey ==
nullptr) {
488 NDN_THROW(Error(
"Failed to set EC curve"));
491 auto guard = make_scope_exit([eckey] { EC_KEY_free(eckey); });
492 if (EC_KEY_generate_key(eckey) != 1) {
493 NDN_THROW(Error(
"Failed to generate EC key"));
496 privateKey->m_impl->key = EVP_PKEY_new();
497 if (privateKey->m_impl->key ==
nullptr)
498 NDN_THROW(Error(
"Failed to create EVP_PKEY"));
499 if (EVP_PKEY_set1_EC_KEY(privateKey->m_impl->key, eckey) != 1)
500 NDN_THROW(Error(
"Failed to assign EC key"));
506 unique_ptr<PrivateKey>
507 PrivateKey::generateHmacKey(uint32_t keySize)
509 std::vector<uint8_t> rawKey(keySize / 8);
512 auto privateKey = make_unique<PrivateKey>();
516 catch (
const PrivateKey::Error&) {
517 NDN_THROW(PrivateKey::Error(
"Failed to generate HMAC key"));
523 unique_ptr<PrivateKey>
528 const auto& rsaParams =
static_cast<const RsaKeyParams&
>(keyParams);
529 return PrivateKey::generateRsaKey(rsaParams.getKeySize());
532 const auto& ecParams =
static_cast<const EcKeyParams&
>(keyParams);
533 return PrivateKey::generateEcKey(ecParams.getKeySize());
536 const auto& hmacParams =
static_cast<const HmacKeyParams&
>(keyParams);
537 return PrivateKey::generateHmacKey(hmacParams.getKeySize());
540 NDN_THROW(std::invalid_argument(
"Unsupported key type " +
541 boost::lexical_cast<std::string>(keyParams.
getKeyType())));
General-purpose automatically managed/resized buffer.
Base class for key parameters.
KeyType getKeyType() const
An output stream that writes to a Buffer.
std::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.
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.
std::shared_ptr< const Buffer > ConstBufferPtr
#define ENSURE_PRIVATE_KEY_LOADED(key)
#define ENSURE_PRIVATE_KEY_NOT_LOADED(key)