security: add PrivateKey::loadRaw() for HMAC keys
Refs: #3075
Change-Id: I535a0e1ec2a48fba0e1dccc4b77ea9900a61a464
diff --git a/.mailmap b/.mailmap
index 60170e7..967715e 100644
--- a/.mailmap
+++ b/.mailmap
@@ -5,3 +5,4 @@
Teng Liang <philoliang2011@gmail.com>
<lybmath2009@gmail.com> <lybmath@ucla.edu>
Hila Ben Abraham <hilata@gmail.com>
+Laqin Fan <flq12021@gmail.com>
diff --git a/ndn-cxx/security/transform/private-key.cpp b/ndn-cxx/security/transform/private-key.cpp
index f4029d3..e6fa54c 100644
--- a/ndn-cxx/security/transform/private-key.cpp
+++ b/ndn-cxx/security/transform/private-key.cpp
@@ -99,6 +99,32 @@
}
void
+PrivateKey::loadRaw(KeyType type, const uint8_t* buf, size_t size)
+{
+ ENSURE_PRIVATE_KEY_NOT_LOADED(m_impl->key);
+
+ int pkeyType;
+ switch (type) {
+ case KeyType::HMAC:
+ pkeyType = EVP_PKEY_HMAC;
+ break;
+ default:
+ NDN_THROW(std::invalid_argument("Unsupported key type " + boost::lexical_cast<std::string>(type)));
+ }
+
+ m_impl->key =
+#if OPENSSL_VERSION_NUMBER >= 0x1010100fL
+ EVP_PKEY_new_raw_private_key(pkeyType, nullptr, buf, size);
+#else
+ EVP_PKEY_new_mac_key(pkeyType, nullptr, buf, static_cast<int>(size));
+#endif
+ if (m_impl->key == nullptr)
+ NDN_THROW(Error("Failed to load private key"));
+
+ m_keySize = size * 8;
+}
+
+void
PrivateKey::loadPkcs1(const uint8_t* buf, size_t size)
{
ENSURE_PRIVATE_KEY_NOT_LOADED(m_impl->key);
@@ -441,16 +467,13 @@
random::generateSecureBytes(rawKey.data(), rawKey.size());
auto privateKey = make_unique<PrivateKey>();
- privateKey->m_impl->key =
-#if OPENSSL_VERSION_NUMBER >= 0x1010100fL
- EVP_PKEY_new_raw_private_key(EVP_PKEY_HMAC, nullptr, rawKey.data(), rawKey.size());
-#else
- EVP_PKEY_new_mac_key(EVP_PKEY_HMAC, nullptr, rawKey.data(), static_cast<int>(rawKey.size()));
-#endif
- if (privateKey->m_impl->key == nullptr)
+ try {
+ privateKey->loadRaw(KeyType::HMAC, rawKey.data(), rawKey.size());
+ }
+ catch (const PrivateKey::Error&) {
NDN_THROW(PrivateKey::Error("Failed to generate HMAC key"));
+ }
- privateKey->m_keySize = keySize;
return privateKey;
}
@@ -471,7 +494,7 @@
return PrivateKey::generateHmacKey(hmacParams.getKeySize());
}
default:
- NDN_THROW(std::invalid_argument("Unsupported asymmetric key type " +
+ NDN_THROW(std::invalid_argument("Unsupported key type " +
boost::lexical_cast<std::string>(keyParams.getKeyType())));
}
}
diff --git a/ndn-cxx/security/transform/private-key.hpp b/ndn-cxx/security/transform/private-key.hpp
index d3ae45c..d16a59a 100644
--- a/ndn-cxx/security/transform/private-key.hpp
+++ b/ndn-cxx/security/transform/private-key.hpp
@@ -74,7 +74,8 @@
* @brief Get the size of the private key in bits
*
* @note The return value is meaningful only if the PrivateKey was created via
- * generatePrivateKey(), otherwise this function will always return zero.
+ * generatePrivateKey() or loaded via loadRaw(), otherwise this function
+ * will always return zero.
*/
size_t
getKeySize() const
@@ -83,6 +84,14 @@
}
/**
+ * @brief Load a raw private key from a buffer @p buf
+ *
+ * @note Currently supports only HMAC keys.
+ */
+ void
+ loadRaw(KeyType type, const uint8_t* buf, size_t size);
+
+ /**
* @brief Load the private key in PKCS#1 format from a buffer @p buf
*/
void
diff --git a/ndn-cxx/security/transform/signer-filter.cpp b/ndn-cxx/security/transform/signer-filter.cpp
index ddaf4cd..3c0535d 100644
--- a/ndn-cxx/security/transform/signer-filter.cpp
+++ b/ndn-cxx/security/transform/signer-filter.cpp
@@ -48,7 +48,7 @@
size_t mdSize = static_cast<size_t>(EVP_MD_size(md)) * 8;
if (key.getKeySize() < mdSize)
NDN_THROW(Error(getIndex(), "HMAC key is shorter than the digest output (" +
- to_string(key.getKeySize()) + " < " + to_string(mdSize) + ")"));
+ to_string(key.getKeySize()) + " < " + to_string(mdSize) + " bits)"));
}
if (EVP_DigestSignInit(m_impl->ctx, nullptr, md, nullptr,
diff --git a/ndn-cxx/security/verification-helpers.hpp b/ndn-cxx/security/verification-helpers.hpp
index b864e3d..c3c848a 100644
--- a/ndn-cxx/security/verification-helpers.hpp
+++ b/ndn-cxx/security/verification-helpers.hpp
@@ -52,6 +52,7 @@
/**
* @brief Verify @p blob using @p key against @p sig.
+ * @note @p key must be a public key in PKCS #8 format.
*/
bool
verifySignature(const uint8_t* blob, size_t blobLen, const uint8_t* sig, size_t sigLen,
@@ -59,12 +60,14 @@
/**
* @brief Verify @p data using @p key.
+ * @note @p key must be a public key in PKCS #8 format.
*/
bool
verifySignature(const Data& data, const uint8_t* key, size_t keyLen);
/**
* @brief Verify @p interest using @p key.
+ * @note @p key must be a public key in PKCS #8 format.
* @note This method verifies only signature of the signed interest.
* @sa docs/specs/signed-interest.rst
*/
diff --git a/tests/unit/security/transform/private-key.t.cpp b/tests/unit/security/transform/private-key.t.cpp
index de1d9b2..673f551 100644
--- a/tests/unit/security/transform/private-key.t.cpp
+++ b/tests/unit/security/transform/private-key.t.cpp
@@ -47,6 +47,21 @@
BOOST_AUTO_TEST_SUITE(Transform)
BOOST_AUTO_TEST_SUITE(TestPrivateKey)
+BOOST_AUTO_TEST_CASE(LoadRaw)
+{
+ const Buffer buf(32);
+ PrivateKey sKey;
+ sKey.loadRaw(KeyType::HMAC, buf.data(), buf.size());
+ BOOST_CHECK_EQUAL(sKey.getKeyType(), KeyType::HMAC);
+ BOOST_CHECK_EQUAL(sKey.getKeySize(), 256);
+
+ PrivateKey sKey2;
+ BOOST_CHECK_THROW(sKey2.loadRaw(KeyType::NONE, buf.data(), buf.size()), std::invalid_argument);
+ BOOST_CHECK_THROW(sKey2.loadRaw(KeyType::RSA, buf.data(), buf.size()), std::invalid_argument);
+ BOOST_CHECK_THROW(sKey2.loadRaw(KeyType::EC, buf.data(), buf.size()), std::invalid_argument);
+ BOOST_CHECK_THROW(sKey2.loadRaw(KeyType::AES, buf.data(), buf.size()), std::invalid_argument);
+}
+
struct RsaKeyTestData
{
const std::string privateKeyPkcs1 =