1
0
mirror of https://github.com/VCMP-SqMod/SqMod.git synced 2025-03-04 03:07:29 +01:00
SqMod/vendor/POCO/Crypto/src/EVPPKey.cpp

318 lines
7.6 KiB
C++
Raw Normal View History

//
// EVPPKey.cpp
//
//
// Library: Crypto
// Package: CryptoCore
// Module: EVPPKey
//
// Copyright (c) 2008, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// SPDX-License-Identifier: BSL-1.0
//
#include "Poco/Crypto/EVPPKey.h"
#include "Poco/Crypto/ECKey.h"
#include "Poco/Crypto/RSAKey.h"
#include "Poco/NumberFormatter.h"
namespace Poco {
namespace Crypto {
EVPPKey::EVPPKey(const std::string& ecCurveName): _pEVPPKey(0)
{
newECKey(ecCurveName.c_str());
poco_check_ptr(_pEVPPKey);
}
EVPPKey::EVPPKey(const char* ecCurveName): _pEVPPKey(0)
{
newECKey(ecCurveName);
poco_check_ptr(_pEVPPKey);
}
EVPPKey::EVPPKey(EVP_PKEY* pEVPPKey): _pEVPPKey(0)
{
duplicate(pEVPPKey, &_pEVPPKey);
poco_check_ptr(_pEVPPKey);
}
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))
{
poco_check_ptr(_pEVPPKey);
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&");
}
poco_check_ptr(_pEVPPKey);
}
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))
{
poco_check_ptr(_pEVPPKey);
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&");
}
poco_check_ptr(_pEVPPKey);
}
EVPPKey::EVPPKey(const EVPPKey& other)
{
duplicate(other._pEVPPKey, &_pEVPPKey);
poco_check_ptr(_pEVPPKey);
}
EVPPKey::EVPPKey(EVPPKey&& other) noexcept:
_pEVPPKey(other._pEVPPKey)
{
other._pEVPPKey = nullptr;
}
EVPPKey& EVPPKey::operator = (const EVPPKey& other)
{
duplicate(other._pEVPPKey, &_pEVPPKey);
poco_check_ptr(_pEVPPKey);
return *this;
}
EVPPKey& EVPPKey::operator = (EVPPKey&& other) noexcept
{
_pEVPPKey = other._pEVPPKey;
other._pEVPPKey = nullptr;
return *this;
}
EVPPKey::~EVPPKey()
{
if (_pEVPPKey) EVP_PKEY_free(_pEVPPKey);
}
void EVPPKey::save(const std::string& publicKeyFile, const std::string& privateKeyFile, const std::string& privateKeyPassphrase) const
{
if (!publicKeyFile.empty() && (publicKeyFile != privateKeyFile))
{
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) const
{
if (pPublicKeyStream && (pPublicKeyStream != pPrivateKeyStream))
{
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);
}
}
EVP_PKEY* EVPPKey::duplicate(const EVP_PKEY* pFromKey, EVP_PKEY** pToKey)
{
if (!pFromKey) throw NullPointerException("EVPPKey::duplicate(): "
"provided key pointer is null.");
*pToKey = EVP_PKEY_new();
if (!*pToKey) throw NullPointerException("EVPPKey::duplicate(): "
"EVP_PKEY_new() returned null.");
int keyType = type(pFromKey);
switch (keyType)
{
case EVP_PKEY_RSA:
{
RSA* pRSA = EVP_PKEY_get1_RSA(const_cast<EVP_PKEY*>(pFromKey));
if (pRSA)
{
EVP_PKEY_set1_RSA(*pToKey, pRSA);
RSA_free(pRSA);
}
else throw OpenSSLException("EVPPKey::duplicate(): EVP_PKEY_get1_RSA()");
break;
}
case EVP_PKEY_EC:
{
EC_KEY* pEC = EVP_PKEY_get1_EC_KEY(const_cast<EVP_PKEY*>(pFromKey));
if (pEC)
{
EVP_PKEY_set1_EC_KEY(*pToKey, pEC);
EC_KEY_free(pEC);
int cmp = EVP_PKEY_cmp_parameters(*pToKey, pFromKey);
if (cmp < 0)
throw OpenSSLException("EVPPKey::duplicate(): EVP_PKEY_cmp_parameters()");
if (0 == cmp)
{
if(!EVP_PKEY_copy_parameters(*pToKey, pFromKey))
throw OpenSSLException("EVPPKey::duplicate(): EVP_PKEY_copy_parameters()");
}
}
else throw OpenSSLException();
break;
}
default:
throw NotImplementedException("EVPPKey:duplicate(); Key type: " +
NumberFormatter::format(keyType));
}
return *pToKey;
}
void EVPPKey::newECKey(const char* ecCurveName)
{
int curveID = OBJ_txt2nid(ecCurveName);
EC_KEY* pEC = EC_KEY_new_by_curve_name(curveID);
if (!pEC) goto err;
if (!EC_KEY_generate_key(pEC)) goto err;
_pEVPPKey = EVP_PKEY_new();
if (!_pEVPPKey) goto err;
if (!EVP_PKEY_set1_EC_KEY(_pEVPPKey, pEC)) goto err;
EC_KEY_free(pEC);
return;
err:
throw OpenSSLException("EVPPKey:newECKey()");
}
void EVPPKey::setKey(ECKey* pKey)
{
poco_check_ptr(pKey);
poco_check_ptr(pKey->impl());
setKey(pKey->impl()->getECKey());
}
void EVPPKey::setKey(RSAKey* pKey)
{
poco_check_ptr(pKey);
poco_check_ptr(pKey->impl());
setKey(pKey->impl()->getRSA());
}
int EVPPKey::passCB(char* buf, int size, int, void* pass)
{
if (pass)
{
int len = (int)std::strlen((char*)pass);
if(len > size) len = size;
std::memcpy(buf, pass, len);
return len;
}
return 0;
}
} } // namespace Poco::Crypto