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 14:42:50 -05:00
parent ba5af017cc
commit 8fff0cf586
6 changed files with 397 additions and 260 deletions

View File

@ -79,6 +79,15 @@ 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 +102,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

@ -194,7 +194,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;
}
@ -250,7 +254,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;
}
@ -278,12 +286,12 @@ private:
// inlines
//
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 "Poco/StreamCopier.h"
#include <sstream>
#include <openssl/evp.h>
@ -33,7 +34,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()");
}
@ -49,6 +50,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;
}
}
@ -60,7 +62,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()");
}
@ -68,8 +70,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()");
}
@ -78,13 +83,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() ? "" : "***"),
"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() ? "" : "***"),
"PEM_read_PUBKEY() or EVP_PKEY_get1_EC_KEY()");
}
@ -93,13 +106,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() ? "" : "***"),
"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() ? "" : "***"),
"PEM_read_bio_PUBKEY() or EVP_PKEY_get1_EC_KEY()");
}
@ -109,6 +130,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)
@ -151,4 +180,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

@ -217,7 +217,10 @@ 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));
@ -297,6 +300,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;
@ -309,7 +315,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");
@ -325,9 +334,8 @@ void EVPTest::testECEVPSaveLoadStream()
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));
ECKey ecKeyNE("secp112r2");
EVPPKey keyNE(&ecKeyNE);
assert (key != keyNE);
@ -347,6 +355,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;
@ -359,7 +370,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);
@ -375,9 +389,8 @@ void EVPTest::testECEVPSaveLoadStreamNoPass()
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));*/
assert (!(key != key2));
ECKey ecKeyNE("secp112r2");
EVPPKey keyNE(&ecKeyNE);
assert (key != keyNE);
@ -398,6 +411,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;
@ -410,7 +426,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");
@ -427,9 +446,8 @@ void EVPTest::testECEVPSaveLoadFile()
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));
ECKey ecKeyNE("secp112r2");
EVPPKey keyNE(&ecKeyNE);
assert (key != keyNE);
@ -448,6 +466,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;
@ -460,7 +481,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());
@ -483,6 +507,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;