1
0
mirror of https://github.com/VCMP-SqMod/SqMod.git synced 2025-06-22 18:17:11 +02:00

Major plugin refactor and cleanup.

Switched to POCO library for unified platform/library interface.
Deprecated the external module API. It was creating more problems than solving.
Removed most built-in libraries in favor of system libraries for easier maintenance.
Cleaned and secured code with help from static analyzers.
This commit is contained in:
Sandu Liviu Catalin
2021-01-30 08:51:39 +02:00
parent e0e34b4030
commit 4a6bfc086c
6219 changed files with 1209835 additions and 454916 deletions

View File

@ -0,0 +1,38 @@
//
// AcceptCertificateHandler.cpp
//
// Library: NetSSL_Win
// Package: SSLCore
// Module: AcceptCertificateHandler
//
// Copyright (c) 2006-2014, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// SPDX-License-Identifier: BSL-1.0
//
#include "Poco/Net/AcceptCertificateHandler.h"
namespace Poco {
namespace Net {
AcceptCertificateHandler::AcceptCertificateHandler(bool server): InvalidCertificateHandler(server)
{
}
AcceptCertificateHandler::~AcceptCertificateHandler()
{
}
void AcceptCertificateHandler::onInvalidCertificate(const void*, VerificationErrorArgs& errorCert)
{
errorCert.setIgnoreError(true);
}
} } // namespace Poco::Net

View File

@ -0,0 +1,44 @@
//
// CertificateHandlerFactory.cpp
//
// Library: NetSSL_Win
// Package: SSLCore
// Module: CertificateHandlerFactory
//
// Copyright (c) 2006-2014, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// SPDX-License-Identifier: BSL-1.0
//
#include "Poco/Net/CertificateHandlerFactory.h"
#include "Poco/Net/SSLManager.h"
namespace Poco {
namespace Net {
CertificateHandlerFactory::CertificateHandlerFactory()
{
}
CertificateHandlerFactory::~CertificateHandlerFactory()
{
}
CertificateHandlerFactoryRegistrar::CertificateHandlerFactoryRegistrar(const std::string& name, CertificateHandlerFactory* pFactory)
{
SSLManager::instance().certificateHandlerFactoryMgr().setFactory(name, pFactory);
}
CertificateHandlerFactoryRegistrar::~CertificateHandlerFactoryRegistrar()
{
}
} } // namespace Poco::Net

View File

@ -0,0 +1,69 @@
//
// CertificateHandlerFactoryMgr.cpp
//
// Library: NetSSL_Win
// Package: SSLCore
// Module: CertificateHandlerFactoryMgr
//
// Copyright (c) 2006-2014, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// SPDX-License-Identifier: BSL-1.0
//
#include "Poco/Net/CertificateHandlerFactoryMgr.h"
#include "Poco/Net/ConsoleCertificateHandler.h"
#include "Poco/Net/AcceptCertificateHandler.h"
#include "Poco/Net/RejectCertificateHandler.h"
namespace Poco {
namespace Net {
CertificateHandlerFactoryMgr::CertificateHandlerFactoryMgr()
{
setFactory("ConsoleCertificateHandler", new CertificateHandlerFactoryImpl<ConsoleCertificateHandler>());
setFactory("AcceptCertificateHandler", new CertificateHandlerFactoryImpl<AcceptCertificateHandler>());
setFactory("RejectCertificateHandler", new CertificateHandlerFactoryImpl<RejectCertificateHandler>());
}
CertificateHandlerFactoryMgr::~CertificateHandlerFactoryMgr()
{
}
void CertificateHandlerFactoryMgr::setFactory(const std::string& name, CertificateHandlerFactory* pFactory)
{
bool success = _factories.insert(make_pair(name, Poco::SharedPtr<CertificateHandlerFactory>(pFactory))).second;
if (!success)
delete pFactory;
poco_assert(success);
}
bool CertificateHandlerFactoryMgr::hasFactory(const std::string& name) const
{
return _factories.find(name) != _factories.end();
}
const CertificateHandlerFactory* CertificateHandlerFactoryMgr::getFactory(const std::string& name) const
{
FactoriesMap::const_iterator it = _factories.find(name);
if (it != _factories.end())
return it->second;
else
return 0;
}
void CertificateHandlerFactoryMgr::removeFactory(const std::string& name)
{
_factories.erase(name);
}
} } // namespace Poco::Net

View File

@ -0,0 +1,53 @@
//
// ConsoleCertificateHandler.cpp
//
// Library: NetSSL_Win
// Package: SSLCore
// Module: ConsoleCertificateHandler
//
// Copyright (c) 2006-2014, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// SPDX-License-Identifier: BSL-1.0
//
#include "Poco/Net/ConsoleCertificateHandler.h"
#include <iostream>
namespace Poco {
namespace Net {
ConsoleCertificateHandler::ConsoleCertificateHandler(bool server): InvalidCertificateHandler(server)
{
}
ConsoleCertificateHandler::~ConsoleCertificateHandler()
{
}
void ConsoleCertificateHandler::onInvalidCertificate(const void*, VerificationErrorArgs& errorCert)
{
const X509Certificate& aCert = errorCert.certificate();
std::cout << "\n";
std::cout << "WARNING: Certificate verification failed\n";
std::cout << "----------------------------------------\n";
std::cout << "Issuer Name: " << aCert.issuerName() << "\n";
std::cout << "Subject Name: " << aCert.subjectName() << "\n\n";
std::cout << "The certificate yielded the error: " << errorCert.errorMessage() << "\n\n";
std::cout << "The error occurred in the certificate chain at position " << errorCert.errorDepth() << "\n";
std::cout << "Accept the certificate (y,n)? ";
char c;
std::cin >> c;
if (c == 'y' || c == 'Y')
errorCert.setIgnoreError(true);
else
errorCert.setIgnoreError(false);
}
} } // namespace Poco::Net

521
vendor/POCO/NetSSL_Win/src/Context.cpp vendored Normal file
View File

@ -0,0 +1,521 @@
//
// Context.cpp
//
// Library: NetSSL_Win
// Package: SSLCore
// Module: Context
//
// Copyright (c) 2006-2014, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// SPDX-License-Identifier: BSL-1.0
//
#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 {
namespace Net {
const std::string Context::CERT_STORE_MY("MY");
const std::string Context::CERT_STORE_ROOT("ROOT");
const std::string Context::CERT_STORE_TRUST("TRUST");
const std::string Context::CERT_STORE_CA("CA");
const std::string Context::CERT_STORE_USERDS("USERDS");
Context::Context(Usage usage,
const std::string& certNameOrPath,
VerificationMode verMode,
int options,
const std::string& certStore):
_usage(usage),
_mode(verMode),
_options(options),
_disabledProtocols(0),
_extendedCertificateVerification(true),
_certNameOrPath(certNameOrPath),
_certStoreName(certStore),
_hMemCertStore(0),
_hCollectionCertStore(0),
_hRootCertStore(0),
_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
NULL, // Use the default provider
0, // Accept the default dwFlags
NULL); // pvPara is not used
if (!_hMemCertStore)
throw SSLException("Failed to create memory certificate store", GetLastError());
_hCollectionCertStore = CertOpenStore(
CERT_STORE_PROV_COLLECTION, // A collection store
0, // Encoding type; not used with a collection store
NULL, // Use the default provider
0, // No flags
NULL); // Not needed
if (!_hCollectionCertStore)
throw SSLException("Failed to create collection store", GetLastError());
if (!CertAddStoreToCollection(_hCollectionCertStore, _hMemCertStore, CERT_PHYSICAL_STORE_ADD_ENABLE_FLAG, 1))
throw SSLException("Failed to add memory certificate store to collection store", GetLastError());
if (_options & OPT_TRUST_ROOTS_WIN_CERT_STORE)
{
// add root certificates
std::wstring rootStore;
Poco::UnicodeConverter::convert(CERT_STORE_ROOT, rootStore);
_hRootCertStore = CertOpenSystemStoreW(0, rootStore.c_str());
if (!_hRootCertStore)
throw SSLException("Failed to open root certificate store", GetLastError());
if (!CertAddStoreToCollection(_hCollectionCertStore, _hRootCertStore, CERT_PHYSICAL_STORE_ADD_ENABLE_FLAG, 1))
throw SSLException("Failed to add root certificate store to collection store", GetLastError());
}
}
void Context::enableExtendedCertificateVerification(bool flag)
{
_extendedCertificateVerification = flag;
}
void Context::addTrustedCert(const Poco::Net::X509Certificate& cert)
{
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)
{
importCertificate();
}
else
{
loadCertificate();
}
return Poco::Net::X509Certificate(_pCert, true);
}
void Context::loadCertificate()
{
std::wstring wcertStoreName;
Poco::UnicodeConverter::convert(_certStoreName, wcertStoreName);
if (!_hCertStore)
{
if (_options & OPT_USE_MACHINE_STORE)
_hCertStore = CertOpenStore(CERT_STORE_PROV_SYSTEM, 0, 0, CERT_SYSTEM_STORE_LOCAL_MACHINE, wcertStoreName.c_str());
else
_hCertStore = CertOpenSystemStoreW(0, wcertStoreName.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();
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 (!_extendedCertificateVerification)
schannelCred.dwFlags |= 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 = schannelCred.hRootStore = isForServerUse() ? _hCollectionCertStore : NULL;
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));
}
}
DWORD Context::proto() const
{
DWORD result = 0;
switch (_usage)
{
case Context::TLS_CLIENT_USE:
case Context::CLIENT_USE:
result = SP_PROT_SSL3_CLIENT
| SP_PROT_TLS1_CLIENT
#if defined(SP_PROT_TLS1_1)
| SP_PROT_TLS1_1_CLIENT
#endif
#if defined(SP_PROT_TLS1_2)
| SP_PROT_TLS1_2_CLIENT
#endif
#if defined(SP_PROT_TLS1_3)
| SP_PROT_TLS1_3_CLIENT
#endif
;
break;
case Context::TLS_SERVER_USE:
case Context::SERVER_USE:
result = SP_PROT_SSL3_SERVER
| SP_PROT_TLS1_SERVER
#if defined(SP_PROT_TLS1_1)
| SP_PROT_TLS1_1_SERVER
#endif
#if defined(SP_PROT_TLS1_2)
| SP_PROT_TLS1_2_SERVER
#endif
#if defined(SP_PROT_TLS1_3)
| SP_PROT_TLS1_3_SERVER
#endif
;
break;
case Context::TLSV1_CLIENT_USE:
result = SP_PROT_TLS1_CLIENT
#if defined(SP_PROT_TLS1_1)
| SP_PROT_TLS1_1_CLIENT
#endif
#if defined(SP_PROT_TLS1_2)
| SP_PROT_TLS1_2_CLIENT
#endif
#if defined(SP_PROT_TLS1_3)
| SP_PROT_TLS1_3_CLIENT
#endif
;
break;
case Context::TLSV1_SERVER_USE:
result = SP_PROT_TLS1_SERVER
#if defined(SP_PROT_TLS1_1)
| SP_PROT_TLS1_1_SERVER
#endif
#if defined(SP_PROT_TLS1_2)
| SP_PROT_TLS1_2_SERVER
#endif
#if defined(SP_PROT_TLS1_3)
| SP_PROT_TLS1_3_SERVER
#endif
;
break;
#if defined(SP_PROT_TLS1_1)
case Context::TLSV1_1_CLIENT_USE:
result = SP_PROT_TLS1_1_CLIENT
#if defined(SP_PROT_TLS1_2)
| SP_PROT_TLS1_2_CLIENT
#endif
#if defined(SP_PROT_TLS1_3)
| SP_PROT_TLS1_3_CLIENT
#endif
;
break;
case Context::TLSV1_1_SERVER_USE:
result = SP_PROT_TLS1_1_SERVER
#if defined(SP_PROT_TLS1_2)
| SP_PROT_TLS1_2_SERVER
#endif
#if defined(SP_PROT_TLS1_3)
| SP_PROT_TLS1_3_SERVER
#endif
;
break;
#endif
#if defined(SP_PROT_TLS1_2)
case Context::TLSV1_2_CLIENT_USE:
result = SP_PROT_TLS1_2_CLIENT
#if defined(SP_PROT_TLS1_3)
| SP_PROT_TLS1_3_CLIENT
#endif
;
break;
case Context::TLSV1_2_SERVER_USE:
result = SP_PROT_TLS1_2_SERVER
#if defined(SP_PROT_TLS1_3)
| SP_PROT_TLS1_3_SERVER
#endif
;
break;
#endif
#if defined(SP_PROT_TLS1_3)
case Context::TLSV1_3_CLIENT_USE:
result = SP_PROT_TLS1_3_CLIENT;
break;
case Context::TLSV1_3_SERVER_USE:
result = SP_PROT_TLS1_3_SERVER;
break;
#endif
default:
throw Poco::InvalidArgumentException("Unsupported SSL/TLS protocol version");
}
return result & enabledProtocols();
}
DWORD Context::enabledProtocols() const
{
DWORD result = 0;
if (!(_disabledProtocols & PROTO_SSLV3))
{
result |= SP_PROT_SSL3_CLIENT | SP_PROT_SSL3_SERVER;
}
if (!(_disabledProtocols & PROTO_TLSV1))
{
result |= SP_PROT_TLS1_CLIENT | SP_PROT_TLS1_SERVER;
}
if (!(_disabledProtocols & PROTO_TLSV1_1))
{
#ifdef SP_PROT_TLS1_1_CLIENT
result |= SP_PROT_TLS1_1_CLIENT | SP_PROT_TLS1_1_SERVER;
#endif
}
if (!(_disabledProtocols & PROTO_TLSV1_2))
{
#ifdef SP_PROT_TLS1_2_CLIENT
result |= SP_PROT_TLS1_2_CLIENT | SP_PROT_TLS1_2_SERVER;
#endif
}
if (!(_disabledProtocols & PROTO_TLSV1_3))
{
#ifdef SP_PROT_TLS1_3_CLIENT
result |= SP_PROT_TLS1_3_CLIENT | SP_PROT_TLS1_3_SERVER;
#endif
}
return result;
}
void Context::disableProtocols(int protocols)
{
_disabledProtocols = protocols;
}
void Context::requireMinimumProtocol(Protocols protocol)
{
_disabledProtocols = 0;
switch (protocol)
{
case PROTO_SSLV3:
_disabledProtocols = PROTO_SSLV2;
break;
case PROTO_TLSV1:
_disabledProtocols = PROTO_SSLV2 | PROTO_SSLV3;
break;
case PROTO_TLSV1_1:
_disabledProtocols = PROTO_SSLV2 | PROTO_SSLV3 | PROTO_TLSV1;
break;
case PROTO_TLSV1_2:
_disabledProtocols = PROTO_SSLV2 | PROTO_SSLV3 | PROTO_TLSV1 | PROTO_TLSV1_1;
break;
case PROTO_TLSV1_3:
_disabledProtocols = PROTO_SSLV2 | PROTO_SSLV3 | PROTO_TLSV1 | PROTO_TLSV1_1 | PROTO_TLSV1_2;
break;
}
}
} } // namespace Poco::Net

View File

@ -0,0 +1,191 @@
//
// HTTPSClientSession.cpp
//
// Library: NetSSL_Win
// Package: HTTPSClient
// Module: HTTPSClientSession
//
// Copyright (c) 2006-2010, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// SPDX-License-Identifier: BSL-1.0
//
#include "Poco/Net/HTTPSClientSession.h"
#include "Poco/Net/SecureStreamSocket.h"
#include "Poco/Net/SecureStreamSocketImpl.h"
#include "Poco/Net/SSLManager.h"
#include "Poco/Net/SSLException.h"
#include "Poco/Net/HTTPRequest.h"
#include "Poco/Net/HTTPResponse.h"
#include "Poco/Net/NetException.h"
#include "Poco/NumberFormatter.h"
using Poco::NumberFormatter;
using Poco::IllegalStateException;
namespace Poco {
namespace Net {
HTTPSClientSession::HTTPSClientSession():
HTTPClientSession(SecureStreamSocket()),
_pContext(SSLManager::instance().defaultClientContext())
{
setPort(HTTPS_PORT);
}
HTTPSClientSession::HTTPSClientSession(const SecureStreamSocket& socket):
HTTPClientSession(socket),
_pContext(socket.context())
{
setPort(HTTPS_PORT);
}
HTTPSClientSession::HTTPSClientSession(const SecureStreamSocket& socket, Session::Ptr pSession):
HTTPClientSession(socket),
_pContext(socket.context()),
_pSession(pSession)
{
setPort(HTTPS_PORT);
}
HTTPSClientSession::HTTPSClientSession(const std::string& host, Poco::UInt16 port):
HTTPClientSession(SecureStreamSocket()),
_pContext(SSLManager::instance().defaultClientContext())
{
setHost(host);
setPort(port);
SecureStreamSocket sss(socket());
sss.setPeerHostName(host);
}
HTTPSClientSession::HTTPSClientSession(Context::Ptr pContext):
HTTPClientSession(SecureStreamSocket(pContext)),
_pContext(pContext)
{
}
HTTPSClientSession::HTTPSClientSession(Context::Ptr pContext, Session::Ptr pSession):
HTTPClientSession(SecureStreamSocket(pContext, pSession)),
_pContext(pContext),
_pSession(pSession)
{
}
HTTPSClientSession::HTTPSClientSession(const std::string& host, Poco::UInt16 port, Context::Ptr pContext):
HTTPClientSession(SecureStreamSocket(pContext)),
_pContext(pContext)
{
setHost(host);
setPort(port);
SecureStreamSocket sss(socket());
sss.setPeerHostName(host);
}
HTTPSClientSession::HTTPSClientSession(const std::string& host, Poco::UInt16 port, Context::Ptr pContext, Session::Ptr pSession):
HTTPClientSession(SecureStreamSocket(pContext, pSession)),
_pContext(pContext),
_pSession(pSession)
{
setHost(host);
setPort(port);
SecureStreamSocket sss(socket());
sss.setPeerHostName(host);
}
HTTPSClientSession::~HTTPSClientSession()
{
}
bool HTTPSClientSession::secure() const
{
return true;
}
void HTTPSClientSession::abort()
{
SecureStreamSocket sss(socket());
sss.abort();
}
X509Certificate HTTPSClientSession::serverCertificate()
{
SecureStreamSocket sss(socket());
return sss.peerCertificate();
}
std::string HTTPSClientSession::proxyRequestPrefix() const
{
return std::string();
}
void HTTPSClientSession::proxyAuthenticate(HTTPRequest& request)
{
}
void HTTPSClientSession::connect(const SocketAddress& address)
{
if (getProxyHost().empty() || bypassProxy())
{
SecureStreamSocket sss(socket());
if (_pContext->sessionCacheEnabled())
{
sss.useSession(_pSession);
}
HTTPSession::connect(address);
if (_pContext->sessionCacheEnabled())
{
_pSession = sss.currentSession();
}
}
else
{
StreamSocket proxySocket(proxyConnect());
SecureStreamSocket secureSocket = SecureStreamSocket::attach(proxySocket, getHost(), _pContext, _pSession);
attachSocket(secureSocket);
if (_pContext->sessionCacheEnabled())
{
_pSession = secureSocket.currentSession();
}
}
}
int HTTPSClientSession::read(char* buffer, std::streamsize length)
{
try
{
return HTTPSession::read(buffer, length);
}
catch(SSLConnectionUnexpectedlyClosedException&)
{
return 0;
}
}
Session::Ptr HTTPSClientSession::sslSession()
{
return _pSession;
}
} } // namespace Poco::Net

View File

@ -0,0 +1,68 @@
//
// HTTPSSessionInstantiator.cpp
//
// Library: NetSSL_Win
// Package: HTTPSClient
// Module: HTTPSSessionInstantiator
//
// Copyright (c) 2006-2009, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// SPDX-License-Identifier: BSL-1.0
//
#include "Poco/Net/HTTPSSessionInstantiator.h"
#include "Poco/Net/HTTPSessionFactory.h"
#include "Poco/Net/HTTPSClientSession.h"
namespace Poco {
namespace Net {
HTTPSSessionInstantiator::HTTPSSessionInstantiator()
{
}
HTTPSSessionInstantiator::HTTPSSessionInstantiator(Context::Ptr pContext) :
_pContext(pContext)
{
}
HTTPSSessionInstantiator::~HTTPSSessionInstantiator()
{
}
HTTPClientSession* HTTPSSessionInstantiator::createClientSession(const Poco::URI& uri)
{
poco_assert (uri.getScheme() == "https");
HTTPSClientSession* pSession = _pContext.isNull() ? new HTTPSClientSession(uri.getHost(), uri.getPort()) : new HTTPSClientSession(uri.getHost(), uri.getPort(), _pContext);
pSession->setProxy(proxyHost(), proxyPort());
pSession->setProxyCredentials(proxyUsername(), proxyPassword());
return pSession;
}
void HTTPSSessionInstantiator::registerInstantiator()
{
HTTPSessionFactory::defaultFactory().registerProtocol("https", new HTTPSSessionInstantiator);
}
void HTTPSSessionInstantiator::registerInstantiator(Context::Ptr context)
{
HTTPSessionFactory::defaultFactory().registerProtocol("https", new HTTPSSessionInstantiator(context));
}
void HTTPSSessionInstantiator::unregisterInstantiator()
{
HTTPSessionFactory::defaultFactory().unregisterProtocol("https");
}
} } // namespace Poco::Net

View File

@ -0,0 +1,184 @@
//
// HTTPSStreamFactory.cpp
//
// Library: NetSSL_Win
// Package: HTTPSClient
// Module: HTTPSStreamFactory
//
// Copyright (c) 2006-2012, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// SPDX-License-Identifier: BSL-1.0
//
#include "Poco/Net/HTTPSStreamFactory.h"
#include "Poco/Net/HTTPSClientSession.h"
#include "Poco/Net/HTTPIOStream.h"
#include "Poco/Net/HTTPRequest.h"
#include "Poco/Net/HTTPResponse.h"
#include "Poco/Net/HTTPCredentials.h"
#include "Poco/Net/NetException.h"
#include "Poco/URI.h"
#include "Poco/URIStreamOpener.h"
#include "Poco/UnbufferedStreamBuf.h"
#include "Poco/NullStream.h"
#include "Poco/StreamCopier.h"
using Poco::URIStreamFactory;
using Poco::URI;
using Poco::URIStreamOpener;
using Poco::UnbufferedStreamBuf;
namespace Poco {
namespace Net {
HTTPSStreamFactory::HTTPSStreamFactory():
_proxyPort(HTTPSession::HTTP_PORT)
{
}
HTTPSStreamFactory::HTTPSStreamFactory(const std::string& proxyHost, Poco::UInt16 proxyPort):
_proxyHost(proxyHost),
_proxyPort(proxyPort)
{
}
HTTPSStreamFactory::HTTPSStreamFactory(const std::string& proxyHost, Poco::UInt16 proxyPort, const std::string& proxyUsername, const std::string& proxyPassword):
_proxyHost(proxyHost),
_proxyPort(proxyPort),
_proxyUsername(proxyUsername),
_proxyPassword(proxyPassword)
{
}
HTTPSStreamFactory::~HTTPSStreamFactory()
{
}
std::istream* HTTPSStreamFactory::open(const URI& uri)
{
poco_assert (uri.getScheme() == "https" || uri.getScheme() == "http");
URI resolvedURI(uri);
URI proxyUri;
HTTPClientSession* pSession = 0;
HTTPResponse res;
try
{
bool retry = false;
bool authorize = false;
int redirects = 0;
std::string username;
std::string password;
do
{
if (!pSession)
{
if (resolvedURI.getScheme() != "http")
pSession = new HTTPSClientSession(resolvedURI.getHost(), resolvedURI.getPort());
else
pSession = new HTTPClientSession(resolvedURI.getHost(), resolvedURI.getPort());
if (proxyUri.empty())
{
if (!_proxyHost.empty())
{
pSession->setProxy(_proxyHost, _proxyPort);
pSession->setProxyCredentials(_proxyUsername, _proxyPassword);
}
}
else
{
pSession->setProxy(proxyUri.getHost(), proxyUri.getPort());
if (!_proxyUsername.empty())
{
pSession->setProxyCredentials(_proxyUsername, _proxyPassword);
}
}
}
std::string path = resolvedURI.getPathAndQuery();
if (path.empty()) path = "/";
HTTPRequest req(HTTPRequest::HTTP_GET, path, HTTPMessage::HTTP_1_1);
if (authorize)
{
HTTPCredentials::extractCredentials(uri, username, password);
HTTPCredentials cred(username, password);
cred.authenticate(req, res);
}
pSession->sendRequest(req);
std::istream& rs = pSession->receiveResponse(res);
bool moved = (res.getStatus() == HTTPResponse::HTTP_MOVED_PERMANENTLY ||
res.getStatus() == HTTPResponse::HTTP_FOUND ||
res.getStatus() == HTTPResponse::HTTP_SEE_OTHER ||
res.getStatus() == HTTPResponse::HTTP_TEMPORARY_REDIRECT);
if (moved)
{
resolvedURI.resolve(res.get("Location"));
if (!username.empty())
{
resolvedURI.setUserInfo(username + ":" + password);
authorize = false;
}
delete pSession;
pSession = 0;
++redirects;
retry = true;
}
else if (res.getStatus() == HTTPResponse::HTTP_OK)
{
return new HTTPResponseStream(rs, pSession);
}
else if (res.getStatus() == HTTPResponse::HTTP_USEPROXY && !retry)
{
// The requested resource MUST be accessed through the proxy
// given by the Location field. The Location field gives the
// URI of the proxy. The recipient is expected to repeat this
// single request via the proxy. 305 responses MUST only be generated by origin servers.
// only use for one single request!
proxyUri.resolve(res.get("Location"));
delete pSession; pSession = 0;
retry = true; // only allow useproxy once
}
else if (res.getStatus() == HTTPResponse::HTTP_UNAUTHORIZED && !authorize)
{
authorize = true;
retry = true;
Poco::NullOutputStream null;
Poco::StreamCopier::copyStream(rs, null);
}
else throw HTTPException(res.getReason(), uri.toString());
}
while (retry && redirects < MAX_REDIRECTS);
throw HTTPException("Too many redirects", uri.toString());
}
catch (...)
{
delete pSession;
throw;
}
}
void HTTPSStreamFactory::registerFactory()
{
URIStreamOpener::defaultOpener().registerStreamFactory("https", new HTTPSStreamFactory);
}
void HTTPSStreamFactory::unregisterFactory()
{
URIStreamOpener::defaultOpener().unregisterStreamFactory("https");
}
} } // namespace Poco::Net

View File

@ -0,0 +1,52 @@
//
// InvalidCertificateHandler.cpp
//
// Library: NetSSL_Win
// Package: SSLCore
// Module: InvalidCertificateHandler
//
// Copyright (c) 2006-2014, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// SPDX-License-Identifier: BSL-1.0
//
#include "Poco/Net/InvalidCertificateHandler.h"
#include "Poco/Net/SSLManager.h"
#include "Poco/Delegate.h"
using Poco::Delegate;
namespace Poco {
namespace Net {
InvalidCertificateHandler::InvalidCertificateHandler(bool handleErrorsOnServerSide): _handleErrorsOnServerSide(handleErrorsOnServerSide)
{
if (_handleErrorsOnServerSide)
SSLManager::instance().ServerVerificationError += Delegate<InvalidCertificateHandler, VerificationErrorArgs>(this, &InvalidCertificateHandler::onInvalidCertificate);
else
SSLManager::instance().ClientVerificationError += Delegate<InvalidCertificateHandler, VerificationErrorArgs>(this, &InvalidCertificateHandler::onInvalidCertificate);
}
InvalidCertificateHandler::~InvalidCertificateHandler()
{
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();
}
}
} } // namespace Poco::Net

View File

@ -0,0 +1,40 @@
//
// KeyConsoleHandler.cpp
//
// 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

View File

@ -0,0 +1,61 @@
//
// KeyFileHandler.cpp
//
// 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

View File

@ -0,0 +1,44 @@
//
// PrivateKeyFactory.cpp
//
// 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

View File

@ -0,0 +1,67 @@
//
// PrivateKeyFactoryMgr.cpp
//
// 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

View File

@ -0,0 +1,46 @@
//
// PrivateKeyPassphraseHandler.cpp
//
// 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

View File

@ -0,0 +1,38 @@
//
// RejectCertificateHandler.cpp
//
// Library: NetSSL_Win
// Package: SSLCore
// Module: RejectCertificateHandler
//
// Copyright (c) 2006-2014, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// SPDX-License-Identifier: BSL-1.0
//
#include "Poco/Net/RejectCertificateHandler.h"
namespace Poco {
namespace Net {
RejectCertificateHandler::RejectCertificateHandler(bool server): InvalidCertificateHandler(server)
{
}
RejectCertificateHandler::~RejectCertificateHandler()
{
}
void RejectCertificateHandler::onInvalidCertificate(const void*, VerificationErrorArgs& errorCert)
{
errorCert.setIgnoreError(false);
}
} } // namespace Poco::Net

View File

@ -0,0 +1,32 @@
//
// SSLException.cpp
//
// Library: NetSSL_Win
// Package: SSLCore
// Module: SSLException
//
// Copyright (c) 2006-2014, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// SPDX-License-Identifier: BSL-1.0
//
#include "Poco/Net/SSLException.h"
#include <typeinfo>
namespace Poco {
namespace Net {
POCO_IMPLEMENT_EXCEPTION(SSLException, NetException, "SSL Exception")
POCO_IMPLEMENT_EXCEPTION(SSLContextException, SSLException, "SSL context exception")
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")
} } // namespace Poco::Net

View File

@ -0,0 +1,438 @@
//
// SSLManager.cpp
//
// Library: NetSSL_Win
// Package: SSLCore
// Module: SSLManager
//
// Copyright (c) 2006-2014, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// SPDX-License-Identifier: BSL-1.0
//
#include "Poco/Net/SSLManager.h"
#include "Poco/Net/Context.h"
#include "Poco/Net/Utility.h"
#include "Poco/Net/PrivateKeyPassphraseHandler.h"
#include "Poco/Net/RejectCertificateHandler.h"
#include "Poco/SingletonHolder.h"
#include "Poco/Delegate.h"
#include "Poco/Util/Application.h"
#include "Poco/Util/OptionException.h"
namespace Poco {
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");
const Context::VerificationMode SSLManager::VAL_VER_MODE(Context::VERIFY_RELAXED);
const std::string SSLManager::CFG_REVOCATION_CHECK("revocationChecking");
const bool SSLManager::VAL_REVOCATION_CHECK(true);
const std::string SSLManager::CFG_TRUST_ROOTS("trustRoots");
const bool SSLManager::VAL_TRUST_ROOTS(true);
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.");
const std::string SSLManager::CFG_CLIENT_PREFIX("schannel.client.");
const std::string SSLManager::CFG_REQUIRE_TLSV1("requireTLSv1");
const std::string SSLManager::CFG_REQUIRE_TLSV1_1("requireTLSv1_1");
const std::string SSLManager::CFG_REQUIRE_TLSV1_2("requireTLSv1_2");
const std::string SSLManager::CFG_REQUIRE_TLSV1_3("requireTLSv1_3");
SSLManager::SSLManager():
_hSecurityModule(0)
{
loadSecurityLibrary();
}
SSLManager::~SSLManager()
{
try
{
shutdown();
}
catch (...)
{
poco_unexpected();
}
}
namespace
{
static Poco::SingletonHolder<SSLManager> singleton;
}
SSLManager& SSLManager::instance()
{
return *singleton.get();
}
void SSLManager::initializeServer(PrivateKeyPassphraseHandlerPtr pPassphraseHandler, InvalidCertificateHandlerPtr pCertHandler, Context::Ptr pContext)
{
_ptrServerPassphraseHandler = pPassphraseHandler;
_ptrServerCertificateHandler = pCertHandler;
_ptrDefaultServerContext = pContext;
}
void SSLManager::initializeClient(PrivateKeyPassphraseHandlerPtr pPassphraseHandler, InvalidCertificateHandlerPtr pCertHandler, Context::Ptr pContext)
{
_ptrClientPassphraseHandler = pPassphraseHandler;
_ptrClientCertificateHandler = pCertHandler;
_ptrDefaultClientContext = pContext;
}
Context::Ptr SSLManager::defaultServerContext()
{
Poco::FastMutex::ScopedLock lock(_mutex);
if (!_ptrDefaultServerContext)
initDefaultContext(true);
return _ptrDefaultServerContext;
}
Context::Ptr SSLManager::defaultClientContext()
{
Poco::FastMutex::ScopedLock lock(_mutex);
if (!_ptrDefaultClientContext)
{
try
{
initDefaultContext(false);
}
catch (Poco::IllegalStateException&)
{
_ptrClientCertificateHandler = new RejectCertificateHandler(false);
_ptrDefaultClientContext = new Context(Context::CLIENT_USE, "");
}
}
return _ptrDefaultClientContext;
}
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);
if (!_ptrServerCertificateHandler)
initCertificateHandler(true);
return _ptrServerCertificateHandler;
}
SSLManager::InvalidCertificateHandlerPtr SSLManager::clientCertificateHandler()
{
Poco::FastMutex::ScopedLock lock(_mutex);
if (!_ptrClientCertificateHandler)
initCertificateHandler(false);
return _ptrClientCertificateHandler;
}
void SSLManager::initDefaultContext(bool server)
{
if (server && _ptrDefaultServerContext) return;
if (!server && _ptrDefaultClientContext) return;
initEvents(server);
const std::string prefix = server ? CFG_SERVER_PREFIX : CFG_CLIENT_PREFIX;
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);
bool requireTLSv1_1 = config.getBool(prefix + CFG_REQUIRE_TLSV1_1, false);
bool requireTLSv1_2 = config.getBool(prefix + CFG_REQUIRE_TLSV1_2, false);
bool requireTLSv1_3 = config.getBool(prefix + CFG_REQUIRE_TLSV1_3, false);
// optional options for which we have defaults defined
Context::VerificationMode verMode = VAL_VER_MODE;
if (config.hasProperty(prefix + CFG_VER_MODE))
{
// either: none, relaxed, strict, once
std::string mode = config.getString(prefix + CFG_VER_MODE);
verMode = Utility::convertVerificationMode(mode);
}
bool revocChecking = config.getBool(prefix + CFG_REVOCATION_CHECK, VAL_REVOCATION_CHECK);
bool trustRoots = config.getBool(prefix + CFG_TRUST_ROOTS, VAL_TRUST_ROOTS);
bool useMachineStore = config.getBool(prefix + CFG_USE_MACHINE_STORE, VAL_USE_MACHINE_STORE);
bool useStrongCrypto = config.getBool(prefix + CFG_USE_STRONG_CRYPTO, VAL_USE_STRONG_CRYPTO);
int options = 0;
if (revocChecking) options |= Context::OPT_PERFORM_REVOCATION_CHECK;
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)
{
if (requireTLSv1_3)
usage = Context::TLSV1_3_SERVER_USE;
else if (requireTLSv1_2)
usage = Context::TLSV1_2_SERVER_USE;
else if (requireTLSv1_1)
usage = Context::TLSV1_1_SERVER_USE;
else if (requireTLSv1)
usage = Context::TLSV1_SERVER_USE;
else
usage = Context::SERVER_USE;
_ptrDefaultServerContext = new Context(usage, certName, verMode, options, certStore);
}
else
{
if (requireTLSv1_3)
usage = Context::TLSV1_3_CLIENT_USE;
else if (requireTLSv1_2)
usage = Context::TLSV1_2_CLIENT_USE;
else if (requireTLSv1_1)
usage = Context::TLSV1_1_CLIENT_USE;
else if (requireTLSv1)
usage = Context::TLSV1_CLIENT_USE;
else
usage = Context::CLIENT_USE;
_ptrDefaultClientContext = new Context(usage, certName, verMode, options, certStore);
}
}
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::AbstractConfiguration& config = appConfig();
std::string className(config.getString(prefix + CFG_CERTIFICATE_HANDLER, VAL_CERTIFICATE_HANDLER));
const CertificateHandlerFactory* pFactory = 0;
if (certificateHandlerFactoryMgr().hasFactory(className))
{
pFactory = certificateHandlerFactoryMgr().getFactory(className);
}
if (pFactory)
{
if (server)
_ptrServerCertificateHandler = pFactory->create(true);
else
_ptrClientCertificateHandler = pFactory->create(false);
}
else throw Poco::Util::UnknownOptionException("No InvalidCertificate handler known with the name", className);
}
void SSLManager::shutdown()
{
ClientVerificationError.clear();
ServerVerificationError.clear();
_ptrServerPassphraseHandler = 0;
_ptrServerCertificateHandler = 0;
_ptrDefaultServerContext = 0;
_ptrClientPassphraseHandler = 0;
_ptrClientCertificateHandler = 0;
_ptrDefaultClientContext = 0;
unloadSecurityLibrary();
}
void SSLManager::loadSecurityLibrary()
{
if (_hSecurityModule) return;
OSVERSIONINFO VerInfo;
std::wstring dllPath;
// Find out which security DLL to use, depending on
// whether we are on Win2k, NT or Win9x
VerInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
if (!GetVersionEx(&VerInfo))
throw Poco::SystemException("Cannot determine OS version");
#if defined(_WIN32_WCE)
dllPath = L"Secur32.dll";
#else
if (VerInfo.dwPlatformId == VER_PLATFORM_WIN32_NT
&& VerInfo.dwMajorVersion == 4)
{
dllPath = L"Security.dll";
}
else if (VerInfo.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS ||
VerInfo.dwPlatformId == VER_PLATFORM_WIN32_NT )
{
dllPath = L"Secur32.dll";
}
else
{
throw Poco::SystemException("Cannot determine which security DLL to use");
}
#endif
//
// Load Security DLL
//
_hSecurityModule = LoadLibraryW(dllPath.c_str());
if(_hSecurityModule == 0)
{
throw Poco::SystemException("Failed to load security DLL");
}
#if defined(_WIN32_WCE)
INIT_SECURITY_INTERFACE pInitSecurityInterface = (INIT_SECURITY_INTERFACE)GetProcAddressW( _hSecurityModule, L"InitSecurityInterfaceW");
#else
INIT_SECURITY_INTERFACE pInitSecurityInterface = (INIT_SECURITY_INTERFACE)GetProcAddress( _hSecurityModule, "InitSecurityInterfaceW");
#endif
if (!pInitSecurityInterface)
{
FreeLibrary(_hSecurityModule);
_hSecurityModule = 0;
throw Poco::SystemException("Failed to initialize security DLL (no init function)");
}
PSecurityFunctionTable pSecurityFunc = pInitSecurityInterface();
if (!pSecurityFunc)
{
FreeLibrary(_hSecurityModule);
_hSecurityModule = 0;
throw Poco::SystemException("Failed to initialize security DLL (no function table)");
}
CopyMemory(&_securityFunctions, pSecurityFunc, sizeof(_securityFunctions));
}
void SSLManager::unloadSecurityLibrary()
{
if (_hSecurityModule)
{
FreeLibrary(_hSecurityModule);
_hSecurityModule = 0;
}
}
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()
{
}
void uninitializeSSL()
{
SSLManager::instance().shutdown();
}
} } // namespace Poco::Net

View File

@ -0,0 +1,63 @@
//
// SecureSMTPClientSession.h
//
// Library: NetSSL_Win
// Package: Mail
// Module: SecureSMTPClientSession
//
// Copyright (c) 2010, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// SPDX-License-Identifier: BSL-1.0
//
#include "Poco/Net/SecureSMTPClientSession.h"
#include "Poco/Net/SecureStreamSocket.h"
#include "Poco/Net/SSLManager.h"
#include "Poco/Net/DialogSocket.h"
namespace Poco {
namespace Net {
SecureSMTPClientSession::SecureSMTPClientSession(const StreamSocket& socket):
SMTPClientSession(socket)
{
}
SecureSMTPClientSession::SecureSMTPClientSession(const std::string& host, Poco::UInt16 port):
SMTPClientSession(host, port)
{
}
SecureSMTPClientSession::~SecureSMTPClientSession()
{
}
bool SecureSMTPClientSession::startTLS()
{
return startTLS(SSLManager::instance().defaultClientContext());
}
bool SecureSMTPClientSession::startTLS(Context::Ptr pContext)
{
int status = 0;
std::string response;
status = sendCommand("STARTTLS", response);
if (!isPositiveCompletion(status)) return false;
SecureStreamSocket sss(SecureStreamSocket::attach(socket(), host(), pContext));
socket() = sss;
return true;
}
} } // namespace Poco::Net

View File

@ -0,0 +1,121 @@
//
// SecureServerSocket.cpp
//
// Library: NetSSL_Win
// Package: SSLSockets
// Module: SecureServerSocket
//
// Copyright (c) 2006-2014, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// SPDX-License-Identifier: BSL-1.0
//
#include "Poco/Net/SecureServerSocket.h"
#include "Poco/Net/SecureServerSocketImpl.h"
#include "Poco/Net/SecureStreamSocket.h"
#include "Poco/Net/SSLManager.h"
#include "Poco/Exception.h"
using Poco::InvalidArgumentException;
namespace Poco {
namespace Net {
SecureServerSocket::SecureServerSocket():
ServerSocket(new SecureServerSocketImpl(SSLManager::instance().defaultServerContext()), true)
{
}
SecureServerSocket::SecureServerSocket(Context::Ptr pContext):
ServerSocket(new SecureServerSocketImpl(pContext), true)
{
}
SecureServerSocket::SecureServerSocket(const Socket& socket):
ServerSocket(socket)
{
if (!dynamic_cast<SecureServerSocketImpl*>(impl()))
throw InvalidArgumentException("Cannot assign incompatible socket");
}
SecureServerSocket::SecureServerSocket(const SocketAddress& address, int backlog):
ServerSocket(new SecureServerSocketImpl(SSLManager::instance().defaultServerContext()), true)
{
impl()->bind(address, true);
impl()->listen(backlog);
}
SecureServerSocket::SecureServerSocket(const SocketAddress& address, int backlog, Context::Ptr pContext):
ServerSocket(new SecureServerSocketImpl(pContext), true)
{
impl()->bind(address, true);
impl()->listen(backlog);
}
SecureServerSocket::SecureServerSocket(Poco::UInt16 port, int backlog):
ServerSocket(new SecureServerSocketImpl(SSLManager::instance().defaultServerContext()), true)
{
IPAddress wildcardAddr;
SocketAddress address(wildcardAddr, port);
impl()->bind(address, true);
impl()->listen(backlog);
}
SecureServerSocket::SecureServerSocket(Poco::UInt16 port, int backlog, Context::Ptr pContext):
ServerSocket(new SecureServerSocketImpl(pContext), true)
{
IPAddress wildcardAddr;
SocketAddress address(wildcardAddr, port);
impl()->bind(address, true);
impl()->listen(backlog);
}
SecureServerSocket::~SecureServerSocket()
{
}
SecureServerSocket& SecureServerSocket::operator = (const Socket& socket)
{
if (&socket != this)
{
if (dynamic_cast<SecureServerSocketImpl*>(socket.impl()))
ServerSocket::operator = (socket);
else
throw InvalidArgumentException("Cannot assign incompatible socket");
}
return *this;
}
StreamSocket SecureServerSocket::acceptConnection(SocketAddress& clientAddr)
{
return SecureStreamSocket(impl()->acceptConnection(clientAddr));
}
StreamSocket SecureServerSocket::acceptConnection()
{
SocketAddress clientAddr;
return SecureStreamSocket(impl()->acceptConnection(clientAddr));
}
Context::Ptr SecureServerSocket::context() const
{
return static_cast<SecureServerSocketImpl*>(impl())->context();
}
} } // namespace Poco::Net

View File

@ -0,0 +1,115 @@
//
// SecureServerSocketImpl.cpp
//
// Library: NetSSL_Win
// Package: SSLSockets
// Module: SecureServerSocketImpl
//
// Copyright (c) 2006-2014, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// SPDX-License-Identifier: BSL-1.0
//
#include "Poco/Net/SecureServerSocketImpl.h"
namespace Poco {
namespace Net {
SecureServerSocketImpl::SecureServerSocketImpl(Context::Ptr pContext):
_impl(new ServerSocketImpl, pContext)
{
}
SecureServerSocketImpl::~SecureServerSocketImpl()
{
reset();
}
SocketImpl* SecureServerSocketImpl::acceptConnection(SocketAddress& clientAddr)
{
return _impl.acceptConnection(clientAddr);
}
void SecureServerSocketImpl::connect(const SocketAddress& address)
{
throw Poco::InvalidAccessException("Cannot connect() a SecureServerSocket");
}
void SecureServerSocketImpl::connect(const SocketAddress& address, const Poco::Timespan& timeout)
{
throw Poco::InvalidAccessException("Cannot connect() a SecureServerSocket");
}
void SecureServerSocketImpl::connectNB(const SocketAddress& address)
{
throw Poco::InvalidAccessException("Cannot connect() a SecureServerSocket");
}
void SecureServerSocketImpl::bind(const SocketAddress& address, bool reuseAddress)
{
_impl.bind(address, reuseAddress);
reset(_impl.sockfd());
}
void SecureServerSocketImpl::listen(int backlog)
{
_impl.listen(backlog);
reset(_impl.sockfd());
}
void SecureServerSocketImpl::close()
{
reset();
_impl.close();
}
int SecureServerSocketImpl::sendBytes(const void* buffer, int length, int flags)
{
throw Poco::InvalidAccessException("Cannot sendBytes() on a SecureServerSocket");
}
int SecureServerSocketImpl::receiveBytes(void* buffer, int length, int flags)
{
throw Poco::InvalidAccessException("Cannot receiveBytes() on a SecureServerSocket");
}
int SecureServerSocketImpl::sendTo(const void* buffer, int length, const SocketAddress& address, int flags)
{
throw Poco::InvalidAccessException("Cannot sendTo() on a SecureServerSocket");
}
int SecureServerSocketImpl::receiveFrom(void* buffer, int length, SocketAddress& address, int flags)
{
throw Poco::InvalidAccessException("Cannot receiveFrom() on a SecureServerSocket");
}
void SecureServerSocketImpl::sendUrgent(unsigned char data)
{
throw Poco::InvalidAccessException("Cannot sendUrgent() on a SecureServerSocket");
}
bool SecureServerSocketImpl::secure() const
{
return true;
}
} } // namespace Poco::Net

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,269 @@
//
// SecureStreamSocket.cpp
//
// Library: NetSSL_Win
// Package: SSLSockets
// Module: SecureStreamSocket
//
// Copyright (c) 2006-2014, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// SPDX-License-Identifier: BSL-1.0
//
#include "Poco/Net/SecureStreamSocket.h"
#include "Poco/Net/SecureStreamSocketImpl.h"
#include "Poco/Net/SocketImpl.h"
#include "Poco/Net/SSLManager.h"
#include "Poco/Exception.h"
using Poco::InvalidArgumentException;
namespace Poco {
namespace Net {
SecureStreamSocket::SecureStreamSocket():
StreamSocket(new SecureStreamSocketImpl(SSLManager::instance().defaultClientContext()))
{
}
SecureStreamSocket::SecureStreamSocket(Context::Ptr pContext):
StreamSocket(new SecureStreamSocketImpl(pContext))
{
}
SecureStreamSocket::SecureStreamSocket(Context::Ptr pContext, Session::Ptr pSession):
StreamSocket(new SecureStreamSocketImpl(pContext))
{
useSession(pSession);
}
SecureStreamSocket::SecureStreamSocket(const SocketAddress& address):
StreamSocket(new SecureStreamSocketImpl(SSLManager::instance().defaultClientContext()))
{
connect(address);
}
SecureStreamSocket::SecureStreamSocket(const SocketAddress& address, const std::string& hostName):
StreamSocket(new SecureStreamSocketImpl(SSLManager::instance().defaultClientContext()))
{
static_cast<SecureStreamSocketImpl*>(impl())->setPeerHostName(hostName);
connect(address);
}
SecureStreamSocket::SecureStreamSocket(const SocketAddress& address, Context::Ptr pContext):
StreamSocket(new SecureStreamSocketImpl(pContext))
{
connect(address);
}
SecureStreamSocket::SecureStreamSocket(const SocketAddress& address, Context::Ptr pContext, Session::Ptr pSession):
StreamSocket(new SecureStreamSocketImpl(pContext))
{
useSession(pSession);
connect(address);
}
SecureStreamSocket::SecureStreamSocket(const SocketAddress& address, const std::string& hostName, Context::Ptr pContext):
StreamSocket(new SecureStreamSocketImpl(pContext))
{
static_cast<SecureStreamSocketImpl*>(impl())->setPeerHostName(hostName);
connect(address);
}
SecureStreamSocket::SecureStreamSocket(const SocketAddress& address, const std::string& hostName, Context::Ptr pContext, Session::Ptr pSession):
StreamSocket(new SecureStreamSocketImpl(pContext))
{
static_cast<SecureStreamSocketImpl*>(impl())->setPeerHostName(hostName);
useSession(pSession);
connect(address);
}
SecureStreamSocket::SecureStreamSocket(const Socket& socket):
StreamSocket(socket)
{
if (!dynamic_cast<SecureStreamSocketImpl*>(impl()))
throw InvalidArgumentException("Cannot assign incompatible socket");
}
SecureStreamSocket::SecureStreamSocket(SocketImpl* pImpl):
StreamSocket(pImpl)
{
if (!dynamic_cast<SecureStreamSocketImpl*>(impl()))
throw InvalidArgumentException("Cannot assign incompatible socket");
}
SecureStreamSocket::~SecureStreamSocket()
{
}
SecureStreamSocket& SecureStreamSocket::operator = (const Socket& socket)
{
if (dynamic_cast<SecureStreamSocketImpl*>(socket.impl()))
StreamSocket::operator = (socket);
else
throw InvalidArgumentException("Cannot assign incompatible socket");
return *this;
}
bool SecureStreamSocket::havePeerCertificate() const
{
return static_cast<SecureStreamSocketImpl*>(impl())->havePeerCertificate();
}
X509Certificate SecureStreamSocket::peerCertificate() const
{
return static_cast<SecureStreamSocketImpl*>(impl())->peerCertificate();
}
void SecureStreamSocket::setPeerHostName(const std::string& hostName)
{
static_cast<SecureStreamSocketImpl*>(impl())->setPeerHostName(hostName);
}
const std::string& SecureStreamSocket::getPeerHostName() const
{
return static_cast<SecureStreamSocketImpl*>(impl())->getPeerHostName();
}
SecureStreamSocket SecureStreamSocket::attach(const StreamSocket& streamSocket)
{
SecureStreamSocketImpl* pImpl = new SecureStreamSocketImpl(static_cast<StreamSocketImpl*>(streamSocket.impl()), SSLManager::instance().defaultClientContext());
SecureStreamSocket result(pImpl);
pImpl->connectSSL();
return result;
}
SecureStreamSocket SecureStreamSocket::attach(const StreamSocket& streamSocket, Context::Ptr pContext)
{
SecureStreamSocketImpl* pImpl = new SecureStreamSocketImpl(static_cast<StreamSocketImpl*>(streamSocket.impl()), pContext);
SecureStreamSocket result(pImpl);
pImpl->connectSSL();
return result;
}
SecureStreamSocket SecureStreamSocket::attach(const StreamSocket& streamSocket, Context::Ptr pContext, Session::Ptr pSession)
{
SecureStreamSocketImpl* pImpl = new SecureStreamSocketImpl(static_cast<StreamSocketImpl*>(streamSocket.impl()), pContext);
SecureStreamSocket result(pImpl);
result.useSession(pSession);
pImpl->connectSSL();
return result;
}
SecureStreamSocket SecureStreamSocket::attach(const StreamSocket& streamSocket, const std::string& peerHostName)
{
SecureStreamSocketImpl* pImpl = new SecureStreamSocketImpl(static_cast<StreamSocketImpl*>(streamSocket.impl()), SSLManager::instance().defaultClientContext());
SecureStreamSocket result(pImpl);
result.setPeerHostName(peerHostName);
pImpl->connectSSL();
return result;
}
SecureStreamSocket SecureStreamSocket::attach(const StreamSocket& streamSocket, const std::string& peerHostName, Context::Ptr pContext)
{
SecureStreamSocketImpl* pImpl = new SecureStreamSocketImpl(static_cast<StreamSocketImpl*>(streamSocket.impl()), pContext);
SecureStreamSocket result(pImpl);
result.setPeerHostName(peerHostName);
pImpl->connectSSL();
return result;
}
SecureStreamSocket SecureStreamSocket::attach(const StreamSocket& streamSocket, const std::string& peerHostName, Context::Ptr pContext, Session::Ptr pSession)
{
SecureStreamSocketImpl* pImpl = new SecureStreamSocketImpl(static_cast<StreamSocketImpl*>(streamSocket.impl()), pContext);
SecureStreamSocket result(pImpl);
result.setPeerHostName(peerHostName);
result.useSession(pSession);
pImpl->connectSSL();
return result;
}
Context::Ptr SecureStreamSocket::context() const
{
return static_cast<SecureStreamSocketImpl*>(impl())->context();
}
void SecureStreamSocket::setLazyHandshake(bool flag)
{
static_cast<SecureStreamSocketImpl*>(impl())->setLazyHandshake(flag);
}
bool SecureStreamSocket::getLazyHandshake() const
{
return static_cast<SecureStreamSocketImpl*>(impl())->getLazyHandshake();
}
void SecureStreamSocket::verifyPeerCertificate()
{
static_cast<SecureStreamSocketImpl*>(impl())->verifyPeerCertificate();
}
void SecureStreamSocket::verifyPeerCertificate(const std::string& hostName)
{
static_cast<SecureStreamSocketImpl*>(impl())->verifyPeerCertificate(hostName);
}
int SecureStreamSocket::completeHandshake()
{
return static_cast<SecureStreamSocketImpl*>(impl())->completeHandshake();
}
Session::Ptr SecureStreamSocket::currentSession()
{
return static_cast<SecureStreamSocketImpl*>(impl())->currentSession();
}
void SecureStreamSocket::useSession(Session::Ptr pSession)
{
static_cast<SecureStreamSocketImpl*>(impl())->useSession(pSession);
}
bool SecureStreamSocket::sessionWasReused()
{
return static_cast<SecureStreamSocketImpl*>(impl())->sessionWasReused();
}
void SecureStreamSocket::abort()
{
static_cast<SecureStreamSocketImpl*>(impl())->abort();
}
} } // namespace Poco::Net

View File

@ -0,0 +1,216 @@
//
// SecureStreamSocketImpl.cpp
//
// Library: NetSSL_Win
// Package: SSLSockets
// Module: SecureStreamSocketImpl
//
// Copyright (c) 2006-2014, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// SPDX-License-Identifier: BSL-1.0
//
#include "Poco/Net/SecureStreamSocketImpl.h"
#include "Poco/Net/SSLException.h"
#include "Poco/Thread.h"
namespace Poco {
namespace Net {
SecureStreamSocketImpl::SecureStreamSocketImpl(Context::Ptr pContext):
_impl(new StreamSocketImpl, pContext),
_lazyHandshake(false)
{
}
SecureStreamSocketImpl::SecureStreamSocketImpl(StreamSocketImpl* pStreamSocket, Context::Ptr pContext):
_impl(pStreamSocket, pContext),
_lazyHandshake(false)
{
pStreamSocket->duplicate();
reset(_impl.sockfd());
}
SecureStreamSocketImpl::~SecureStreamSocketImpl()
{
reset();
}
SocketImpl* SecureStreamSocketImpl::acceptConnection(SocketAddress& clientAddr)
{
throw Poco::InvalidAccessException("Cannot acceptConnection() on a SecureStreamSocketImpl");
}
void SecureStreamSocketImpl::acceptSSL()
{
_impl.acceptSSL();
}
void SecureStreamSocketImpl::connect(const SocketAddress& address)
{
_impl.connect(address, !_lazyHandshake);
reset(_impl.sockfd());
}
void SecureStreamSocketImpl::connect(const SocketAddress& address, const Poco::Timespan& timeout)
{
_impl.connect(address, timeout, !_lazyHandshake);
reset(_impl.sockfd());
}
void SecureStreamSocketImpl::connectNB(const SocketAddress& address)
{
_impl.connectNB(address);
reset(_impl.sockfd());
}
void SecureStreamSocketImpl::connectSSL()
{
_impl.connectSSL(!_lazyHandshake);
}
void SecureStreamSocketImpl::bind(const SocketAddress& address, bool reuseAddress)
{
throw Poco::InvalidAccessException("Cannot bind() a SecureStreamSocketImpl");
}
void SecureStreamSocketImpl::listen(int backlog)
{
throw Poco::InvalidAccessException("Cannot listen() on a SecureStreamSocketImpl");
}
void SecureStreamSocketImpl::close()
{
reset();
_impl.close();
}
void SecureStreamSocketImpl::abort()
{
reset();
_impl.abort();
}
int SecureStreamSocketImpl::sendBytes(const void* buffer, int length, int flags)
{
return _impl.sendBytes(buffer, length, flags);
}
int SecureStreamSocketImpl::receiveBytes(void* buffer, int length, int flags)
{
return _impl.receiveBytes(buffer, length, flags);
}
int SecureStreamSocketImpl::sendTo(const void* buffer, int length, const SocketAddress& address, int flags)
{
throw Poco::InvalidAccessException("Cannot sendTo() on a SecureStreamSocketImpl");
}
int SecureStreamSocketImpl::receiveFrom(void* buffer, int length, SocketAddress& address, int flags)
{
throw Poco::InvalidAccessException("Cannot receiveFrom() on a SecureStreamSocketImpl");
}
void SecureStreamSocketImpl::sendUrgent(unsigned char data)
{
throw Poco::InvalidAccessException("Cannot sendUrgent() on a SecureStreamSocketImpl");
}
int SecureStreamSocketImpl::available()
{
return _impl.available();
}
void SecureStreamSocketImpl::shutdownReceive()
{
}
void SecureStreamSocketImpl::shutdownSend()
{
}
void SecureStreamSocketImpl::shutdown()
{
_impl.shutdown();
}
bool SecureStreamSocketImpl::secure() const
{
return true;
}
bool SecureStreamSocketImpl::havePeerCertificate() const
{
return _impl.peerCertificate() != 0;
}
X509Certificate SecureStreamSocketImpl::peerCertificate() const
{
if (havePeerCertificate())
{
return X509Certificate(_impl.peerCertificate(), true);
}
else throw SSLException("No certificate available");
}
void SecureStreamSocketImpl::setLazyHandshake(bool flag)
{
_lazyHandshake = flag;
}
bool SecureStreamSocketImpl::getLazyHandshake() const
{
return _lazyHandshake;
}
void SecureStreamSocketImpl::verifyPeerCertificate()
{
_impl.verifyPeerCertificate();
}
void SecureStreamSocketImpl::verifyPeerCertificate(const std::string& hostName)
{
_impl.verifyPeerCertificate(hostName);
}
int SecureStreamSocketImpl::completeHandshake()
{
_impl.completeHandshake();
return 0;
}
} } // namespace Poco::Net

38
vendor/POCO/NetSSL_Win/src/Session.cpp vendored Normal file
View File

@ -0,0 +1,38 @@
//
// Session.cpp
//
// Library: NetSSL_Win
// Package: SSLCore
// Module: Session
//
// Copyright (c) 2010-2014, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// SPDX-License-Identifier: BSL-1.0
//
#if defined(__APPLE__)
// Some OpenSSL functions are deprecated in OS X 10.7
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
#endif
#include "Poco/Net/Session.h"
namespace Poco {
namespace Net {
Session::Session()
{
}
Session::~Session()
{
}
} } // namespace Poco::Net

203
vendor/POCO/NetSSL_Win/src/Utility.cpp vendored Normal file
View File

@ -0,0 +1,203 @@
//
// Utility.cpp
//
// Library: NetSSL_Win
// Package: SSLCore
// Module: Utility
//
// Copyright (c) 2006-2014, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// SPDX-License-Identifier: BSL-1.0
//
#include "Poco/Net/Utility.h"
#include "Poco/String.h"
#include "Poco/NumberFormatter.h"
#include "Poco/Util/OptionException.h"
#include <windows.h>
#include <winerror.h>
namespace Poco {
namespace Net {
Poco::FastMutex Utility::_mutex;
Context::VerificationMode Utility::convertVerificationMode(const std::string& vMode)
{
std::string mode = Poco::toLower(vMode);
Context::VerificationMode verMode = Context::VERIFY_STRICT;
if (mode == "none")
verMode = Context::VERIFY_NONE;
else if (mode == "relaxed")
verMode = Context::VERIFY_RELAXED;
else if (mode == "strict")
verMode = Context::VERIFY_STRICT;
else
throw Poco::Util::OptionException(std::string("Wrong value >") + vMode + std::string("< for a verificationMode. Can only be none, relaxed, strict or once."));
return verMode;
}
inline void add(std::map<long, const std::string>& messageMap, long key, const std::string& val)
{
messageMap.insert(std::make_pair(key, val));
}
std::map<long, const std::string> Utility::initSSPIErr()
{
std::map<long, const std::string> messageMap;
add(messageMap, NTE_BAD_UID, "Bad UID");
add(messageMap, NTE_BAD_HASH, "Bad Hash");
add(messageMap, NTE_BAD_KEY, "Bad Key");
add(messageMap, NTE_BAD_LEN, "Bad Length");
add(messageMap, NTE_BAD_DATA, "Bad Data");
add(messageMap, NTE_BAD_SIGNATURE, "Invalid signature");
add(messageMap, NTE_BAD_VER, "Bad Version of provider");
add(messageMap, NTE_BAD_ALGID, "Invalid algorithm specified");
add(messageMap, NTE_BAD_FLAGS, "Invalid flags specified");
add(messageMap, NTE_BAD_TYPE, "Invalid type specified");
add(messageMap, NTE_BAD_KEY_STATE, "Key not valid for use in specified state");
add(messageMap, NTE_BAD_HASH_STATE, "Hash not valid for use in specified state");
add(messageMap, NTE_NO_KEY, "Key does not exist");
add(messageMap, NTE_NO_MEMORY, "Insufficient memory available for the operation");
add(messageMap, NTE_EXISTS, "Object already exists");
add(messageMap, NTE_PERM, "Permission denied");
add(messageMap, NTE_NOT_FOUND, "Object was not found");
add(messageMap, NTE_DOUBLE_ENCRYPT, "Data already encrypted");
add(messageMap, NTE_BAD_PROVIDER, "Invalid provider specified");
add(messageMap, NTE_BAD_PROV_TYPE, "Invalid provider type specified");
add(messageMap, NTE_BAD_PUBLIC_KEY, "Provider's public key is invalid");
add(messageMap, NTE_BAD_KEYSET, "Keyset does not exist");
add(messageMap, NTE_PROV_TYPE_NOT_DEF, "Provider type not defined");
add(messageMap, NTE_PROV_TYPE_ENTRY_BAD, "Provider type as registered is invalid");
add(messageMap, NTE_KEYSET_NOT_DEF, "The keyset is not defined");
add(messageMap, NTE_KEYSET_ENTRY_BAD, "Keyset as registered is invalid");
add(messageMap, NTE_PROV_TYPE_NO_MATCH, "Provider type does not match registered value");
add(messageMap, NTE_SIGNATURE_FILE_BAD, "The digital signature file is corrupt");
add(messageMap, NTE_PROVIDER_DLL_FAIL, "Provider DLL failed to initialize correctly");
add(messageMap, NTE_PROV_DLL_NOT_FOUND, "Provider DLL could not be found");
add(messageMap, NTE_BAD_KEYSET_PARAM, "The Keyset parameter is invalid");
add(messageMap, NTE_FAIL, "NTE_FAIL: An internal error occurred");
add(messageMap, NTE_SYS_ERR, "NTE_SYS_ERR: A base error occurred");
add(messageMap, NTE_SILENT_CONTEXT, "Provider could not perform the action since the context was acquired as silent");
add(messageMap, NTE_TOKEN_KEYSET_STORAGE_FULL, "The security token does not have storage space available for an additional container");
add(messageMap, NTE_TEMPORARY_PROFILE, "The profile for the user is a temporary profile");
add(messageMap, NTE_FIXEDPARAMETER, "The key parameters could not be set because the CSP uses fixed parameters");
add(messageMap, SEC_E_INSUFFICIENT_MEMORY, "Not enough memory is available to complete this request");
add(messageMap, SEC_E_INVALID_HANDLE, "The handle specified is invalid");
add(messageMap, SEC_E_UNSUPPORTED_FUNCTION, "The function requested is not supported");
add(messageMap, SEC_E_TARGET_UNKNOWN, "The specified target is unknown or unreachable");
add(messageMap, SEC_E_INTERNAL_ERROR, "The Local Security Authority cannot be contacted");
add(messageMap, SEC_E_SECPKG_NOT_FOUND, "The requested security package does not exist");
add(messageMap, SEC_E_NOT_OWNER, "The caller is not the owner of the desired credentials");
add(messageMap, SEC_E_CANNOT_INSTALL, "The security package failed to initialize, and cannot be installed");
add(messageMap, SEC_E_INVALID_TOKEN, "The token supplied to the function is invalid");
add(messageMap, SEC_E_CANNOT_PACK, "The security package is not able to marshall the logon buffer, so the logon attempt has failed");
add(messageMap, SEC_E_QOP_NOT_SUPPORTED, "The per-message Quality of Protection is not supported by the security package");
add(messageMap, SEC_E_NO_IMPERSONATION, "The security context does not allow impersonation of the client");
add(messageMap, SEC_E_LOGON_DENIED, "The logon attempt failed");
add(messageMap, SEC_E_UNKNOWN_CREDENTIALS, "The credentials supplied to the package were not recognized");
add(messageMap, SEC_E_NO_CREDENTIALS, "No credentials are available in the security package");
add(messageMap, SEC_E_MESSAGE_ALTERED, "The message or signature supplied for verification has been altered");
add(messageMap, SEC_E_OUT_OF_SEQUENCE, "The message supplied for verification is out of sequence");
add(messageMap, SEC_E_NO_AUTHENTICATING_AUTHORITY, "No authority could be contacted for authentication");
add(messageMap, SEC_I_CONTINUE_NEEDED, "The function completed successfully, but must be called again to complete the context");
add(messageMap, SEC_I_COMPLETE_NEEDED, "The function completed successfully, but CompleteToken must be called");
add(messageMap, SEC_I_COMPLETE_AND_CONTINUE, "The function completed successfully, but both CompleteToken and this function must be called to complete the context");
add(messageMap, SEC_I_LOCAL_LOGON, "The logon was completed, but no network authority was available. The logon was made using locally known information");
add(messageMap, SEC_E_BAD_PKGID, "The requested security package does not exist");
add(messageMap, SEC_E_CONTEXT_EXPIRED, "The context has expired and can no longer be used");
add(messageMap, SEC_E_INCOMPLETE_MESSAGE, "The supplied message is incomplete. The signature was not verified");
add(messageMap, SEC_E_INCOMPLETE_CREDENTIALS, "The credentials supplied were not complete, and could not be verified. The context could not be initialized");
add(messageMap, SEC_E_BUFFER_TOO_SMALL, "The buffers supplied to a function was too small");
add(messageMap, SEC_I_RENEGOTIATE, "The context data must be renegotiated with the peer");
add(messageMap, SEC_E_WRONG_PRINCIPAL, "The target principal name is incorrect");
add(messageMap, SEC_I_NO_LSA_CONTEXT, "There is no LSA mode context associated with this context");
add(messageMap, SEC_E_TIME_SKEW, "The clocks on the client and server machines are skewed");
add(messageMap, SEC_E_UNTRUSTED_ROOT, "The certificate chain was issued by an authority that is not trusted");
add(messageMap, SEC_E_ILLEGAL_MESSAGE, "The message received was unexpected or badly formatted");
add(messageMap, SEC_E_CERT_UNKNOWN, "An unknown error occurred while processing the certificate");
add(messageMap, SEC_E_CERT_EXPIRED, "The received certificate has expired");
add(messageMap, SEC_E_ENCRYPT_FAILURE, "The specified data could not be encrypted");
add(messageMap, SEC_E_DECRYPT_FAILURE, "The specified data could not be decrypted");
add(messageMap, SEC_E_ALGORITHM_MISMATCH, "The client and server cannot communicate, because they do not possess a common algorithm");
add(messageMap, SEC_E_SECURITY_QOS_FAILED, "The security context could not be established due to a failure in the requested quality of service (e.g. mutual authentication or delegation)");
add(messageMap, SEC_E_UNFINISHED_CONTEXT_DELETED, "A security context was deleted before the context was completed. This is considered a logon failure");
add(messageMap, SEC_E_NO_TGT_REPLY, "The client is trying to negotiate a context and the server requires user-to-user but didn't send a TGT reply");
add(messageMap, SEC_E_NO_IP_ADDRESSES, "Unable to accomplish the requested task because the local machine does not have any IP addresses");
add(messageMap, SEC_E_WRONG_CREDENTIAL_HANDLE, "The supplied credential handle does not match the credential associated with the security context");
add(messageMap, SEC_E_CRYPTO_SYSTEM_INVALID, "The crypto system or checksum function is invalid because a required function is unavailable");
add(messageMap, SEC_E_MAX_REFERRALS_EXCEEDED, "The number of maximum ticket referrals has been exceeded");
add(messageMap, SEC_E_MUST_BE_KDC, "The local machine must be a Kerberos KDC (domain controller) and it is not");
add(messageMap, SEC_E_STRONG_CRYPTO_NOT_SUPPORTED, "The other end of the security negotiation is requires strong crypto but it is not supported on the local machine");
add(messageMap, SEC_E_TOO_MANY_PRINCIPALS, "The KDC reply contained more than one principal name");
add(messageMap, SEC_E_NO_PA_DATA, "Expected to find PA data for a hint of what type to use, but it was not found");
//80092001
add(messageMap, CRYPT_E_SELF_SIGNED, "The specified certificate is self signed");
add(messageMap, CRYPT_E_DELETED_PREV, "The previous certificate or CRL context was deleted");
add(messageMap, CRYPT_E_NO_MATCH, "Cannot find the requested object");
add(messageMap, CRYPT_E_UNEXPECTED_MSG_TYPE, "The certificate does not have a property that references a private key");
add(messageMap, CRYPT_E_NO_KEY_PROPERTY, "Cannot find the certificate and private key for decryption");
add(messageMap, CRYPT_E_NO_DECRYPT_CERT, "Cannot find the certificate and private key to use for decryption");
add(messageMap, CRYPT_E_BAD_MSG, "Not a cryptographic message or the cryptographic message is not formatted correctly");
add(messageMap, CRYPT_E_NO_SIGNER, "The signed cryptographic message does not have a signer for the specified signer index");
add(messageMap, CRYPT_E_PENDING_CLOSE, "Final closure is pending until additional frees or closes");
add(messageMap, CRYPT_E_REVOKED, "The certificate is revoked");
add(messageMap, CRYPT_E_NO_REVOCATION_DLL, "No Dll or exported function was found to verify revocation");
add(messageMap, CRYPT_E_NO_REVOCATION_CHECK, "The revocation function was unable to check revocation for the certificate");
add(messageMap, CRYPT_E_REVOCATION_OFFLINE, "The revocation function was unable to check revocation because the revocation server was offline");
add(messageMap, CRYPT_E_NOT_IN_REVOCATION_DATABASE, "The certificate is not in the revocation server's database");
add(messageMap, CRYPT_E_INVALID_NUMERIC_STRING, "The string contains a non-numeric character");
add(messageMap, CRYPT_E_INVALID_PRINTABLE_STRING, "The string contains a non-printable character");
add(messageMap, CRYPT_E_INVALID_IA5_STRING, "The string contains a character not in the 7 bit ASCII character set");
add(messageMap, CRYPT_E_INVALID_X500_STRING, "The string contains an invalid X500 name attribute key, oid, value or delimiter");
add(messageMap, CRYPT_E_NOT_CHAR_STRING, "The dwValueType for the CERT_NAME_VALUE is not one of the character strings. Most likely it is either a CERT_RDN_ENCODED_BLOB or CERT_TDN_OCTED_STRING");
add(messageMap, CRYPT_E_FILERESIZED, "The Put operation can not continue. The file needs to be resized. However, there is already a signature present. A complete signing operation must be done");
add(messageMap, CRYPT_E_SECURITY_SETTINGS, "The cryptographic operation failed due to a local security option setting");
add(messageMap, CRYPT_E_NO_VERIFY_USAGE_DLL, "No DLL or exported function was found to verify subject usage");
add(messageMap, CRYPT_E_NO_VERIFY_USAGE_CHECK, "The called function was unable to do a usage check on the subject");
add(messageMap, CRYPT_E_VERIFY_USAGE_OFFLINE, "Since the server was offline, the called function was unable to complete the usage check");
add(messageMap, CRYPT_E_NOT_IN_CTL, "The subject was not found in a Certificate Trust List (CTL)");
add(messageMap, CRYPT_E_NO_TRUSTED_SIGNER, "None of the signers of the cryptographic message or certificate trust list is trusted");
add(messageMap, CRYPT_E_MISSING_PUBKEY_PARA, "The public key's algorithm parameters are missing");
add(messageMap, TRUST_E_CERT_SIGNATURE, "The signature of the certificate cannot be verified.");
add(messageMap, TRUST_E_BASIC_CONSTRAINTS, "The basic constraints of the certificate are not valid or missing");
add(messageMap, CERT_E_UNTRUSTEDROOT, "A certification chain processed correctly but terminated in a root certificate not trusted by the trust provider");
add(messageMap, CERT_E_UNTRUSTEDTESTROOT, "The root certificate is a testing certificate and policy settings disallow test certificates");
add(messageMap, CERT_E_CHAINING, "A chain of certificates was not correctly created");
add(messageMap, CERT_E_WRONG_USAGE, "The certificate is not valid for the requested usage");
add(messageMap, CERT_E_EXPIRED, "A required certificate is not within its validity period");
add(messageMap, CERT_E_VALIDITYPERIODNESTING, "The validity periods of the certification chain do not nest correctly");
add(messageMap, CERT_E_PURPOSE, "A certificate is being used for a purpose that is not supported");
add(messageMap, CERT_E_ROLE, "A certificate that can only be used as an end entity is being used as a CA or visa versa");
add(messageMap, CERT_E_CN_NO_MATCH, "The CN name of the certificate does not match the passed value");
add(messageMap, CERT_E_REVOKED, "A certificate in the chain has been explicitly revoked by its issuer");
add(messageMap, CERT_E_REVOCATION_FAILURE, "The revocation process could not continue. The certificates could not be checked");
return messageMap;
}
const std::string& Utility::formatError(long errCode)
{
Poco::FastMutex::ScopedLock lock(_mutex);
static const std::string def("Internal SSPI error");
static const std::map<long, const std::string> errs(initSSPIErr());
const std::map<long, const std::string>::const_iterator it = errs.find(errCode);
if (it != errs.end())
return it->second;
else
return def;
}
} } // namespace Poco::Net

View File

@ -0,0 +1,37 @@
//
// VerificationErrorArgs.cpp
//
// Library: NetSSL_Win
// Package: SSLCore
// Module: VerificationErrorArgs
//
// Copyright (c) 2006-2014, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// SPDX-License-Identifier: BSL-1.0
//
#include "Poco/Net/VerificationErrorArgs.h"
namespace Poco {
namespace Net {
VerificationErrorArgs::VerificationErrorArgs(const X509Certificate& cert, int errDepth, int errNum, const std::string& errMsg):
_cert(cert),
_errorDepth(errDepth),
_errorNumber(errNum),
_errorMessage(errMsg),
_ignoreError(false)
{
}
VerificationErrorArgs::~VerificationErrorArgs()
{
}
} } // namespace Poco::Net

View File

@ -0,0 +1,568 @@
//
// X509Certificate.cpp
//
// Library: NetSSL_Win
// Package: Certificate
// Module: X509Certificate
//
// Copyright (c) 2006-2014, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// SPDX-License-Identifier: BSL-1.0
//
#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 "Poco/RegularExpression.h"
#include "Poco/Net/DNS.h"
namespace Poco {
namespace Net {
X509Certificate::X509Certificate(const std::string& path):
_pCert(0)
{
importCertificate(path);
init();
}
X509Certificate::X509Certificate(std::istream& istr):
_pCert(0)
{
importCertificate(istr);
init();
}
X509Certificate::X509Certificate(const std::string& certName, const std::string& certStoreName, bool useMachineStore):
_pCert(0)
{
loadCertificate(certName, certStoreName, useMachineStore);
init();
}
X509Certificate::X509Certificate(PCCERT_CONTEXT pCert):
_pCert(pCert)
{
poco_check_ptr(_pCert);
init();
}
X509Certificate::X509Certificate(const X509Certificate& cert):
_issuerName(cert._issuerName),
_subjectName(cert._subjectName),
_pCert(cert._pCert)
{
_pCert = CertDuplicateCertificateContext(_pCert);
}
X509Certificate::X509Certificate(X509Certificate&& cert) noexcept:
_issuerName(std::move(cert._issuerName)),
_subjectName(std::move(cert._subjectName)),
_pCert(cert._pCert)
{
cert._pCert = nullptr;
}
X509Certificate::X509Certificate(PCCERT_CONTEXT pCert, bool shared):
_pCert(pCert)
{
poco_check_ptr(_pCert);
if (shared)
{
_pCert = CertDuplicateCertificateContext(_pCert);
}
init();
}
X509Certificate& X509Certificate::operator = (const X509Certificate& cert)
{
X509Certificate tmp(cert);
swap(tmp);
return *this;
}
X509Certificate& X509Certificate::operator = (X509Certificate&& cert) noexcept
{
_issuerName = std::move(cert._issuerName);
_subjectName = std::move(cert._subjectName);
_pCert = cert._pCert; cert._pCert = nullptr;
return *this;
}
void X509Certificate::swap(X509Certificate& cert)
{
using std::swap;
swap(cert._issuerName, _issuerName);
swap(cert._subjectName, _subjectName);
swap(cert._pCert, _pCert);
}
X509Certificate::~X509Certificate()
{
if (_pCert) CertFreeCertificateContext(_pCert);
}
void X509Certificate::init()
{
std::string name = issuerName(NID_COUNTRY);
if (!name.empty())
{
_issuerName += "/C=";
_issuerName += name;
}
name = issuerName(NID_STATE_OR_PROVINCE);
if (!name.empty())
{
_issuerName += "/ST=";
_issuerName += name;
}
name = issuerName(NID_LOCALITY_NAME);
if (!name.empty())
{
_issuerName += "/L=";
_issuerName += name;
}
name = issuerName(NID_ORGANIZATION_NAME);
if (!name.empty())
{
_issuerName += "/O=";
_issuerName += name;
}
name = issuerName(NID_ORGANIZATION_UNIT_NAME);
if (!name.empty())
{
_issuerName += "/OU=";
_issuerName += name;
}
name = issuerName(NID_COMMON_NAME);
if (!name.empty())
{
_issuerName += "/CN=";
_issuerName += name;
}
name = subjectName(NID_COUNTRY);
if (!name.empty())
{
_subjectName += "/C=";
_subjectName += name;
}
name = subjectName(NID_STATE_OR_PROVINCE);
if (!name.empty())
{
_subjectName += "/ST=";
_subjectName += name;
}
name = subjectName(NID_LOCALITY_NAME);
if (!name.empty())
{
_subjectName += "/L=";
_subjectName += name;
}
name = subjectName(NID_ORGANIZATION_NAME);
if (!name.empty())
{
_subjectName += "/O=";
_subjectName += name;
}
name = subjectName(NID_ORGANIZATION_UNIT_NAME);
if (!name.empty())
{
_subjectName += "/OU=";
_subjectName += name;
}
name = subjectName(NID_COMMON_NAME);
if (!name.empty())
{
_subjectName += "/CN=";
_subjectName += name;
}}
std::string X509Certificate::commonName() const
{
return subjectName(NID_COMMON_NAME);
}
std::string X509Certificate::issuerName(NID nid) const
{
std::string result;
DWORD size = CertGetNameStringW(_pCert, CERT_NAME_ATTR_TYPE, CERT_NAME_ISSUER_FLAG, nid2oid(nid), 0, 0);
Poco::Buffer<wchar_t> data(size);
CertGetNameStringW(_pCert, CERT_NAME_ATTR_TYPE, CERT_NAME_ISSUER_FLAG, nid2oid(nid), data.begin(), size);
Poco::UnicodeConverter::convert(data.begin(), result);
return result;
}
std::string X509Certificate::subjectName(NID nid) const
{
std::string result;
DWORD size = CertGetNameStringW(_pCert, CERT_NAME_ATTR_TYPE, 0, nid2oid(nid), 0, 0);
Poco::Buffer<wchar_t> data(size);
CertGetNameStringW(_pCert, CERT_NAME_ATTR_TYPE, 0, nid2oid(nid), data.begin(), size);
Poco::UnicodeConverter::convert(data.begin(), result);
return result;
}
void X509Certificate::extractNames(std::string& cmnName, std::set<std::string>& domainNames) const
{
domainNames.clear();
cmnName = commonName();
PCERT_EXTENSION pExt = _pCert->pCertInfo->rgExtension;
for (int i = 0; i < _pCert->pCertInfo->cExtension; i++, pExt++)
{
if (std::strcmp(pExt->pszObjId, szOID_SUBJECT_ALT_NAME2) == 0)
{
DWORD flags(0);
#if defined(CRYPT_DECODE_ENABLE_PUNYCODE_FLAG)
flags |= CRYPT_DECODE_ENABLE_PUNYCODE_FLAG;
#endif
Poco::Buffer<char> buffer(256);
DWORD bufferSize = static_cast<DWORD>(buffer.sizeBytes());
BOOL rc = CryptDecodeObjectEx(
X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
pExt->pszObjId,
pExt->Value.pbData,
pExt->Value.cbData,
flags,
0,
buffer.begin(),
&bufferSize);
if (!rc && GetLastError() == ERROR_MORE_DATA)
{
buffer.resize(bufferSize);
rc = CryptDecodeObjectEx(
X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
pExt->pszObjId,
pExt->Value.pbData,
pExt->Value.cbData,
flags,
0,
buffer.begin(),
&bufferSize);
}
if (rc)
{
PCERT_ALT_NAME_INFO pNameInfo = reinterpret_cast<PCERT_ALT_NAME_INFO>(buffer.begin());
for (int i = 0; i < pNameInfo->cAltEntry; i++)
{
std::wstring waltName(pNameInfo->rgAltEntry[i].pwszDNSName);
std::string altName;
Poco::UnicodeConverter::toUTF8(waltName, altName);
domainNames.insert(altName);
}
}
}
}
if (!cmnName.empty() && domainNames.empty())
{
domainNames.insert(cmnName);
}
}
Poco::DateTime X509Certificate::validFrom() const
{
Poco::Timestamp ts = Poco::Timestamp::fromFileTimeNP(_pCert->pCertInfo->NotBefore.dwLowDateTime, _pCert->pCertInfo->NotBefore.dwHighDateTime);
return Poco::DateTime(ts);
}
Poco::DateTime X509Certificate::expiresOn() const
{
Poco::Timestamp ts = Poco::Timestamp::fromFileTimeNP(_pCert->pCertInfo->NotAfter.dwLowDateTime, _pCert->pCertInfo->NotAfter.dwHighDateTime);
return Poco::DateTime(ts);
}
bool X509Certificate::issuedBy(const X509Certificate& issuerCertificate) const
{
CERT_CHAIN_PARA chainPara;
PCCERT_CHAIN_CONTEXT pChainContext = 0;
std::memset(&chainPara, 0, sizeof(chainPara));
chainPara.cbSize = sizeof(chainPara);
if (!CertGetCertificateChain(
NULL,
_pCert,
NULL,
NULL,
&chainPara,
0,
NULL,
&pChainContext))
{
throw SSLException("Cannot get certificate chain", subjectName(), GetLastError());
}
bool result = false;
for (DWORD i = 0; i < pChainContext->cChain && !result; i++)
{
for (DWORD k = 0; k < pChainContext->rgpChain[i]->cElement && !result; k++)
{
PCCERT_CONTEXT pChainCert = pChainContext->rgpChain[i]->rgpElement[k]->pCertContext;
if (CertCompareCertificate(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, issuerCertificate.system()->pCertInfo, pChainCert->pCertInfo))
{
if (CertComparePublicKeyInfo(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, &issuerCertificate.system()->pCertInfo->SubjectPublicKeyInfo, &pChainCert->pCertInfo->SubjectPublicKeyInfo))
{
result = true;
}
}
}
}
CertFreeCertificateChain(pChainContext);
return result;
}
void* X509Certificate::nid2oid(NID nid)
{
const char* result = 0;
switch (nid)
{
case NID_COMMON_NAME:
result = szOID_COMMON_NAME;
break;
case NID_COUNTRY:
result = szOID_COUNTRY_NAME;
break;
case NID_LOCALITY_NAME:
result = szOID_LOCALITY_NAME;
break;
case NID_STATE_OR_PROVINCE:
result = szOID_STATE_OR_PROVINCE_NAME;
break;
case NID_ORGANIZATION_NAME:
result = szOID_ORGANIZATION_NAME;
break;
case NID_ORGANIZATION_UNIT_NAME:
result = szOID_ORGANIZATIONAL_UNIT_NAME;
break;
default:
poco_bugcheck();
result = "";
break;
}
return const_cast<char*>(result);
}
void X509Certificate::loadCertificate(const std::string& certName, const std::string& certStoreName, bool useMachineStore)
{
std::wstring wcertStoreName;
Poco::UnicodeConverter::convert(certStoreName, wcertStoreName);
HCERTSTORE hCertStore;
if (useMachineStore)
hCertStore = CertOpenStore(CERT_STORE_PROV_SYSTEM, 0, 0, CERT_SYSTEM_STORE_LOCAL_MACHINE, wcertStoreName.c_str());
else
hCertStore = CertOpenSystemStoreW(0, wcertStoreName.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 = static_cast<DWORD>(certName.size());
cert_rdn_attr.Value.pbData = reinterpret_cast<BYTE*>(const_cast<char*>(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 < 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(std::istream& istr)
{
std::string data;
Poco::StreamCopier::copyToString(istr, data);
if (!data.empty())
{
importCertificate(data.data(), data.size());
}
else throw Poco::IOException("failed to read certificate from stream");
}
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());
}
}
bool X509Certificate::verify(const std::string& hostName) const
{
return verify(*this, hostName);
}
bool X509Certificate::verify(const Poco::Net::X509Certificate& certificate, const std::string& hostName)
{
std::string commonName;
std::set<std::string> dnsNames;
certificate.extractNames(commonName, dnsNames);
if (!commonName.empty()) dnsNames.insert(commonName);
bool ok = (dnsNames.find(hostName) != dnsNames.end());
if (!ok)
{
for (std::set<std::string>::const_iterator it = dnsNames.begin(); !ok && it != dnsNames.end(); ++it)
{
try
{
// two cases: strData contains wildcards or not
if (containsWildcards(*it))
{
// a compare by IPAddress is not possible with wildcards
// only allow compare by name
ok = matchWildcard(*it, hostName);
}
else
{
// it depends on hostName if we compare by IP or by alias
IPAddress ip;
if (IPAddress::tryParse(hostName, ip))
{
// compare by IP
const HostEntry& heData = DNS::resolve(*it);
const HostEntry::AddressList& addr = heData.addresses();
HostEntry::AddressList::const_iterator it = addr.begin();
HostEntry::AddressList::const_iterator itEnd = addr.end();
for (; it != itEnd && !ok; ++it)
{
ok = (*it == ip);
}
}
else
{
ok = Poco::icompare(*it, hostName) == 0;
}
}
}
catch (NoAddressFoundException&)
{
}
catch (HostNotFoundException&)
{
}
}
}
return ok;
}
bool X509Certificate::containsWildcards(const std::string& commonName)
{
return (commonName.find('*') != std::string::npos || commonName.find('?') != std::string::npos);
}
bool X509Certificate::matchWildcard(const std::string& wildcard, const std::string& hostName)
{
// fix wildcards
std::string wildcardExpr("^");
wildcardExpr += Poco::replace(wildcard, ".", "\\.");
Poco::replaceInPlace(wildcardExpr, "*", ".*");
Poco::replaceInPlace(wildcardExpr, "..*", ".*");
Poco::replaceInPlace(wildcardExpr, "?", ".?");
Poco::replaceInPlace(wildcardExpr, "..?", ".?");
wildcardExpr += "$";
Poco::RegularExpression expr(wildcardExpr, Poco::RegularExpression::RE_CASELESS);
return expr.match(hostName);
}
} } // namespace Poco::Net