security: use EVP_DigestSign* routines in SignerFilter
Change-Id: Ib87c4681084bf0389de527450a2248fe2161e6ee
diff --git a/src/security/transform/private-key.cpp b/src/security/transform/private-key.cpp
index 3ec0ff6..8139a0f 100644
--- a/src/security/transform/private-key.cpp
+++ b/src/security/transform/private-key.cpp
@@ -84,6 +84,22 @@
PrivateKey::~PrivateKey() = default;
+KeyType
+PrivateKey::getKeyType() const
+{
+ if (!m_impl->key)
+ return KeyType::NONE;
+
+ switch (detail::getEvpPkeyType(m_impl->key)) {
+ case EVP_PKEY_RSA:
+ return KeyType::RSA;
+ case EVP_PKEY_EC:
+ return KeyType::EC;
+ default:
+ return KeyType::NONE;
+ }
+}
+
void
PrivateKey::loadPkcs1(const uint8_t* buf, size_t size)
{
diff --git a/src/security/transform/private-key.hpp b/src/security/transform/private-key.hpp
index 98f5bd6..17d582b 100644
--- a/src/security/transform/private-key.hpp
+++ b/src/security/transform/private-key.hpp
@@ -22,6 +22,7 @@
#ifndef NDN_CXX_SECURITY_TRANSFORM_PRIVATE_KEY_HPP
#define NDN_CXX_SECURITY_TRANSFORM_PRIVATE_KEY_HPP
+#include "../security-common.hpp"
#include "../../encoding/buffer.hpp"
namespace ndn {
@@ -68,6 +69,12 @@
~PrivateKey();
/**
+ * @brief Get the type of the private key
+ */
+ KeyType
+ getKeyType() const;
+
+ /**
* @brief Load the private key in PKCS#1 format from a buffer @p buf
*/
void
diff --git a/src/security/transform/public-key.cpp b/src/security/transform/public-key.cpp
index 13b8f00..16dd3d1 100644
--- a/src/security/transform/public-key.cpp
+++ b/src/security/transform/public-key.cpp
@@ -71,7 +71,8 @@
KeyType
PublicKey::getKeyType() const
{
- ENSURE_PUBLIC_KEY_LOADED(m_impl->key);
+ if (!m_impl->key)
+ return KeyType::NONE;
switch (detail::getEvpPkeyType(m_impl->key)) {
case EVP_PKEY_RSA:
diff --git a/src/security/transform/signer-filter.cpp b/src/security/transform/signer-filter.cpp
index ab9fdb3..959723c 100644
--- a/src/security/transform/signer-filter.cpp
+++ b/src/security/transform/signer-filter.cpp
@@ -20,6 +20,7 @@
*/
#include "signer-filter.hpp"
+#include "private-key.hpp"
#include "../detail/openssl-helper.hpp"
#include <boost/lexical_cast.hpp>
@@ -31,66 +32,65 @@
class SignerFilter::Impl
{
public:
- Impl(const PrivateKey& key)
- : m_key(key)
- , m_md(BIO_new(BIO_f_md()))
- , m_sink(BIO_new(BIO_s_null()))
+ Impl() noexcept
{
- BIO_push(m_md, m_sink);
+#if OPENSSL_VERSION_NUMBER < 0x1010000fL
+ ctx = EVP_MD_CTX_create();
+#else
+ ctx = EVP_MD_CTX_new();
+#endif
}
~Impl()
{
- BIO_free_all(m_md);
+#if OPENSSL_VERSION_NUMBER < 0x1010000fL
+ EVP_MD_CTX_destroy(ctx);
+#else
+ EVP_MD_CTX_free(ctx);
+#endif
}
public:
- const PrivateKey& m_key;
-
- BIO* m_md;
- BIO* m_sink;
+ EVP_MD_CTX* ctx;
};
+
SignerFilter::SignerFilter(DigestAlgorithm algo, const PrivateKey& key)
- : m_impl(new Impl(key))
+ : m_impl(make_unique<Impl>())
{
const EVP_MD* md = detail::digestAlgorithmToEvpMd(algo);
if (md == nullptr)
BOOST_THROW_EXCEPTION(Error(getIndex(), "Unsupported digest algorithm " +
boost::lexical_cast<std::string>(algo)));
- if (!BIO_set_md(m_impl->m_md, md))
- BOOST_THROW_EXCEPTION(Error(getIndex(), "Cannot set digest " +
- boost::lexical_cast<std::string>(algo)));
+ if (EVP_DigestSignInit(m_impl->ctx, nullptr, md, nullptr,
+ reinterpret_cast<EVP_PKEY*>(key.getEvpPkey())) != 1)
+ BOOST_THROW_EXCEPTION(Error(getIndex(), "Failed to initialize signing context with " +
+ boost::lexical_cast<std::string>(algo) + " digest and " +
+ boost::lexical_cast<std::string>(key.getKeyType()) + " key"));
}
+SignerFilter::~SignerFilter() = default;
+
size_t
SignerFilter::convert(const uint8_t* buf, size_t size)
{
- int wLen = BIO_write(m_impl->m_md, buf, size);
+ if (EVP_DigestSignUpdate(m_impl->ctx, buf, size) != 1)
+ BOOST_THROW_EXCEPTION(Error(getIndex(), "Failed to accept more input"));
- if (wLen <= 0) { // fail to write data
- if (!BIO_should_retry(m_impl->m_md)) {
- // we haven't written everything but some error happens, and we cannot retry
- BOOST_THROW_EXCEPTION(Error(getIndex(), "Failed to accept more input"));
- }
- return 0;
- }
- else { // update number of bytes written
- return wLen;
- }
+ return size;
}
void
SignerFilter::finalize()
{
- EVP_PKEY* key = reinterpret_cast<EVP_PKEY*>(m_impl->m_key.getEvpPkey());
- auto buffer = make_unique<OBuffer>(EVP_PKEY_size(key));
- unsigned int sigLen = 0;
+ size_t sigLen = 0;
+ if (EVP_DigestSignFinal(m_impl->ctx, nullptr, &sigLen) != 1)
+ BOOST_THROW_EXCEPTION(Error(getIndex(), "Failed to estimate buffer length"));
- EVP_MD_CTX* ctx = nullptr;
- BIO_get_md_ctx(m_impl->m_md, &ctx);
- EVP_SignFinal(ctx, &(*buffer)[0], &sigLen, key); // should be ok, enough space is allocated in buffer
+ auto buffer = make_unique<OBuffer>(sigLen);
+ if (EVP_DigestSignFinal(m_impl->ctx, buffer->data(), &sigLen) != 1)
+ BOOST_THROW_EXCEPTION(Error(getIndex(), "Failed to finalize signature"));
buffer->erase(buffer->begin() + sigLen, buffer->end());
setOutputBuffer(std::move(buffer));
diff --git a/src/security/transform/signer-filter.hpp b/src/security/transform/signer-filter.hpp
index a6d06c5..fda45f1 100644
--- a/src/security/transform/signer-filter.hpp
+++ b/src/security/transform/signer-filter.hpp
@@ -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).
@@ -23,13 +23,14 @@
#define NDN_CXX_SECURITY_TRANSFORM_SIGNER_FILTER_HPP
#include "transform-base.hpp"
-#include "private-key.hpp"
#include "../security-common.hpp"
namespace ndn {
namespace security {
namespace transform {
+class PrivateKey;
+
/**
* @brief The module to sign data.
*/
@@ -37,10 +38,12 @@
{
public:
/**
- * @brief Create a signer module to generate signature using algorithm @p algo and @p key
+ * @brief Create a module to sign using digest algorithm @p algo and private key @p key
*/
SignerFilter(DigestAlgorithm algo, const PrivateKey& key);
+ ~SignerFilter();
+
private:
/**
* @brief Write data @p buf into signer
diff --git a/tests/unit-tests/security/transform/private-key.t.cpp b/tests/unit-tests/security/transform/private-key.t.cpp
index 539f3b1..6a6ba93 100644
--- a/tests/unit-tests/security/transform/private-key.t.cpp
+++ b/tests/unit-tests/security/transform/private-key.t.cpp
@@ -295,6 +295,7 @@
PrivateKey sKey;
sKey.loadPkcs1Base64(reinterpret_cast<const uint8_t*>(dataSet.privateKeyPkcs1.c_str()),
dataSet.privateKeyPkcs1.size());
+ BOOST_CHECK_EQUAL(sKey.getKeyType(), KeyType::RSA);
const uint8_t plainText[] = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07};
@@ -320,10 +321,12 @@
PublicKey pKey;
pKey.loadPkcs8Base64(reinterpret_cast<const uint8_t*>(dataSet.publicKeyPkcs8.c_str()),
dataSet.publicKeyPkcs8.size());
+ BOOST_CHECK_EQUAL(pKey.getKeyType(), KeyType::RSA);
PrivateKey sKey;
sKey.loadPkcs1Base64(reinterpret_cast<const uint8_t*>(dataSet.privateKeyPkcs1.c_str()),
dataSet.privateKeyPkcs1.size());
+ BOOST_CHECK_EQUAL(sKey.getKeyType(), KeyType::RSA);
const uint8_t plainText[] = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07};
@@ -340,6 +343,7 @@
PrivateKey sKey;
sKey.loadPkcs1Base64(reinterpret_cast<const uint8_t*>(dataSet.privateKeyPkcs1.c_str()),
dataSet.privateKeyPkcs1.size());
+ BOOST_CHECK_EQUAL(sKey.getKeyType(), KeyType::EC);
OBufferStream os;
bufferSource("Y2lhbyFob2xhIWhlbGxvIQ==") >> base64Decode() >> streamSink(os);
diff --git a/tests/unit-tests/security/transform/public-key.t.cpp b/tests/unit-tests/security/transform/public-key.t.cpp
index 41b0582..fee246f 100644
--- a/tests/unit-tests/security/transform/public-key.t.cpp
+++ b/tests/unit-tests/security/transform/public-key.t.cpp
@@ -114,6 +114,7 @@
PublicKey pKey;
pKey.loadPkcs8Base64(reinterpret_cast<const uint8_t*>(dataSet.publicKeyPkcs8.c_str()),
dataSet.publicKeyPkcs8.size());
+ BOOST_CHECK_EQUAL(pKey.getKeyType(), KeyType::EC);
OBufferStream os;
bufferSource("Y2lhbyFob2xhIWhlbGxvIQ==") >> base64Decode() >> streamSink(os);
diff --git a/tests/unit-tests/security/transform/signer-filter.t.cpp b/tests/unit-tests/security/transform/signer-filter.t.cpp
index f041e12..450f9ff 100644
--- a/tests/unit-tests/security/transform/signer-filter.t.cpp
+++ b/tests/unit-tests/security/transform/signer-filter.t.cpp
@@ -24,6 +24,7 @@
#include "encoding/buffer-stream.hpp"
#include "security/transform/base64-decode.hpp"
#include "security/transform/buffer-source.hpp"
+#include "security/transform/private-key.hpp"
#include "security/transform/stream-sink.hpp"
#include "security/verification-helpers.hpp"
@@ -83,6 +84,8 @@
PrivateKey sKey;
sKey.loadPkcs1Base64(reinterpret_cast<const uint8_t*>(privateKeyPkcs1.data()), privateKeyPkcs1.size());
+ BOOST_CHECK_THROW(SignerFilter(DigestAlgorithm::NONE, sKey), Error);
+
OBufferStream os2;
bufferSource(data, sizeof(data)) >> signerFilter(DigestAlgorithm::SHA256, sKey) >> streamSink(os2);
auto sig = os2.buf();
@@ -118,6 +121,8 @@
PrivateKey sKey;
sKey.loadPkcs1Base64(reinterpret_cast<const uint8_t*>(privateKeyPkcs1.data()), privateKeyPkcs1.size());
+ BOOST_CHECK_THROW(SignerFilter(DigestAlgorithm::NONE, sKey), Error);
+
OBufferStream os2;
bufferSource(data, sizeof(data)) >> signerFilter(DigestAlgorithm::SHA256, sKey) >> streamSink(os2);
auto sig = os2.buf();
@@ -125,6 +130,12 @@
BOOST_CHECK(verifySignature(data, sizeof(data), sig->buf(), sig->size(), pubKey->buf(), pubKey->size()));
}
+BOOST_AUTO_TEST_CASE(InvalidKey)
+{
+ PrivateKey sKey;
+ BOOST_CHECK_THROW(SignerFilter(DigestAlgorithm::SHA256, sKey), Error);
+}
+
BOOST_AUTO_TEST_SUITE_END() // TestSignerFilter
BOOST_AUTO_TEST_SUITE_END() // Transform
BOOST_AUTO_TEST_SUITE_END() // Security
diff --git a/tests/unit-tests/security/transform/verifier-filter.t.cpp b/tests/unit-tests/security/transform/verifier-filter.t.cpp
index 98a7c32..a877889 100644
--- a/tests/unit-tests/security/transform/verifier-filter.t.cpp
+++ b/tests/unit-tests/security/transform/verifier-filter.t.cpp
@@ -25,6 +25,7 @@
#include "security/transform/base64-decode.hpp"
#include "security/transform/bool-sink.hpp"
#include "security/transform/buffer-source.hpp"
+#include "security/transform/private-key.hpp"
#include "security/transform/signer-filter.hpp"
#include "security/transform/stream-sink.hpp"