security: simplify PrivateKey implementation and improve error handling
Change-Id: I3270e4e9fe3dd942caab6bbe0b17db678b64648b
diff --git a/src/security/detail/openssl-helper.cpp b/src/security/detail/openssl-helper.cpp
index 8f8422a..12d1106 100644
--- a/src/security/detail/openssl-helper.cpp
+++ b/src/security/detail/openssl-helper.cpp
@@ -1,6 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
-/**
- * Copyright (c) 2013-2016 Regents of the University of California.
+/*
+ * Copyright (c) 2013-2017 Regents of the University of California.
*
* This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
*
@@ -36,26 +36,18 @@
}
}
-EvpPkey::EvpPkey()
- : m_key(nullptr)
-{
-}
-
-EvpPkey::~EvpPkey()
-{
- EVP_PKEY_free(m_key);
-}
-
EvpPkeyCtx::EvpPkeyCtx(EVP_PKEY* key)
: m_ctx(EVP_PKEY_CTX_new(key, nullptr))
{
- BOOST_ASSERT(m_ctx != nullptr);
+ if (m_ctx == nullptr)
+ BOOST_THROW_EXCEPTION(std::runtime_error("EVP_PKEY_CTX creation failed"));
}
EvpPkeyCtx::EvpPkeyCtx(int id)
: m_ctx(EVP_PKEY_CTX_new_id(id, nullptr))
{
- BOOST_ASSERT(m_ctx != nullptr);
+ if (m_ctx == nullptr)
+ BOOST_THROW_EXCEPTION(std::runtime_error("EVP_PKEY_CTX creation failed"));
}
EvpPkeyCtx::~EvpPkeyCtx()
@@ -63,14 +55,11 @@
EVP_PKEY_CTX_free(m_ctx);
}
-#if OPENSSL_VERSION_NUMBER < 0x1010000fL
-Bio::Bio(BIO_METHOD* method)
-#else
-Bio::Bio(const BIO_METHOD* method)
-#endif // OPENSSL_VERSION_NUMBER < 0x1010000fL
+Bio::Bio(Bio::MethodPtr method)
: m_bio(BIO_new(method))
{
- BOOST_ASSERT(m_bio != nullptr);
+ if (m_bio == nullptr)
+ BOOST_THROW_EXCEPTION(std::runtime_error("BIO creation failed"));
}
Bio::~Bio()
@@ -78,6 +67,22 @@
BIO_free_all(m_bio);
}
+bool
+Bio::read(uint8_t* buf, size_t buflen) const noexcept
+{
+ BOOST_ASSERT(buflen <= std::numeric_limits<int>::max());
+ int n = BIO_read(m_bio, buf, static_cast<int>(buflen));
+ return n >= 0 && static_cast<size_t>(n) == buflen;
+}
+
+bool
+Bio::write(const uint8_t* buf, size_t buflen) noexcept
+{
+ BOOST_ASSERT(buflen <= std::numeric_limits<int>::max());
+ int n = BIO_write(m_bio, buf, static_cast<int>(buflen));
+ return n >= 0 && static_cast<size_t>(n) == buflen;
+}
+
} // namespace detail
} // namespace security
} // namespace ndn
diff --git a/src/security/detail/openssl-helper.hpp b/src/security/detail/openssl-helper.hpp
index 50f21bc..ddd1ea6 100644
--- a/src/security/detail/openssl-helper.hpp
+++ b/src/security/detail/openssl-helper.hpp
@@ -1,6 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
-/**
- * Copyright (c) 2013-2016 Regents of the University of California.
+/*
+ * Copyright (c) 2013-2017 Regents of the University of California.
*
* This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
*
@@ -22,8 +22,8 @@
#ifndef NDN_CXX_SECURITY_DETAIL_OPENSSL_HELPER_HPP
#define NDN_CXX_SECURITY_DETAIL_OPENSSL_HELPER_HPP
-#include "../security-common.hpp"
#include "openssl.hpp"
+#include "../security-common.hpp"
namespace ndn {
namespace security {
@@ -32,30 +32,7 @@
const EVP_MD*
toDigestEvpMd(DigestAlgorithm algo);
-class EvpPkey
-{
-public:
- EvpPkey();
-
- ~EvpPkey();
-
- EVP_PKEY*
- get() const
- {
- return m_key;
- }
-
- EVP_PKEY**
- operator&()
- {
- return &m_key;
- }
-
-private:
- EVP_PKEY* m_key;
-};
-
-class EvpPkeyCtx
+class EvpPkeyCtx : noncopyable
{
public:
explicit
@@ -66,8 +43,7 @@
~EvpPkeyCtx();
- EVP_PKEY_CTX*
- get() const
+ operator EVP_PKEY_CTX*() const
{
return m_ctx;
}
@@ -76,24 +52,31 @@
EVP_PKEY_CTX* m_ctx;
};
-class Bio
+class Bio : noncopyable
{
public:
- explicit
#if OPENSSL_VERSION_NUMBER < 0x1010000fL
- Bio(BIO_METHOD* method);
+ using MethodPtr = BIO_METHOD*;
#else
- Bio(const BIO_METHOD* method);
+ using MethodPtr = const BIO_METHOD*;
#endif // OPENSSL_VERSION_NUMBER < 0x1010000fL
+ explicit
+ Bio(MethodPtr method);
+
~Bio();
- BIO*
- get() const
+ operator BIO*() const
{
return m_bio;
}
+ bool
+ read(uint8_t* buf, size_t buflen) const noexcept;
+
+ bool
+ write(const uint8_t* buf, size_t buflen) noexcept;
+
private:
BIO* m_bio;
};
diff --git a/src/security/transform/private-key.cpp b/src/security/transform/private-key.cpp
index c67d3d9..17251c4 100644
--- a/src/security/transform/private-key.cpp
+++ b/src/security/transform/private-key.cpp
@@ -29,14 +29,21 @@
#include "../key-params.hpp"
#include "../../encoding/buffer-stream.hpp"
+#include <boost/lexical_cast.hpp>
#include <cstring>
#define ENSURE_PRIVATE_KEY_LOADED(key) \
do { \
- if (key == nullptr) \
+ if ((key) == nullptr) \
BOOST_THROW_EXCEPTION(Error("Private key has not been loaded yet")); \
} while (false)
+#define ENSURE_PRIVATE_KEY_NOT_LOADED(key) \
+ do { \
+ if ((key) != nullptr) \
+ BOOST_THROW_EXCEPTION(Error("Private key has already been loaded")); \
+ } while (false)
+
namespace ndn {
namespace security {
namespace transform {
@@ -56,7 +63,7 @@
class PrivateKey::Impl
{
public:
- Impl()
+ Impl() noexcept
: key(nullptr)
{
}
@@ -71,7 +78,7 @@
};
PrivateKey::PrivateKey()
- : m_impl(new Impl)
+ : m_impl(make_unique<Impl>())
{
}
@@ -80,12 +87,11 @@
void
PrivateKey::loadPkcs1(const uint8_t* buf, size_t size)
{
- detail::Bio mem(BIO_s_mem());
- BIO_write(mem.get(), buf, size);
+ ENSURE_PRIVATE_KEY_NOT_LOADED(m_impl->key);
+ opensslInitAlgorithms();
- d2i_PrivateKey_bio(mem.get(), &m_impl->key);
-
- ENSURE_PRIVATE_KEY_LOADED(m_impl->key);
+ if (d2i_AutoPrivateKey(&m_impl->key, &buf, static_cast<long>(size)) == nullptr)
+ BOOST_THROW_EXCEPTION(Error("Failed to load private key"));
}
void
@@ -116,18 +122,19 @@
PrivateKey::loadPkcs8(const uint8_t* buf, size_t size, const char* pw, size_t pwLen)
{
BOOST_ASSERT(std::strlen(pw) == pwLen);
+ ENSURE_PRIVATE_KEY_NOT_LOADED(m_impl->key);
opensslInitAlgorithms();
- detail::Bio mem(BIO_s_mem());
- BIO_write(mem.get(), buf, size);
+ detail::Bio membio(BIO_s_mem());
+ if (!membio.write(buf, size))
+ BOOST_THROW_EXCEPTION(Error("Failed to copy buffer"));
- m_impl->key = d2i_PKCS8PrivateKey_bio(mem.get(), &m_impl->key, nullptr, const_cast<char*>(pw));
-
- ENSURE_PRIVATE_KEY_LOADED(m_impl->key);
+ if (d2i_PKCS8PrivateKey_bio(membio, &m_impl->key, nullptr, const_cast<char*>(pw)) == nullptr)
+ BOOST_THROW_EXCEPTION(Error("Failed to load private key"));
}
static inline int
-passwordCallback(char* buf, int size, int rwflag, void* u)
+passwordCallbackWrapper(char* buf, int size, int rwflag, void* u)
{
BOOST_ASSERT(size >= 0);
auto cb = reinterpret_cast<PrivateKey::PasswordCallback*>(u);
@@ -137,17 +144,20 @@
void
PrivateKey::loadPkcs8(const uint8_t* buf, size_t size, PasswordCallback pwCallback)
{
+ ENSURE_PRIVATE_KEY_NOT_LOADED(m_impl->key);
opensslInitAlgorithms();
- detail::Bio mem(BIO_s_mem());
- BIO_write(mem.get(), buf, size);
+ detail::Bio membio(BIO_s_mem());
+ if (!membio.write(buf, size))
+ BOOST_THROW_EXCEPTION(Error("Failed to copy buffer"));
if (pwCallback)
- m_impl->key = d2i_PKCS8PrivateKey_bio(mem.get(), &m_impl->key, passwordCallback, &pwCallback);
+ m_impl->key = d2i_PKCS8PrivateKey_bio(membio, nullptr, &passwordCallbackWrapper, &pwCallback);
else
- m_impl->key = d2i_PKCS8PrivateKey_bio(mem.get(), &m_impl->key, nullptr, nullptr);
+ m_impl->key = d2i_PKCS8PrivateKey_bio(membio, nullptr, nullptr, nullptr);
- ENSURE_PRIVATE_KEY_LOADED(m_impl->key);
+ if (m_impl->key == nullptr)
+ BOOST_THROW_EXCEPTION(Error("Failed to load private key"));
}
void
@@ -241,8 +251,7 @@
uint8_t* pkcs8 = nullptr;
int len = i2d_PUBKEY(m_impl->key, &pkcs8);
-
- if (len <= 0)
+ if (len < 0)
BOOST_THROW_EXCEPTION(Error("Failed to derive public key"));
auto result = make_shared<Buffer>(pkcs8, len);
@@ -256,15 +265,20 @@
{
ENSURE_PRIVATE_KEY_LOADED(m_impl->key);
+ int keyType =
#if OPENSSL_VERSION_NUMBER < 0x1010000fL
- switch (EVP_PKEY_type(m_impl->key->type)) {
+ EVP_PKEY_type(m_impl->key->type);
#else
- switch (EVP_PKEY_base_id(m_impl->key)) {
+ EVP_PKEY_base_id(m_impl->key);
#endif // OPENSSL_VERSION_NUMBER < 0x1010000fL
+
+ switch (keyType) {
+ case EVP_PKEY_NONE:
+ BOOST_THROW_EXCEPTION(Error("Failed to determine key type"));
case EVP_PKEY_RSA:
return rsaDecrypt(cipherText, cipherLen);
default:
- BOOST_THROW_EXCEPTION(Error("Decryption is not supported for this key type"));
+ BOOST_THROW_EXCEPTION(Error("Decryption is not supported for key type " + to_string(keyType)));
}
}
@@ -280,14 +294,12 @@
ENSURE_PRIVATE_KEY_LOADED(m_impl->key);
opensslInitAlgorithms();
- detail::Bio mem(BIO_s_mem());
- int ret = i2d_PrivateKey_bio(mem.get(), m_impl->key);
- if (ret != 1)
- BOOST_THROW_EXCEPTION(Error("Cannot convert key into PKCS1 format"));
+ detail::Bio membio(BIO_s_mem());
+ if (!i2d_PrivateKey_bio(membio, m_impl->key))
+ BOOST_THROW_EXCEPTION(Error("Cannot convert key to PKCS #1 format"));
- int len8 = BIO_pending(mem.get());
- auto buffer = make_shared<Buffer>(len8);
- BIO_read(mem.get(), buffer->buf(), len8);
+ auto buffer = make_shared<Buffer>(BIO_pending(membio));
+ membio.read(buffer->buf(), buffer->size());
return buffer;
}
@@ -299,15 +311,13 @@
ENSURE_PRIVATE_KEY_LOADED(m_impl->key);
opensslInitAlgorithms();
- detail::Bio mem(BIO_s_mem());
- int ret = i2d_PKCS8PrivateKey_bio(mem.get(), m_impl->key, EVP_des_cbc(),
- const_cast<char*>(pw), pwLen, nullptr, nullptr);
- if (ret != 1)
- BOOST_THROW_EXCEPTION(Error("Cannot convert key into PKCS8 format"));
+ detail::Bio membio(BIO_s_mem());
+ if (!i2d_PKCS8PrivateKey_bio(membio, m_impl->key, EVP_des_cbc(), nullptr, 0,
+ nullptr, const_cast<char*>(pw)))
+ BOOST_THROW_EXCEPTION(Error("Cannot convert key to PKCS #8 format"));
- int len8 = BIO_pending(mem.get());
- auto buffer = make_shared<Buffer>(len8);
- BIO_read(mem.get(), buffer->buf(), len8);
+ auto buffer = make_shared<Buffer>(BIO_pending(membio));
+ membio.read(buffer->buf(), buffer->size());
return buffer;
}
@@ -318,16 +328,13 @@
ENSURE_PRIVATE_KEY_LOADED(m_impl->key);
opensslInitAlgorithms();
- detail::Bio mem(BIO_s_mem());
- int ret = i2d_PKCS8PrivateKey_bio(mem.get(), m_impl->key, EVP_des_cbc(),
- nullptr, 0,
- passwordCallback, &pwCallback);
- if (ret != 1)
- BOOST_THROW_EXCEPTION(Error("Cannot convert key into PKCS8 format"));
+ detail::Bio membio(BIO_s_mem());
+ if (!i2d_PKCS8PrivateKey_bio(membio, m_impl->key, EVP_des_cbc(), nullptr, 0,
+ &passwordCallbackWrapper, &pwCallback))
+ BOOST_THROW_EXCEPTION(Error("Cannot convert key to PKCS #8 format"));
- int len8 = BIO_pending(mem.get());
- auto buffer = make_shared<Buffer>(len8);
- BIO_read(mem.get(), buffer->buf(), len8);
+ auto buffer = make_shared<Buffer>(BIO_pending(membio));
+ membio.read(buffer->buf(), buffer->size());
return buffer;
}
@@ -337,101 +344,76 @@
{
detail::EvpPkeyCtx ctx(m_impl->key);
- if (EVP_PKEY_decrypt_init(ctx.get()) <= 0)
+ if (EVP_PKEY_decrypt_init(ctx) <= 0)
BOOST_THROW_EXCEPTION(Error("Failed to initialize decryption context"));
- if (EVP_PKEY_CTX_set_rsa_padding(ctx.get(), RSA_PKCS1_OAEP_PADDING) <= 0)
+ if (EVP_PKEY_CTX_set_rsa_padding(ctx, RSA_PKCS1_OAEP_PADDING) <= 0)
BOOST_THROW_EXCEPTION(Error("Failed to set padding"));
size_t outlen = 0;
// Determine buffer length
- if (EVP_PKEY_decrypt(ctx.get(), nullptr, &outlen, cipherText, cipherLen) <= 0)
+ if (EVP_PKEY_decrypt(ctx, nullptr, &outlen, cipherText, cipherLen) <= 0)
BOOST_THROW_EXCEPTION(Error("Failed to estimate output length"));
auto out = make_shared<Buffer>(outlen);
-
- if (EVP_PKEY_decrypt(ctx.get(), out->buf(), &outlen, cipherText, cipherLen) <= 0)
- BOOST_THROW_EXCEPTION(Error("Failed to decrypt cipher text"));
+ if (EVP_PKEY_decrypt(ctx, out->buf(), &outlen, cipherText, cipherLen) <= 0)
+ BOOST_THROW_EXCEPTION(Error("Failed to decrypt ciphertext"));
out->resize(outlen);
return out;
}
-static unique_ptr<PrivateKey>
-generateRsaKey(uint32_t keySize)
+unique_ptr<PrivateKey>
+PrivateKey::generateRsaKey(uint32_t keySize)
{
detail::EvpPkeyCtx kctx(EVP_PKEY_RSA);
- int ret = EVP_PKEY_keygen_init(kctx.get());
- if (ret != 1)
- BOOST_THROW_EXCEPTION(PrivateKey::Error("Fail to generate RSA key"));
+ if (EVP_PKEY_keygen_init(kctx) <= 0)
+ BOOST_THROW_EXCEPTION(PrivateKey::Error("Failed to initialize RSA keygen context"));
- ret = EVP_PKEY_CTX_set_rsa_keygen_bits(kctx.get(), keySize);
- if (ret != 1)
- BOOST_THROW_EXCEPTION(PrivateKey::Error("Fail to generate RSA key"));
-
- detail::EvpPkey key;
- ret = EVP_PKEY_keygen(kctx.get(), &key);
- if (ret != 1)
- BOOST_THROW_EXCEPTION(PrivateKey::Error("Fail to generate RSA key"));
-
- detail::Bio mem(BIO_s_mem());
- i2d_PrivateKey_bio(mem.get(), key.get());
- int len = BIO_pending(mem.get());
- Buffer buffer(len);
- BIO_read(mem.get(), buffer.buf(), len);
+ if (EVP_PKEY_CTX_set_rsa_keygen_bits(kctx, static_cast<int>(keySize)) <= 0)
+ BOOST_THROW_EXCEPTION(PrivateKey::Error("Failed to set RSA key length"));
auto privateKey = make_unique<PrivateKey>();
- privateKey->loadPkcs1(buffer.buf(), buffer.size());
+ if (EVP_PKEY_keygen(kctx, &privateKey->m_impl->key) <= 0)
+ BOOST_THROW_EXCEPTION(PrivateKey::Error("Failed to generate RSA key"));
return privateKey;
}
-static unique_ptr<PrivateKey>
-generateEcKey(uint32_t keySize)
+unique_ptr<PrivateKey>
+PrivateKey::generateEcKey(uint32_t keySize)
{
- detail::EvpPkeyCtx ctx(EVP_PKEY_EC);
+ detail::EvpPkeyCtx pctx(EVP_PKEY_EC);
- int ret = EVP_PKEY_paramgen_init(ctx.get());
- if (ret != 1)
- BOOST_THROW_EXCEPTION(PrivateKey::Error("Fail to generate EC key"));
+ if (EVP_PKEY_paramgen_init(pctx) <= 0)
+ BOOST_THROW_EXCEPTION(PrivateKey::Error("Failed to initialize EC paramgen context"));
+ int ret;
switch (keySize) {
case 256:
- ret = EVP_PKEY_CTX_set_ec_paramgen_curve_nid(ctx.get(), NID_X9_62_prime256v1);
+ ret = EVP_PKEY_CTX_set_ec_paramgen_curve_nid(pctx, NID_X9_62_prime256v1); // same as secp256r1
break;
case 384:
- ret = EVP_PKEY_CTX_set_ec_paramgen_curve_nid(ctx.get(), NID_secp384r1);
+ ret = EVP_PKEY_CTX_set_ec_paramgen_curve_nid(pctx, NID_secp384r1);
break;
default:
- BOOST_THROW_EXCEPTION(PrivateKey::Error("Fail to generate EC key"));
+ BOOST_THROW_EXCEPTION(PrivateKey::Error("Unsupported EC key length"));
}
- if (ret != 1)
- BOOST_THROW_EXCEPTION(PrivateKey::Error("Fail to generate EC key"));
+ if (ret <= 0)
+ BOOST_THROW_EXCEPTION(PrivateKey::Error("Failed to set EC curve"));
- detail::EvpPkey params;
- ret = EVP_PKEY_paramgen(ctx.get(), ¶ms);
- if (ret != 1)
- BOOST_THROW_EXCEPTION(PrivateKey::Error("Fail to generate EC key"));
+ Impl params;
+ if (EVP_PKEY_paramgen(pctx, ¶ms.key) <= 0)
+ BOOST_THROW_EXCEPTION(PrivateKey::Error("Failed to generate EC parameters"));
- detail::EvpPkeyCtx kctx(params.get());
- ret = EVP_PKEY_keygen_init(kctx.get());
- if (ret != 1)
- BOOST_THROW_EXCEPTION(PrivateKey::Error("Fail to generate EC key"));
-
- detail::EvpPkey key;
- ret = EVP_PKEY_keygen(kctx.get(), &key);
- if (ret != 1)
- BOOST_THROW_EXCEPTION(PrivateKey::Error("Fail to generate EC key"));
-
- detail::Bio mem(BIO_s_mem());
- i2d_PrivateKey_bio(mem.get(), key.get());
- int len = BIO_pending(mem.get());
- Buffer buffer(len);
- BIO_read(mem.get(), buffer.buf(), len);
+ detail::EvpPkeyCtx kctx(params.key);
+ if (EVP_PKEY_keygen_init(kctx) <= 0)
+ BOOST_THROW_EXCEPTION(PrivateKey::Error("Failed to initialize EC keygen context"));
auto privateKey = make_unique<PrivateKey>();
- privateKey->loadPkcs1(buffer.buf(), buffer.size());
+ if (EVP_PKEY_keygen(kctx, &privateKey->m_impl->key) <= 0)
+ BOOST_THROW_EXCEPTION(PrivateKey::Error("Failed to generate EC key"));
return privateKey;
}
@@ -442,14 +424,15 @@
switch (keyParams.getKeyType()) {
case KeyType::RSA: {
const RsaKeyParams& rsaParams = static_cast<const RsaKeyParams&>(keyParams);
- return generateRsaKey(rsaParams.getKeySize());
+ return PrivateKey::generateRsaKey(rsaParams.getKeySize());
}
case KeyType::EC: {
const EcKeyParams& ecParams = static_cast<const EcKeyParams&>(keyParams);
- return generateEcKey(ecParams.getKeySize());
+ return PrivateKey::generateEcKey(ecParams.getKeySize());
}
default:
- BOOST_THROW_EXCEPTION(std::invalid_argument("Unsupported asymmetric key type"));
+ BOOST_THROW_EXCEPTION(std::invalid_argument("Unsupported asymmetric key type " +
+ boost::lexical_cast<std::string>(keyParams.getKeyType())));
}
}
diff --git a/src/security/transform/private-key.hpp b/src/security/transform/private-key.hpp
index 500386b..98f5bd6 100644
--- a/src/security/transform/private-key.hpp
+++ b/src/security/transform/private-key.hpp
@@ -22,7 +22,6 @@
#ifndef NDN_CXX_SECURITY_TRANSFORM_PRIVATE_KEY_HPP
#define NDN_CXX_SECURITY_TRANSFORM_PRIVATE_KEY_HPP
-#include "public-key.hpp"
#include "../../encoding/buffer.hpp"
namespace ndn {
@@ -48,8 +47,6 @@
}
};
- friend class SignerFilter;
-
/**
* @brief Callback for application to handle password input
*
@@ -62,9 +59,9 @@
public:
/**
- * @brief Create a private key instance
+ * @brief Create an empty private key instance
*
- * One must call loadXXXX(...) to load private key.
+ * One must call loadXXXX(...) to load a private key.
*/
PrivateKey();
@@ -96,7 +93,6 @@
/**
* @brief Load the private key in encrypted PKCS#8 format from a buffer @p buf with passphrase @p pw
- *
* @pre strlen(pw) == pwLen
*/
void
@@ -113,7 +109,6 @@
/**
* @brief Load the private key in encrypted PKCS#8 format from a stream @p is with passphrase @p pw
- *
* @pre strlen(pw) == pwLen
*/
void
@@ -131,7 +126,6 @@
/**
* @brief Load the private key in base64-encoded encrypted PKCS#8 format from a buffer @p buf
* with passphrase @p pw
- *
* @pre strlen(pw) == pwLen
*/
void
@@ -149,7 +143,6 @@
/**
* @brief Load the private key in base64-encoded encrypted PKCS#8 format from a stream @p is
* with passphrase @p pw
- *
* @pre strlen(pw) == pwLen
*/
void
@@ -213,7 +206,7 @@
derivePublicKey() const;
/**
- * @return Plain text of @p cipherText decrypted using the private key.
+ * @return Plain text of @p cipherText decrypted using this private key.
*
* Only RSA encryption is supported for now.
*/
@@ -221,10 +214,12 @@
decrypt(const uint8_t* cipherText, size_t cipherLen) const;
private:
+ friend class SignerFilter;
+
/**
- * @return A pointer to an EVP_PKEY instance.
+ * @return A pointer to an OpenSSL EVP_PKEY instance.
*
- * One need to explicitly cast the return value to EVP_PKEY*.
+ * The caller needs to explicitly cast the return value to `EVP_PKEY*`.
*/
void*
getEvpPkey() const;
@@ -243,17 +238,26 @@
rsaDecrypt(const uint8_t* cipherText, size_t cipherLen) const;
private:
+ friend unique_ptr<PrivateKey> generatePrivateKey(const KeyParams&);
+
+ static unique_ptr<PrivateKey>
+ generateRsaKey(uint32_t keySize);
+
+ static unique_ptr<PrivateKey>
+ generateEcKey(uint32_t keySize);
+
+private:
class Impl;
const unique_ptr<Impl> m_impl;
};
/**
- * @brief generate a private key according to @p keyParams.
+ * @brief Generate a private key according to @p keyParams
*
- * @note the public key can be derived from the private key
+ * @note The public key can be derived from the private key.
*
- * @throw std::argument_error if the key type is not supported
- * @throw std::runtime_error when failing to generate the key
+ * @throw std::invalid_argument the specified key type is not supported
+ * @throw std::runtime_error key generation fails
*/
unique_ptr<PrivateKey>
generatePrivateKey(const KeyParams& keyParams);
diff --git a/src/security/transform/public-key.cpp b/src/security/transform/public-key.cpp
index 82edd13..c17fdc0 100644
--- a/src/security/transform/public-key.cpp
+++ b/src/security/transform/public-key.cpp
@@ -1,5 +1,5 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
-/**
+/*
* Copyright (c) 2013-2017 Regents of the University of California.
*
* This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
@@ -141,15 +141,20 @@
{
ENSURE_PUBLIC_KEY_LOADED(m_impl->key);
+ int keyType =
#if OPENSSL_VERSION_NUMBER < 0x1010000fL
- switch (EVP_PKEY_type(m_impl->key->type)) {
+ EVP_PKEY_type(m_impl->key->type);
#else
- switch (EVP_PKEY_base_id(m_impl->key)) {
+ EVP_PKEY_base_id(m_impl->key);
#endif // OPENSSL_VERSION_NUMBER < 0x1010000fL
- case EVP_PKEY_RSA:
- return rsaEncrypt(plainText, plainLen);
- default:
- BOOST_THROW_EXCEPTION(Error("Encryption is not supported for this key type"));
+
+ switch (keyType) {
+ case EVP_PKEY_NONE:
+ BOOST_THROW_EXCEPTION(Error("Failed to determine key type"));
+ case EVP_PKEY_RSA:
+ return rsaEncrypt(plainText, plainLen);
+ default:
+ BOOST_THROW_EXCEPTION(Error("Encryption is not supported for key type " + to_string(keyType)));
}
}
@@ -181,20 +186,20 @@
{
detail::EvpPkeyCtx ctx(m_impl->key);
- if (EVP_PKEY_encrypt_init(ctx.get()) <= 0)
+ if (EVP_PKEY_encrypt_init(ctx) <= 0)
BOOST_THROW_EXCEPTION(Error("Failed to initialize encryption context"));
- if (EVP_PKEY_CTX_set_rsa_padding(ctx.get(), RSA_PKCS1_OAEP_PADDING) <= 0)
+ if (EVP_PKEY_CTX_set_rsa_padding(ctx, RSA_PKCS1_OAEP_PADDING) <= 0)
BOOST_THROW_EXCEPTION(Error("Failed to set padding"));
size_t outlen = 0;
// Determine buffer length
- if (EVP_PKEY_encrypt(ctx.get(), nullptr, &outlen, plainText, plainLen) <= 0)
+ if (EVP_PKEY_encrypt(ctx, nullptr, &outlen, plainText, plainLen) <= 0)
BOOST_THROW_EXCEPTION(Error("Failed to estimate output length"));
auto out = make_shared<Buffer>(outlen);
- if (EVP_PKEY_encrypt(ctx.get(), out->buf(), &outlen, plainText, plainLen) <= 0)
+ if (EVP_PKEY_encrypt(ctx, out->buf(), &outlen, plainText, plainLen) <= 0)
BOOST_THROW_EXCEPTION(Error("Failed to encrypt plaintext"));
out->resize(outlen);