mirror of
https://github.com/pocoproject/poco.git
synced 2025-10-18 11:39:00 +02:00
optimizations, certificate verification, code cleanup
This commit is contained in:
@@ -52,54 +52,22 @@ public:
|
|||||||
ulVersion = SECBUFFER_VERSION;
|
ulVersion = SECBUFFER_VERSION;
|
||||||
}
|
}
|
||||||
|
|
||||||
AutoSecBufferDesc(const AutoSecBufferDesc& desc):
|
|
||||||
/// Creates a AutoSecBufferDesc from another buffer, resets the other buffer!
|
|
||||||
_pSec(desc._pSec),
|
|
||||||
_autoRelease(desc._autoRelease)
|
|
||||||
{
|
|
||||||
poco_check_ptr (_pSec);
|
|
||||||
poco_static_assert (numBufs > 0);
|
|
||||||
|
|
||||||
for (int i = 0; i < numBufs; ++i)
|
|
||||||
{
|
|
||||||
_buffers[i].pvBuffer = desc._buffers[i].pvBuffer;
|
|
||||||
_buffers[i].cbBuffer = desc._buffers[i].cbBuffer;
|
|
||||||
_buffers[i].BufferType = desc._buffers[i].BufferType;
|
|
||||||
}
|
|
||||||
cBuffers = numBufs;
|
|
||||||
pBuffers = _buffers;
|
|
||||||
ulVersion = SECBUFFER_VERSION;
|
|
||||||
// steal the buffers from the original one
|
|
||||||
const_cast<AutoSecBufferDesc*>(&desc)->initBuffers();
|
|
||||||
}
|
|
||||||
|
|
||||||
AutoSecBufferDesc& operator = (const AutoSecBufferDesc& desc)
|
|
||||||
{
|
|
||||||
if (&desc != this)
|
|
||||||
{
|
|
||||||
_pSec = desc._pSec;
|
|
||||||
_autoRelease = desc._autoRelease;
|
|
||||||
for (int i = 0; i < numBufs; ++i)
|
|
||||||
{
|
|
||||||
_buffers[i].pvBuffer = desc._buffers[i].pvBuffer;
|
|
||||||
_buffers[i].cbBuffer = desc._buffers[i].cbBuffer;
|
|
||||||
_buffers[i].BufferType = desc._buffers[i].BufferType;
|
|
||||||
}
|
|
||||||
cBuffers = numBufs;
|
|
||||||
pBuffers = _buffers;
|
|
||||||
ulVersion = desc.ulVersion;
|
|
||||||
// steal the buffers from the original one
|
|
||||||
const_cast<AutoSecBufferDesc*>(&desc)->initBuffers();
|
|
||||||
}
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
~AutoSecBufferDesc()
|
~AutoSecBufferDesc()
|
||||||
/// Destroys the AutoSecBufferDesc
|
/// Destroys the AutoSecBufferDesc
|
||||||
{
|
{
|
||||||
release();
|
release();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void reset(bool autoRelease)
|
||||||
|
{
|
||||||
|
release();
|
||||||
|
_autoRelease = autoRelease;
|
||||||
|
initBuffers();
|
||||||
|
cBuffers = numBufs;
|
||||||
|
pBuffers = _buffers;
|
||||||
|
ulVersion = SECBUFFER_VERSION;
|
||||||
|
}
|
||||||
|
|
||||||
void release()
|
void release()
|
||||||
{
|
{
|
||||||
if (_autoRelease)
|
if (_autoRelease)
|
||||||
@@ -157,6 +125,9 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
AutoSecBufferDesc(const AutoSecBufferDesc& desc);
|
||||||
|
AutoSecBufferDesc& operator = (const AutoSecBufferDesc& desc);
|
||||||
|
|
||||||
void release(int idx, bool force)
|
void release(int idx, bool force)
|
||||||
{
|
{
|
||||||
if (force && _buffers[idx].pvBuffer)
|
if (force && _buffers[idx].pvBuffer)
|
||||||
|
@@ -93,12 +93,9 @@ public:
|
|||||||
///
|
///
|
||||||
/// Client: Same as VERIFY_RELAXED.
|
/// Client: Same as VERIFY_RELAXED.
|
||||||
|
|
||||||
VERIFY_ONCE = 3
|
VERIFY_ONCE = 1
|
||||||
/// Server: Only request a client certificate on the initial
|
/// Same as VERIFY_RELAXED (provided for interface compatibility with
|
||||||
/// TLS/SSL handshake. Do not ask for a client certificate
|
/// the OpenSSL implementation.
|
||||||
/// again in case of a renegotiation.
|
|
||||||
///
|
|
||||||
/// Client: Same as VERIFY_RELAXED.
|
|
||||||
};
|
};
|
||||||
|
|
||||||
enum Options
|
enum Options
|
||||||
@@ -160,6 +157,16 @@ public:
|
|||||||
bool sessionCacheEnabled() const;
|
bool sessionCacheEnabled() const;
|
||||||
/// Returns true iff the session cache is enabled.
|
/// Returns true iff the session cache is enabled.
|
||||||
|
|
||||||
|
void enableExtendedCertificateVerification(bool flag = true);
|
||||||
|
/// Enable or disable the automatic post-connection
|
||||||
|
/// extended certificate verification.
|
||||||
|
///
|
||||||
|
/// See X509Certificate::verify() for more information.
|
||||||
|
|
||||||
|
bool extendedCertificateVerificationEnabled() const;
|
||||||
|
/// Returns true iff automatic extended certificate
|
||||||
|
/// verification is enabled.
|
||||||
|
|
||||||
int options() const;
|
int options() const;
|
||||||
/// Returns the options flags.
|
/// Returns the options flags.
|
||||||
|
|
||||||
@@ -202,6 +209,7 @@ private:
|
|||||||
Usage _usage;
|
Usage _usage;
|
||||||
Context::VerificationMode _mode;
|
Context::VerificationMode _mode;
|
||||||
int _options;
|
int _options;
|
||||||
|
bool _extendedCertificateVerification;
|
||||||
std::string _certNameOrPath;
|
std::string _certNameOrPath;
|
||||||
std::string _certStoreName;
|
std::string _certStoreName;
|
||||||
HCERTSTORE _hMemCertStore;
|
HCERTSTORE _hMemCertStore;
|
||||||
@@ -245,9 +253,16 @@ inline bool Context::isForServerUse() const
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
inline bool Context::extendedCertificateVerificationEnabled() const
|
||||||
|
{
|
||||||
|
return _extendedCertificateVerification;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
inline bool Context::sessionCacheEnabled() const
|
inline bool Context::sessionCacheEnabled() const
|
||||||
{
|
{
|
||||||
return false;
|
return true;
|
||||||
|
/// Session cache is always enabled with Schannel.
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@@ -25,7 +25,6 @@
|
|||||||
#include "Poco/Net/Context.h"
|
#include "Poco/Net/Context.h"
|
||||||
#include "Poco/Net/AutoSecBufferDesc.h"
|
#include "Poco/Net/AutoSecBufferDesc.h"
|
||||||
#include "Poco/Net/X509Certificate.h"
|
#include "Poco/Net/X509Certificate.h"
|
||||||
#include "Poco/SharedPtr.h"
|
|
||||||
#include "Poco/Buffer.h"
|
#include "Poco/Buffer.h"
|
||||||
#include <winsock2.h>
|
#include <winsock2.h>
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
@@ -46,33 +45,12 @@ class NetSSL_Win_API SecureSocketImpl
|
|||||||
/// The SocketImpl for SecureStreamSocket.
|
/// The SocketImpl for SecureStreamSocket.
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
enum
|
|
||||||
{
|
|
||||||
IO_BUFFER_SIZE = 65536,
|
|
||||||
TIMEOUT_MILLISECS = 200
|
|
||||||
};
|
|
||||||
|
|
||||||
enum Mode
|
enum Mode
|
||||||
{
|
{
|
||||||
MODE_CLIENT,
|
MODE_CLIENT,
|
||||||
MODE_SERVER
|
MODE_SERVER
|
||||||
};
|
};
|
||||||
|
|
||||||
enum State
|
|
||||||
{
|
|
||||||
ST_INITIAL = 0,
|
|
||||||
ST_CONNECTING,
|
|
||||||
ST_CLIENTHANDSHAKESTART,
|
|
||||||
ST_CLIENTHANDSHAKECONDREAD,
|
|
||||||
ST_CLIENTHANDSHAKEINCOMPLETE,
|
|
||||||
ST_CLIENTHANDSHAKEOK,
|
|
||||||
ST_CLIENTHANDSHAKEEXTERROR,
|
|
||||||
ST_CLIENTHANDSHAKECONTINUE,
|
|
||||||
ST_VERIFY,
|
|
||||||
ST_DONE,
|
|
||||||
ST_ERROR
|
|
||||||
};
|
|
||||||
|
|
||||||
SecureSocketImpl(Poco::AutoPtr<SocketImpl> pSocketImpl, Context::Ptr pContext);
|
SecureSocketImpl(Poco::AutoPtr<SocketImpl> pSocketImpl, Context::Ptr pContext);
|
||||||
/// Creates the SecureSocketImpl.
|
/// Creates the SecureSocketImpl.
|
||||||
|
|
||||||
@@ -160,8 +138,14 @@ public:
|
|||||||
const std::string& getPeerHostName() const;
|
const std::string& getPeerHostName() const;
|
||||||
/// Returns the peer host name.
|
/// Returns the peer host name.
|
||||||
|
|
||||||
State getState() const;
|
void verifyPeerCertificate();
|
||||||
/// Returns the state of the socket
|
/// Performs post-connect (or post-accept) peer certificate validation,
|
||||||
|
/// using the peer host name set with setPeerHostName(), or the peer's
|
||||||
|
/// IP address string if no peer host name has been set.
|
||||||
|
|
||||||
|
void verifyPeerCertificate(const std::string& hostName);
|
||||||
|
/// Performs post-connect (or post-accept) peer certificate validation
|
||||||
|
/// using the given peer host name.
|
||||||
|
|
||||||
Context::Ptr context() const;
|
Context::Ptr context() const;
|
||||||
/// Returns the Context.
|
/// Returns the Context.
|
||||||
@@ -172,23 +156,40 @@ public:
|
|||||||
poco_socket_t sockfd();
|
poco_socket_t sockfd();
|
||||||
/// Returns the underlying socket descriptor.
|
/// Returns the underlying socket descriptor.
|
||||||
|
|
||||||
|
int available() const;
|
||||||
|
/// Returns the number of bytes available in the buffer.
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
IO_BUFFER_SIZE = 32768,
|
||||||
|
TIMEOUT_MILLISECS = 200
|
||||||
|
};
|
||||||
|
|
||||||
|
enum State
|
||||||
|
{
|
||||||
|
ST_INITIAL = 0,
|
||||||
|
ST_CONNECTING,
|
||||||
|
ST_CLIENTHANDSHAKESTART,
|
||||||
|
ST_CLIENTHANDSHAKECONDREAD,
|
||||||
|
ST_CLIENTHANDSHAKEINCOMPLETE,
|
||||||
|
ST_CLIENTHANDSHAKEOK,
|
||||||
|
ST_CLIENTHANDSHAKEEXTERROR,
|
||||||
|
ST_CLIENTHANDSHAKECONTINUE,
|
||||||
|
ST_VERIFY,
|
||||||
|
ST_DONE,
|
||||||
|
ST_ERROR
|
||||||
|
};
|
||||||
|
|
||||||
int sendRawBytes(const void* buffer, int length, int flags = 0);
|
int sendRawBytes(const void* buffer, int length, int flags = 0);
|
||||||
/// Sends the data in clearText
|
|
||||||
|
|
||||||
int receiveRawBytes(void* buffer, int length, int flags = 0);
|
int receiveRawBytes(void* buffer, int length, int flags = 0);
|
||||||
/// Receives raw data from the socket and stores it
|
|
||||||
/// in buffer. Up to length bytes are received.
|
|
||||||
///
|
|
||||||
/// Returns the number of bytes received.
|
|
||||||
|
|
||||||
void clientConnectVerify();
|
void clientConnectVerify();
|
||||||
void sendInitialTokenOutBuffer();
|
void sendInitialTokenOutBuffer();
|
||||||
void performServerHandshake();
|
void performServerHandshake();
|
||||||
bool serverHandshakeLoop(PCtxtHandle phContext, PCredHandle phCred, bool requireClientAuth, bool doInitialRead, bool newContext);
|
bool serverHandshakeLoop(PCtxtHandle phContext, PCredHandle phCred, bool requireClientAuth, bool doInitialRead, bool newContext);
|
||||||
void clientVerifyCertificate(PCCERT_CONTEXT pServerCert, const std::string& serverName, DWORD dwCertFlags);
|
void clientVerifyCertificate(const std::string& hostName);
|
||||||
void verifyCertificateChainClient(PCCERT_CONTEXT pServerCert, PCCERT_CHAIN_CONTEXT pChainContext);
|
void verifyCertificateChainClient(PCCERT_CONTEXT pServerCert, PCCERT_CHAIN_CONTEXT pChainContext);
|
||||||
void serverVerifyCertificate(PCCERT_CONTEXT pPeerCert, DWORD dwCertFlags);
|
void serverVerifyCertificate();
|
||||||
LONG serverDisconnect(PCredHandle phCreds, CtxtHandle* phContext);
|
LONG serverDisconnect(PCredHandle phCreds, CtxtHandle* phContext);
|
||||||
LONG clientDisconnect(PCredHandle phCreds, CtxtHandle* phContext);
|
LONG clientDisconnect(PCredHandle phCreds, CtxtHandle* phContext);
|
||||||
bool loadSecurityLibrary();
|
bool loadSecurityLibrary();
|
||||||
@@ -201,8 +202,8 @@ protected:
|
|||||||
void performInitialClientHandshake();
|
void performInitialClientHandshake();
|
||||||
SECURITY_STATUS performClientHandshakeLoop();
|
SECURITY_STATUS performClientHandshakeLoop();
|
||||||
void performClientHandshakeLoopIncompleteMessage();
|
void performClientHandshakeLoopIncompleteMessage();
|
||||||
void performClientHandshakeLoopCondRead();
|
void performClientHandshakeLoopCondReceive();
|
||||||
void performClientHandshakeLoopRead();
|
void performClientHandshakeLoopReceive();
|
||||||
void performClientHandshakeLoopOK();
|
void performClientHandshakeLoopOK();
|
||||||
void performClientHandshakeLoopInit();
|
void performClientHandshakeLoopInit();
|
||||||
void performClientHandshakeExtraBuffer();
|
void performClientHandshakeExtraBuffer();
|
||||||
@@ -219,7 +220,9 @@ protected:
|
|||||||
void completeHandshake();
|
void completeHandshake();
|
||||||
static int lastError();
|
static int lastError();
|
||||||
void stateMachine();
|
void stateMachine();
|
||||||
|
State getState() const;
|
||||||
void setState(State st);
|
void setState(State st);
|
||||||
|
static bool isLocalHost(const std::string& hostName);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
SecureSocketImpl(const SecureSocketImpl&);
|
SecureSocketImpl(const SecureSocketImpl&);
|
||||||
@@ -231,34 +234,30 @@ private:
|
|||||||
std::string _peerHostName;
|
std::string _peerHostName;
|
||||||
bool _useMachineStore;
|
bool _useMachineStore;
|
||||||
bool _clientAuthRequired;
|
bool _clientAuthRequired;
|
||||||
PCCERT_CONTEXT _pServerCertificate;
|
|
||||||
|
SecurityFunctionTableW& _securityFunctions;
|
||||||
|
|
||||||
|
PCCERT_CONTEXT _pOwnCertificate;
|
||||||
PCCERT_CONTEXT _pPeerCertificate;
|
PCCERT_CONTEXT _pPeerCertificate;
|
||||||
|
|
||||||
CredHandle _hCreds;
|
CredHandle _hCreds;
|
||||||
CtxtHandle _hContext;
|
CtxtHandle _hContext;
|
||||||
DWORD _clientFlags;
|
DWORD _contextFlags;
|
||||||
DWORD _serverFlags;
|
|
||||||
|
|
||||||
SecurityFunctionTableW& _securityFunctions;
|
Poco::Buffer<BYTE> _overflowBuffer;
|
||||||
|
Poco::Buffer<BYTE> _sendBuffer;
|
||||||
BYTE* _pReceiveBuffer;
|
Poco::Buffer<BYTE> _recvBuffer;
|
||||||
DWORD _receiveBufferSize;
|
DWORD _recvBufferOffset;
|
||||||
|
|
||||||
BYTE* _pIOBuffer;
|
|
||||||
DWORD _ioBufferOffset;
|
|
||||||
DWORD _ioBufferSize;
|
DWORD _ioBufferSize;
|
||||||
|
|
||||||
SecPkgContext_StreamSizes _streamSizes;
|
SecPkgContext_StreamSizes _streamSizes;
|
||||||
AutoSecBufferDesc<1> _outSecBuffer;
|
AutoSecBufferDesc<1> _outSecBuffer;
|
||||||
AutoSecBufferDesc<2> _inSecBuffer;
|
AutoSecBufferDesc<2> _inSecBuffer;
|
||||||
Poco::SharedPtr<Poco::Buffer<BYTE> > _pSendBuffer;
|
|
||||||
SecBuffer _extraSecBuffer;
|
SecBuffer _extraSecBuffer;
|
||||||
bool _doReadFirst;
|
|
||||||
DWORD _bytesRead;
|
|
||||||
SECURITY_STATUS _securityStatus;
|
SECURITY_STATUS _securityStatus;
|
||||||
State _state;
|
State _state;
|
||||||
DWORD _outFlags;
|
DWORD _outFlags;
|
||||||
std::string _hostName;
|
bool _needData;
|
||||||
bool _needHandshake;
|
bool _needHandshake;
|
||||||
|
|
||||||
friend class SecureStreamSocketImpl;
|
friend class SecureStreamSocketImpl;
|
||||||
|
@@ -123,6 +123,25 @@ public:
|
|||||||
/// Returns true if verification against the issuer certificate
|
/// Returns true if verification against the issuer certificate
|
||||||
/// was successful, false otherwise.
|
/// was successful, false otherwise.
|
||||||
|
|
||||||
|
bool verify(const std::string& hostName) const;
|
||||||
|
/// Verifies the validity of the certificate against the host name.
|
||||||
|
///
|
||||||
|
/// For this check to be successful, the certificate must contain
|
||||||
|
/// a domain name that matches the domain name
|
||||||
|
/// of the host.
|
||||||
|
///
|
||||||
|
/// Returns true if verification succeeded, or false otherwise.
|
||||||
|
|
||||||
|
static bool verify(const Poco::Net::X509Certificate& cert, const std::string& hostName);
|
||||||
|
/// Verifies the validity of the certificate against the host name.
|
||||||
|
///
|
||||||
|
/// For this check to be successful, the certificate must contain
|
||||||
|
/// a domain name that matches the domain name
|
||||||
|
/// of the host.
|
||||||
|
///
|
||||||
|
/// Returns true if verification succeeded, or false otherwise.
|
||||||
|
|
||||||
|
|
||||||
const PCCERT_CONTEXT system() const;
|
const PCCERT_CONTEXT system() const;
|
||||||
/// Returns the underlying WinCrypt certificate.
|
/// Returns the underlying WinCrypt certificate.
|
||||||
|
|
||||||
@@ -139,6 +158,9 @@ protected:
|
|||||||
void importPEMCertificate(const char* pBuffer, std::size_t size);
|
void importPEMCertificate(const char* pBuffer, std::size_t size);
|
||||||
void importDERCertificate(const char* pBuffer, std::size_t size);
|
void importDERCertificate(const char* pBuffer, std::size_t size);
|
||||||
|
|
||||||
|
static bool containsWildcards(const std::string& commonName);
|
||||||
|
static bool matchWildcard(const std::string& alias, const std::string& hostName);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
enum
|
enum
|
||||||
{
|
{
|
||||||
|
@@ -48,6 +48,7 @@ Context::Context(Usage usage,
|
|||||||
_usage(usage),
|
_usage(usage),
|
||||||
_mode(verMode),
|
_mode(verMode),
|
||||||
_options(options),
|
_options(options),
|
||||||
|
_extendedCertificateVerification(true),
|
||||||
_certNameOrPath(certNameOrPath),
|
_certNameOrPath(certNameOrPath),
|
||||||
_certStoreName(certStore),
|
_certStoreName(certStore),
|
||||||
_hMemCertStore(0),
|
_hMemCertStore(0),
|
||||||
@@ -126,6 +127,12 @@ void Context::init()
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Context::enableExtendedCertificateVerification(bool flag)
|
||||||
|
{
|
||||||
|
_extendedCertificateVerification = flag;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void Context::addTrustedCert(const Poco::Net::X509Certificate& cert)
|
void Context::addTrustedCert(const Poco::Net::X509Certificate& cert)
|
||||||
{
|
{
|
||||||
Poco::FastMutex::ScopedLock lock(_mutex);
|
Poco::FastMutex::ScopedLock lock(_mutex);
|
||||||
@@ -278,7 +285,7 @@ void Context::acquireSchannelCredentials(CredHandle& credHandle) const
|
|||||||
|
|
||||||
if (isForServerUse())
|
if (isForServerUse())
|
||||||
{
|
{
|
||||||
if (_mode == Context::VERIFY_STRICT)
|
if (_mode >= Context::VERIFY_STRICT)
|
||||||
schannelCred.dwFlags |= SCH_CRED_NO_SYSTEM_MAPPER;
|
schannelCred.dwFlags |= SCH_CRED_NO_SYSTEM_MAPPER;
|
||||||
|
|
||||||
if (_mode == Context::VERIFY_NONE)
|
if (_mode == Context::VERIFY_NONE)
|
||||||
@@ -286,13 +293,16 @@ void Context::acquireSchannelCredentials(CredHandle& credHandle) const
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (_mode == Context::VERIFY_STRICT)
|
if (_mode >= Context::VERIFY_STRICT)
|
||||||
schannelCred.dwFlags |= SCH_CRED_NO_DEFAULT_CREDS;
|
schannelCred.dwFlags |= SCH_CRED_NO_DEFAULT_CREDS;
|
||||||
else
|
else
|
||||||
schannelCred.dwFlags |= SCH_CRED_USE_DEFAULT_CREDS;
|
schannelCred.dwFlags |= SCH_CRED_USE_DEFAULT_CREDS;
|
||||||
|
|
||||||
if (_mode == Context::VERIFY_NONE)
|
if (_mode == Context::VERIFY_NONE)
|
||||||
schannelCred.dwFlags |= SCH_CRED_MANUAL_CRED_VALIDATION | SCH_CRED_NO_SERVERNAME_CHECK;
|
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 defined(SCH_USE_STRONG_CRYPTO)
|
||||||
|
File diff suppressed because it is too large
Load Diff
@@ -142,7 +142,7 @@ void SecureStreamSocketImpl::sendUrgent(unsigned char data)
|
|||||||
|
|
||||||
int SecureStreamSocketImpl::available()
|
int SecureStreamSocketImpl::available()
|
||||||
{
|
{
|
||||||
return 0; // TODO _impl.available();
|
return _impl.available();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -198,22 +198,19 @@ bool SecureStreamSocketImpl::getLazyHandshake() const
|
|||||||
|
|
||||||
void SecureStreamSocketImpl::verifyPeerCertificate()
|
void SecureStreamSocketImpl::verifyPeerCertificate()
|
||||||
{
|
{
|
||||||
// TODO
|
_impl.verifyPeerCertificate();
|
||||||
// _impl.verifyPeerCertificate();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void SecureStreamSocketImpl::verifyPeerCertificate(const std::string& hostName)
|
void SecureStreamSocketImpl::verifyPeerCertificate(const std::string& hostName)
|
||||||
{
|
{
|
||||||
// TODO
|
_impl.verifyPeerCertificate(hostName);
|
||||||
// _impl.verifyPeerCertificate(hostName);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int SecureStreamSocketImpl::completeHandshake()
|
int SecureStreamSocketImpl::completeHandshake()
|
||||||
{
|
{
|
||||||
// TODO
|
_impl.completeHandshake();
|
||||||
// return _impl.completeHandshake();
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -27,7 +27,8 @@
|
|||||||
#include "Poco/Buffer.h"
|
#include "Poco/Buffer.h"
|
||||||
#include "Poco/UnicodeConverter.h"
|
#include "Poco/UnicodeConverter.h"
|
||||||
#include "Poco/Format.h"
|
#include "Poco/Format.h"
|
||||||
#include <sstream>
|
#include "Poco/RegularExpression.h"
|
||||||
|
#include "Poco/Net/DNS.h"
|
||||||
|
|
||||||
|
|
||||||
namespace Poco {
|
namespace Poco {
|
||||||
@@ -142,8 +143,53 @@ std::string X509Certificate::subjectName(NID nid) const
|
|||||||
void X509Certificate::extractNames(std::string& cmnName, std::set<std::string>& domainNames) const
|
void X509Certificate::extractNames(std::string& cmnName, std::set<std::string>& domainNames) const
|
||||||
{
|
{
|
||||||
domainNames.clear();
|
domainNames.clear();
|
||||||
// TODO: extract subject alternative names
|
|
||||||
cmnName = commonName();
|
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 = 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->pwszDNSName);
|
||||||
|
std::string altName;
|
||||||
|
Poco::UnicodeConverter::toUTF8(waltName, altName);
|
||||||
|
domainNames.insert(altName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
if (!cmnName.empty() && domainNames.empty())
|
if (!cmnName.empty() && domainNames.empty())
|
||||||
{
|
{
|
||||||
domainNames.insert(cmnName);
|
domainNames.insert(cmnName);
|
||||||
@@ -167,16 +213,46 @@ Poco::DateTime X509Certificate::expiresOn() const
|
|||||||
|
|
||||||
bool X509Certificate::issuedBy(const X509Certificate& issuerCertificate) const
|
bool X509Certificate::issuedBy(const X509Certificate& issuerCertificate) const
|
||||||
{
|
{
|
||||||
HCERTSTORE hCertStore = CertOpenSystemStoreW(NULL, L"CA");
|
class CertStoreHandle
|
||||||
if (!hCertStore) throw Poco::SystemException("Cannot open CA store");
|
|
||||||
// TODO
|
|
||||||
try
|
|
||||||
{
|
{
|
||||||
PCCERT_CONTEXT pIssuer = 0;
|
public:
|
||||||
|
CertStoreHandle(HCERTSTORE hStore):
|
||||||
|
_hStore(hStore)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
~CertStoreHandle()
|
||||||
|
{
|
||||||
|
if (_hStore) CertCloseStore(_hStore, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
HCERTSTORE handle() const
|
||||||
|
{
|
||||||
|
return _hStore;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
HCERTSTORE _hStore;
|
||||||
|
};
|
||||||
|
|
||||||
|
CertStoreHandle caStore(CertOpenSystemStoreW(0, L"CA"));
|
||||||
|
CertStoreHandle rootStore(CertOpenSystemStoreW(0, L"ROOT"));
|
||||||
|
|
||||||
|
bool result = false;
|
||||||
|
PCCERT_CONTEXT pIssuer;
|
||||||
|
PCCERT_CONTEXT pIssued = _pCert;
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
DWORD flags = CERT_STORE_REVOCATION_FLAG | CERT_STORE_SIGNATURE_FLAG | CERT_STORE_TIME_VALIDITY_FLAG;
|
DWORD flags = CERT_STORE_REVOCATION_FLAG | CERT_STORE_SIGNATURE_FLAG | CERT_STORE_TIME_VALIDITY_FLAG;
|
||||||
pIssuer = CertGetIssuerCertificateFromStore(hCertStore, _pCert, 0, &flags);
|
pIssuer = 0;
|
||||||
|
if (caStore.handle())
|
||||||
|
{
|
||||||
|
pIssuer = CertGetIssuerCertificateFromStore(caStore.handle(), pIssued, 0, &flags);
|
||||||
|
}
|
||||||
|
if (!pIssuer && rootStore.handle())
|
||||||
|
{
|
||||||
|
pIssuer = CertGetIssuerCertificateFromStore(rootStore.handle(), pIssued, 0, &flags);
|
||||||
|
}
|
||||||
if (pIssuer)
|
if (pIssuer)
|
||||||
{
|
{
|
||||||
X509Certificate issuer(pIssuer);
|
X509Certificate issuer(pIssuer);
|
||||||
@@ -184,15 +260,22 @@ bool X509Certificate::issuedBy(const X509Certificate& issuerCertificate) const
|
|||||||
flags &= ~(CERT_STORE_NO_CRL_FLAG | CERT_STORE_REVOCATION_FLAG);
|
flags &= ~(CERT_STORE_NO_CRL_FLAG | CERT_STORE_REVOCATION_FLAG);
|
||||||
if (flags)
|
if (flags)
|
||||||
break;
|
break;
|
||||||
|
if (CertCompareCertificate(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, issuerCertificate.system()->pCertInfo, issuer.system()->pCertInfo))
|
||||||
|
{
|
||||||
|
result = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (CertCompareCertificate(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, pIssuer->pCertInfo, pIssued->pCertInfo))
|
||||||
|
{
|
||||||
|
// reached self-signed certificate
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else break;
|
else break;
|
||||||
}
|
}
|
||||||
while (pIssuer);
|
while (pIssuer);
|
||||||
}
|
|
||||||
catch (...)
|
return result;
|
||||||
{
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -321,4 +404,86 @@ void X509Certificate::importDERCertificate(const char* pBuffer, std::size_t size
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
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
|
} } // namespace Poco::Net
|
||||||
|
@@ -293,13 +293,21 @@ void HTTPSClientSessionTest::testInterop()
|
|||||||
HTTPRequest request(HTTPRequest::HTTP_GET, "/public/poco/NetSSL.txt");
|
HTTPRequest request(HTTPRequest::HTTP_GET, "/public/poco/NetSSL.txt");
|
||||||
s.sendRequest(request);
|
s.sendRequest(request);
|
||||||
Poco::Net::X509Certificate cert = s.serverCertificate();
|
Poco::Net::X509Certificate cert = s.serverCertificate();
|
||||||
|
|
||||||
HTTPResponse response;
|
HTTPResponse response;
|
||||||
std::istream& rs = s.receiveResponse(response);
|
std::istream& rs = s.receiveResponse(response);
|
||||||
std::ostringstream ostr;
|
std::ostringstream ostr;
|
||||||
StreamCopier::copyStream(rs, ostr);
|
StreamCopier::copyStream(rs, ostr);
|
||||||
std::string str(ostr.str());
|
std::string str(ostr.str());
|
||||||
assert (str == "This is a test file for NetSSL.\n");
|
assert (str == "This is a test file for NetSSL.\n");
|
||||||
assert (cert.commonName() == "secure.appinf.com" || cert.commonName() == "*.appinf.com");
|
|
||||||
|
std::string commonName;
|
||||||
|
std::set<std::string> domainNames;
|
||||||
|
cert.extractNames(commonName, domainNames);
|
||||||
|
|
||||||
|
assert (commonName == "secure.appinf.com" || commonName == "*.appinf.com");
|
||||||
|
assert (domainNames.find("appinf.com") != domainNames.end()
|
||||||
|
|| domainNames.find("*.appinf.com") != domainNames.end());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@@ -204,7 +204,8 @@ void HTTPSServerTest::testIdentityRequestKeepAlive()
|
|||||||
assert (response.getContentLength() == body.size());
|
assert (response.getContentLength() == body.size());
|
||||||
assert (response.getContentType() == "text/plain");
|
assert (response.getContentType() == "text/plain");
|
||||||
assert (!response.getKeepAlive());
|
assert (!response.getKeepAlive());
|
||||||
assert (rbody == body);}
|
assert (rbody == body);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void HTTPSServerTest::testChunkedRequestKeepAlive()
|
void HTTPSServerTest::testChunkedRequestKeepAlive()
|
||||||
|
Reference in New Issue
Block a user