fix incomplete EC key creation from curve name; make sure tests use curves that exist; add validation checks on EC key creation

This commit is contained in:
Alex Fabijanic 2017-09-28 15:17:15 -05:00
parent 03e97dd0f7
commit 528b5d615a
6 changed files with 398 additions and 258 deletions

View File

@ -79,6 +79,16 @@ public:
ECKeyImpl::Ptr impl() const;
/// Returns the impl object.
static std::string getCurveName(int nid = -1);
/// Returns elliptical curve name corresponding to
/// the given nid; if nid is not found, returns
/// empty string.
///
/// If nid is -1, returns first curve name.
///
/// If no curves are found, returns empty string;
private:
ECKeyImpl::Ptr _pImpl;
};
@ -93,6 +103,12 @@ inline ECKeyImpl::Ptr ECKey::impl() const
}
inline std::string ECKey::getCurveName(int nid)
{
return ECKeyImpl::getCurveName(nid);
}
} } // namespace Poco::Crypto

View File

@ -104,7 +104,17 @@ public:
/// If a null pointer is passed for a stream, the corresponding
/// key is not exported.
static std::string getCurveName(int nid = -1);
/// Returns elliptical curve name corresponding to
/// the given nid; if nid is not found, returns
/// empty string.
///
/// If nid is -1, returns first curve name.
///
/// If no curves are found, returns empty string;
private:
void checkEC(const std::string& method, const std::string& func) const;
void freeEC();
EC_KEY* _pEC;

View File

@ -196,7 +196,11 @@ private:
*ppKey = (K*)getFunc(pKey);
EVP_PKEY_free(pKey);
}
else *ppKey = (K*)pKey;
else
{
poco_assert_dbg (typeid(K*) == typeid(EVP_PKEY*));
*ppKey = (K*)pKey;
}
if(!*ppKey) goto error;
return true;
}
@ -252,7 +256,11 @@ private:
*ppKey = (K*)getFunc(pKey);
EVP_PKEY_free(pKey);
}
else *ppKey = (K*)pKey;
else
{
poco_assert_dbg (typeid(K*) == typeid(EVP_PKEY*));
*ppKey = (K*)pKey;
}
if (!*ppKey) goto error;
return true;
}
@ -282,10 +290,9 @@ private:
inline bool EVPPKey::operator == (const EVPPKey& other) const
{
poco_assert_dbg(other._pEVPPKey && _pEVPPKey);
int r = EVP_PKEY_cmp(_pEVPPKey, other._pEVPPKey);
if (r < 0) throw OpenSSLException("EVPPKey::operator ==()");
return (1 == r);
poco_check_ptr (other._pEVPPKey);
poco_check_ptr (_pEVPPKey);
return (1 == EVP_PKEY_cmp(_pEVPPKey, other._pEVPPKey));
}

View File

@ -17,6 +17,7 @@
#include "Poco/Crypto/X509Certificate.h"
#include "Poco/Crypto/PKCS12Container.h"
#include "Poco/FileStream.h"
#include "Poco/Format.h"
#include <sstream>
#include <openssl/evp.h>
#if OPENSSL_VERSION_NUMBER >= 0x00908000L
@ -32,7 +33,7 @@ ECKeyImpl::ECKeyImpl(const EVPPKey& key):
KeyPairImpl("ec", KT_EC_IMPL),
_pEC(EVP_PKEY_get1_EC_KEY(const_cast<EVP_PKEY*>((const EVP_PKEY*)key)))
{
if (!_pEC) throw OpenSSLException("ECKeyImpl(const EVPPKey&)");
checkEC("ECKeyImpl(const EVPPKey&)", "EVP_PKEY_get1_EC_KEY()");
}
@ -48,6 +49,7 @@ ECKeyImpl::ECKeyImpl(const X509Certificate& cert):
{
_pEC = EVP_PKEY_get1_EC_KEY(pKey);
EVP_PKEY_free(pKey);
checkEC("ECKeyImpl(const const X509Certificate&)", "EVP_PKEY_get1_EC_KEY()");
return;
}
}
@ -59,7 +61,7 @@ ECKeyImpl::ECKeyImpl(const PKCS12Container& cont):
KeyPairImpl("ec", KT_EC_IMPL),
_pEC(EVP_PKEY_get1_EC_KEY(cont.getKey()))
{
if (!_pEC) throw OpenSSLException();
checkEC("ECKeyImpl(const PKCS12Container&)", "EVP_PKEY_get1_EC_KEY()");
}
@ -67,8 +69,11 @@ ECKeyImpl::ECKeyImpl(int curve):
KeyPairImpl("ec", KT_EC_IMPL),
_pEC(EC_KEY_new_by_curve_name(curve))
{
if (!EC_KEY_generate_key(_pEC))
throw OpenSSLException("ECKeyImpl(int)");
poco_check_ptr(_pEC);
EC_KEY_set_asn1_flag(_pEC, OPENSSL_EC_NAMED_CURVE);
if (!(EC_KEY_generate_key(_pEC)))
throw OpenSSLException("ECKeyImpl(int curve): EC_KEY_generate_key()");
checkEC("ECKeyImpl(int curve)", "EC_KEY_generate_key()");
}
@ -77,13 +82,21 @@ ECKeyImpl::ECKeyImpl(const std::string& publicKeyFile,
const std::string& privateKeyPassphrase): KeyPairImpl("ec", KT_EC_IMPL), _pEC(0)
{
if (EVPPKey::loadKey(&_pEC, PEM_read_PrivateKey, EVP_PKEY_get1_EC_KEY, privateKeyFile, privateKeyPassphrase))
{
checkEC(Poco::format("ECKeyImpl(%s, %s, %s)",
publicKeyFile, privateKeyFile, privateKeyPassphrase.empty() ? privateKeyPassphrase : std::string("***")),
"PEM_read_PrivateKey() or EVP_PKEY_get1_EC_KEY()");
return; // private key is enough
}
// no private key, this must be public key only, otherwise throw
if (!EVPPKey::loadKey(&_pEC, PEM_read_PUBKEY, EVP_PKEY_get1_EC_KEY, publicKeyFile))
{
throw OpenSSLException("ECKeyImpl(const string&, const string&, const string&");
}
checkEC(Poco::format("ECKeyImpl(%s, %s, %s)",
publicKeyFile, privateKeyFile, privateKeyPassphrase.empty() ? privateKeyPassphrase : std::string("***")),
"PEM_read_PUBKEY() or EVP_PKEY_get1_EC_KEY()");
}
@ -92,13 +105,21 @@ ECKeyImpl::ECKeyImpl(std::istream* pPublicKeyStream,
const std::string& privateKeyPassphrase): KeyPairImpl("ec", KT_EC_IMPL), _pEC(0)
{
if (EVPPKey::loadKey(&_pEC, PEM_read_bio_PrivateKey, EVP_PKEY_get1_EC_KEY, pPrivateKeyStream, privateKeyPassphrase))
{
checkEC(Poco::format("ECKeyImpl(stream, stream, %s)",
privateKeyPassphrase.empty() ? privateKeyPassphrase : std::string("***")),
"PEM_read_bio_PrivateKey() or EVP_PKEY_get1_EC_KEY()");
return; // private key is enough
}
// no private key, this must be public key only, otherwise throw
if (!EVPPKey::loadKey(&_pEC, PEM_read_bio_PUBKEY, EVP_PKEY_get1_EC_KEY, pPublicKeyStream))
{
throw OpenSSLException("ECKeyImpl(istream*, istream*, const string&");
}
checkEC(Poco::format("ECKeyImpl(stream, stream, %s)",
privateKeyPassphrase.empty() ? privateKeyPassphrase : std::string("***")),
"PEM_read_bio_PUBKEY() or EVP_PKEY_get1_EC_KEY()");
}
@ -108,6 +129,14 @@ ECKeyImpl::~ECKeyImpl()
}
void ECKeyImpl::checkEC(const std::string& method, const std::string& func) const
{
if (!_pEC) throw OpenSSLException(Poco::format("%s: %s", method, func));
if (!EC_KEY_check_key(_pEC))
throw OpenSSLException(Poco::format("%s: EC_KEY_check_key()", method));
}
void ECKeyImpl::freeEC()
{
if (_pEC)
@ -150,4 +179,28 @@ int ECKeyImpl::groupId() const
}
std::string ECKeyImpl::getCurveName(int nid)
{
std::string curveName;
size_t len = EC_get_builtin_curves(NULL, 0);
EC_builtin_curve* pCurves =
(EC_builtin_curve*) OPENSSL_malloc(sizeof(EC_builtin_curve) * len);
if (!pCurves) return curveName;
if (!EC_get_builtin_curves(pCurves, len))
{
OPENSSL_free(pCurves);
return curveName;
}
if (-1 == nid) nid = pCurves[0].nid;
int bufLen = 128;
char buf[bufLen] = {0};
OBJ_obj2txt(buf, bufLen, OBJ_nid2obj(nid), 0);
curveName = buf;
OPENSSL_free(pCurves);
return curveName;
}
} } // namespace Poco::Crypto

View File

@ -37,7 +37,10 @@ void ECTest::testECNewKeys()
{
try
{
ECKey key("secp521r1");
std::string curveName = ECKey::getCurveName();
if (!curveName.empty())
{
ECKey key(curveName);
std::ostringstream strPub;
std::ostringstream strPriv;
key.save(&strPub, &strPriv, "testpwd");
@ -56,6 +59,9 @@ void ECTest::testECNewKeys()
std::string pubFromPrivate = strPub3.str();
assert (pubFromPrivate == pubKey);
}
else
std::cerr << "No elliptic curves found!" << std::endl;
}
catch (Poco::Exception& ex)
{
std::cerr << ex.displayText() << std::endl;
@ -68,7 +74,10 @@ void ECTest::testECNewKeysNoPassphrase()
{
try
{
ECKey key("secp521r1");
std::string curveName = ECKey::getCurveName();
if (!curveName.empty())
{
ECKey key(curveName);
std::ostringstream strPub;
std::ostringstream strPriv;
key.save(&strPub, &strPriv);
@ -87,6 +96,9 @@ void ECTest::testECNewKeysNoPassphrase()
std::string pubFromPrivate = strPub3.str();
assert (pubFromPrivate == pubKey);
}
else
std::cerr << "No elliptic curves found!" << std::endl;
}
catch (Poco::Exception& ex)
{
std::cerr << ex.displayText() << std::endl;
@ -98,9 +110,12 @@ void ECTest::testECNewKeysNoPassphrase()
void ECTest::testECDSASignSha256()
{
try
{
std::string curveName = ECKey::getCurveName();
if (!curveName.empty())
{
std::string msg("Test this sign message");
ECKey key("secp521r1");
ECKey key(curveName);
ECDSADigestEngine eng(key, "SHA256");
eng.update(msg.c_str(), static_cast<unsigned>(msg.length()));
const Poco::DigestEngine::Digest& sig = eng.signature();
@ -115,6 +130,9 @@ void ECTest::testECDSASignSha256()
eng2.update(msg.c_str(), static_cast<unsigned>(msg.length()));
assert(eng2.verify(sig));
}
else
std::cerr << "No elliptic curves found!" << std::endl;
}
catch (Poco::Exception& ex)
{
std::cerr << ex.displayText() << std::endl;
@ -126,10 +144,13 @@ void ECTest::testECDSASignSha256()
void ECTest::testECDSASignManipulated()
{
try
{
std::string curveName = ECKey::getCurveName();
if (!curveName.empty())
{
std::string msg("Test this sign message");
std::string msgManip("Test that sign message");
ECKey key("secp521r1");
ECKey key(curveName);
ECDSADigestEngine eng(key, "SHA256");
eng.update(msg.c_str(), static_cast<unsigned>(msg.length()));
const Poco::DigestEngine::Digest& sig = eng.signature();
@ -145,6 +166,9 @@ void ECTest::testECDSASignManipulated()
eng2.update(msgManip.c_str(), static_cast<unsigned>(msgManip.length()));
assert (!eng2.verify(sig));
}
else
std::cerr << "No elliptic curves found!" << std::endl;
}
catch (Poco::Exception& ex)
{
std::cerr << ex.displayText() << std::endl;

View File

@ -213,20 +213,23 @@ void EVPTest::testECEVPPKey()
{
try
{
EVPPKey* pKey = new EVPPKey("secp521r1");
std::string curveName = ECKey::getCurveName();
if (!curveName.empty())
{
EVPPKey*pKey = new EVPPKey(curveName);
assert (pKey != 0);
assert (!pKey->isSupported(0));
assert (!pKey->isSupported(-1));
assert (pKey->isSupported(pKey->type()));
assert (pKey->type() == EVP_PKEY_EC);
BIO* bioPriv1 = BIO_new(BIO_s_mem());
BIO* bioPub1 = BIO_new(BIO_s_mem());
BIO*bioPriv1 = BIO_new(BIO_s_mem());
BIO*bioPub1 = BIO_new(BIO_s_mem());
assert (0 != PEM_write_bio_PrivateKey(bioPriv1, *pKey, NULL, NULL, 0, 0, NULL));
assert (0 != PEM_write_bio_PUBKEY(bioPub1, *pKey));
char* pPrivData1;
char*pPrivData1;
long sizePriv1 = BIO_get_mem_data(bioPriv1, &pPrivData1);
char* pPubData1;
char*pPubData1;
long sizePub1 = BIO_get_mem_data(bioPub1, &pPubData1);
// construct EVPPKey from EVP_PKEY*
@ -235,13 +238,13 @@ void EVPTest::testECEVPPKey()
// EVPPKey makes duplicate, so freeing the original must be ok
delete pKey;
BIO* bioPriv2 = BIO_new(BIO_s_mem());
BIO* bioPub2 = BIO_new(BIO_s_mem());
BIO*bioPriv2 = BIO_new(BIO_s_mem());
BIO*bioPub2 = BIO_new(BIO_s_mem());
assert (0 != PEM_write_bio_PrivateKey(bioPriv2, evpPKey, NULL, NULL, 0, 0, NULL));
assert (0 != PEM_write_bio_PUBKEY(bioPub2, evpPKey));
char* pPrivData2;
char*pPrivData2;
long sizePriv2 = BIO_get_mem_data(bioPriv2, &pPrivData2);
char* pPubData2;
char*pPubData2;
long sizePub2 = BIO_get_mem_data(bioPub2, &pPubData2);
assert (sizePriv1 && (sizePriv1 == sizePriv2));
@ -290,6 +293,9 @@ void EVPTest::testECEVPPKey()
BIO_free(bioPub1);
BIO_free(bioPriv1);
}
else
std::cerr << "No elliptic curves found!" << std::endl;
}
catch (Poco::Exception& ex)
{
std::cerr << ex.displayText() << std::endl;
@ -302,7 +308,10 @@ void EVPTest::testECEVPSaveLoadStream()
{
try
{
EVPPKey key("secp521r1");
std::string curveName = ECKey::getCurveName();
if (!curveName.empty())
{
EVPPKey key(curveName);
std::ostringstream strPub;
std::ostringstream strPriv;
key.save(&strPub, &strPriv, "testpwd");
@ -340,6 +349,9 @@ void EVPTest::testECEVPSaveLoadStream()
std::string pubFromPrivate = strPub3.str();
assert (pubFromPrivate == pubKey);
}
else
std::cerr << "No elliptic curves found!" << std::endl;
}
catch (Poco::Exception& ex)
{
std::cerr << ex.displayText() << std::endl;
@ -352,7 +364,10 @@ void EVPTest::testECEVPSaveLoadStreamNoPass()
{
try
{
EVPPKey key("secp521r1");
std::string curveName = ECKey::getCurveName();
if (!curveName.empty())
{
EVPPKey key(curveName);
std::ostringstream strPub;
std::ostringstream strPriv;
key.save(&strPub, &strPriv);
@ -391,6 +406,9 @@ void EVPTest::testECEVPSaveLoadStreamNoPass()
std::string pubFromPrivate = strPub3.str();
assert (pubFromPrivate == pubKey);
}
else
std::cerr << "No elliptic curves found!" << std::endl;
}
catch (Poco::Exception& ex)
{
std::cerr << ex.displayText() << std::endl;
@ -403,7 +421,10 @@ void EVPTest::testECEVPSaveLoadFile()
{
try
{
EVPPKey key("secp521r1");
std::string curveName = ECKey::getCurveName();
if (!curveName.empty())
{
EVPPKey key(curveName);
TemporaryFile filePub;
TemporaryFile filePriv;
key.save(filePub.path(), filePriv.path(), "testpwd");
@ -441,6 +462,9 @@ void EVPTest::testECEVPSaveLoadFile()
std::string pubFromPrivate = strPub3.str();
assert (pubFromPrivate == pubKey);
}
else
std::cerr << "No elliptic curves found!" << std::endl;
}
catch (Poco::Exception& ex)
{
std::cerr << ex.displayText() << std::endl;
@ -453,7 +477,10 @@ void EVPTest::testECEVPSaveLoadFileNoPass()
{
try
{
EVPPKey key("secp521r1");
std::string curveName = ECKey::getCurveName();
if (!curveName.empty())
{
EVPPKey key(curveName);
TemporaryFile filePub;
TemporaryFile filePriv;
key.save(filePub.path(), filePriv.path());
@ -476,6 +503,9 @@ void EVPTest::testECEVPSaveLoadFileNoPass()
std::string pubFromPrivate = strPub3.str();
assert (pubFromPrivate == pubKey);
}
else
std::cerr << "No elliptic curves found!" << std::endl;
}
catch (Poco::Exception& ex)
{
std::cerr << ex.displayText() << std::endl;