backport EVPPKey file/stream load/save capabilities

This commit is contained in:
Alex Fabijanic
2017-09-19 22:04:32 -05:00
parent dbd82953cb
commit ab90c48da2
55 changed files with 1244 additions and 832 deletions

View File

@@ -30,7 +30,6 @@
#include <vector>
#include <openssl/objects.h>
#include <openssl/ec.h>
#include <openssl/pem.h>
namespace Poco {
@@ -102,16 +101,8 @@ public:
/// key is not exported.
private:
typedef EVP_PKEY* (*PEM_read_bio_Key_fn)(BIO*, EVP_PKEY**, pem_password_cb*, void*);
typedef EVP_PKEY* (*PEM_read_Key_fn)(FILE*, EVP_PKEY**, pem_password_cb*, void*);
static int passCB(char* buf, int size, int, void* pass);
bool loadKey(PEM_read_Key_fn func, const std::string& keyFile, const std::string& pass = "");
bool loadKey(PEM_read_bio_Key_fn func, std::istream* pKeyStream, const std::string& pass = "");
void freeEC();
static ByteVec convertToByteVec(const BIGNUM* bn);
EC_KEY* _pEC;
};
@@ -131,6 +122,28 @@ inline const EC_KEY* ECKeyImpl::getECKey() const
}
inline std::string ECKeyImpl::groupName() const
{
return OBJ_nid2sn(groupId());
}
inline void ECKeyImpl::save(const std::string& publicKeyFile,
const std::string& privateKeyFile,
const std::string& privateKeyPassphrase)
{
EVPPKey(_pEC).save(publicKeyFile, privateKeyFile, privateKeyPassphrase);
}
inline void ECKeyImpl::save(std::ostream* pPublicKeyStream,
std::ostream* pPrivateKeyStream,
const std::string& privateKeyPassphrase)
{
EVPPKey(_pEC).save(pPublicKeyStream, pPrivateKeyStream, privateKeyPassphrase);
}
} } // namespace Poco::Crypto

View File

@@ -21,9 +21,12 @@
#include "Poco/Crypto/Crypto.h"
#include "Poco/Crypto/CryptoException.h"
#include "Poco/StreamCopier.h"
#include <openssl/ec.h>
#include <openssl/rsa.h>
#include <openssl/evp.h>
#include <openssl/pem.h>
#include <sstream>
namespace Poco {
@@ -57,12 +60,23 @@ public:
template<typename K>
explicit EVPPKey(K* pKey): _pEVPPKey(EVP_PKEY_new())
/// Constructs EVPPKey from a "native" key pointer.
/// Constructs EVPPKey from a "native" OpenSSL (RSA or EC_KEY),
/// or a Poco wrapper (RSAKey, ECKey) key pointer.
{
if (!_pEVPPKey) throw OpenSSLException();
setKey(pKey);
}
EVPPKey(const std::string& publicKeyFile, const std::string& privateKeyFile, const std::string& privateKeyPassphrase = "");
/// Creates the EVPPKey, by reading public and private key from the given files and
/// using the given passphrase for the private key. Can only by used for signing if
/// a private key is available.
EVPPKey(std::istream* pPublicKeyStream, std::istream* pPrivateKeyStream, const std::string& privateKeyPassphrase = "");
/// Creates the EVPPKey. Can only by used for signing if pPrivKey
/// is not null. If a private key file is specified, you don't need to
/// specify a public key file. OpenSSL will auto-create it from the private key.
EVPPKey(const EVPPKey& other);
/// Copy constructor.
@@ -80,6 +94,18 @@ public:
~EVPPKey();
/// Destroys the EVPPKey.
void save(const std::string& publicKeyFile, const std::string& privateKeyFile = "", const std::string& privateKeyPassphrase = "");
/// Exports the public and/or private keys to the given files.
///
/// If an empty filename is specified, the corresponding key
/// is not exported.
void save(std::ostream* pPublicKeyStream, std::ostream* pPrivateKeyStream = 0, const std::string& privateKeyPassphrase = "");
/// Exports the public and/or private key to the given streams.
///
/// If a null pointer is passed for a stream, the corresponding
/// key is not exported.
int type() const;
/// Retuns the EVPPKey type NID.
@@ -103,8 +129,118 @@ private:
void setKey(RSAKey* pKey);
void setKey(EC_KEY* pKey);
void setKey(RSA* pKey);
static int passCB(char* buf, int size, int, void* pass);
typedef EVP_PKEY* (*PEM_read_FILE_Key_fn)(FILE*, EVP_PKEY**, pem_password_cb*, void*);
typedef EVP_PKEY* (*PEM_read_BIO_Key_fn)(BIO*, EVP_PKEY**, pem_password_cb*, void*);
typedef void* (*EVP_PKEY_get_Key_fn)(EVP_PKEY* pkey);
// The following load*() functions are used by both native and EVP_PKEY type key
// loading from BIO/FILE.
// When used for EVP key loading, getFunc is null (ie. native key is not extracted
// from the loaded EVP_PKEY).
template <typename K, typename F>
static bool loadKey(K** ppKey,
PEM_read_FILE_Key_fn readFunc,
F getFunc,
const std::string& keyFile,
const std::string& pass = "")
{
poco_assert_dbg (((typeid(K) == typeid(RSA) || typeid(K) == typeid(EC_KEY)) && getFunc) ||
((typeid(K) == typeid(EVP_PKEY)) && !getFunc));
poco_check_ptr (ppKey);
poco_assert_dbg (!*ppKey);
if (!keyFile.empty())
{
if (!getFunc) *ppKey = (K*)EVP_PKEY_new();
EVP_PKEY* pKey = getFunc ? EVP_PKEY_new() : (EVP_PKEY*)*ppKey;
if (pKey)
{
FILE* pFile = fopen(keyFile.c_str(), "r");
if (pFile)
{
readFunc(pFile, &pKey, passCB, pass.empty() ? (void*)0 : (void*)pass.c_str());
fclose(pFile);
if (getFunc)
{
*ppKey = (K*)getFunc(pKey);
EVP_PKEY_free(pKey);
}
else *ppKey = (K*)pKey;
if (!*ppKey) goto error;
return true;
}
else
{
EVP_PKEY_free(pKey);
throw IOException("ECKeyImpl, cannot open file", keyFile);
}
}
else goto error;
}
return false;
error:
throw OpenSSLException("EVPKey::loadKey(string)");
}
template <typename K, typename F>
static bool loadKey(K** ppKey,
PEM_read_BIO_Key_fn readFunc,
F getFunc,
std::istream* pIstr,
const std::string& pass = "")
{
poco_assert_dbg (((typeid(K) == typeid(RSA) || typeid(K) == typeid(EC_KEY)) && getFunc) ||
((typeid(K) == typeid(EVP_PKEY)) && !getFunc));
poco_check_ptr(ppKey);
poco_assert_dbg(!*ppKey);
if (pIstr)
{
std::ostringstream ostr;
Poco::StreamCopier::copyStream(*pIstr, ostr);
std::string key = ostr.str();
BIO *pBIO = BIO_new_mem_buf(const_cast<char*>(key.data()), static_cast<int>(key.size()));
if (pBIO)
{
if (!getFunc) *ppKey = (K*)EVP_PKEY_new();
EVP_PKEY* pKey = getFunc ? EVP_PKEY_new() : (EVP_PKEY*)*ppKey;
if (pKey)
{
if (readFunc(pBIO, &pKey, passCB, pass.empty() ? (void*)0 : (void*)pass.c_str()))
{
BIO_free(pBIO);
if (getFunc)
{
*ppKey = (K*)getFunc(pKey);
EVP_PKEY_free(pKey);
}
else *ppKey = (K*)pKey;
if (!*ppKey) goto error;
return true;
}
goto error;
}
else
{
BIO_free(pBIO);
goto error;
}
}
else goto error;
}
return false;
error:
throw OpenSSLException("EVPKey::loadKey(stream)");
}
EVP_PKEY* _pEVPPKey;
friend class ECKeyImpl;
friend class RSAKeyImpl;
};
//