summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--BuildTools/SCons/SConscript.boot4
-rw-r--r--Swift/SConscript2
-rw-r--r--Swiften/Client/ClientError.h2
-rw-r--r--Swiften/Client/CoreClient.cpp6
-rw-r--r--Swiften/TLS/CertificateVerificationError.h2
-rw-r--r--Swiften/TLS/Schannel/SchannelCertificate.h7
-rw-r--r--Swiften/TLS/Schannel/SchannelContext.cpp143
-rw-r--r--Swiften/TLS/Schannel/SchannelContext.h4
-rw-r--r--Swiften/TLS/Schannel/SchannelUtil.h135
9 files changed, 287 insertions, 18 deletions
diff --git a/BuildTools/SCons/SConscript.boot b/BuildTools/SCons/SConscript.boot
index 188184c..dc8a8a5 100644
--- a/BuildTools/SCons/SConscript.boot
+++ b/BuildTools/SCons/SConscript.boot
@@ -49,18 +49,19 @@ vars.Add(PathVariable("sqlite_libdir", "SQLite library location", None, PathVari
vars.Add("sqlite_libname", "SQLite library name", "libsqlite3" if os.name == "nt" else "sqlite3")
vars.Add(PathVariable("avahi_includedir", "Avahi headers location", None, PathVariable.PathAccept))
vars.Add(PathVariable("avahi_libdir", "Avahi library location", None, PathVariable.PathAccept))
vars.Add(PathVariable("qt", "Qt location", "", PathVariable.PathAccept))
vars.Add(PathVariable("docbook_xml", "DocBook XML", None, PathVariable.PathAccept))
vars.Add(PathVariable("docbook_xsl", "DocBook XSL", None, PathVariable.PathAccept))
vars.Add(BoolVariable("build_examples", "Build example programs", "yes"))
vars.Add(BoolVariable("enable_variants", "Build in a separate dir under build/, depending on compile flags", "no"))
vars.Add(BoolVariable("experimental", "Build experimental features", "no"))
+vars.Add(BoolVariable("set_iterator_debug_level", "Set _ITERATOR_DEBUG_LEVEL=0", "yes"))
################################################################################
# Set up default build & configure environment
################################################################################
env = Environment(CPPPATH = ["#"], ENV = {
'PATH' : os.environ['PATH'],
'LD_LIBRARY_PATH' : os.environ.get("LD_LIBRARY_PATH", ""),
}, variables = vars)
@@ -128,19 +129,20 @@ if env["optimize"] :
env.Append(CCFLAGS = ["-O2"])
if env["target"] == "xcode" and os.environ["CONFIGURATION"] == "Release" :
env.Append(CCFLAGS = ["-Os"])
if env["debug"] :
if env["PLATFORM"] == "win32" :
env.Append(CCFLAGS = ["/Zi", "/MDd"])
env.Append(LINKFLAGS = ["/DEBUG"])
- env.Append(CPPDEFINES = ["_ITERATOR_DEBUG_LEVEL=0"])
+ if env["set_iterator_debug_level"] :
+ env.Append(CPPDEFINES = ["_ITERATOR_DEBUG_LEVEL=0"])
else :
env.Append(CCFLAGS = ["-g"])
elif env["PLATFORM"] == "win32" :
env.Append(CCFLAGS = ["/MD"])
if env.get("universal", 0) :
assert(env["PLATFORM"] == "darwin")
env.Append(CCFLAGS = [
"-isysroot", "/Developer/SDKs/MacOSX10.4u.sdk",
diff --git a/Swift/SConscript b/Swift/SConscript
index b66058b..49aa985 100644
--- a/Swift/SConscript
+++ b/Swift/SConscript
@@ -5,12 +5,12 @@ Import("env")
SConscript("Controllers/SConscript")
if env["SCONS_STAGE"] == "build" :
if not GetOption("help") and not env.get("HAVE_OPENSSL", 0) and not env.get("HAVE_SCHANNEL", 0) :
print "Error: Swift requires OpenSSL support, and OpenSSL was not found."
if "Swift" in env["PROJECTS"] :
env["PROJECTS"].remove("Swift")
elif not GetOption("help") and not env.get("HAVE_QT", 0) :
print "Error: Swift requires Qt. Not building Swift."
- env["PROJECTS"].remove("Swift")
+# env["PROJECTS"].remove("Swift")
elif env["target"] == "native":
SConscript("QtUI/SConscript")
diff --git a/Swiften/Client/ClientError.h b/Swiften/Client/ClientError.h
index baf1b0a..2f2d2af 100644
--- a/Swiften/Client/ClientError.h
+++ b/Swiften/Client/ClientError.h
@@ -34,18 +34,20 @@ namespace Swift {
CertificateNotYetValidError,
CertificateSelfSignedError,
CertificateRejectedError,
CertificateUntrustedError,
InvalidCertificatePurposeError,
CertificatePathLengthExceededError,
InvalidCertificateSignatureError,
InvalidCAError,
InvalidServerIdentityError,
+ RevokedError,
+ RevocationCheckFailedError
};
ClientError(Type type = UnknownError) : type_(type) {}
Type getType() const { return type_; }
private:
Type type_;
};
diff --git a/Swiften/Client/CoreClient.cpp b/Swiften/Client/CoreClient.cpp
index f7e3b21..14481c6 100644
--- a/Swiften/Client/CoreClient.cpp
+++ b/Swiften/Client/CoreClient.cpp
@@ -265,18 +265,24 @@ void CoreClient::handleSessionFinished(boost::shared_ptr<Error> error) {
case CertificateVerificationError::InvalidSignature:
clientError = ClientError(ClientError::InvalidCertificateSignatureError);
break;
case CertificateVerificationError::InvalidCA:
clientError = ClientError(ClientError::InvalidCAError);
break;
case CertificateVerificationError::InvalidServerIdentity:
clientError = ClientError(ClientError::InvalidServerIdentityError);
break;
+ case CertificateVerificationError::Revoked:
+ clientError = ClientError(ClientError::RevokedError);
+ break;
+ case CertificateVerificationError::RevocationCheckFailed:
+ clientError = ClientError(ClientError::RevocationCheckFailedError);
+ break;
}
}
actualError = boost::optional<ClientError>(clientError);
}
onDisconnected(actualError);
}
void CoreClient::handleNeedCredentials() {
assert(session_);
diff --git a/Swiften/TLS/CertificateVerificationError.h b/Swiften/TLS/CertificateVerificationError.h
index 22e6eaf..b17f5df 100644
--- a/Swiften/TLS/CertificateVerificationError.h
+++ b/Swiften/TLS/CertificateVerificationError.h
@@ -20,18 +20,20 @@ namespace Swift {
NotYetValid,
SelfSigned,
Rejected,
Untrusted,
InvalidPurpose,
PathLengthExceeded,
InvalidSignature,
InvalidCA,
InvalidServerIdentity,
+ Revoked,
+ RevocationCheckFailed
};
CertificateVerificationError(Type type = UnknownError) : type(type) {}
Type getType() const {
return type;
}
private:
diff --git a/Swiften/TLS/Schannel/SchannelCertificate.h b/Swiften/TLS/Schannel/SchannelCertificate.h
index f531cff..395d3ec 100644
--- a/Swiften/TLS/Schannel/SchannelCertificate.h
+++ b/Swiften/TLS/Schannel/SchannelCertificate.h
@@ -42,20 +42,25 @@ namespace Swift
{
return m_dnsNames;
}
std::vector<std::string> getXMPPAddresses() const
{
return m_xmppAddresses;
}
- ByteArray toDER() const;
+ ScopedCertContext getCertContext() const
+ {
+ return m_cert;
+ }
+ ByteArray toDER() const;
+
private:
void parse();
std::string wstrToStr(const std::wstring& wstr);
void addSRVName(const std::string& name)
{
m_srvNames.push_back(name);
}
diff --git a/Swiften/TLS/Schannel/SchannelContext.cpp b/Swiften/TLS/Schannel/SchannelContext.cpp
index b2fea65..9be1ded 100644
--- a/Swiften/TLS/Schannel/SchannelContext.cpp
+++ b/Swiften/TLS/Schannel/SchannelContext.cpp
@@ -1,27 +1,27 @@
/*
* Copyright (c) 2011 Soren Dreijer
* Licensed under the simplified BSD license.
* See Documentation/Licenses/BSD-simplified.txt for more information.
*/
-#include <Swiften/TLS/Schannel/SchannelContext.h>
-#include <Swiften/TLS/Schannel/SchannelCertificate.h>
+#include "Swiften/TLS/Schannel/SchannelContext.h"
+#include "Swiften/TLS/Schannel/SchannelCertificate.h"
#include <Swiften/TLS/CAPICertificate.h>
+#include <WinHTTP.h> // For SECURITY_FLAG_IGNORE_CERT_CN_INVALID
namespace Swift {
//------------------------------------------------------------------------
SchannelContext::SchannelContext()
: m_state(Start)
, m_secContext(0)
-, m_verificationError(CertificateVerificationError::UnknownError)
, m_my_cert_store(NULL)
, m_cert_store_name("MY")
, m_cert_name()
{
m_ctxtFlags = ISC_REQ_ALLOCATE_MEMORY |
ISC_REQ_CONFIDENTIALITY |
ISC_REQ_EXTENDED_ERROR |
ISC_REQ_INTEGRITY |
ISC_REQ_REPLAY_DETECT |
@@ -44,19 +44,19 @@ SchannelContext::~SchannelContext()
void SchannelContext::determineStreamSizes()
{
QueryContextAttributes(m_ctxtHandle, SECPKG_ATTR_STREAM_SIZES, &m_streamSizes);
}
//------------------------------------------------------------------------
void SchannelContext::connect()
{
- PCCERT_CONTEXT pCertContext = NULL;
+ ScopedCertContext pCertContext;
m_state = Connecting;
// If a user name is specified, then attempt to find a client
// certificate. Otherwise, just create a NULL credential.
if (!m_cert_name.empty())
{
if (m_my_cert_store == NULL)
{
@@ -80,24 +80,24 @@ void SchannelContext::connect()
// We use an empty list for client certificates
PCCERT_CONTEXT clientCerts[1] = {0};
SCHANNEL_CRED sc = {0};
sc.dwVersion = SCHANNEL_CRED_VERSION;
/////SSL3?
sc.grbitEnabledProtocols = SP_PROT_SSL3_CLIENT | SP_PROT_TLS1_CLIENT | SP_PROT_TLS1_1_CLIENT | SP_PROT_TLS1_2_CLIENT;
- sc.dwFlags = SCH_CRED_AUTO_CRED_VALIDATION | SCH_CRED_REVOCATION_CHECK_CHAIN;
+ sc.dwFlags = SCH_CRED_MANUAL_CRED_VALIDATION;
if (pCertContext)
{
sc.cCreds = 1;
- sc.paCred = &pCertContext;
+ sc.paCred = pCertContext.GetPointer();
sc.dwFlags |= SCH_CRED_NO_DEFAULT_CREDS;
}
else
{
sc.cCreds = 0; // Let Crypto API find the appropriate certificate for us
sc.paCred = clientCerts;
sc.dwFlags |= SCH_CRED_USE_DEFAULT_CREDS;
}
@@ -108,22 +108,19 @@ void SchannelContext::connect()
NULL,
UNISP_NAME,
SECPKG_CRED_OUTBOUND,
NULL,
&sc,
NULL,
NULL,
m_credHandle.Reset(),
NULL);
-
- // cleanup: Free the certificate context. Schannel has already made its own copy.
- if (pCertContext) CertFreeCertificateContext(pCertContext);
-
+
if (status != SEC_E_OK)
{
// We failed to obtain the credentials handle
indicateError();
return;
}
SecBuffer outBuffers[2];
@@ -158,36 +155,109 @@ void SchannelContext::connect()
0,
m_ctxtHandle.Reset(),
&outBufferDesc,
&m_secContext,
NULL);
if (status != SEC_E_OK && status != SEC_I_CONTINUE_NEEDED)
{
// We failed to initialize the security context
+ handleCertError(status);
indicateError();
return;
}
// Start the handshake
sendDataOnNetwork(outBuffers[0].pvBuffer, outBuffers[0].cbBuffer);
if (status == SEC_E_OK)
{
+ status = validateServerCertificate();
+ if (status != SEC_E_OK)
+ handleCertError(status);
+
m_state = Connected;
determineStreamSizes();
onConnected();
}
}
//------------------------------------------------------------------------
+SECURITY_STATUS SchannelContext::validateServerCertificate()
+{
+ SchannelCertificate::ref pServerCert = boost::dynamic_pointer_cast<SchannelCertificate>( getPeerCertificate() );
+ if (!pServerCert)
+ return SEC_E_WRONG_PRINCIPAL;
+
+ const LPSTR usage[] =
+ {
+ szOID_PKIX_KP_SERVER_AUTH,
+ szOID_SERVER_GATED_CRYPTO,
+ szOID_SGC_NETSCAPE
+ };
+
+ CERT_CHAIN_PARA chainParams = {0};
+ chainParams.cbSize = sizeof(chainParams);
+ chainParams.RequestedUsage.dwType = USAGE_MATCH_TYPE_OR;
+ chainParams.RequestedUsage.Usage.cUsageIdentifier = ARRAYSIZE(usage);
+ chainParams.RequestedUsage.Usage.rgpszUsageIdentifier = const_cast<LPSTR*>(usage);
+
+ DWORD chainFlags = CERT_CHAIN_CACHE_END_CERT | CERT_CHAIN_REVOCATION_CHECK_CHAIN_EXCLUDE_ROOT;
+
+ ScopedCertChainContext pChainContext;
+
+ BOOL success = CertGetCertificateChain(
+ NULL, // Use the chain engine for the current user (assumes a user is logged in)
+ pServerCert->getCertContext(),
+ NULL,
+ NULL,
+ &chainParams,
+ chainFlags,
+ NULL,
+ pChainContext.Reset());
+
+ if (!success)
+ return GetLastError();
+
+ SSL_EXTRA_CERT_CHAIN_POLICY_PARA sslChainPolicy = {0};
+ sslChainPolicy.cbSize = sizeof(sslChainPolicy);
+ sslChainPolicy.dwAuthType = AUTHTYPE_SERVER;
+ sslChainPolicy.fdwChecks = SECURITY_FLAG_IGNORE_CERT_CN_INVALID; // Swiften checks the server name for us. Is this the correct way to disable server name checking?
+ sslChainPolicy.pwszServerName = NULL;
+
+ CERT_CHAIN_POLICY_PARA certChainPolicy = {0};
+ certChainPolicy.cbSize = sizeof(certChainPolicy);
+ certChainPolicy.dwFlags = CERT_CHAIN_POLICY_IGNORE_INVALID_NAME_FLAG; // Swiften checks the server name for us. Is this the correct way to disable server name checking?
+ certChainPolicy.pvExtraPolicyPara = &sslChainPolicy;
+
+ CERT_CHAIN_POLICY_STATUS certChainPolicyStatus = {0};
+ certChainPolicyStatus.cbSize = sizeof(certChainPolicyStatus);
+
+ // Verify the chain
+ if (!CertVerifyCertificateChainPolicy(
+ CERT_CHAIN_POLICY_SSL,
+ pChainContext,
+ &certChainPolicy,
+ &certChainPolicyStatus))
+ {
+ return GetLastError();
+ }
+
+ if (certChainPolicyStatus.dwError != S_OK)
+ return certChainPolicyStatus.dwError;
+
+ return S_OK;
+}
+
+//------------------------------------------------------------------------
+
void SchannelContext::appendNewData(const SafeByteArray& data)
{
size_t originalSize = m_receivedData.size();
m_receivedData.resize( originalSize + data.size() );
memcpy( &m_receivedData[0] + originalSize, &data[0], data.size() );
}
//------------------------------------------------------------------------
@@ -264,41 +334,87 @@ void SchannelContext::continueHandshake(const SafeByteArray& data)
if (pExtraBuffer->BufferType == SECBUFFER_EXTRA)
m_receivedData.erase(m_receivedData.begin(), m_receivedData.end() - pExtraBuffer->cbBuffer);
else
m_receivedData.clear();
break;
}
else if (status == SEC_E_OK)
{
+ status = validateServerCertificate();
+ if (status != SEC_E_OK)
+ handleCertError(status);
+
SecBuffer* pExtraBuffer = &inBuffers[1];
if (pExtraBuffer && pExtraBuffer->cbBuffer > 0)
m_receivedData.erase(m_receivedData.begin(), m_receivedData.end() - pExtraBuffer->cbBuffer);
else
m_receivedData.clear();
m_state = Connected;
determineStreamSizes();
onConnected();
}
else
{
// We failed to initialize the security context
+ handleCertError(status);
indicateError();
return;
}
}
}
//------------------------------------------------------------------------
+void SchannelContext::handleCertError(SECURITY_STATUS status)
+{
+ if (status == SEC_E_UNTRUSTED_ROOT ||
+ status == CERT_E_UNTRUSTEDROOT ||
+ status == CRYPT_E_ISSUER_SERIALNUMBER ||
+ status == CRYPT_E_SIGNER_NOT_FOUND ||
+ status == CRYPT_E_NO_TRUSTED_SIGNER)
+ {
+ m_verificationError = CertificateVerificationError::Untrusted;
+ }
+ else if (status == SEC_E_CERT_EXPIRED ||
+ status == CERT_E_EXPIRED)
+ {
+ m_verificationError = CertificateVerificationError::Expired;
+ }
+ else if (status == CRYPT_E_SELF_SIGNED)
+ {
+ m_verificationError = CertificateVerificationError::SelfSigned;
+ }
+ else if (status == CRYPT_E_HASH_VALUE ||
+ status == TRUST_E_CERT_SIGNATURE)
+ {
+ m_verificationError = CertificateVerificationError::InvalidSignature;
+ }
+ else if (status == CRYPT_E_REVOKED)
+ {
+ m_verificationError = CertificateVerificationError::Revoked;
+ }
+ else if (status == CRYPT_E_NO_REVOCATION_CHECK ||
+ status == CRYPT_E_REVOCATION_OFFLINE)
+ {
+ m_verificationError = CertificateVerificationError::RevocationCheckFailed;
+ }
+ else
+ {
+ m_verificationError = CertificateVerificationError::UnknownError;
+ }
+}
+
+//------------------------------------------------------------------------
+
void SchannelContext::sendDataOnNetwork(const void* pData, size_t dataSize)
{
if (dataSize > 0 && pData)
{
SafeByteArray byteArray(dataSize);
memcpy(&byteArray[0], pData, dataSize);
onDataForNetwork(byteArray);
}
@@ -443,18 +559,21 @@ void SchannelContext::decryptAndProcessData(const SafeByteArray& data)
m_receivedData.erase(m_receivedData.begin(), m_receivedData.begin() + inData);
}
}
}
//------------------------------------------------------------------------
void SchannelContext::encryptAndSendData(const SafeByteArray& data)
{
+ if (m_streamSizes.cbMaximumMessage == 0)
+ return;
+
SecBuffer outBuffers[4] = {0};
// Calculate the largest required size of the send buffer
size_t messageBufferSize = (data.size() > m_streamSizes.cbMaximumMessage)
? m_streamSizes.cbMaximumMessage
: data.size();
// Allocate a packet for the encrypted data
SafeByteArray sendBuffer;
@@ -538,20 +657,20 @@ Certificate::ref SchannelContext::getPeerCertificate() const
return pCertificate;
}
//------------------------------------------------------------------------
CertificateVerificationError::ref SchannelContext::getPeerCertificateVerificationError() const
{
boost::shared_ptr<CertificateVerificationError> pCertError;
- if (m_state == Error)
- pCertError.reset( new CertificateVerificationError(m_verificationError) );
+ if (m_verificationError)
+ pCertError.reset( new CertificateVerificationError(*m_verificationError) );
return pCertError;
}
//------------------------------------------------------------------------
ByteArray SchannelContext::getFinishMessage() const
{
// TODO: Implement
diff --git a/Swiften/TLS/Schannel/SchannelContext.h b/Swiften/TLS/Schannel/SchannelContext.h
index 7726c41..70b0694 100644
--- a/Swiften/TLS/Schannel/SchannelContext.h
+++ b/Swiften/TLS/Schannel/SchannelContext.h
@@ -45,39 +45,41 @@ namespace Swift
virtual Certificate::ref getPeerCertificate() const;
virtual CertificateVerificationError::ref getPeerCertificateVerificationError() const;
virtual ByteArray getFinishMessage() const;
private:
void determineStreamSizes();
void continueHandshake(const SafeByteArray& data);
void indicateError();
+ void handleCertError(SECURITY_STATUS status) ;
void sendDataOnNetwork(const void* pData, size_t dataSize);
void forwardDataToApplication(const void* pData, size_t dataSize);
void decryptAndProcessData(const SafeByteArray& data);
void encryptAndSendData(const SafeByteArray& data);
void appendNewData(const SafeByteArray& data);
+ SECURITY_STATUS validateServerCertificate();
private:
enum SchannelState
{
Start,
Connecting,
Connected,
Error
};
SchannelState m_state;
- CertificateVerificationError m_verificationError;
+ boost::optional<CertificateVerificationError> m_verificationError;
ULONG m_secContext;
ScopedCredHandle m_credHandle;
ScopedCtxtHandle m_ctxtHandle;
DWORD m_ctxtFlags;
SecPkgContext_StreamSizes m_streamSizes;
std::vector<char> m_receivedData;
diff --git a/Swiften/TLS/Schannel/SchannelUtil.h b/Swiften/TLS/Schannel/SchannelUtil.h
index 0a54f16..4f73aac 100644
--- a/Swiften/TLS/Schannel/SchannelUtil.h
+++ b/Swiften/TLS/Schannel/SchannelUtil.h
@@ -240,19 +240,19 @@ namespace Swift
{
}
explicit ScopedCertContext(PCCERT_CONTEXT pCert)
: m_pHandle( new HandleContext(pCert) )
{
}
// Copy constructor
- explicit ScopedCertContext(const ScopedCertContext& rhs)
+ ScopedCertContext(const ScopedCertContext& rhs)
{
m_pHandle = rhs.m_pHandle;
}
~ScopedCertContext()
{
m_pHandle.reset();
}
@@ -261,34 +261,165 @@ namespace Swift
FreeContext();
return &m_pHandle->m_pCertCtxt;
}
operator PCCERT_CONTEXT() const
{
return m_pHandle->m_pCertCtxt;
}
+ PCCERT_CONTEXT* GetPointer() const
+ {
+ return &m_pHandle->m_pCertCtxt;
+ }
+
PCCERT_CONTEXT operator->() const
{
return m_pHandle->m_pCertCtxt;
}
ScopedCertContext& operator=(const ScopedCertContext& sh)
{
// Only update the internal handle if it's different
if (&m_pHandle->m_pCertCtxt != &sh.m_pHandle->m_pCertCtxt)
{
m_pHandle = sh.m_pHandle;
}
return *this;
}
+ ScopedCertContext& operator=(PCCERT_CONTEXT pCertCtxt)
+ {
+ // Only update the internal handle if it's different
+ if (m_pHandle && m_pHandle->m_pCertCtxt != pCertCtxt)
+ m_pHandle.reset( new HandleContext(pCertCtxt) );
+
+ return *this;
+ }
+
+ void FreeContext()
+ {
+ m_pHandle.reset( new HandleContext );
+ }
+
+ private:
+ boost::shared_ptr<HandleContext> m_pHandle;
+ };
+
+ //------------------------------------------------------------------------
+
+ //
+ // Convenience wrapper around the Schannel HCERTSTORE.
+ //
+ class ScopedCertStore : boost::noncopyable
+ {
+ public:
+ ScopedCertStore(HCERTSTORE hCertStore)
+ : m_hCertStore(hCertStore)
+ {
+ }
+
+ ~ScopedCertStore()
+ {
+ // Forcefully free all memory related to the store, i.e. we assume all CertContext's that have been opened via this
+ // cert store have been closed at this point.
+ if (m_hCertStore)
+ CertCloseStore(m_hCertStore, CERT_CLOSE_STORE_FORCE_FLAG);
+ }
+
+ operator HCERTSTORE() const
+ {
+ return m_hCertStore;
+ }
+
+ private:
+ HCERTSTORE m_hCertStore;
+ };
+
+ //------------------------------------------------------------------------
+
+ //
+ // Convenience wrapper around the Schannel CERT_CHAIN_CONTEXT.
+ //
+ class ScopedCertChainContext
+ {
+ private:
+ struct HandleContext
+ {
+ HandleContext()
+ : m_pCertChainCtxt(NULL)
+ {
+ }
+
+ HandleContext(PCCERT_CHAIN_CONTEXT pCert)
+ : m_pCertChainCtxt(pCert)
+ {
+ }
+
+ ~HandleContext()
+ {
+ if (m_pCertChainCtxt)
+ CertFreeCertificateChain(m_pCertChainCtxt);
+ }
+
+ PCCERT_CHAIN_CONTEXT m_pCertChainCtxt;
+ };
+
+ public:
+ ScopedCertChainContext()
+ : m_pHandle( new HandleContext )
+ {
+ }
+
+ explicit ScopedCertChainContext(PCCERT_CHAIN_CONTEXT pCert)
+ : m_pHandle( new HandleContext(pCert) )
+ {
+ }
+
+ // Copy constructor
+ ScopedCertChainContext(const ScopedCertChainContext& rhs)
+ {
+ m_pHandle = rhs.m_pHandle;
+ }
+
+ ~ScopedCertChainContext()
+ {
+ m_pHandle.reset();
+ }
+
+ PCCERT_CHAIN_CONTEXT* Reset()
+ {
+ FreeContext();
+ return &m_pHandle->m_pCertChainCtxt;
+ }
+
+ operator PCCERT_CHAIN_CONTEXT() const
+ {
+ return m_pHandle->m_pCertChainCtxt;
+ }
+
+ PCCERT_CHAIN_CONTEXT operator->() const
+ {
+ return m_pHandle->m_pCertChainCtxt;
+ }
+
+ ScopedCertChainContext& operator=(const ScopedCertChainContext& sh)
+ {
+ // Only update the internal handle if it's different
+ if (&m_pHandle->m_pCertChainCtxt != &sh.m_pHandle->m_pCertChainCtxt)
+ {
+ m_pHandle = sh.m_pHandle;
+ }
+
+ return *this;
+ }
+
void FreeContext()
{
m_pHandle.reset( new HandleContext );
}
private:
boost::shared_ptr<HandleContext> m_pHandle;
- };
+ };
}