mirror of
https://github.com/pocoproject/poco.git
synced 2025-10-29 04:17:55 +01:00
Added support for loading certificates and private key pairs from PKCS #12 files, as well as loading certificates (without private key) from PEM or DER files. Some code restructuring and cleanup.
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
//
|
||||
// AcceptCertificateHandler.cpp
|
||||
//
|
||||
// $Id: //poco/1.4/NetSSL_Win/src/AcceptCertificateHandler.cpp#1 $
|
||||
// $Id$
|
||||
//
|
||||
// Library: NetSSL_Win
|
||||
// Package: SSLCore
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
//
|
||||
// Context.cpp
|
||||
//
|
||||
// $Id: //poco/1.4/NetSSL_Schannel/src/Context.cpp#1 $
|
||||
// $Id$
|
||||
//
|
||||
// Library: NetSSL_Schannel
|
||||
// Library: NetSSL_Win
|
||||
// Package: SSLCore
|
||||
// Module: Context
|
||||
//
|
||||
@@ -17,7 +17,16 @@
|
||||
#include "Poco/Net/Context.h"
|
||||
#include "Poco/Net/SSLManager.h"
|
||||
#include "Poco/Net/SSLException.h"
|
||||
#include "Poco/Net/Utility.h"
|
||||
#include "Poco/UnicodeConverter.h"
|
||||
#include "Poco/Format.h"
|
||||
#include "Poco/File.h"
|
||||
#include "Poco/FileStream.h"
|
||||
#include "Poco/MemoryStream.h"
|
||||
#include "Poco/Base64Decoder.h"
|
||||
#include "Poco/Buffer.h"
|
||||
#include <algorithm>
|
||||
#include <cctype>
|
||||
|
||||
|
||||
namespace Poco {
|
||||
@@ -32,20 +41,54 @@ const std::string Context::CERT_STORE_USERDS("USERDS");
|
||||
|
||||
|
||||
Context::Context(Usage usage,
|
||||
const std::string& certName,
|
||||
const std::string& certNameOrPath,
|
||||
VerificationMode verMode,
|
||||
int options,
|
||||
const std::string& certStore):
|
||||
_usage(usage),
|
||||
_mode(verMode),
|
||||
_options(options),
|
||||
_certificateName(certName),
|
||||
_certificateStoreName(certStore),
|
||||
_certNameOrPath(certNameOrPath),
|
||||
_certStoreName(certStore),
|
||||
_hMemCertStore(0),
|
||||
_hCollectionCertStore(0),
|
||||
_hRootCertStore(0),
|
||||
_mutex()
|
||||
_hCertStore(0),
|
||||
_pCert(0),
|
||||
_securityFunctions(SSLManager::instance().securityFunctions())
|
||||
{
|
||||
init();
|
||||
}
|
||||
|
||||
|
||||
Context::~Context()
|
||||
{
|
||||
if (_pCert)
|
||||
{
|
||||
CertFreeCertificateContext(_pCert);
|
||||
}
|
||||
if (_hCertStore)
|
||||
{
|
||||
CertCloseStore(_hCertStore, 0);
|
||||
}
|
||||
CertCloseStore(_hCollectionCertStore, 0);
|
||||
CertCloseStore(_hMemCertStore, 0);
|
||||
if (_hRootCertStore)
|
||||
{
|
||||
CertCloseStore(_hRootCertStore, 0);
|
||||
}
|
||||
if (_hCreds.dwLower != 0 && _hCreds.dwUpper != 0)
|
||||
{
|
||||
_securityFunctions.FreeCredentialsHandle(&_hCreds);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Context::init()
|
||||
{
|
||||
_hCreds.dwLower = 0;
|
||||
_hCreds.dwUpper = 0;
|
||||
|
||||
_hMemCertStore = CertOpenStore(
|
||||
CERT_STORE_PROV_MEMORY, // The memory provider type
|
||||
0, // The encoding type is not needed
|
||||
@@ -83,22 +126,229 @@ Context::Context(Usage usage,
|
||||
}
|
||||
|
||||
|
||||
Context::~Context()
|
||||
void Context::addTrustedCert(const Poco::Net::X509Certificate& cert)
|
||||
{
|
||||
CertCloseStore(_hCollectionCertStore, 0);
|
||||
CertCloseStore(_hMemCertStore, 0);
|
||||
if (_hRootCertStore)
|
||||
Poco::FastMutex::ScopedLock lock(_mutex);
|
||||
if (!CertAddCertificateContextToStore(_hMemCertStore, cert.system(), CERT_STORE_ADD_REPLACE_EXISTING, 0))
|
||||
throw CertificateException("Failed to add certificate to store", GetLastError());
|
||||
}
|
||||
|
||||
|
||||
Poco::Net::X509Certificate Context::certificate()
|
||||
{
|
||||
if (_pCert)
|
||||
return Poco::Net::X509Certificate(_pCert, true);
|
||||
|
||||
if (_certNameOrPath.empty())
|
||||
throw NoCertificateException("Certificate requested, but no certificate name or path provided");
|
||||
|
||||
if (_options & OPT_LOAD_CERT_FROM_FILE)
|
||||
{
|
||||
CertCloseStore(_hRootCertStore, 0);
|
||||
importCertificate();
|
||||
}
|
||||
else
|
||||
{
|
||||
loadCertificate();
|
||||
}
|
||||
|
||||
return Poco::Net::X509Certificate(_pCert, true);
|
||||
}
|
||||
|
||||
|
||||
void Context::loadCertificate()
|
||||
{
|
||||
std::wstring wcertStore;
|
||||
Poco::UnicodeConverter::convert(_certStoreName, wcertStore);
|
||||
if (!_hCertStore)
|
||||
{
|
||||
if (_options & OPT_USE_MACHINE_STORE)
|
||||
_hCertStore = CertOpenStore(CERT_STORE_PROV_SYSTEM, 0, 0, CERT_SYSTEM_STORE_LOCAL_MACHINE, _certStoreName.c_str());
|
||||
else
|
||||
_hCertStore = CertOpenSystemStoreW(0, wcertStore.c_str());
|
||||
}
|
||||
if (!_hCertStore) throw CertificateException("Failed to open certificate store", _certStoreName, GetLastError());
|
||||
|
||||
CERT_RDN_ATTR cert_rdn_attr;
|
||||
cert_rdn_attr.pszObjId = szOID_COMMON_NAME;
|
||||
cert_rdn_attr.dwValueType = CERT_RDN_ANY_TYPE;
|
||||
cert_rdn_attr.Value.cbData = (DWORD) _certNameOrPath.size();
|
||||
cert_rdn_attr.Value.pbData = (BYTE *) _certNameOrPath.c_str();
|
||||
|
||||
CERT_RDN cert_rdn;
|
||||
cert_rdn.cRDNAttr = 1;
|
||||
cert_rdn.rgRDNAttr = &cert_rdn_attr;
|
||||
|
||||
_pCert = CertFindCertificateInStore(_hCertStore, X509_ASN_ENCODING, 0, CERT_FIND_SUBJECT_ATTR, &cert_rdn, NULL);
|
||||
if (!_pCert) throw NoCertificateException(Poco::format("Failed to find certificate %s in store %s", _certNameOrPath, _certStoreName));
|
||||
}
|
||||
|
||||
|
||||
void Context::importCertificate()
|
||||
{
|
||||
Poco::File certFile(_certNameOrPath);
|
||||
if (!certFile.exists()) throw Poco::FileNotFoundException(_certNameOrPath);
|
||||
Poco::File::FileSize size = certFile.getSize();
|
||||
if (size > 4096) throw Poco::DataFormatException("PKCS #12 certificate file too large", _certNameOrPath);
|
||||
Poco::Buffer<char> buffer(static_cast<std::size_t>(size));
|
||||
Poco::FileInputStream istr(_certNameOrPath);
|
||||
istr.read(buffer.begin(), buffer.size());
|
||||
if (istr.gcount() != size) throw Poco::IOException("error reading PKCS #12 certificate file");
|
||||
importCertificate(buffer.begin(), buffer.size());
|
||||
}
|
||||
|
||||
|
||||
void Context::importCertificate(const char* pBuffer, std::size_t size)
|
||||
{
|
||||
std::string password;
|
||||
SSLManager::instance().PrivateKeyPassphraseRequired.notify(&SSLManager::instance(), password);
|
||||
std::wstring wpassword;
|
||||
Poco::UnicodeConverter::toUTF16(password, wpassword);
|
||||
|
||||
// clear UTF-8 password
|
||||
std::fill(const_cast<char*>(password.data()), const_cast<char*>(password.data() + password.size()), 'X');
|
||||
|
||||
CRYPT_DATA_BLOB blob;
|
||||
blob.cbData = static_cast<DWORD>(size);
|
||||
blob.pbData = reinterpret_cast<BYTE*>(const_cast<char*>(pBuffer));
|
||||
|
||||
HCERTSTORE hTempStore = PFXImportCertStore(&blob, wpassword.data(), PKCS12_ALLOW_OVERWRITE_KEY | PKCS12_INCLUDE_EXTENDED_PROPERTIES);
|
||||
|
||||
// clear UTF-16 password
|
||||
std::fill(const_cast<wchar_t*>(wpassword.data()), const_cast<wchar_t*>(wpassword.data() + password.size()), L'X');
|
||||
|
||||
if (hTempStore)
|
||||
{
|
||||
PCCERT_CONTEXT pCert = 0;
|
||||
pCert = CertEnumCertificatesInStore(hTempStore, pCert);
|
||||
while (pCert)
|
||||
{
|
||||
PCCERT_CONTEXT pStoreCert = 0;
|
||||
BOOL res = CertAddCertificateContextToStore(_hMemCertStore, pCert, CERT_STORE_ADD_REPLACE_EXISTING, &pStoreCert);
|
||||
if (res)
|
||||
{
|
||||
if (!_pCert)
|
||||
{
|
||||
_pCert = pStoreCert;
|
||||
}
|
||||
else
|
||||
{
|
||||
CertFreeCertificateContext(pStoreCert);
|
||||
pStoreCert = 0;
|
||||
}
|
||||
}
|
||||
pCert = CertEnumCertificatesInStore(hTempStore, pCert);
|
||||
}
|
||||
CertCloseStore(hTempStore, 0);
|
||||
}
|
||||
else throw CertificateException("failed to import certificate", GetLastError());
|
||||
}
|
||||
|
||||
|
||||
CredHandle& Context::credentials()
|
||||
{
|
||||
Poco::FastMutex::ScopedLock lock(_mutex);
|
||||
|
||||
if (_hCreds.dwLower == 0 && _hCreds.dwUpper == 0)
|
||||
{
|
||||
acquireSchannelCredentials(_hCreds);
|
||||
}
|
||||
return _hCreds;
|
||||
}
|
||||
|
||||
|
||||
void Context::acquireSchannelCredentials(CredHandle& credHandle) const
|
||||
{
|
||||
SCHANNEL_CRED schannelCred;
|
||||
ZeroMemory(&schannelCred, sizeof(schannelCred));
|
||||
schannelCred.dwVersion = SCHANNEL_CRED_VERSION;
|
||||
|
||||
if (_pCert)
|
||||
{
|
||||
schannelCred.cCreds = 1; // how many cred are stored in &pCertContext
|
||||
schannelCred.paCred = &const_cast<PCCERT_CONTEXT>(_pCert);
|
||||
}
|
||||
|
||||
schannelCred.grbitEnabledProtocols = proto();
|
||||
|
||||
// Windows NT and Windows Me/98/95: revocation checking not supported via flags
|
||||
if (_options & Context::OPT_PERFORM_REVOCATION_CHECK)
|
||||
schannelCred.dwFlags |= SCH_CRED_REVOCATION_CHECK_CHAIN;
|
||||
else
|
||||
schannelCred.dwFlags |= SCH_CRED_IGNORE_NO_REVOCATION_CHECK | SCH_CRED_IGNORE_REVOCATION_OFFLINE;
|
||||
|
||||
if (isForServerUse())
|
||||
{
|
||||
if (_mode == Context::VERIFY_STRICT)
|
||||
schannelCred.dwFlags |= SCH_CRED_NO_SYSTEM_MAPPER;
|
||||
|
||||
if (_mode == Context::VERIFY_NONE)
|
||||
schannelCred.dwFlags |= SCH_CRED_MANUAL_CRED_VALIDATION;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (_mode == Context::VERIFY_STRICT)
|
||||
schannelCred.dwFlags |= SCH_CRED_NO_DEFAULT_CREDS;
|
||||
else
|
||||
schannelCred.dwFlags |= SCH_CRED_USE_DEFAULT_CREDS;
|
||||
|
||||
if (_mode == Context::VERIFY_NONE)
|
||||
schannelCred.dwFlags |= SCH_CRED_MANUAL_CRED_VALIDATION | SCH_CRED_NO_SERVERNAME_CHECK;
|
||||
}
|
||||
|
||||
#if defined(SCH_USE_STRONG_CRYPTO)
|
||||
if (_options & Context::OPT_USE_STRONG_CRYPTO)
|
||||
schannelCred.dwFlags |= SCH_USE_STRONG_CRYPTO;
|
||||
#endif
|
||||
|
||||
schannelCred.hRootStore = _hCollectionCertStore;
|
||||
|
||||
TimeStamp tsExpiry;
|
||||
tsExpiry.LowPart = tsExpiry.HighPart = 0;
|
||||
SECURITY_STATUS status = _securityFunctions.AcquireCredentialsHandleW(
|
||||
NULL,
|
||||
UNISP_NAME_W,
|
||||
isForServerUse() ? SECPKG_CRED_INBOUND : SECPKG_CRED_OUTBOUND,
|
||||
NULL,
|
||||
&schannelCred,
|
||||
NULL,
|
||||
NULL,
|
||||
&credHandle,
|
||||
&tsExpiry);
|
||||
|
||||
if (status != SEC_E_OK)
|
||||
{
|
||||
throw SSLException("Failed to acquire Schannel credentials", Utility::formatError(status));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Context::addTrustedCert(const Poco::Net::X509Certificate& cert)
|
||||
DWORD Context::proto() const
|
||||
{
|
||||
Poco::FastMutex::ScopedLock lock(_mutex);
|
||||
CertAddCertificateContextToStore(_hMemCertStore, cert.system(), CERT_STORE_ADD_REPLACE_EXISTING, 0);
|
||||
switch (_usage)
|
||||
{
|
||||
case Context::CLIENT_USE:
|
||||
return SP_PROT_SSL3_CLIENT | SP_PROT_TLS1_CLIENT;
|
||||
case Context::SERVER_USE:
|
||||
return SP_PROT_SSL3_SERVER | SP_PROT_TLS1_SERVER;
|
||||
case Context::TLSV1_CLIENT_USE:
|
||||
return SP_PROT_TLS1_CLIENT;
|
||||
case Context::TLSV1_SERVER_USE:
|
||||
return SP_PROT_TLS1_SERVER;
|
||||
#if defined(SP_PROT_TLS1_1)
|
||||
case Context::TLSV1_1_CLIENT_USE:
|
||||
return SP_PROT_TLS1_1_CLIENT;
|
||||
case Context::TLSV1_1_SERVER_USE:
|
||||
return SP_PROT_TLS1_1_SERVER;
|
||||
#endif
|
||||
#if defined(SP_PROT_TLS1_2)
|
||||
case Context::TLSV1_2_CLIENT_USE:
|
||||
return SP_PROT_TLS1_2_CLIENT;
|
||||
case Context::TLSV1_2_SERVER_USE:
|
||||
return SP_PROT_TLS1_2_SERVER;
|
||||
#endif
|
||||
default:
|
||||
throw Poco::InvalidArgumentException("Unsupported SSL/TLS protocol version");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
} } // namespace Poco::Net
|
||||
|
||||
@@ -37,10 +37,17 @@ InvalidCertificateHandler::InvalidCertificateHandler(bool handleErrorsOnServerSi
|
||||
|
||||
InvalidCertificateHandler::~InvalidCertificateHandler()
|
||||
{
|
||||
if (_handleErrorsOnServerSide)
|
||||
SSLManager::instance().ServerVerificationError -= Delegate<InvalidCertificateHandler, VerificationErrorArgs>(this, &InvalidCertificateHandler::onInvalidCertificate);
|
||||
else
|
||||
SSLManager::instance().ClientVerificationError -= Delegate<InvalidCertificateHandler, VerificationErrorArgs>(this, &InvalidCertificateHandler::onInvalidCertificate);
|
||||
try
|
||||
{
|
||||
if (_handleErrorsOnServerSide)
|
||||
SSLManager::instance().ServerVerificationError -= Delegate<InvalidCertificateHandler, VerificationErrorArgs>(this, &InvalidCertificateHandler::onInvalidCertificate);
|
||||
else
|
||||
SSLManager::instance().ClientVerificationError -= Delegate<InvalidCertificateHandler, VerificationErrorArgs>(this, &InvalidCertificateHandler::onInvalidCertificate);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
poco_unexpected();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
42
NetSSL_Win/src/KeyConsoleHandler.cpp
Normal file
42
NetSSL_Win/src/KeyConsoleHandler.cpp
Normal file
@@ -0,0 +1,42 @@
|
||||
//
|
||||
// KeyConsoleHandler.cpp
|
||||
//
|
||||
// $Id$
|
||||
//
|
||||
// Library: NetSSL_Win
|
||||
// Package: SSLCore
|
||||
// Module: KeyConsoleHandler
|
||||
//
|
||||
// Copyright (c) 2006-2014, Applied Informatics Software Engineering GmbH.
|
||||
// and Contributors.
|
||||
//
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
//
|
||||
|
||||
|
||||
#include "Poco/Net/KeyConsoleHandler.h"
|
||||
#include <iostream>
|
||||
|
||||
|
||||
namespace Poco {
|
||||
namespace Net {
|
||||
|
||||
|
||||
KeyConsoleHandler::KeyConsoleHandler(bool server):PrivateKeyPassphraseHandler(server)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
KeyConsoleHandler::~KeyConsoleHandler()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
void KeyConsoleHandler::onPrivateKeyRequested(const void* pSender, std::string& privateKey)
|
||||
{
|
||||
std::cout << "Please enter the passphrase for the private key: ";
|
||||
std::cin >> privateKey;
|
||||
}
|
||||
|
||||
|
||||
} } // namespace Poco::Net
|
||||
63
NetSSL_Win/src/KeyFileHandler.cpp
Normal file
63
NetSSL_Win/src/KeyFileHandler.cpp
Normal file
@@ -0,0 +1,63 @@
|
||||
//
|
||||
// KeyFileHandler.cpp
|
||||
//
|
||||
// $Id$
|
||||
//
|
||||
// Library: NetSSL_Win
|
||||
// Package: SSLCore
|
||||
// Module: KeyFileHandler
|
||||
//
|
||||
// Copyright (c) 2006-2014, Applied Informatics Software Engineering GmbH.
|
||||
// and Contributors.
|
||||
//
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
//
|
||||
|
||||
|
||||
#include "Poco/Net/KeyFileHandler.h"
|
||||
#include "Poco/Net/SSLManager.h"
|
||||
#include "Poco/File.h"
|
||||
#include "Poco/Util/AbstractConfiguration.h"
|
||||
#include "Poco/Util/Application.h"
|
||||
#include "Poco/Util/OptionException.h"
|
||||
|
||||
|
||||
namespace Poco {
|
||||
namespace Net {
|
||||
|
||||
|
||||
const std::string KeyFileHandler::CFG_PRIV_KEY_FILE("privateKeyPassphraseHandler.options.password");
|
||||
|
||||
|
||||
KeyFileHandler::KeyFileHandler(bool server):PrivateKeyPassphraseHandler(server)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
KeyFileHandler::~KeyFileHandler()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
void KeyFileHandler::onPrivateKeyRequested(const void* pSender, std::string& privateKey)
|
||||
{
|
||||
try
|
||||
{
|
||||
Poco::Util::AbstractConfiguration& config = Poco::Util::Application::instance().config();
|
||||
std::string prefix = serverSide() ? SSLManager::CFG_SERVER_PREFIX : SSLManager::CFG_CLIENT_PREFIX;
|
||||
if (!config.hasProperty(prefix + CFG_PRIV_KEY_FILE))
|
||||
throw Poco::Util::EmptyOptionException(std::string("Missing Configuration Entry: ") + prefix + CFG_PRIV_KEY_FILE);
|
||||
|
||||
privateKey = config.getString(prefix + CFG_PRIV_KEY_FILE);
|
||||
}
|
||||
catch (Poco::NullPointerException&)
|
||||
{
|
||||
throw Poco::IllegalStateException(
|
||||
"An application configuration is required to obtain the private key passphrase, "
|
||||
"but no Poco::Util::Application instance is available."
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
} } // namespace Poco::Net
|
||||
46
NetSSL_Win/src/PrivateKeyFactory.cpp
Normal file
46
NetSSL_Win/src/PrivateKeyFactory.cpp
Normal file
@@ -0,0 +1,46 @@
|
||||
//
|
||||
// PrivateKeyFactory.cpp
|
||||
//
|
||||
// $Id$
|
||||
//
|
||||
// Library: NetSSL_Win
|
||||
// Package: SSLCore
|
||||
// Module: PrivateKeyFactory
|
||||
//
|
||||
// Copyright (c) 2006-2014, Applied Informatics Software Engineering GmbH.
|
||||
// and Contributors.
|
||||
//
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
//
|
||||
|
||||
|
||||
#include "Poco/Net/PrivateKeyFactory.h"
|
||||
#include "Poco/Net/SSLManager.h"
|
||||
|
||||
|
||||
namespace Poco {
|
||||
namespace Net {
|
||||
|
||||
|
||||
PrivateKeyFactory::PrivateKeyFactory()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
PrivateKeyFactory::~PrivateKeyFactory()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
PrivateKeyFactoryRegistrar::PrivateKeyFactoryRegistrar(const std::string& name, PrivateKeyFactory* pFactory)
|
||||
{
|
||||
SSLManager::instance().privateKeyFactoryMgr().setFactory(name, pFactory);
|
||||
}
|
||||
|
||||
|
||||
PrivateKeyFactoryRegistrar::~PrivateKeyFactoryRegistrar()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
} } // namespace Poco::Net
|
||||
69
NetSSL_Win/src/PrivateKeyFactoryMgr.cpp
Normal file
69
NetSSL_Win/src/PrivateKeyFactoryMgr.cpp
Normal file
@@ -0,0 +1,69 @@
|
||||
//
|
||||
// PrivateKeyFactoryMgr.cpp
|
||||
//
|
||||
// $Id$
|
||||
//
|
||||
// Library: NetSSL_Win
|
||||
// Package: SSLCore
|
||||
// Module: PrivateKeyFactoryMgr
|
||||
//
|
||||
// Copyright (c) 2006-2014, Applied Informatics Software Engineering GmbH.
|
||||
// and Contributors.
|
||||
//
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
//
|
||||
|
||||
|
||||
#include "Poco/Net/PrivateKeyFactoryMgr.h"
|
||||
#include "Poco/Net/KeyFileHandler.h"
|
||||
#include "Poco/Net/KeyConsoleHandler.h"
|
||||
|
||||
|
||||
namespace Poco {
|
||||
namespace Net {
|
||||
|
||||
|
||||
PrivateKeyFactoryMgr::PrivateKeyFactoryMgr()
|
||||
{
|
||||
setFactory("KeyFileHandler", new PrivateKeyFactoryImpl<KeyFileHandler>());
|
||||
setFactory("KeyConsoleHandler", new PrivateKeyFactoryImpl<KeyConsoleHandler>());
|
||||
}
|
||||
|
||||
|
||||
PrivateKeyFactoryMgr::~PrivateKeyFactoryMgr()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
void PrivateKeyFactoryMgr::setFactory(const std::string& name, PrivateKeyFactory* pFactory)
|
||||
{
|
||||
bool success = _factories.insert(make_pair(name, Poco::SharedPtr<PrivateKeyFactory>(pFactory))).second;
|
||||
if (!success)
|
||||
delete pFactory;
|
||||
poco_assert(success);
|
||||
}
|
||||
|
||||
|
||||
bool PrivateKeyFactoryMgr::hasFactory(const std::string& name) const
|
||||
{
|
||||
return _factories.find(name) != _factories.end();
|
||||
}
|
||||
|
||||
|
||||
const PrivateKeyFactory* PrivateKeyFactoryMgr::getFactory(const std::string& name) const
|
||||
{
|
||||
FactoriesMap::const_iterator it = _factories.find(name);
|
||||
if (it != _factories.end())
|
||||
return it->second;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void PrivateKeyFactoryMgr::removeFactory(const std::string& name)
|
||||
{
|
||||
_factories.erase(name);
|
||||
}
|
||||
|
||||
|
||||
} } // namespace Poco::Net
|
||||
48
NetSSL_Win/src/PrivateKeyPassphraseHandler.cpp
Normal file
48
NetSSL_Win/src/PrivateKeyPassphraseHandler.cpp
Normal file
@@ -0,0 +1,48 @@
|
||||
//
|
||||
// PrivateKeyPassphraseHandler.cpp
|
||||
//
|
||||
// $Id$
|
||||
//
|
||||
// Library: NetSSL_Win
|
||||
// Package: SSLCore
|
||||
// Module: PrivateKeyPassphraseHandler
|
||||
//
|
||||
// Copyright (c) 2006-2014, Applied Informatics Software Engineering GmbH.
|
||||
// and Contributors.
|
||||
//
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
//
|
||||
|
||||
|
||||
#include "Poco/Net/PrivateKeyPassphraseHandler.h"
|
||||
#include "Poco/Net/SSLManager.h"
|
||||
#include "Poco/Delegate.h"
|
||||
|
||||
|
||||
using Poco::Delegate;
|
||||
|
||||
|
||||
namespace Poco {
|
||||
namespace Net {
|
||||
|
||||
|
||||
PrivateKeyPassphraseHandler::PrivateKeyPassphraseHandler(bool onServerSide): _serverSide(onServerSide)
|
||||
{
|
||||
SSLManager::instance().PrivateKeyPassphraseRequired += Delegate<PrivateKeyPassphraseHandler, std::string>(this, &PrivateKeyPassphraseHandler::onPrivateKeyRequested);
|
||||
}
|
||||
|
||||
|
||||
PrivateKeyPassphraseHandler::~PrivateKeyPassphraseHandler()
|
||||
{
|
||||
try
|
||||
{
|
||||
SSLManager::instance().PrivateKeyPassphraseRequired -= Delegate<PrivateKeyPassphraseHandler, std::string>(this, &PrivateKeyPassphraseHandler::onPrivateKeyRequested);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
poco_unexpected();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
} } // namespace Poco::Net
|
||||
@@ -1,7 +1,7 @@
|
||||
//
|
||||
// SSLException.cpp
|
||||
//
|
||||
// $Id: //poco/1.4/NetSSL_Win/src/SSLException.cpp#1 $
|
||||
// $Id$
|
||||
//
|
||||
// Library: NetSSL_Win
|
||||
// Package: SSLCore
|
||||
@@ -24,8 +24,10 @@ namespace Net {
|
||||
|
||||
POCO_IMPLEMENT_EXCEPTION(SSLException, NetException, "SSL Exception")
|
||||
POCO_IMPLEMENT_EXCEPTION(SSLContextException, SSLException, "SSL context exception")
|
||||
POCO_IMPLEMENT_EXCEPTION(InvalidCertificateException, SSLException, "Invalid certficate")
|
||||
POCO_IMPLEMENT_EXCEPTION(CertificateValidationException, SSLException, "Certificate validation error")
|
||||
POCO_IMPLEMENT_EXCEPTION(CertificateException, SSLException, "Certificate exception")
|
||||
POCO_IMPLEMENT_EXCEPTION(NoCertificateException, CertificateException, "No certificate")
|
||||
POCO_IMPLEMENT_EXCEPTION(InvalidCertificateException, CertificateException, "Invalid certficate")
|
||||
POCO_IMPLEMENT_EXCEPTION(CertificateValidationException, CertificateException, "Certificate validation error")
|
||||
POCO_IMPLEMENT_EXCEPTION(SSLConnectionUnexpectedlyClosedException, SSLException, "SSL connection unexpectedly closed")
|
||||
|
||||
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
//
|
||||
// SSLManager.cpp
|
||||
//
|
||||
// $Id: //poco/1.4/NetSSL_Schannel/src/SSLManager.cpp#1 $
|
||||
// $Id$
|
||||
//
|
||||
// Library: NetSSL_Schannel
|
||||
// Library: NetSSL_Win
|
||||
// Package: SSLCore
|
||||
// Module: SSLManager
|
||||
//
|
||||
@@ -17,11 +17,11 @@
|
||||
#include "Poco/Net/SSLManager.h"
|
||||
#include "Poco/Net/Context.h"
|
||||
#include "Poco/Net/Utility.h"
|
||||
#include "Poco/Net/PrivateKeyPassphraseHandler.h"
|
||||
#include "Poco/SingletonHolder.h"
|
||||
#include "Poco/Delegate.h"
|
||||
#include "Poco/Util/Application.h"
|
||||
#include "Poco/Util/OptionException.h"
|
||||
#include "Poco/Util/LayeredConfiguration.h"
|
||||
|
||||
|
||||
namespace Poco {
|
||||
@@ -30,6 +30,8 @@ namespace Net {
|
||||
|
||||
const std::string SSLManager::CFG_CERT_NAME("certificateName");
|
||||
const std::string SSLManager::VAL_CERT_NAME("");
|
||||
const std::string SSLManager::CFG_CERT_PATH("certificatePath");
|
||||
const std::string SSLManager::VAL_CERT_PATH("");
|
||||
const std::string SSLManager::CFG_CERT_STORE("certificateStore");
|
||||
const std::string SSLManager::VAL_CERT_STORE("MY");
|
||||
const std::string SSLManager::CFG_VER_MODE("verificationMode");
|
||||
@@ -42,6 +44,8 @@ const std::string SSLManager::CFG_USE_MACHINE_STORE("useMachineStore");
|
||||
const bool SSLManager::VAL_USE_MACHINE_STORE(false);
|
||||
const std::string SSLManager::CFG_USE_STRONG_CRYPTO("useStrongCrypto");
|
||||
const bool SSLManager::VAL_USE_STRONG_CRYPTO(true);
|
||||
const std::string SSLManager::CFG_DELEGATE_HANDLER("privateKeyPassphraseHandler.name");
|
||||
const std::string SSLManager::VAL_DELEGATE_HANDLER("KeyConsoleHandler");
|
||||
const std::string SSLManager::CFG_CERTIFICATE_HANDLER("invalidCertificateHandler.name");
|
||||
const std::string SSLManager::VAL_CERTIFICATE_HANDLER("ConsoleCertificateHandler");
|
||||
const std::string SSLManager::CFG_SERVER_PREFIX("schannel.server.");
|
||||
@@ -60,7 +64,15 @@ SSLManager::SSLManager():
|
||||
|
||||
SSLManager::~SSLManager()
|
||||
{
|
||||
shutdown();
|
||||
try
|
||||
{
|
||||
shutdown();
|
||||
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
poco_unexpected();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -76,17 +88,19 @@ SSLManager& SSLManager::instance()
|
||||
}
|
||||
|
||||
|
||||
void SSLManager::initializeServer(InvalidCertificateHandlerPtr& ptrHandler, Context::Ptr ptrContext)
|
||||
void SSLManager::initializeServer(PrivateKeyPassphraseHandlerPtr pPassphraseHandler, InvalidCertificateHandlerPtr pCertHandler, Context::Ptr pContext)
|
||||
{
|
||||
_ptrServerCertificateHandler = ptrHandler;
|
||||
_ptrDefaultServerContext = ptrContext;
|
||||
_ptrServerPassphraseHandler = pPassphraseHandler;
|
||||
_ptrServerCertificateHandler = pCertHandler;
|
||||
_ptrDefaultServerContext = pContext;
|
||||
}
|
||||
|
||||
|
||||
void SSLManager::initializeClient(InvalidCertificateHandlerPtr& ptrHandler, Context::Ptr ptrContext)
|
||||
void SSLManager::initializeClient(PrivateKeyPassphraseHandlerPtr pPassphraseHandler, InvalidCertificateHandlerPtr pCertHandler, Context::Ptr pContext)
|
||||
{
|
||||
_ptrClientCertificateHandler = ptrHandler;
|
||||
_ptrDefaultClientContext = ptrContext;
|
||||
_ptrClientPassphraseHandler = pPassphraseHandler;
|
||||
_ptrClientCertificateHandler = pCertHandler;
|
||||
_ptrDefaultClientContext = pContext;
|
||||
}
|
||||
|
||||
|
||||
@@ -112,6 +126,28 @@ Context::Ptr SSLManager::defaultClientContext()
|
||||
}
|
||||
|
||||
|
||||
SSLManager::PrivateKeyPassphraseHandlerPtr SSLManager::serverPassphraseHandler()
|
||||
{
|
||||
Poco::FastMutex::ScopedLock lock(_mutex);
|
||||
|
||||
if (!_ptrServerPassphraseHandler)
|
||||
initPassphraseHandler(true);
|
||||
|
||||
return _ptrServerPassphraseHandler;
|
||||
}
|
||||
|
||||
|
||||
SSLManager::PrivateKeyPassphraseHandlerPtr SSLManager::clientPassphraseHandler()
|
||||
{
|
||||
Poco::FastMutex::ScopedLock lock(_mutex);
|
||||
|
||||
if (!_ptrClientPassphraseHandler)
|
||||
initPassphraseHandler(false);
|
||||
|
||||
return _ptrClientPassphraseHandler;
|
||||
}
|
||||
|
||||
|
||||
SSLManager::InvalidCertificateHandlerPtr SSLManager::serverCertificateHandler()
|
||||
{
|
||||
Poco::FastMutex::ScopedLock lock(_mutex);
|
||||
@@ -142,8 +178,9 @@ void SSLManager::initDefaultContext(bool server)
|
||||
initEvents(server);
|
||||
|
||||
const std::string prefix = server ? CFG_SERVER_PREFIX : CFG_CLIENT_PREFIX;
|
||||
Poco::Util::LayeredConfiguration& config = Poco::Util::Application::instance().config();
|
||||
Poco::Util::AbstractConfiguration& config = appConfig();
|
||||
std::string certName = config.getString(prefix + CFG_CERT_NAME, VAL_CERT_NAME);
|
||||
std::string certPath = config.getString(prefix + CFG_CERT_PATH, VAL_CERT_PATH);
|
||||
std::string certStore = config.getString(prefix + CFG_CERT_STORE, VAL_CERT_STORE);
|
||||
|
||||
bool requireTLSv1 = config.getBool(prefix + CFG_REQUIRE_TLSV1, false);
|
||||
@@ -168,6 +205,11 @@ void SSLManager::initDefaultContext(bool server)
|
||||
if (trustRoots) options |= Context::OPT_TRUST_ROOTS_WIN_CERT_STORE;
|
||||
if (useMachineStore) options |= Context::OPT_USE_MACHINE_STORE;
|
||||
if (useStrongCrypto) options |= Context::OPT_USE_STRONG_CRYPTO;
|
||||
if (!certPath.empty())
|
||||
{
|
||||
options |= Context::OPT_LOAD_CERT_FROM_FILE;
|
||||
certName = certPath;
|
||||
}
|
||||
|
||||
Context::Usage usage;
|
||||
if (server)
|
||||
@@ -199,17 +241,45 @@ void SSLManager::initDefaultContext(bool server)
|
||||
|
||||
void SSLManager::initEvents(bool server)
|
||||
{
|
||||
initPassphraseHandler(server);
|
||||
initCertificateHandler(server);
|
||||
}
|
||||
|
||||
|
||||
void SSLManager::initPassphraseHandler(bool server)
|
||||
{
|
||||
if (server && _ptrServerPassphraseHandler) return;
|
||||
if (!server && _ptrClientPassphraseHandler) return;
|
||||
|
||||
std::string prefix = server ? CFG_SERVER_PREFIX : CFG_CLIENT_PREFIX;
|
||||
Poco::Util::AbstractConfiguration& config = appConfig();
|
||||
|
||||
std::string className(config.getString(prefix + CFG_DELEGATE_HANDLER, VAL_DELEGATE_HANDLER));
|
||||
|
||||
const PrivateKeyFactory* pFactory = 0;
|
||||
if (privateKeyFactoryMgr().hasFactory(className))
|
||||
{
|
||||
pFactory = privateKeyFactoryMgr().getFactory(className);
|
||||
}
|
||||
|
||||
if (pFactory)
|
||||
{
|
||||
if (server)
|
||||
_ptrServerPassphraseHandler = pFactory->create(server);
|
||||
else
|
||||
_ptrClientPassphraseHandler = pFactory->create(server);
|
||||
}
|
||||
else throw Poco::Util::UnknownOptionException(std::string("No passphrase handler known with the name ") + className);
|
||||
}
|
||||
|
||||
|
||||
void SSLManager::initCertificateHandler(bool server)
|
||||
{
|
||||
if (server && _ptrServerCertificateHandler) return;
|
||||
if (!server && _ptrClientCertificateHandler) return;
|
||||
|
||||
std::string prefix = server ? CFG_SERVER_PREFIX : CFG_CLIENT_PREFIX;
|
||||
Poco::Util::LayeredConfiguration& config = Poco::Util::Application::instance().config();
|
||||
Poco::Util::AbstractConfiguration& config = appConfig();
|
||||
|
||||
std::string className(config.getString(prefix + CFG_CERTIFICATE_HANDLER, VAL_CERTIFICATE_HANDLER));
|
||||
|
||||
@@ -234,8 +304,10 @@ void SSLManager::shutdown()
|
||||
{
|
||||
ClientVerificationError.clear();
|
||||
ServerVerificationError.clear();
|
||||
_ptrServerPassphraseHandler = 0;
|
||||
_ptrServerCertificateHandler = 0;
|
||||
_ptrDefaultServerContext = 0;
|
||||
_ptrClientPassphraseHandler = 0;
|
||||
_ptrClientCertificateHandler = 0;
|
||||
_ptrDefaultClientContext = 0;
|
||||
|
||||
@@ -321,6 +393,22 @@ void SSLManager::unloadSecurityLibrary()
|
||||
}
|
||||
|
||||
|
||||
Poco::Util::AbstractConfiguration& SSLManager::appConfig()
|
||||
{
|
||||
try
|
||||
{
|
||||
return Poco::Util::Application::instance().config();
|
||||
}
|
||||
catch (Poco::NullPointerException&)
|
||||
{
|
||||
throw Poco::IllegalStateException(
|
||||
"An application configuration is required to initialize the Poco::Net::SSLManager, "
|
||||
"but no Poco::Util::Application instance is available."
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void initializeSSL()
|
||||
{
|
||||
}
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
//
|
||||
// SecureSocketImpl.cpp
|
||||
//
|
||||
// $Id: //poco/1.4/NetSSL_Schannel/src/SecureSocketImpl.cpp#1 $
|
||||
// $Id$
|
||||
//
|
||||
// Library: NetSSL_Schannel
|
||||
// Library: NetSSL_Win
|
||||
// Package: SSLSockets
|
||||
// Module: SecureSocketImpl
|
||||
//
|
||||
@@ -75,9 +75,7 @@ SecureSocketImpl::SecureSocketImpl(Poco::AutoPtr<SocketImpl> pSocketImpl, Contex
|
||||
_pSocket(pSocketImpl),
|
||||
_pContext(pContext),
|
||||
_mode(pContext->isForServerUse() ? MODE_SERVER : MODE_CLIENT),
|
||||
_useMachineStore((pContext->options() & Context::OPT_USE_MACHINE_STORE) != 0),
|
||||
_clientAuthRequired(pContext->verificationMode() >= Context::VERIFY_STRICT),
|
||||
_hCertificateStore(0),
|
||||
_pServerCertificate(0),
|
||||
_pPeerCertificate(0),
|
||||
_hCreds(),
|
||||
@@ -155,7 +153,6 @@ void SecureSocketImpl::cleanup()
|
||||
|
||||
if (_hCreds.dwLower != 0 && _hCreds.dwUpper != 0)
|
||||
{
|
||||
_securityFunctions.FreeCredentialsHandle(&_hCreds);
|
||||
_hCreds.dwLower = 0;
|
||||
_hCreds.dwUpper = 0;
|
||||
}
|
||||
@@ -179,12 +176,6 @@ void SecureSocketImpl::cleanup()
|
||||
_pPeerCertificate = 0;
|
||||
}
|
||||
|
||||
if (_hCertificateStore)
|
||||
{
|
||||
CertCloseStore(_hCertificateStore, 0);
|
||||
_hCertificateStore = 0;
|
||||
}
|
||||
|
||||
// must release buffers before unloading library
|
||||
_outSecBuffer.release();
|
||||
_inSecBuffer.release();
|
||||
@@ -657,116 +648,22 @@ void SecureSocketImpl::setPeerHostName(const std::string& peerHostName)
|
||||
}
|
||||
|
||||
|
||||
PCCERT_CONTEXT SecureSocketImpl::loadCertificate(const std::string& certStore, const std::string& certName, bool useMachineStore, bool mustFindCertificate)
|
||||
PCCERT_CONTEXT SecureSocketImpl::loadCertificate(bool mustFindCertificate)
|
||||
{
|
||||
if (mustFindCertificate && certName.empty())
|
||||
throw SSLException("Certificate required, but no certificate name provided");
|
||||
|
||||
PCCERT_CONTEXT pCert = 0;
|
||||
|
||||
std::wstring wcertStore;
|
||||
Poco::UnicodeConverter::convert(certStore, wcertStore);
|
||||
if (!_hCertificateStore)
|
||||
try
|
||||
{
|
||||
if (useMachineStore)
|
||||
_hCertificateStore = CertOpenStore(CERT_STORE_PROV_SYSTEM, 0, 0, CERT_SYSTEM_STORE_LOCAL_MACHINE, certStore.c_str());
|
||||
Poco::Net::X509Certificate cert = _pContext->certificate();
|
||||
PCCERT_CONTEXT pCert = cert.system();
|
||||
// TODO: avoid use of PCCERT_CONTEXT
|
||||
CertDuplicateCertificateContext(pCert);
|
||||
return pCert;
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
if (mustFindCertificate)
|
||||
throw;
|
||||
else
|
||||
_hCertificateStore = CertOpenSystemStoreW(0, wcertStore.c_str());
|
||||
}
|
||||
if (!_hCertificateStore)
|
||||
{
|
||||
throw SSLException("Failed to open certificate store", certStore, GetLastError());
|
||||
}
|
||||
if (!certName.empty())
|
||||
{
|
||||
CERT_RDN_ATTR cert_rdn_attr;
|
||||
cert_rdn_attr.pszObjId = szOID_COMMON_NAME;
|
||||
cert_rdn_attr.dwValueType = CERT_RDN_ANY_TYPE;
|
||||
cert_rdn_attr.Value.cbData = (DWORD) certName.size();
|
||||
cert_rdn_attr.Value.pbData = (BYTE *) certName.c_str();
|
||||
|
||||
CERT_RDN cert_rdn;
|
||||
cert_rdn.cRDNAttr = 1;
|
||||
cert_rdn.rgRDNAttr = &cert_rdn_attr;
|
||||
|
||||
pCert = CertFindCertificateInStore(_hCertificateStore, X509_ASN_ENCODING, 0, CERT_FIND_SUBJECT_ATTR, &cert_rdn, NULL);
|
||||
if (!pCert)
|
||||
{
|
||||
// we throw independently of mustFind. If a name is specified we consider it an error
|
||||
// if we don't find the given certificate
|
||||
throw SSLException(Poco::format("Failed to find certificate %s in store %s", certName, certStore));
|
||||
}
|
||||
}
|
||||
|
||||
if (mustFindCertificate && !pCert)
|
||||
throw SSLException(Poco::format("Failed to find certificate %s in store %s", certName, certStore));
|
||||
|
||||
return pCert;
|
||||
}
|
||||
|
||||
|
||||
void SecureSocketImpl::acquireSchannelContext(Mode mode, PCCERT_CONTEXT pCertContext, CredHandle& outHandle)
|
||||
{
|
||||
SCHANNEL_CRED schannelCred;
|
||||
ZeroMemory(&schannelCred, sizeof(schannelCred));
|
||||
schannelCred.dwVersion = SCHANNEL_CRED_VERSION;
|
||||
|
||||
if (pCertContext != 0)
|
||||
{
|
||||
schannelCred.cCreds = 1; // how many cred are stored in &pCertContext
|
||||
schannelCred.paCred = &pCertContext;
|
||||
}
|
||||
|
||||
schannelCred.grbitEnabledProtocols = proto();
|
||||
|
||||
// Windows NT and Windows Me/98/95: revocation checking not supported via flags
|
||||
if (_pContext->options() & Context::OPT_PERFORM_REVOCATION_CHECK)
|
||||
schannelCred.dwFlags |= SCH_CRED_REVOCATION_CHECK_CHAIN;
|
||||
else
|
||||
schannelCred.dwFlags |= SCH_CRED_IGNORE_NO_REVOCATION_CHECK | SCH_CRED_IGNORE_REVOCATION_OFFLINE;
|
||||
|
||||
if (mode == MODE_SERVER)
|
||||
{
|
||||
if (_pContext->verificationMode() == Context::VERIFY_STRICT)
|
||||
schannelCred.dwFlags |= SCH_CRED_NO_SYSTEM_MAPPER;
|
||||
|
||||
if (_pContext->verificationMode() == Context::VERIFY_NONE)
|
||||
schannelCred.dwFlags |= SCH_CRED_MANUAL_CRED_VALIDATION;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (_pContext->verificationMode() == Context::VERIFY_STRICT)
|
||||
schannelCred.dwFlags |= SCH_CRED_NO_DEFAULT_CREDS;
|
||||
else
|
||||
schannelCred.dwFlags |= SCH_CRED_USE_DEFAULT_CREDS;
|
||||
|
||||
if (_pContext->verificationMode() == Context::VERIFY_NONE)
|
||||
schannelCred.dwFlags |= SCH_CRED_MANUAL_CRED_VALIDATION | SCH_CRED_NO_SERVERNAME_CHECK;
|
||||
}
|
||||
|
||||
#if defined(SCH_USE_STRONG_CRYPTO)
|
||||
if (_pContext->options() & Context::OPT_USE_STRONG_CRYPTO)
|
||||
schannelCred.dwFlags |= SCH_USE_STRONG_CRYPTO;
|
||||
#endif
|
||||
|
||||
schannelCred.hRootStore = _pContext->certificateStore();
|
||||
|
||||
TimeStamp tsExpiry;
|
||||
tsExpiry.LowPart = tsExpiry.HighPart = 0;
|
||||
SECURITY_STATUS status = _securityFunctions.AcquireCredentialsHandleW(
|
||||
NULL,
|
||||
UNISP_NAME_W,
|
||||
mode == MODE_SERVER ? SECPKG_CRED_INBOUND : SECPKG_CRED_OUTBOUND,
|
||||
NULL,
|
||||
&schannelCred,
|
||||
NULL,
|
||||
NULL,
|
||||
&outHandle,
|
||||
&tsExpiry);
|
||||
|
||||
if (status != SEC_E_OK)
|
||||
{
|
||||
throw SSLException("Failed to acquire Schannel credentials", Utility::formatError(status));
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -818,8 +715,8 @@ void SecureSocketImpl::clientConnectVerify()
|
||||
|
||||
void SecureSocketImpl::initClientContext()
|
||||
{
|
||||
_pServerCertificate = loadCertificate(_pContext->certificateStoreName(), _pContext->certificateName(), _useMachineStore, false);
|
||||
acquireSchannelContext(MODE_CLIENT, _pServerCertificate, _hCreds);
|
||||
_pServerCertificate = loadCertificate(false);
|
||||
_hCreds = _pContext->credentials();
|
||||
}
|
||||
|
||||
|
||||
@@ -1104,8 +1001,8 @@ void SecureSocketImpl::performClientHandshakeLoopIncompleteMessage()
|
||||
|
||||
void SecureSocketImpl::initServerContext()
|
||||
{
|
||||
_pServerCertificate = loadCertificate(_pContext->certificateStoreName(), _pContext->certificateName(), _useMachineStore, true);
|
||||
acquireSchannelContext(MODE_SERVER, _pServerCertificate, _hCreds);
|
||||
_pServerCertificate = loadCertificate(true);
|
||||
_hCreds = _pContext->credentials();
|
||||
}
|
||||
|
||||
|
||||
@@ -1593,36 +1490,6 @@ LONG SecureSocketImpl::serverDisconnect(PCredHandle phCreds, CtxtHandle *phConte
|
||||
}
|
||||
|
||||
|
||||
DWORD SecureSocketImpl::proto() const
|
||||
{
|
||||
switch (_pContext->usage())
|
||||
{
|
||||
case Context::CLIENT_USE:
|
||||
return SP_PROT_SSL3_CLIENT | SP_PROT_TLS1_CLIENT;
|
||||
case Context::SERVER_USE:
|
||||
return SP_PROT_SSL3_SERVER | SP_PROT_TLS1_SERVER;
|
||||
case Context::TLSV1_CLIENT_USE:
|
||||
return SP_PROT_TLS1_CLIENT;
|
||||
case Context::TLSV1_SERVER_USE:
|
||||
return SP_PROT_TLS1_SERVER;
|
||||
#if defined(SP_PROT_TLS1_1)
|
||||
case Context::TLSV1_1_CLIENT_USE:
|
||||
return SP_PROT_TLS1_1_CLIENT;
|
||||
case Context::TLSV1_1_SERVER_USE:
|
||||
return SP_PROT_TLS1_1_SERVER;
|
||||
#endif
|
||||
#if defined(SP_PROT_TLS1_2)
|
||||
case Context::TLSV1_2_CLIENT_USE:
|
||||
return SP_PROT_TLS1_2_CLIENT;
|
||||
case Context::TLSV1_2_SERVER_USE:
|
||||
return SP_PROT_TLS1_2_SERVER;
|
||||
#endif
|
||||
default:
|
||||
throw Poco::InvalidArgumentException("Unsupported SSL/TLS protocol version");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void SecureSocketImpl::stateIllegal()
|
||||
{
|
||||
throw Poco::IllegalStateException("SSL state machine");
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
//
|
||||
// Utility.cpp
|
||||
//
|
||||
// $Id: //poco/1.4/NetSSL_Schannel/src/Utility.cpp#1 $
|
||||
// $Id$
|
||||
//
|
||||
// Library: NetSSL_Schannel
|
||||
// Library: NetSSL_Win
|
||||
// Package: SSLCore
|
||||
// Module: Utility
|
||||
//
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
//
|
||||
// X509Certificate.cpp
|
||||
//
|
||||
// $Id: //poco/1.4/Crypto/src/X509Certificate.cpp#1 $
|
||||
// $Id$
|
||||
//
|
||||
// Library: Crypto
|
||||
// Package: Certificate
|
||||
@@ -15,13 +15,18 @@
|
||||
|
||||
|
||||
#include "Poco/Net/X509Certificate.h"
|
||||
#include "Poco/Net/SSLException.h"
|
||||
#include "Poco/StreamCopier.h"
|
||||
#include "Poco/String.h"
|
||||
#include "Poco/DateTimeParser.h"
|
||||
#include "Poco/Base64Encoder.h"
|
||||
#include "Poco/Base64Decoder.h"
|
||||
#include "Poco/File.h"
|
||||
#include "Poco/FileStream.h"
|
||||
#include "Poco/MemoryStream.h"
|
||||
#include "Poco/Buffer.h"
|
||||
#include "Poco/UnicodeConverter.h"
|
||||
#include "Poco/Format.h"
|
||||
#include <sstream>
|
||||
|
||||
|
||||
@@ -29,17 +34,17 @@ namespace Poco {
|
||||
namespace Net {
|
||||
|
||||
|
||||
X509Certificate::X509Certificate(std::istream& istr):
|
||||
_pCert(0)
|
||||
{
|
||||
load(istr);
|
||||
}
|
||||
|
||||
|
||||
X509Certificate::X509Certificate(const std::string& path):
|
||||
_pCert(0)
|
||||
{
|
||||
load(path);
|
||||
importCertificate(path);
|
||||
}
|
||||
|
||||
|
||||
X509Certificate::X509Certificate(const std::string& certName, const std::string& certStoreName, bool useMachineStore):
|
||||
_pCert(0)
|
||||
{
|
||||
loadCertificate(certName, certStoreName, useMachineStore);
|
||||
}
|
||||
|
||||
|
||||
@@ -98,36 +103,6 @@ X509Certificate::~X509Certificate()
|
||||
}
|
||||
|
||||
|
||||
void X509Certificate::load(std::istream& istr)
|
||||
{
|
||||
poco_assert (!_pCert);
|
||||
|
||||
// TODO
|
||||
|
||||
init();
|
||||
}
|
||||
|
||||
|
||||
void X509Certificate::load(const std::string& path)
|
||||
{
|
||||
Poco::FileInputStream istr(path);
|
||||
load(istr);
|
||||
}
|
||||
|
||||
|
||||
void X509Certificate::save(std::ostream& stream) const
|
||||
{
|
||||
// TODO
|
||||
}
|
||||
|
||||
|
||||
void X509Certificate::save(const std::string& path) const
|
||||
{
|
||||
Poco::FileOutputStream ostr(path);
|
||||
save(ostr);
|
||||
}
|
||||
|
||||
|
||||
void X509Certificate::init()
|
||||
{
|
||||
wchar_t data[256];
|
||||
@@ -253,4 +228,97 @@ void* X509Certificate::nid2oid(NID nid)
|
||||
}
|
||||
|
||||
|
||||
void X509Certificate::loadCertificate(const std::string& certName, const std::string& certStoreName, bool useMachineStore)
|
||||
{
|
||||
std::wstring wcertStore;
|
||||
Poco::UnicodeConverter::convert(certStoreName, wcertStore);
|
||||
HCERTSTORE hCertStore;
|
||||
if (useMachineStore)
|
||||
hCertStore = CertOpenStore(CERT_STORE_PROV_SYSTEM, 0, 0, CERT_SYSTEM_STORE_LOCAL_MACHINE, certStoreName.c_str());
|
||||
else
|
||||
hCertStore = CertOpenSystemStoreW(0, wcertStore.c_str());
|
||||
|
||||
if (!hCertStore) throw CertificateException("Failed to open certificate store", certStoreName, GetLastError());
|
||||
|
||||
CERT_RDN_ATTR cert_rdn_attr;
|
||||
cert_rdn_attr.pszObjId = szOID_COMMON_NAME;
|
||||
cert_rdn_attr.dwValueType = CERT_RDN_ANY_TYPE;
|
||||
cert_rdn_attr.Value.cbData = (DWORD) certName.size();
|
||||
cert_rdn_attr.Value.pbData = (BYTE *) certName.c_str();
|
||||
|
||||
CERT_RDN cert_rdn;
|
||||
cert_rdn.cRDNAttr = 1;
|
||||
cert_rdn.rgRDNAttr = &cert_rdn_attr;
|
||||
|
||||
_pCert = CertFindCertificateInStore(hCertStore, X509_ASN_ENCODING, 0, CERT_FIND_SUBJECT_ATTR, &cert_rdn, NULL);
|
||||
if (!_pCert)
|
||||
{
|
||||
CertCloseStore(hCertStore, 0);
|
||||
throw NoCertificateException(Poco::format("Failed to find certificate %s in store %s", certName, certStoreName));
|
||||
}
|
||||
CertCloseStore(hCertStore, 0);
|
||||
}
|
||||
|
||||
|
||||
void X509Certificate::importCertificate(const std::string& certPath)
|
||||
{
|
||||
Poco::File certFile(certPath);
|
||||
if (!certFile.exists()) throw Poco::FileNotFoundException(certPath);
|
||||
Poco::File::FileSize size = certFile.getSize();
|
||||
if (size > 4096) throw Poco::DataFormatException("certificate file too large", certPath);
|
||||
if (size < 32) throw Poco::DataFormatException("certificate file too small", certPath);
|
||||
Poco::Buffer<char> buffer(static_cast<std::size_t>(size));
|
||||
Poco::FileInputStream istr(certPath);
|
||||
istr.read(buffer.begin(), buffer.size());
|
||||
if (istr.gcount() != size) throw Poco::IOException("error reading certificate file");
|
||||
importCertificate(buffer.begin(), buffer.size());
|
||||
}
|
||||
|
||||
|
||||
void X509Certificate::importCertificate(const char* pBuffer, std::size_t size)
|
||||
{
|
||||
if (std::memcmp(pBuffer, "-----BEGIN CERTIFICATE-----", 27) == 0)
|
||||
importPEMCertificate(pBuffer + 27, size - 27);
|
||||
else
|
||||
importDERCertificate(pBuffer, size);
|
||||
}
|
||||
|
||||
|
||||
void X509Certificate::importPEMCertificate(const char* pBuffer, std::size_t size)
|
||||
{
|
||||
Poco::Buffer<char> derBuffer(size);
|
||||
std::size_t derSize = 0;
|
||||
|
||||
const char* pemBegin = pBuffer;
|
||||
const char* pemEnd = pemBegin + (size - 25);
|
||||
while (pemEnd > pemBegin && std::memcmp(pemEnd, "-----END CERTIFICATE-----", 25) != 0) --pemEnd;
|
||||
if (pemEnd == pemBegin) throw Poco::DataFormatException("Not a valid PEM file - end marker missing");
|
||||
|
||||
Poco::MemoryInputStream istr(pemBegin, pemEnd - pemBegin);
|
||||
Poco::Base64Decoder dec(istr);
|
||||
|
||||
char* derBegin = derBuffer.begin();
|
||||
char* derEnd = derBegin;
|
||||
|
||||
int ch = dec.get();
|
||||
while (ch != -1)
|
||||
{
|
||||
*derEnd++ = static_cast<char>(ch);
|
||||
ch = dec.get();
|
||||
}
|
||||
|
||||
importDERCertificate(derBegin, derEnd - derBegin);
|
||||
}
|
||||
|
||||
|
||||
void X509Certificate::importDERCertificate(const char* pBuffer, std::size_t size)
|
||||
{
|
||||
_pCert = CertCreateCertificateContext(X509_ASN_ENCODING, reinterpret_cast<const BYTE*>(pBuffer), static_cast<DWORD>(size));
|
||||
if (!_pCert)
|
||||
{
|
||||
throw Poco::DataFormatException("Failed to load certificate from file", GetLastError());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
} } // namespace Poco::Net
|
||||
|
||||
Reference in New Issue
Block a user