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)