mirror of
https://github.com/pocoproject/poco.git
synced 2025-11-11 00:44:48 +01:00
backport EVPPKey file/stream load/save capabilities
This commit is contained in:
@@ -77,11 +77,11 @@ ECKeyImpl::ECKeyImpl(const std::string& publicKeyFile,
|
||||
const std::string& privateKeyFile,
|
||||
const std::string& privateKeyPassphrase): KeyPairImpl("ec", KT_EC_IMPL), _pEC(0)
|
||||
{
|
||||
if (loadKey(PEM_read_PrivateKey, privateKeyFile, privateKeyPassphrase))
|
||||
if (EVPPKey::loadKey(&_pEC, PEM_read_PrivateKey, EVP_PKEY_get1_EC_KEY, privateKeyFile, privateKeyPassphrase))
|
||||
return; // private key is enough
|
||||
|
||||
// no private key, this must be public key only, otherwise throw
|
||||
if (!loadKey(PEM_read_PUBKEY, publicKeyFile))
|
||||
if (!EVPPKey::loadKey(&_pEC, PEM_read_PUBKEY, EVP_PKEY_get1_EC_KEY, publicKeyFile))
|
||||
{
|
||||
throw OpenSSLException("ECKeyImpl(const string&, const string&, const string&");
|
||||
}
|
||||
@@ -92,11 +92,11 @@ ECKeyImpl::ECKeyImpl(std::istream* pPublicKeyStream,
|
||||
std::istream* pPrivateKeyStream,
|
||||
const std::string& privateKeyPassphrase): KeyPairImpl("ec", KT_EC_IMPL), _pEC(0)
|
||||
{
|
||||
if (loadKey(PEM_read_bio_PrivateKey, pPrivateKeyStream, privateKeyPassphrase))
|
||||
if (EVPPKey::loadKey(&_pEC, PEM_read_bio_PrivateKey, EVP_PKEY_get1_EC_KEY, pPrivateKeyStream, privateKeyPassphrase))
|
||||
return; // private key is enough
|
||||
|
||||
// no private key, this must be public key only, otherwise throw
|
||||
if (!loadKey(PEM_read_bio_PUBKEY, pPublicKeyStream))
|
||||
if (!EVPPKey::loadKey(&_pEC, PEM_read_bio_PUBKEY, EVP_PKEY_get1_EC_KEY, pPublicKeyStream))
|
||||
{
|
||||
throw OpenSSLException("ECKeyImpl(istream*, istream*, const string&");
|
||||
}
|
||||
@@ -119,84 +119,6 @@ void ECKeyImpl::freeEC()
|
||||
}
|
||||
|
||||
|
||||
int ECKeyImpl::passCB(char* buf, int size, int, void* pass)
|
||||
{
|
||||
int len = (int) strlen((char*)pass);
|
||||
if (len > size) len = size;
|
||||
memcpy(buf, pass, len);
|
||||
return len;
|
||||
}
|
||||
|
||||
|
||||
bool ECKeyImpl::loadKey(PEM_read_Key_fn func, const std::string& keyFile, const std::string& pass)
|
||||
{
|
||||
if (!keyFile.empty())
|
||||
{
|
||||
EVP_PKEY* pKey = EVP_PKEY_new();
|
||||
if (pKey)
|
||||
{
|
||||
FILE* pFile = fopen(keyFile.c_str(), "r");
|
||||
if (pFile)
|
||||
{
|
||||
func(pFile, &pKey, passCB, pass.empty() ? (void*)0 : (void*)pass.c_str());
|
||||
_pEC = EVP_PKEY_get1_EC_KEY(pKey);
|
||||
EVP_PKEY_free(pKey);
|
||||
if (!_pEC) goto error;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
EVP_PKEY_free(pKey);
|
||||
throw IOException("ECKeyImpl, cannot open file", keyFile);
|
||||
}
|
||||
}
|
||||
else goto error;
|
||||
}
|
||||
return false;
|
||||
|
||||
error:
|
||||
throw OpenSSLException("ECKeyImpl(const string&, const string&, const string&)");
|
||||
}
|
||||
|
||||
|
||||
bool ECKeyImpl::loadKey(PEM_read_bio_Key_fn func, std::istream* pIstr, const std::string& pass)
|
||||
{
|
||||
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)
|
||||
{
|
||||
EVP_PKEY* pKey = EVP_PKEY_new();
|
||||
if (pKey)
|
||||
{
|
||||
if (func(pBIO, &pKey, passCB, pass.empty() ? (void*)0 : (void*)pass.c_str()))
|
||||
{
|
||||
_pEC = EVP_PKEY_get1_EC_KEY(pKey);
|
||||
EVP_PKEY_free(pKey);
|
||||
BIO_free(pBIO);
|
||||
if (!_pEC) goto error;
|
||||
return true;
|
||||
}
|
||||
goto error;
|
||||
}
|
||||
else
|
||||
{
|
||||
BIO_free(pBIO);
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
else goto error;
|
||||
}
|
||||
return false;
|
||||
|
||||
error:
|
||||
throw OpenSSLException("ECKeyImpl::ECKeyImpl(const string&, const string&, const string&)");
|
||||
}
|
||||
|
||||
|
||||
int ECKeyImpl::size() const
|
||||
{
|
||||
int sz = -1;
|
||||
@@ -211,14 +133,14 @@ int ECKeyImpl::size() const
|
||||
}
|
||||
|
||||
|
||||
std::string ECKeyImpl::groupName() const
|
||||
int ECKeyImpl::groupId() const
|
||||
{
|
||||
if (_pEC)
|
||||
{
|
||||
const EC_GROUP* ecGroup = EC_KEY_get0_group(_pEC);
|
||||
if (ecGroup)
|
||||
{
|
||||
return OBJ_nid2sn(EC_GROUP_get_curve_name(ecGroup));
|
||||
return EC_GROUP_get_curve_name(ecGroup);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -229,129 +151,4 @@ std::string ECKeyImpl::groupName() const
|
||||
}
|
||||
|
||||
|
||||
void ECKeyImpl::save(const std::string& publicKeyFile,
|
||||
const std::string& privateKeyFile,
|
||||
const std::string& privateKeyPassphrase)
|
||||
{
|
||||
if (!publicKeyFile.empty())
|
||||
{
|
||||
BIO* bio = BIO_new(BIO_s_file());
|
||||
if (!bio) throw Poco::IOException("Cannot create BIO for writing public key file", publicKeyFile);
|
||||
try
|
||||
{
|
||||
if (BIO_write_filename(bio, const_cast<char*>(publicKeyFile.c_str())))
|
||||
{
|
||||
EVPPKey pKey(_pEC);
|
||||
if (!PEM_write_bio_PUBKEY(bio, pKey))
|
||||
{
|
||||
throw Poco::WriteFileException("Failed to write public key to file", publicKeyFile);
|
||||
}
|
||||
}
|
||||
else throw Poco::CreateFileException("Cannot create public key file");
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
BIO_free(bio);
|
||||
throw;
|
||||
}
|
||||
BIO_free(bio);
|
||||
}
|
||||
|
||||
if (!privateKeyFile.empty())
|
||||
{
|
||||
BIO* bio = BIO_new(BIO_s_file());
|
||||
if (!bio) throw Poco::IOException("Cannot create BIO for writing private key file", privateKeyFile);
|
||||
try
|
||||
{
|
||||
if (BIO_write_filename(bio, const_cast<char*>(privateKeyFile.c_str())))
|
||||
{
|
||||
EVPPKey pKey(_pEC);
|
||||
int rc = 0;
|
||||
if (privateKeyPassphrase.empty())
|
||||
{
|
||||
rc = PEM_write_bio_PrivateKey(bio, pKey, 0, 0, 0, 0, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
rc = PEM_write_bio_PrivateKey(bio, pKey, EVP_des_ede3_cbc(),
|
||||
reinterpret_cast<unsigned char*>(const_cast<char*>(privateKeyPassphrase.c_str())),
|
||||
static_cast<int>(privateKeyPassphrase.length()), 0, 0);
|
||||
}
|
||||
if (!rc)
|
||||
throw Poco::FileException("Failed to write private key to file", privateKeyFile);
|
||||
}
|
||||
else throw Poco::CreateFileException("Cannot create private key file", privateKeyFile);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
BIO_free(bio);
|
||||
throw;
|
||||
}
|
||||
BIO_free(bio);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void ECKeyImpl::save(std::ostream* pPublicKeyStream,
|
||||
std::ostream* pPrivateKeyStream,
|
||||
const std::string& privateKeyPassphrase)
|
||||
{
|
||||
if (pPublicKeyStream)
|
||||
{
|
||||
BIO* bio = BIO_new(BIO_s_mem());
|
||||
if (!bio) throw Poco::IOException("Cannot create BIO for writing public key");
|
||||
EVPPKey pKey(_pEC);
|
||||
if (!PEM_write_bio_PUBKEY(bio, pKey))
|
||||
{
|
||||
BIO_free(bio);
|
||||
throw Poco::WriteFileException("Failed to write public key to stream");
|
||||
}
|
||||
char* pData;
|
||||
long size = BIO_get_mem_data(bio, &pData);
|
||||
pPublicKeyStream->write(pData, static_cast<std::streamsize>(size));
|
||||
BIO_free(bio);
|
||||
}
|
||||
|
||||
if (pPrivateKeyStream)
|
||||
{
|
||||
BIO* bio = BIO_new(BIO_s_mem());
|
||||
if (!bio) throw Poco::IOException("Cannot create BIO for writing public key");
|
||||
EVPPKey pKey(_pEC);
|
||||
int rc = 0;
|
||||
if (privateKeyPassphrase.empty())
|
||||
rc = PEM_write_bio_PrivateKey(bio, pKey, 0, 0, 0, 0, 0);
|
||||
else
|
||||
rc = PEM_write_bio_PrivateKey(bio, pKey, EVP_des_ede3_cbc(),
|
||||
reinterpret_cast<unsigned char*>(const_cast<char*>(privateKeyPassphrase.c_str())),
|
||||
static_cast<int>(privateKeyPassphrase.length()), 0, 0);
|
||||
if (!rc)
|
||||
{
|
||||
BIO_free(bio);
|
||||
throw Poco::FileException("Failed to write private key to stream");
|
||||
}
|
||||
char* pData;
|
||||
long size = BIO_get_mem_data(bio, &pData);
|
||||
pPrivateKeyStream->write(pData, static_cast<std::streamsize>(size));
|
||||
BIO_free(bio);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
ECKeyImpl::ByteVec ECKeyImpl::convertToByteVec(const BIGNUM* bn)
|
||||
{
|
||||
int numBytes = BN_num_bytes(bn);
|
||||
ByteVec byteVector(numBytes);
|
||||
|
||||
ByteVec::value_type* buffer = new ByteVec::value_type[numBytes];
|
||||
BN_bn2bin(bn, buffer);
|
||||
|
||||
for (int i = 0; i < numBytes; ++i)
|
||||
byteVector[i] = buffer[i];
|
||||
|
||||
delete [] buffer;
|
||||
|
||||
return byteVector;
|
||||
}
|
||||
|
||||
|
||||
} } // namespace Poco::Crypto
|
||||
|
||||
@@ -41,6 +41,36 @@ EVPPKey::EVPPKey(EVP_PKEY* pEVPPKey): _pEVPPKey(0)
|
||||
}
|
||||
|
||||
|
||||
EVPPKey::EVPPKey(const std::string& publicKeyFile,
|
||||
const std::string& privateKeyFile,
|
||||
const std::string& privateKeyPassphrase): _pEVPPKey(0)
|
||||
{
|
||||
if (loadKey(&_pEVPPKey, PEM_read_PrivateKey, (EVP_PKEY_get_Key_fn)0, privateKeyFile, privateKeyPassphrase))
|
||||
return; // private key is enough
|
||||
|
||||
// no private key, this must be public key only, otherwise throw
|
||||
if (!loadKey(&_pEVPPKey, PEM_read_PUBKEY, (EVP_PKEY_get_Key_fn)0, publicKeyFile))
|
||||
{
|
||||
throw OpenSSLException("ECKeyImpl(const string&, const string&, const string&");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
EVPPKey::EVPPKey(std::istream* pPublicKeyStream,
|
||||
std::istream* pPrivateKeyStream,
|
||||
const std::string& privateKeyPassphrase): _pEVPPKey(0)
|
||||
{
|
||||
if (loadKey(&_pEVPPKey, PEM_read_bio_PrivateKey, (EVP_PKEY_get_Key_fn)0, pPrivateKeyStream, privateKeyPassphrase))
|
||||
return; // private key is enough
|
||||
|
||||
// no private key, this must be public key only, otherwise throw
|
||||
if (!loadKey(&_pEVPPKey, PEM_read_bio_PUBKEY, (EVP_PKEY_get_Key_fn)0, pPublicKeyStream))
|
||||
{
|
||||
throw OpenSSLException("ECKeyImpl(istream*, istream*, const string&");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
EVPPKey::EVPPKey(const EVPPKey& other)
|
||||
{
|
||||
duplicate(other._pEVPPKey);
|
||||
@@ -77,6 +107,106 @@ EVPPKey::~EVPPKey()
|
||||
}
|
||||
|
||||
|
||||
void EVPPKey::save(const std::string& publicKeyFile, const std::string& privateKeyFile, const std::string& privateKeyPassphrase)
|
||||
{
|
||||
if (!publicKeyFile.empty())
|
||||
{
|
||||
BIO* bio = BIO_new(BIO_s_file());
|
||||
if (!bio) throw Poco::IOException("Cannot create BIO for writing public key file", publicKeyFile);
|
||||
try
|
||||
{
|
||||
if (BIO_write_filename(bio, const_cast<char*>(publicKeyFile.c_str())))
|
||||
{
|
||||
if (!PEM_write_bio_PUBKEY(bio, _pEVPPKey))
|
||||
{
|
||||
throw Poco::WriteFileException("Failed to write public key to file", publicKeyFile);
|
||||
}
|
||||
}
|
||||
else throw Poco::CreateFileException("Cannot create public key file");
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
BIO_free(bio);
|
||||
throw;
|
||||
}
|
||||
BIO_free(bio);
|
||||
}
|
||||
|
||||
if (!privateKeyFile.empty())
|
||||
{
|
||||
BIO* bio = BIO_new(BIO_s_file());
|
||||
if (!bio) throw Poco::IOException("Cannot create BIO for writing private key file", privateKeyFile);
|
||||
try
|
||||
{
|
||||
if (BIO_write_filename(bio, const_cast<char*>(privateKeyFile.c_str())))
|
||||
{
|
||||
int rc = 0;
|
||||
if (privateKeyPassphrase.empty())
|
||||
{
|
||||
rc = PEM_write_bio_PrivateKey(bio, _pEVPPKey, 0, 0, 0, 0, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
rc = PEM_write_bio_PrivateKey(bio, _pEVPPKey, EVP_des_ede3_cbc(),
|
||||
reinterpret_cast<unsigned char*>(const_cast<char*>(privateKeyPassphrase.c_str())),
|
||||
static_cast<int>(privateKeyPassphrase.length()), 0, 0);
|
||||
}
|
||||
if (!rc)
|
||||
throw Poco::FileException("Failed to write private key to file", privateKeyFile);
|
||||
}
|
||||
else throw Poco::CreateFileException("Cannot create private key file", privateKeyFile);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
BIO_free(bio);
|
||||
throw;
|
||||
}
|
||||
BIO_free(bio);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void EVPPKey::save(std::ostream* pPublicKeyStream, std::ostream* pPrivateKeyStream, const std::string& privateKeyPassphrase)
|
||||
{
|
||||
if (pPublicKeyStream)
|
||||
{
|
||||
BIO* bio = BIO_new(BIO_s_mem());
|
||||
if (!bio) throw Poco::IOException("Cannot create BIO for writing public key");
|
||||
if (!PEM_write_bio_PUBKEY(bio, _pEVPPKey))
|
||||
{
|
||||
BIO_free(bio);
|
||||
throw Poco::WriteFileException("Failed to write public key to stream");
|
||||
}
|
||||
char* pData;
|
||||
long size = BIO_get_mem_data(bio, &pData);
|
||||
pPublicKeyStream->write(pData, static_cast<std::streamsize>(size));
|
||||
BIO_free(bio);
|
||||
}
|
||||
|
||||
if (pPrivateKeyStream)
|
||||
{
|
||||
BIO* bio = BIO_new(BIO_s_mem());
|
||||
if (!bio) throw Poco::IOException("Cannot create BIO for writing public key");
|
||||
int rc = 0;
|
||||
if (privateKeyPassphrase.empty())
|
||||
rc = PEM_write_bio_PrivateKey(bio, _pEVPPKey, 0, 0, 0, 0, 0);
|
||||
else
|
||||
rc = PEM_write_bio_PrivateKey(bio, _pEVPPKey, EVP_des_ede3_cbc(),
|
||||
reinterpret_cast<unsigned char*>(const_cast<char*>(privateKeyPassphrase.c_str())),
|
||||
static_cast<int>(privateKeyPassphrase.length()), 0, 0);
|
||||
if (!rc)
|
||||
{
|
||||
BIO_free(bio);
|
||||
throw Poco::FileException("Failed to write private key to stream");
|
||||
}
|
||||
char* pData;
|
||||
long size = BIO_get_mem_data(bio, &pData);
|
||||
pPrivateKeyStream->write(pData, static_cast<std::streamsize>(size));
|
||||
BIO_free(bio);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void EVPPKey::duplicate(EVP_PKEY* pEVPPKey)
|
||||
{
|
||||
if (!pEVPPKey) throw NullPointerException("EVPPKey::duplicate(): "
|
||||
@@ -129,7 +259,7 @@ void EVPPKey::newECKey(const char* ecCurveName)
|
||||
EC_KEY_free(pEC);
|
||||
return;
|
||||
err:
|
||||
throw OpenSSLException();
|
||||
throw OpenSSLException("EVPPKey:newECKey()");
|
||||
}
|
||||
|
||||
|
||||
@@ -148,4 +278,14 @@ void EVPPKey::setKey(RSAKey* pKey)
|
||||
setKey(pKey->impl()->getRSA());
|
||||
}
|
||||
|
||||
|
||||
int EVPPKey::passCB(char* buf, int size, int, void* pass)
|
||||
{
|
||||
int len = (int) strlen((char*)pass);
|
||||
if (len > size) len = size;
|
||||
memcpy(buf, pass, len);
|
||||
return len;
|
||||
}
|
||||
|
||||
|
||||
} } // namespace Poco::Crypto
|
||||
|
||||
@@ -96,7 +96,7 @@ RSAKeyImpl::RSAKeyImpl(const std::string& publicKeyFile,
|
||||
_pRSA(0)
|
||||
{
|
||||
poco_assert_dbg(_pRSA == 0);
|
||||
|
||||
|
||||
_pRSA = RSA_new();
|
||||
if (!publicKeyFile.empty())
|
||||
{
|
||||
@@ -162,7 +162,7 @@ RSAKeyImpl::RSAKeyImpl(std::istream* pPublicKeyStream,
|
||||
_pRSA(0)
|
||||
{
|
||||
poco_assert_dbg(_pRSA == 0);
|
||||
|
||||
|
||||
_pRSA = RSA_new();
|
||||
if (pPublicKeyStream)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user