29 #include "ndn-cxx/security/impl/openssl-helper.hpp" 
   35 #include <boost/lexical_cast.hpp> 
   38 #define ENSURE_PRIVATE_KEY_LOADED(key) \ 
   40     if ((key) == nullptr) \ 
   41       NDN_THROW(Error("Private key has not been loaded yet")); \
 
   44 #define ENSURE_PRIVATE_KEY_NOT_LOADED(key) \ 
   46     if ((key) != nullptr) \ 
   47       NDN_THROW(Error("Private key has already been loaded")); \
 
   55 opensslInitAlgorithms()
 
   57 #if OPENSSL_VERSION_NUMBER < 0x1010000fL 
   58   static bool isInitialized = 
false;
 
   60     OpenSSL_add_all_algorithms();
 
   66 class PrivateKey::Impl : noncopyable
 
   75   EVP_PKEY* key = 
nullptr;
 
   77 #if OPENSSL_VERSION_NUMBER < 0x1010100fL 
   83   : m_impl(make_unique<Impl>())
 
   95   switch (detail::getEvpPkeyType(m_impl->key)) {
 
  113       return static_cast<size_t>(EVP_PKEY_bits(m_impl->key));
 
  115 #if OPENSSL_VERSION_NUMBER >= 0x1010100fL 
  117       EVP_PKEY_get_raw_private_key(m_impl->key, 
nullptr, &nBytes);
 
  120       return m_impl->keySize;
 
  133                     boost::lexical_cast<std::string>(
getKeyType())));
 
  135   const uint8_t* buf = 
nullptr;
 
  137 #if OPENSSL_VERSION_NUMBER >= 0x1010000fL 
  138   buf = EVP_PKEY_get0_hmac(m_impl->key, &len);
 
  140   const auto* octstr = 
reinterpret_cast<ASN1_OCTET_STRING*
>(EVP_PKEY_get0(m_impl->key));
 
  142   len = octstr->length;
 
  162     pkeyType = EVP_PKEY_HMAC;
 
  165     NDN_THROW(std::invalid_argument(
"Unsupported key type " + boost::lexical_cast<std::string>(type)));
 
  169 #if OPENSSL_VERSION_NUMBER >= 0x1010100fL 
  170       EVP_PKEY_new_raw_private_key(pkeyType, 
nullptr, buf.data(), buf.size());
 
  172       EVP_PKEY_new_mac_key(pkeyType, 
nullptr, buf.data(), 
static_cast<int>(buf.size()));
 
  174   if (m_impl->key == 
nullptr)
 
  177 #if OPENSSL_VERSION_NUMBER < 0x1010100fL 
  178   m_impl->keySize = buf.size() * 8;
 
  186   opensslInitAlgorithms();
 
  188   auto ptr = buf.data();
 
  189   if (d2i_AutoPrivateKey(&m_impl->key, &ptr, 
static_cast<long>(buf.size())) == 
nullptr)
 
  220   BOOST_ASSERT(std::strlen(pw) == pwLen);
 
  222   opensslInitAlgorithms();
 
  224   detail::Bio membio(BIO_s_mem());
 
  225   if (!membio.write(buf))
 
  228   if (d2i_PKCS8PrivateKey_bio(membio, &m_impl->key, 
nullptr, 
const_cast<char*
>(pw)) == 
nullptr)
 
  233 passwordCallbackWrapper(
char* buf, 
int size, 
int rwflag, 
void* u)
 
  235   BOOST_ASSERT(size >= 0);
 
  237   return (*cb)(buf, 
static_cast<size_t>(size), rwflag);
 
  244   opensslInitAlgorithms();
 
  246   detail::Bio membio(BIO_s_mem());
 
  247   if (!membio.write(buf))
 
  251     m_impl->key = d2i_PKCS8PrivateKey_bio(membio, 
nullptr, &passwordCallbackWrapper, &pwCallback);
 
  253     m_impl->key = d2i_PKCS8PrivateKey_bio(membio, 
nullptr, 
nullptr, 
nullptr);
 
  255   if (m_impl->key == 
nullptr)
 
  348   uint8_t* pkcs8 = 
nullptr;
 
  349   int len = i2d_PUBKEY(m_impl->key, &pkcs8);
 
  353   auto result = make_shared<Buffer>(pkcs8, len);
 
  364   int keyType = detail::getEvpPkeyType(m_impl->key);
 
  369       return rsaDecrypt(cipherText);
 
  376 PrivateKey::getEvpPkey()
 const 
  382 PrivateKey::toPkcs1()
 const 
  385   opensslInitAlgorithms();
 
  387   detail::Bio membio(BIO_s_mem());
 
  388   if (!i2d_PrivateKey_bio(membio, m_impl->key))
 
  389     NDN_THROW(Error(
"Cannot convert key to PKCS #1 format"));
 
  391   auto buffer = make_shared<Buffer>(BIO_pending(membio));
 
  392   if (!membio.read(*buffer))
 
  393     NDN_THROW(Error(
"Read error during PKCS #1 conversion"));
 
  399 PrivateKey::toPkcs8(
const char* pw, 
size_t pwLen)
 const 
  401   BOOST_ASSERT(std::strlen(pw) == pwLen);
 
  403   opensslInitAlgorithms();
 
  405   detail::Bio membio(BIO_s_mem());
 
  406   if (!i2d_PKCS8PrivateKey_bio(membio, m_impl->key, EVP_aes_256_cbc(), 
nullptr, 0,
 
  407                                nullptr, 
const_cast<char*
>(pw)))
 
  408     NDN_THROW(Error(
"Cannot convert key to PKCS #8 format"));
 
  410   auto buffer = make_shared<Buffer>(BIO_pending(membio));
 
  411   if (!membio.read(*buffer))
 
  412     NDN_THROW(Error(
"Read error during PKCS #8 conversion"));
 
  418 PrivateKey::toPkcs8(PasswordCallback pwCallback)
 const 
  421   opensslInitAlgorithms();
 
  423   detail::Bio membio(BIO_s_mem());
 
  424   if (!i2d_PKCS8PrivateKey_bio(membio, m_impl->key, EVP_aes_256_cbc(), 
nullptr, 0,
 
  425                                &passwordCallbackWrapper, &pwCallback))
 
  426     NDN_THROW(Error(
"Cannot convert key to PKCS #8 format"));
 
  428   auto buffer = make_shared<Buffer>(BIO_pending(membio));
 
  429   if (!membio.read(*buffer))
 
  430     NDN_THROW(Error(
"Read error during PKCS #8 conversion"));
 
  436 PrivateKey::rsaDecrypt(span<const uint8_t> cipherText)
 const 
  438   detail::EvpPkeyCtx ctx(m_impl->key);
 
  440   if (EVP_PKEY_decrypt_init(ctx) <= 0)
 
  441     NDN_THROW(Error(
"Failed to initialize decryption context"));
 
  443   if (EVP_PKEY_CTX_set_rsa_padding(ctx, RSA_PKCS1_OAEP_PADDING) <= 0)
 
  444     NDN_THROW(Error(
"Failed to set padding"));
 
  448   if (EVP_PKEY_decrypt(ctx, 
nullptr, &outlen, cipherText.data(), cipherText.size()) <= 0)
 
  449     NDN_THROW(Error(
"Failed to estimate output length"));
 
  451   auto out = make_shared<Buffer>(outlen);
 
  452   if (EVP_PKEY_decrypt(ctx, out->data(), &outlen, cipherText.data(), cipherText.size()) <= 0)
 
  453     NDN_THROW(Error(
"Failed to decrypt ciphertext"));
 
  459 unique_ptr<PrivateKey>
 
  460 PrivateKey::generateRsaKey(uint32_t keySize)
 
  462   detail::EvpPkeyCtx kctx(EVP_PKEY_RSA);
 
  464   if (EVP_PKEY_keygen_init(kctx) <= 0)
 
  465     NDN_THROW(PrivateKey::Error(
"Failed to initialize RSA keygen context"));
 
  467   if (EVP_PKEY_CTX_set_rsa_keygen_bits(kctx, 
static_cast<int>(keySize)) <= 0)
 
  468     NDN_THROW(PrivateKey::Error(
"Failed to set RSA key length"));
 
  470   auto privateKey = make_unique<PrivateKey>();
 
  471   if (EVP_PKEY_keygen(kctx, &privateKey->m_impl->key) <= 0)
 
  472     NDN_THROW(PrivateKey::Error(
"Failed to generate RSA key"));
 
  477 unique_ptr<PrivateKey>
 
  478 PrivateKey::generateEcKey(uint32_t keySize)
 
  480   EC_KEY* eckey = 
nullptr;
 
  483     eckey = EC_KEY_new_by_curve_name(NID_secp224r1);
 
  486     eckey = EC_KEY_new_by_curve_name(NID_X9_62_prime256v1); 
 
  489     eckey = EC_KEY_new_by_curve_name(NID_secp384r1);
 
  492     eckey = EC_KEY_new_by_curve_name(NID_secp521r1);
 
  497   if (eckey == 
nullptr) {
 
  498     NDN_THROW(Error(
"Failed to set EC curve"));
 
  501   auto guard = make_scope_exit([eckey] { EC_KEY_free(eckey); });
 
  503 #if OPENSSL_VERSION_NUMBER < 0x1010000fL 
  504   EC_KEY_set_asn1_flag(eckey, OPENSSL_EC_NAMED_CURVE);
 
  507   if (EC_KEY_generate_key(eckey) != 1) {
 
  508     NDN_THROW(Error(
"Failed to generate EC key"));
 
  511   auto privateKey = make_unique<PrivateKey>();
 
  512   privateKey->m_impl->key = EVP_PKEY_new();
 
  513   if (privateKey->m_impl->key == 
nullptr)
 
  514     NDN_THROW(Error(
"Failed to create EVP_PKEY"));
 
  515   if (EVP_PKEY_set1_EC_KEY(privateKey->m_impl->key, eckey) != 1)
 
  516     NDN_THROW(Error(
"Failed to assign EC key"));
 
  521 unique_ptr<PrivateKey>
 
  522 PrivateKey::generateHmacKey(uint32_t keySize)
 
  524   std::vector<uint8_t> rawKey(keySize / 8);
 
  527   auto privateKey = make_unique<PrivateKey>();
 
  531   catch (
const PrivateKey::Error&) {
 
  532     NDN_THROW(PrivateKey::Error(
"Failed to generate HMAC key"));
 
  538 unique_ptr<PrivateKey>
 
  543       const auto& rsaParams = 
static_cast<const RsaKeyParams&
>(keyParams);
 
  544       return PrivateKey::generateRsaKey(rsaParams.getKeySize());
 
  547       const auto& ecParams = 
static_cast<const EcKeyParams&
>(keyParams);
 
  548       return PrivateKey::generateEcKey(ecParams.getKeySize());
 
  551       const auto& hmacParams = 
static_cast<const HmacKeyParams&
>(keyParams);
 
  552       return PrivateKey::generateHmacKey(hmacParams.getKeySize());
 
  555       NDN_THROW(std::invalid_argument(
"Unsupported key type " +
 
  556                                       boost::lexical_cast<std::string>(keyParams.
getKeyType())));
 
Base class for key parameters.
 
KeyType getKeyType() const
 
implements an output stream that constructs ndn::Buffer
 
shared_ptr< Buffer > buf()
Flush written data to the stream and return 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)