security: insert OpenSSL initialization call in PrivateKey::loadPkcs8
Change-Id: I71dc0c3ac71fa5db4f3be8ce51aea06e4cf7c088
Refs: #4204
diff --git a/src/security/transform/private-key.cpp b/src/security/transform/private-key.cpp
index 9cad918..c67d3d9 100644
--- a/src/security/transform/private-key.cpp
+++ b/src/security/transform/private-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).
@@ -41,6 +41,18 @@
namespace security {
namespace transform {
+static void
+opensslInitAlgorithms()
+{
+#if OPENSSL_VERSION_NUMBER < 0x1010000fL
+ static bool isInitialized = false;
+ if (!isInitialized) {
+ OpenSSL_add_all_algorithms();
+ isInitialized = true;
+ }
+#endif // OPENSSL_VERSION_NUMBER < 0x1010000fL
+}
+
class PrivateKey::Impl
{
public:
@@ -104,6 +116,7 @@
PrivateKey::loadPkcs8(const uint8_t* buf, size_t size, const char* pw, size_t pwLen)
{
BOOST_ASSERT(std::strlen(pw) == pwLen);
+ opensslInitAlgorithms();
detail::Bio mem(BIO_s_mem());
BIO_write(mem.get(), buf, size);
@@ -116,14 +129,16 @@
static inline int
passwordCallback(char* buf, int size, int rwflag, void* u)
{
+ BOOST_ASSERT(size >= 0);
auto cb = reinterpret_cast<PrivateKey::PasswordCallback*>(u);
- return (*cb)(buf, size, rwflag);
+ return (*cb)(buf, static_cast<size_t>(size), rwflag);
}
void
PrivateKey::loadPkcs8(const uint8_t* buf, size_t size, PasswordCallback pwCallback)
{
- OpenSSL_add_all_algorithms();
+ opensslInitAlgorithms();
+
detail::Bio mem(BIO_s_mem());
BIO_write(mem.get(), buf, size);
@@ -246,10 +261,10 @@
#else
switch (EVP_PKEY_base_id(m_impl->key)) {
#endif // OPENSSL_VERSION_NUMBER < 0x1010000fL
- case EVP_PKEY_RSA:
- return rsaDecrypt(cipherText, cipherLen);
- default:
- BOOST_THROW_EXCEPTION(Error("Decryption is not supported for this key type"));
+ case EVP_PKEY_RSA:
+ return rsaDecrypt(cipherText, cipherLen);
+ default:
+ BOOST_THROW_EXCEPTION(Error("Decryption is not supported for this key type"));
}
}
@@ -263,8 +278,8 @@
PrivateKey::toPkcs1() const
{
ENSURE_PRIVATE_KEY_LOADED(m_impl->key);
+ opensslInitAlgorithms();
- OpenSSL_add_all_algorithms();
detail::Bio mem(BIO_s_mem());
int ret = i2d_PrivateKey_bio(mem.get(), m_impl->key);
if (ret != 1)
@@ -280,11 +295,10 @@
ConstBufferPtr
PrivateKey::toPkcs8(const char* pw, size_t pwLen) const
{
- ENSURE_PRIVATE_KEY_LOADED(m_impl->key);
-
BOOST_ASSERT(std::strlen(pw) == pwLen);
+ ENSURE_PRIVATE_KEY_LOADED(m_impl->key);
+ opensslInitAlgorithms();
- OpenSSL_add_all_algorithms();
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);
@@ -302,8 +316,8 @@
PrivateKey::toPkcs8(PasswordCallback pwCallback) const
{
ENSURE_PRIVATE_KEY_LOADED(m_impl->key);
+ opensslInitAlgorithms();
- OpenSSL_add_all_algorithms();
detail::Bio mem(BIO_s_mem());
int ret = i2d_PKCS8PrivateKey_bio(mem.get(), m_impl->key, EVP_des_cbc(),
nullptr, 0,
diff --git a/src/security/transform/private-key.hpp b/src/security/transform/private-key.hpp
index 3eb1d7a..500386b 100644
--- a/src/security/transform/private-key.hpp
+++ b/src/security/transform/private-key.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).
@@ -53,9 +53,10 @@
/**
* @brief Callback for application to handle password input
*
- * Password should be stored in @p buf and should not be longer than @p size. It is
- * recommended to ask the user to verify the passphrase if @p shouldConfirm is true, e.g., by
- * prompting for the password twice.
+ * The password must be written to @p buf and must not be longer than @p bufSize chars.
+ * It is recommended to ask the user to verify the password if @p shouldConfirm is true,
+ * e.g., by prompting for it twice. The callback must return the number of characters
+ * in the password or 0 if an error occurred.
*/
typedef function<int(char* buf, size_t bufSize, bool shouldConfirm)> PasswordCallback;
diff --git a/tests/unit-tests/security/transform/private-key.t.cpp b/tests/unit-tests/security/transform/private-key.t.cpp
index d1ab196..49a5ea1 100644
--- a/tests/unit-tests/security/transform/private-key.t.cpp
+++ b/tests/unit-tests/security/transform/private-key.t.cpp
@@ -25,7 +25,7 @@
#include "encoding/buffer-stream.hpp"
#include "boost-test.hpp"
-#include <boost/mpl/list.hpp>
+#include <boost/mpl/vector.hpp>
#include <sstream>
@@ -158,27 +158,25 @@
std::string publicKeyPkcs8;
};
-typedef boost::mpl::list<RsaKeyTestData,
- EcKeyTestData> KeyTestDataSets;
+using KeyTestDataSets = boost::mpl::vector<RsaKeyTestData, EcKeyTestData>;
-void
+static void
checkPkcs8Encoding(ConstBufferPtr encoding, const std::string& password, ConstBufferPtr pkcs1)
{
PrivateKey sKey;
- BOOST_REQUIRE_NO_THROW(sKey.loadPkcs8(encoding->buf(), encoding->size(),
- password.c_str(), password.size()));
+ sKey.loadPkcs8(encoding->buf(), encoding->size(), password.c_str(), password.size());
OBufferStream os;
- BOOST_REQUIRE_NO_THROW(sKey.savePkcs1(os));
+ sKey.savePkcs1(os);
ConstBufferPtr keyPkcs1Str = os.buf();
- BOOST_CHECK_EQUAL_COLLECTIONS(pkcs1->begin(), pkcs1->end(), keyPkcs1Str->begin(), keyPkcs1Str->end());
+ BOOST_CHECK_EQUAL_COLLECTIONS(pkcs1->begin(), pkcs1->end(),
+ keyPkcs1Str->begin(), keyPkcs1Str->end());
}
-void
+static void
checkPkcs8Base64Encoding(ConstBufferPtr encoding, const std::string& password, ConstBufferPtr pkcs1)
{
OBufferStream os;
bufferSource(*encoding) >> base64Decode() >> streamSink(os);
-
checkPkcs8Encoding(os.buf(), password, pkcs1);
}
@@ -195,7 +193,7 @@
const uint8_t* sKeyPkcs1 = sKeyPkcs1Buf->buf();
size_t sKeyPkcs1Len = sKeyPkcs1Buf->size();
- // load key in base64 encoded pkcs1 format
+ // load key in base64-encoded pkcs1 format
PrivateKey sKey;
BOOST_REQUIRE_NO_THROW(sKey.loadPkcs1Base64(sKeyPkcs1Base64, sKeyPkcs1Base64Len));
@@ -212,7 +210,7 @@
PrivateKey sKey4;
BOOST_REQUIRE_NO_THROW(sKey4.loadPkcs1(ss4));
- // save key in base64 encoded pkcs1 format
+ // save key in base64-encoded pkcs1 format
OBufferStream os2;
BOOST_REQUIRE_NO_THROW(sKey.savePkcs1Base64(os2));
ConstBufferPtr keyPkcs1Base64Str = os2.buf();
@@ -239,13 +237,13 @@
std::string password("password");
std::string wrongpw("wrongpw");
- auto pwCallback = [&] (char* buf, size_t size, int rwflag) -> int {
+ auto pwCallback = [&password] (char* buf, size_t size, int) -> int {
+ BOOST_REQUIRE_LE(password.size(), size);
std::copy(password.begin(), password.end(), buf);
- return password.size();
+ return static_cast<int>(password.size());
};
-
- // load key in base64 encoded pkcs8 format
+ // load key in base64-encoded pkcs8 format
PrivateKey sKey5;
BOOST_REQUIRE_NO_THROW(sKey5.loadPkcs8Base64(sKeyPkcs8Base64, sKeyPkcs8Base64Len,
password.c_str(), password.size()));
@@ -281,10 +279,11 @@
// load key using wrong password, Error is expected.
PrivateKey sKey13;
- BOOST_REQUIRE_THROW(sKey13.loadPkcs8Base64(sKeyPkcs8Base64, sKeyPkcs8Base64Len, wrongpw.c_str(), wrongpw.size()),
- PrivateKey::Error);
+ BOOST_CHECK_THROW(sKey13.loadPkcs8Base64(sKeyPkcs8Base64, sKeyPkcs8Base64Len,
+ wrongpw.c_str(), wrongpw.size()),
+ PrivateKey::Error);
- // save key in base64 encoded pkcs8 format
+ // save key in base64-encoded pkcs8 format
OBufferStream os14;
BOOST_REQUIRE_NO_THROW(sKey.savePkcs8Base64(os14, password.c_str(), password.size()));
ConstBufferPtr encoded14 = os14.buf();
@@ -377,10 +376,9 @@
decryptText->begin(), decryptText->end());
}
-typedef boost::mpl::list<RsaKeyParams,
- EcKeyParams> TestKeyParams;
+using KeyParams = boost::mpl::vector<RsaKeyParams, EcKeyParams>;
-BOOST_AUTO_TEST_CASE_TEMPLATE(GenerateKey, T, TestKeyParams)
+BOOST_AUTO_TEST_CASE_TEMPLATE(GenerateKey, T, KeyParams)
{
BOOST_REQUIRE_NO_THROW(generatePrivateKey(T()));
@@ -389,8 +387,7 @@
ConstBufferPtr pKeyBits = sKey->derivePublicKey();
pKey.loadPkcs8(pKeyBits->buf(), pKeyBits->size());
- uint8_t data[] = {0x01, 0x02, 0x03, 0x04};
-
+ const uint8_t data[] = {0x01, 0x02, 0x03, 0x04};
OBufferStream os;
BOOST_REQUIRE_NO_THROW(bufferSource(data, sizeof(data)) >>
signerFilter(DigestAlgorithm::SHA256, *sKey) >>
@@ -401,10 +398,8 @@
BOOST_REQUIRE_NO_THROW(bufferSource(data, sizeof(data)) >>
verifierFilter(DigestAlgorithm::SHA256, pKey, sig->buf(), sig->size()) >>
boolSink(result));
-
BOOST_CHECK(result);
-
unique_ptr<PrivateKey> sKey2 = generatePrivateKey(T());
OBufferStream os1;