From 5bbd542b6b5fadf3d1c43dd4d42eebffc344ba55 Mon Sep 17 00:00:00 2001 From: Matej Kenda Date: Thu, 18 Dec 2025 17:25:30 +0100 Subject: [PATCH] fix(Crypto): Prevent stdin password prompt when loading protected key (#4627) (#5128) --- Crypto/include/Poco/Crypto/EVPPKey.h | 17 ++++++---- Crypto/testsuite/src/EVPTest.cpp | 48 ++++++++++++++++++++++++++++ Crypto/testsuite/src/EVPTest.h | 1 + 3 files changed, 59 insertions(+), 7 deletions(-) diff --git a/Crypto/include/Poco/Crypto/EVPPKey.h b/Crypto/include/Poco/Crypto/EVPPKey.h index 060ca83f6..3170282a1 100644 --- a/Crypto/include/Poco/Crypto/EVPPKey.h +++ b/Crypto/include/Poco/Crypto/EVPPKey.h @@ -230,8 +230,8 @@ private: if (pFile) { - pem_password_cb* pCB = pass.empty() ? (pem_password_cb*)nullptr : &passCB; - void* pPassword = pass.empty() ? (void*)nullptr : (void*)pass.c_str(); + pem_password_cb* pCB = &passCB; + void* pPassword = const_cast(pass.c_str()); if (readFunc(pFile, &pKey, pCB, pPassword)) { fclose(pFile); pFile = nullptr; @@ -248,14 +248,16 @@ private: if (!*ppKey) goto error; return true; } - if (getFunc) EVP_PKEY_free(pKey); + EVP_PKEY_free(pKey); + if (!getFunc) *ppKey = nullptr; goto error; } else { std::string msg = Poco::format("EVPPKey::loadKey('%s')\n", keyFile); getError(msg); - if (getFunc) EVP_PKEY_free(pKey); + EVP_PKEY_free(pKey); + if (!getFunc) *ppKey = nullptr; throw IOException(msg); } } @@ -295,8 +297,8 @@ private: EVP_PKEY* pKey = getFunc ? EVP_PKEY_new() : (EVP_PKEY*)*ppKey; if (pKey) { - pem_password_cb* pCB = pass.empty() ? (pem_password_cb*)nullptr : &passCB; - void* pPassword = pass.empty() ? (void*)nullptr : (void*)pass.c_str(); + pem_password_cb* pCB = &passCB; + void* pPassword = const_cast(pass.c_str()); if (readFunc(pBIO, &pKey, pCB, pPassword)) { BIO_free(pBIO); pBIO = nullptr; @@ -313,7 +315,8 @@ private: if (!*ppKey) goto error; return true; } - if (getFunc) EVP_PKEY_free(pKey); + EVP_PKEY_free(pKey); + if (!getFunc) *ppKey = nullptr; goto error; } else goto error; diff --git a/Crypto/testsuite/src/EVPTest.cpp b/Crypto/testsuite/src/EVPTest.cpp index c739b3ddf..48cb6e8da 100644 --- a/Crypto/testsuite/src/EVPTest.cpp +++ b/Crypto/testsuite/src/EVPTest.cpp @@ -571,6 +571,53 @@ void EVPTest::testECEVPSaveLoadFileNoPass() } +void EVPTest::testECEVPLoadKeyWrongPassword() +{ + // Test for issue #4627: Loading a password-protected key with empty password + // should throw an exception, not prompt stdin. + try + { + std::string curveName = ECKey::getCurveName(); + if (!curveName.empty()) + { + EVPPKey key(curveName); + TemporaryFile filePub; + TemporaryFile filePriv; + key.save(filePub.path(), filePriv.path(), "testpwd"); + + // Try to load with empty password - should throw, not prompt stdin + try + { + EVPPKey keyBadPass("", filePriv.path(), ""); + fail("Loading password-protected key with empty password should throw"); + } + catch (const Poco::Exception&) + { + // Expected - key requires password but none provided + } + + // Try to load with wrong password - should also throw + try + { + EVPPKey keyBadPass("", filePriv.path(), "wrongpwd"); + fail("Loading password-protected key with wrong password should throw"); + } + catch (const Poco::Exception&) + { + // Expected - wrong password + } + } + else + std::cerr << "No elliptic curves found!" << std::endl; + } + catch (Poco::Exception& ex) + { + std::cerr << ex.displayText() << std::endl; + throw; + } +} + + void EVPTest::testRSAEVPKeyFromX509() { std::istringstream str(anyPemRSA); @@ -744,6 +791,7 @@ CppUnit::Test* EVPTest::suite() CppUnit_addTest(pSuite, EVPTest, testECEVPSaveLoadStreamNoPass); CppUnit_addTest(pSuite, EVPTest, testECEVPSaveLoadFile); CppUnit_addTest(pSuite, EVPTest, testECEVPSaveLoadFileNoPass); + CppUnit_addTest(pSuite, EVPTest, testECEVPLoadKeyWrongPassword); CppUnit_addTest(pSuite, EVPTest, testRSAEVPKeyFromX509); CppUnit_addTest(pSuite, EVPTest, testRSAEVPKeyFromPKCS12); #if OPENSSL_VERSION_NUMBER >= 0x10000000L diff --git a/Crypto/testsuite/src/EVPTest.h b/Crypto/testsuite/src/EVPTest.h index 0a7966cb7..1d524fd3d 100644 --- a/Crypto/testsuite/src/EVPTest.h +++ b/Crypto/testsuite/src/EVPTest.h @@ -33,6 +33,7 @@ public: void testECEVPSaveLoadStreamNoPass(); void testECEVPSaveLoadFile(); void testECEVPSaveLoadFileNoPass(); + void testECEVPLoadKeyWrongPassword(); void testRSAEVPKeyFromX509(); void testRSAEVPKeyFromPKCS12();