You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
2300 lines
62 KiB
2300 lines
62 KiB
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
|
|
Microsoft Windows, Copyright (C) Microsoft Corporation, 2000
|
|
|
|
File: Chain.cpp
|
|
|
|
Content: Implementation of CChain.
|
|
|
|
History: 11-15-99 dsie created
|
|
|
|
------------------------------------------------------------------------------*/
|
|
|
|
#include "StdAfx.h"
|
|
#include "CAPICOM.h"
|
|
#include "Chain.h"
|
|
|
|
#include "Convert.h"
|
|
#include "Common.h"
|
|
#include "OIDs.h"
|
|
#include "Certificates.h"
|
|
#include "CertificateStatus.h"
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Exported functions.
|
|
//
|
|
|
|
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
|
|
Function : CreateChainObject
|
|
|
|
Synopsis : Create and initialize an IChain object by building the chain
|
|
of a specified certificate and policy.
|
|
|
|
Parameter: PCCERT_CONTEXT pCertContext - Pointer to CERT_CONTEXT.
|
|
|
|
ICertificateStatus * pIStatus - Pointer to ICertificateStatus
|
|
object.
|
|
|
|
HCERTSTORE hAdditionalStore - Additional store handle.
|
|
|
|
VARIANT_BOOL * pVal - Pointer to VARIANT_BOOL to receive chain
|
|
overall validity result.
|
|
|
|
IChain ** ppIChain - Pointer to pointer to IChain object.
|
|
|
|
Remark :
|
|
|
|
------------------------------------------------------------------------------*/
|
|
|
|
HRESULT CreateChainObject (PCCERT_CONTEXT pCertContext,
|
|
ICertificateStatus * pIStatus,
|
|
HCERTSTORE hAdditionalStore,
|
|
VARIANT_BOOL * pbResult,
|
|
IChain ** ppIChain)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
CComObject<CChain> * pCChain = NULL;
|
|
|
|
DebugTrace("Entering CreateChainObject().\n");
|
|
|
|
//
|
|
// Sanity check.
|
|
//
|
|
ATLASSERT(pCertContext);
|
|
ATLASSERT(pIStatus);
|
|
ATLASSERT(pbResult);
|
|
ATLASSERT(ppIChain);
|
|
|
|
try
|
|
{
|
|
//
|
|
// Create the object. Note that the ref count will still be 0
|
|
// after the object is created.
|
|
//
|
|
if (FAILED(hr = CComObject<CChain>::CreateInstance(&pCChain)))
|
|
{
|
|
DebugTrace("Error [%#x]: CComObject<CChain>::CreateInstance() failed.\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
|
|
//
|
|
// Initialize object.
|
|
//
|
|
if (FAILED(hr = pCChain->Init(pCertContext,
|
|
pIStatus,
|
|
hAdditionalStore,
|
|
pbResult)))
|
|
{
|
|
DebugTrace("Error [%#x]: pCChain->Init() failed.\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
|
|
//
|
|
// Return IChain pointer to caller.
|
|
//
|
|
if (FAILED(hr = pCChain->QueryInterface(ppIChain)))
|
|
{
|
|
DebugTrace("Error [%#x]: pCChain->QueryInterface() failed.\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
}
|
|
|
|
catch(...)
|
|
{
|
|
hr = E_POINTER;
|
|
|
|
DebugTrace("Exception: invalid parameter.\n");
|
|
goto ErrorExit;
|
|
}
|
|
|
|
CommonExit:
|
|
|
|
DebugTrace("Leaving CreateChainObject().\n");
|
|
|
|
return hr;
|
|
|
|
ErrorExit:
|
|
//
|
|
// Sanity check.
|
|
//
|
|
ATLASSERT(FAILED(hr));
|
|
|
|
//
|
|
// Free resource.
|
|
//
|
|
if (pCChain)
|
|
{
|
|
delete pCChain;
|
|
}
|
|
|
|
goto CommonExit;
|
|
}
|
|
|
|
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
|
|
Function : CreateChainObject
|
|
|
|
Synopsis : Create and initialize an IChain object by building the chain
|
|
of a specified certificate and policy.
|
|
|
|
Parameter: ICertificate * pICertificate - Poitner to ICertificate.
|
|
|
|
HCERTSTORE hAdditionalStore - Additional store handle.
|
|
|
|
VARIANT_BOOL * pVal - Pointer to VARIANT_BOOL to receive chain
|
|
overall validity result.
|
|
|
|
IChain ** ppIChain - Pointer to pointer to IChain object.
|
|
|
|
Remark :
|
|
|
|
------------------------------------------------------------------------------*/
|
|
|
|
HRESULT CreateChainObject (ICertificate * pICertificate,
|
|
HCERTSTORE hAdditionalStore,
|
|
VARIANT_BOOL * pbResult,
|
|
IChain ** ppIChain)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
PCCERT_CONTEXT pCertContext = NULL;
|
|
CComPtr<ICertificateStatus> pIStatus = NULL;
|
|
|
|
DebugTrace("Entering CreateChainObject().\n");
|
|
|
|
//
|
|
// Sanity check.
|
|
//
|
|
ATLASSERT(pICertificate);
|
|
ATLASSERT(pbResult);
|
|
ATLASSERT(ppIChain);
|
|
|
|
try
|
|
{
|
|
|
|
//
|
|
// Get CERT_CONTEXT.
|
|
//
|
|
if (FAILED(hr = ::GetCertContext(pICertificate, &pCertContext)))
|
|
{
|
|
DebugTrace("Error [%#x]: GetCertContext() failed.\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
|
|
//
|
|
// Get status check object.
|
|
//
|
|
if (FAILED(hr = pICertificate->IsValid(&pIStatus)))
|
|
{
|
|
DebugTrace("Error [%#x]: pICertificate->IsValid() failed.\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
|
|
//
|
|
// Create the object.
|
|
//
|
|
if (FAILED(hr = ::CreateChainObject(pCertContext,
|
|
pIStatus,
|
|
hAdditionalStore,
|
|
pbResult,
|
|
ppIChain)))
|
|
{
|
|
DebugTrace("Error [%#x]: CreateChainObject() failed.\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
}
|
|
|
|
catch(...)
|
|
{
|
|
hr = E_POINTER;
|
|
|
|
DebugTrace("Exception: invalid parameter.\n");
|
|
goto ErrorExit;
|
|
}
|
|
|
|
CommonExit:
|
|
//
|
|
// Free resource.
|
|
//
|
|
if (pCertContext)
|
|
{
|
|
::CertFreeCertificateContext(pCertContext);
|
|
}
|
|
|
|
DebugTrace("Leaving CreateChainObject().\n");
|
|
|
|
return hr;
|
|
|
|
ErrorExit:
|
|
//
|
|
// Sanity check.
|
|
//
|
|
ATLASSERT(FAILED(hr));
|
|
|
|
goto CommonExit;
|
|
}
|
|
|
|
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
|
|
Function : CreateChainObject
|
|
|
|
Synopsis : Create and initialize an IChain object from a built chain.
|
|
|
|
Parameter: PCCERT_CHAIN_CONTEXT pChainContext - Chain context.
|
|
|
|
IChain ** ppIChain - Pointer to pointer to IChain object.
|
|
|
|
Remark :
|
|
|
|
------------------------------------------------------------------------------*/
|
|
|
|
HRESULT CreateChainObject (PCCERT_CHAIN_CONTEXT pChainContext,
|
|
IChain ** ppIChain)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
CComObject<CChain> * pCChain = NULL;
|
|
|
|
DebugTrace("Entering CreateChainObject().\n");
|
|
|
|
//
|
|
// Sanity check.
|
|
//
|
|
ATLASSERT(pChainContext);
|
|
ATLASSERT(ppIChain);
|
|
|
|
try
|
|
{
|
|
//
|
|
// Create the object. Note that the ref count will still be 0
|
|
// after the object is created.
|
|
//
|
|
if (FAILED(hr = CComObject<CChain>::CreateInstance(&pCChain)))
|
|
{
|
|
DebugTrace("Error [%#x]: CComObject<CChain>::CreateInstance() failed.\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
|
|
//
|
|
// Initialize object.
|
|
//
|
|
if (FAILED(hr = pCChain->PutContext(pChainContext)))
|
|
{
|
|
DebugTrace("Error [%#x]: pCChain->Init() failed.\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
|
|
//
|
|
// Return IChain pointer to caller.
|
|
//
|
|
if (FAILED(hr = pCChain->QueryInterface(ppIChain)))
|
|
{
|
|
DebugTrace("Error [%#x]: pCChain->QueryInterface() failed.\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
}
|
|
|
|
catch(...)
|
|
{
|
|
hr = E_POINTER;
|
|
|
|
DebugTrace("Exception: invalid parameter.\n");
|
|
goto ErrorExit;
|
|
}
|
|
|
|
CommonExit:
|
|
|
|
DebugTrace("Leaving CreateChainObject().\n");
|
|
|
|
return hr;
|
|
|
|
ErrorExit:
|
|
//
|
|
// Sanity check.
|
|
//
|
|
ATLASSERT(FAILED(hr));
|
|
|
|
//
|
|
// Free resource.
|
|
//
|
|
if (pCChain)
|
|
{
|
|
delete pCChain;
|
|
}
|
|
|
|
goto CommonExit;
|
|
}
|
|
|
|
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
|
|
Function : GetChainContext
|
|
|
|
Synopsis : Return an array of PCCERT_CONTEXT from the chain.
|
|
|
|
Parameter: IChain * pIChain - Pointer to IChain.
|
|
|
|
CRYPT_DATA_BLOB * pChainBlob - Pointer to blob to recevie the
|
|
size and array of PCERT_CONTEXT
|
|
for the chain.
|
|
Remark :
|
|
|
|
------------------------------------------------------------------------------*/
|
|
|
|
STDMETHODIMP GetChainContext (IChain * pIChain,
|
|
CRYPT_DATA_BLOB * pChainBlob)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
DWORD dwCerts = 0;
|
|
PCCERT_CHAIN_CONTEXT pChainContext = NULL;
|
|
PCERT_SIMPLE_CHAIN pSimpleChain = NULL;
|
|
PCCERT_CONTEXT * rgCertContext = NULL;
|
|
CComPtr<IChainContext> pIChainContext = NULL;
|
|
|
|
DebugTrace("Entering GetChainContext().\n");
|
|
|
|
//
|
|
// Sanity check.
|
|
//
|
|
ATLASSERT(pIChain);
|
|
ATLASSERT(pChainBlob);
|
|
|
|
//
|
|
// Get ICCertificate interface pointer.
|
|
//
|
|
if (FAILED(hr = pIChain->QueryInterface(IID_IChainContext, (void **) &pIChainContext)))
|
|
{
|
|
DebugTrace("Error [%#x]: pIChainContext->QueryInterface() failed.\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
|
|
//
|
|
// Get the CHAIN_CONTEXT.
|
|
//
|
|
if (FAILED(hr = pIChainContext->get_ChainContext((long *) &pChainContext)))
|
|
{
|
|
DebugTrace("Error [%#x]: pIChainContext->get_ChainContext() failed.\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
|
|
//
|
|
// Process only the simple chain.
|
|
//
|
|
pSimpleChain = *pChainContext->rgpChain;
|
|
|
|
//
|
|
// Should have at least one cert in the chain.
|
|
//
|
|
ATLASSERT(pSimpleChain->cElement);
|
|
|
|
//
|
|
// Allocate memory for array of PCERT_CONTEXT to return.
|
|
//
|
|
if (!(rgCertContext = (PCCERT_CONTEXT *) ::CoTaskMemAlloc(pSimpleChain->cElement * sizeof(PCCERT_CONTEXT))))
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
|
|
DebugTrace("Error: out of memory.\n");
|
|
goto ErrorExit;
|
|
}
|
|
|
|
//
|
|
// Now loop through all certs in the chain.
|
|
//
|
|
for (dwCerts = 0; dwCerts < pSimpleChain->cElement; dwCerts++)
|
|
{
|
|
//
|
|
// Add the cert.
|
|
//
|
|
if (!(rgCertContext[dwCerts] = ::CertDuplicateCertificateContext(pSimpleChain->rgpElement[dwCerts]->pCertContext)))
|
|
{
|
|
hr = HRESULT_FROM_WIN32(::GetLastError());
|
|
|
|
DebugTrace("Error [%#x]: CertDuplicateCertificateContext() failed.\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Return PCCERT_CONTEXT array.
|
|
//
|
|
pChainBlob->cbData = dwCerts;
|
|
pChainBlob->pbData = (BYTE *) rgCertContext;
|
|
|
|
CommonExit:
|
|
//
|
|
// Free resource.
|
|
//
|
|
if (pChainContext)
|
|
{
|
|
::CertFreeCertificateChain(pChainContext);
|
|
}
|
|
|
|
DebugTrace("Leaving GetChainContext().\n");
|
|
|
|
return hr;
|
|
|
|
ErrorExit:
|
|
//
|
|
// Sanity check.
|
|
//
|
|
ATLASSERT(FAILED(hr));
|
|
|
|
//
|
|
// Free resource.
|
|
//
|
|
if (rgCertContext)
|
|
{
|
|
while (dwCerts--)
|
|
{
|
|
if (rgCertContext[dwCerts])
|
|
{
|
|
::CertFreeCertificateContext(rgCertContext[dwCerts]);
|
|
}
|
|
}
|
|
|
|
::CoTaskMemFree((LPVOID) rgCertContext);
|
|
}
|
|
|
|
goto CommonExit;
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// CChain
|
|
//
|
|
|
|
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
|
|
Function : CChain::get_Certificates
|
|
|
|
Synopsis : Return the certificate chain in the form of ICertificates
|
|
collection object.
|
|
|
|
Parameter: ICertificates ** pVal - Pointer to pointer to ICertificates
|
|
collection object.
|
|
|
|
Remark : This collection is ordered with index 1 being the end certificate
|
|
and Certificates.Count() being the root certificate.
|
|
|
|
------------------------------------------------------------------------------*/
|
|
|
|
STDMETHODIMP CChain::get_Certificates (ICertificates ** pVal)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
CComPtr<ICertificates2> pICertificates2 = NULL;
|
|
CAPICOM_CERTIFICATES_SOURCE ccs = {CAPICOM_CERTIFICATES_LOAD_FROM_CHAIN, 0};
|
|
|
|
DebugTrace("Entering CChain::get_Certificates().\n");
|
|
|
|
try
|
|
{
|
|
//
|
|
// Lock access to this object.
|
|
//
|
|
m_Lock.Lock();
|
|
|
|
//
|
|
// Check parameters.
|
|
//
|
|
if (NULL == pVal)
|
|
{
|
|
hr = E_INVALIDARG;
|
|
|
|
DebugTrace("Error [%#x]: Parameter pVal is NULL.\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
|
|
//
|
|
// Make sure chain has been built.
|
|
//
|
|
if (NULL == m_pChainContext)
|
|
{
|
|
hr = CAPICOM_E_CHAIN_NOT_BUILT;
|
|
|
|
DebugTrace("Error [%#x]: chain object was not initialized.\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
|
|
ccs.pChainContext = m_pChainContext;
|
|
|
|
//
|
|
// Create a ICertificates2 object.
|
|
//
|
|
if (FAILED(hr = ::CreateCertificatesObject(ccs, m_dwCurrentSafety, FALSE, &pICertificates2)))
|
|
{
|
|
DebugTrace("Error [%#x]: CreateCertificatesObject() failed.\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
|
|
//
|
|
// Return ICertificates to calller.
|
|
//
|
|
if (FAILED(hr = pICertificates2->QueryInterface(__uuidof(ICertificates), (void **) pVal)))
|
|
{
|
|
DebugTrace("Error [%#x]: pICertificates2->QueryInterface() failed.\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
}
|
|
|
|
catch(...)
|
|
{
|
|
hr = E_POINTER;
|
|
|
|
DebugTrace("Exception: invalid parameter.\n");
|
|
goto ErrorExit;
|
|
}
|
|
|
|
UnlockExit:
|
|
//
|
|
// Unlock access to this object.
|
|
//
|
|
m_Lock.Unlock();
|
|
|
|
DebugTrace("Leaving CChain::get_Certificates().\n");
|
|
|
|
return hr;
|
|
|
|
ErrorExit:
|
|
//
|
|
// Sanity check.
|
|
//
|
|
ATLASSERT(FAILED(hr));
|
|
|
|
ReportError(hr);
|
|
|
|
goto UnlockExit;
|
|
}
|
|
|
|
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
|
|
Function : CChain::get_Status
|
|
|
|
Synopsis : Return validity status for the chain or a specific certificate in
|
|
the chain.
|
|
|
|
Parameter: long Index - 0 to specify chain status, 1 for the end cert
|
|
status, or Certificates.Count() for the root cert
|
|
status.
|
|
|
|
long * pVal - Pointer to a long integer to receive the status,
|
|
which can be ORed with the following flags:
|
|
|
|
//
|
|
// These can be applied to certificates and chains.
|
|
//
|
|
CAPICOM_TRUST_IS_NOT_TIME_VALID = 0x00000001
|
|
CAPICOM_TRUST_IS_NOT_TIME_NESTED = 0x00000002
|
|
CAPICOM_TRUST_IS_REVOKED = 0x00000004
|
|
CAPICOM_TRUST_IS_NOT_SIGNATURE_VALID = 0x00000008
|
|
CAPICOM_TRUST_IS_NOT_VALID_FOR_USAGE = 0x00000010
|
|
CAPICOM_TRUST_IS_UNTRUSTED_ROOT = 0x00000020
|
|
CAPICOM_TRUST_REVOCATION_STATUS_UNKNOWN = 0x00000040
|
|
CAPICOM_TRUST_IS_CYCLIC = 0x00000080
|
|
|
|
CAPICOM_TRUST_INVALID_EXTENSION = 0x00000100
|
|
CAPICOM_TRUST_INVALID_POLICY_CONSTRAINTS = 0x00000200
|
|
CAPICOM_TRUST_INVALID_BASIC_CONSTRAINTS = 0x00000400
|
|
CAPICOM_TRUST_INVALID_NAME_CONSTRAINTS = 0x00000800
|
|
CAPICOM_TRUST_HAS_NOT_SUPPORTED_NAME_CONSTRAINT = 0x00001000
|
|
CAPICOM_TRUST_HAS_NOT_DEFINED_NAME_CONSTRAINT = 0x00002000
|
|
CAPICOM_TRUST_HAS_NOT_PERMITTED_NAME_CONSTRAINT = 0x00004000
|
|
CAPICOM_TRUST_HAS_EXCLUDED_NAME_CONSTRAINT = 0x00008000
|
|
|
|
CAPICOM_TRUST_IS_OFFLINE_REVOCATION = 0x01000000
|
|
CAPICOM_TRUST_NO_ISSUANCE_CHAIN_POLICY = 0x02000000
|
|
|
|
//
|
|
// These can be applied to chains only.
|
|
//
|
|
CAPICOM_TRUST_IS_PARTIAL_CHAIN = 0x00010000
|
|
CAPICOM_TRUST_CTL_IS_NOT_TIME_VALID = 0x00020000
|
|
CAPICOM_TRUST_CTL_IS_NOT_SIGNATURE_VALID = 0x00040000
|
|
CAPICOM_TRUST_CTL_IS_NOT_VALID_FOR_USAGE = 0x00080000
|
|
|
|
Remark :
|
|
|
|
------------------------------------------------------------------------------*/
|
|
|
|
STDMETHODIMP CChain::get_Status (long Index,
|
|
long * pVal)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
DWORD dwIndex = (DWORD) Index;
|
|
|
|
DebugTrace("Entering CChain::get_Status().\n");
|
|
|
|
try
|
|
{
|
|
//
|
|
// Lock access to this object.
|
|
//
|
|
m_Lock.Lock();
|
|
|
|
//
|
|
// Check parameters.
|
|
//
|
|
if (NULL == pVal)
|
|
{
|
|
hr = E_INVALIDARG;
|
|
|
|
DebugTrace("Error [%#x]: Parameter pVal is NULL.\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
|
|
//
|
|
// Make sure chain has been built.
|
|
//
|
|
if (NULL == m_pChainContext)
|
|
{
|
|
hr = CAPICOM_E_CHAIN_NOT_BUILT;
|
|
|
|
DebugTrace("Error [%#x]: chain object was not initialized.\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
|
|
//
|
|
// Return requested status.
|
|
//
|
|
if (0 == dwIndex)
|
|
{
|
|
*pVal = (long) m_dwStatus;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// We only look at the first simple chain.
|
|
//
|
|
PCERT_SIMPLE_CHAIN pChain = m_pChainContext->rgpChain[0];
|
|
|
|
//
|
|
// Make sure index is not out of range.
|
|
//
|
|
if (dwIndex > pChain->cElement)
|
|
{
|
|
hr = E_INVALIDARG;
|
|
|
|
DebugTrace("Error [%#x]: certificate index (%#x) out of range.\n", hr, dwIndex);
|
|
goto ErrorExit;
|
|
}
|
|
|
|
*pVal = (long) pChain->rgpElement[dwIndex - 1]->TrustStatus.dwErrorStatus;
|
|
}
|
|
}
|
|
|
|
catch(...)
|
|
{
|
|
hr = E_POINTER;
|
|
|
|
DebugTrace("Exception: invalid parameter.\n");
|
|
goto ErrorExit;
|
|
}
|
|
|
|
UnlockExit:
|
|
//
|
|
// Unlock access to this object.
|
|
//
|
|
m_Lock.Unlock();
|
|
|
|
DebugTrace("Leaving CChain::get_Status().\n");
|
|
|
|
return hr;
|
|
|
|
ErrorExit:
|
|
//
|
|
// Sanity check.
|
|
//
|
|
ATLASSERT(FAILED(hr));
|
|
|
|
ReportError(hr);
|
|
|
|
goto UnlockExit;
|
|
}
|
|
|
|
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
|
|
Function : CChain::Build
|
|
|
|
Synopsis : Build the chain.
|
|
|
|
Parameter: ICertificate * pICertificate - Pointer to certificate for which
|
|
the chain is to build.
|
|
|
|
VARIANT_BOOL * pVal - Pointer to VARIANT_BOOL to receive chain
|
|
overall validity result.
|
|
Remark :
|
|
|
|
------------------------------------------------------------------------------*/
|
|
|
|
STDMETHODIMP CChain::Build (ICertificate * pICertificate,
|
|
VARIANT_BOOL * pVal)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
PCCERT_CONTEXT pCertContext = NULL;
|
|
CComPtr<ICertificateStatus> pIStatus = NULL;
|
|
|
|
DebugTrace("Entering CChain::Build().\n");
|
|
|
|
try
|
|
{
|
|
//
|
|
// Lock access to this object.
|
|
//
|
|
m_Lock.Lock();
|
|
|
|
//
|
|
// Check parameters.
|
|
//
|
|
if (NULL == pICertificate)
|
|
{
|
|
hr = E_INVALIDARG;
|
|
|
|
DebugTrace("Error [%#x]: Parameter pICertificate is NULL.\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
if (NULL == pVal)
|
|
{
|
|
hr = E_INVALIDARG;
|
|
|
|
DebugTrace("Error [%#x]: Parameter pVal is NULL.\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
|
|
//
|
|
// Get CERT_CONTEXT.
|
|
//
|
|
if (FAILED(hr = ::GetCertContext(pICertificate, &pCertContext)))
|
|
{
|
|
DebugTrace("Error [%#x]: GetCertContext() failed.\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
|
|
//
|
|
// Get status check object.
|
|
//
|
|
if (FAILED(hr = pICertificate->IsValid(&pIStatus)))
|
|
{
|
|
DebugTrace("Error [%#x]: pICertificate->IsValid() failed.\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
|
|
//
|
|
// Build the chain.
|
|
//
|
|
if (FAILED(hr = Init(pCertContext, pIStatus, NULL, pVal)))
|
|
{
|
|
DebugTrace("Error [%#x]: CChain::Init() failed.\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
}
|
|
|
|
catch(...)
|
|
{
|
|
hr = E_POINTER;
|
|
|
|
DebugTrace("Exception: invalid parameter.\n");
|
|
goto ErrorExit;
|
|
}
|
|
|
|
UnlockExit:
|
|
//
|
|
// Free resource.
|
|
//
|
|
if (pCertContext)
|
|
{
|
|
::CertFreeCertificateContext(pCertContext);
|
|
}
|
|
|
|
//
|
|
// Unlock access to this object.
|
|
//
|
|
m_Lock.Unlock();
|
|
|
|
DebugTrace("Leaving CChain::Build().\n");
|
|
|
|
return hr;
|
|
|
|
ErrorExit:
|
|
//
|
|
// Sanity check.
|
|
//
|
|
ATLASSERT(FAILED(hr));
|
|
|
|
ReportError(hr);
|
|
|
|
goto UnlockExit;
|
|
}
|
|
|
|
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
|
|
Function : CChain::CertificatePolicies
|
|
|
|
Synopsis : Return the certificate policies OIDs collection for which this
|
|
chain is valid.
|
|
|
|
Parameter: IOID ** pVal - Pointer to pointer to IOIDs to receive the
|
|
interface pointer.
|
|
|
|
Remark :
|
|
|
|
------------------------------------------------------------------------------*/
|
|
|
|
STDMETHODIMP CChain::CertificatePolicies (IOIDs ** pVal)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
DebugTrace("Entering CChain::CertificatePolicies().\n");
|
|
|
|
try
|
|
{
|
|
//
|
|
// Lock access to this object.
|
|
//
|
|
m_Lock.Lock();
|
|
|
|
//
|
|
// Check parameters.
|
|
//
|
|
if (NULL == pVal)
|
|
{
|
|
hr = E_INVALIDARG;
|
|
|
|
DebugTrace("Error [%#x]: Parameter pVal is NULL.\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
|
|
//
|
|
// Make sure chain has been built.
|
|
//
|
|
if (NULL == m_pChainContext)
|
|
{
|
|
hr = CAPICOM_E_CHAIN_NOT_BUILT;
|
|
|
|
DebugTrace("Error [%#x]: chain object was not initialized.\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
|
|
//
|
|
// Make sure OS is XP and above.
|
|
//
|
|
if (IsWinXPAndAbove())
|
|
{
|
|
//
|
|
// Make sure rgbElement is present.
|
|
//
|
|
if (1 > m_pChainContext->cChain)
|
|
{
|
|
hr = CAPICOM_E_UNKNOWN;
|
|
|
|
DebugTrace("Error [%#x]: m_pChainContext->cChain = %d.\n",
|
|
hr, m_pChainContext->cChain);
|
|
goto ErrorExit;
|
|
}
|
|
|
|
if (1 > m_pChainContext->rgpChain[0]->cElement)
|
|
{
|
|
hr = CAPICOM_E_UNKNOWN;
|
|
|
|
DebugTrace("Error [%#x]: m_pChainContext->rgpChain[0]->cElement = %d.\n",
|
|
hr, m_pChainContext->rgpChain[0]->cElement);
|
|
goto ErrorExit;
|
|
}
|
|
|
|
//
|
|
// Create the OIDs collection for the simple chain.
|
|
//
|
|
if (FAILED(hr = ::CreateOIDsObject(m_pChainContext->rgpChain[0]->rgpElement[0]->pIssuanceUsage,
|
|
TRUE, pVal)))
|
|
{
|
|
DebugTrace("Error [%#x]: CreateOIDsObject() failed.\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
CERT_ENHKEY_USAGE PolicyUsages = {0, NULL};
|
|
|
|
//
|
|
// Create the OIDs collection for the simple chain.
|
|
//
|
|
if (FAILED(hr = ::CreateOIDsObject(&PolicyUsages, TRUE, pVal)))
|
|
{
|
|
DebugTrace("Error [%#x]: CreateOIDsObject() failed.\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
}
|
|
}
|
|
|
|
catch(...)
|
|
{
|
|
hr = E_POINTER;
|
|
|
|
DebugTrace("Exception: invalid parameter.\n");
|
|
goto ErrorExit;
|
|
}
|
|
|
|
UnlockExit:
|
|
//
|
|
// Unlock access to this object.
|
|
//
|
|
m_Lock.Unlock();
|
|
|
|
DebugTrace("Leaving CChain::CertificatePolicies().\n");
|
|
|
|
return hr;
|
|
|
|
ErrorExit:
|
|
//
|
|
// Sanity check.
|
|
//
|
|
ATLASSERT(FAILED(hr));
|
|
|
|
ReportError(hr);
|
|
|
|
goto UnlockExit;
|
|
}
|
|
|
|
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
|
|
Function : CChain::ApplicationPolicies
|
|
|
|
Synopsis : Return the application policies OIDs collection for which this
|
|
chain is valid.
|
|
|
|
Parameter: IOID ** pVal - Pointer to pointer to IOIDs to receive the
|
|
interface pointer.
|
|
|
|
Remark :
|
|
|
|
------------------------------------------------------------------------------*/
|
|
|
|
STDMETHODIMP CChain::ApplicationPolicies (IOIDs ** pVal)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
DebugTrace("Entering CChain::ApplicationPolicies().\n");
|
|
|
|
try
|
|
{
|
|
//
|
|
// Lock access to this object.
|
|
//
|
|
m_Lock.Lock();
|
|
|
|
//
|
|
// Check parameters.
|
|
//
|
|
if (NULL == pVal)
|
|
{
|
|
hr = E_INVALIDARG;
|
|
|
|
DebugTrace("Error [%#x]: Parameter pVal is NULL.\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
|
|
//
|
|
// Make sure chain has been built.
|
|
//
|
|
if (NULL == m_pChainContext)
|
|
{
|
|
hr = CAPICOM_E_CHAIN_NOT_BUILT;
|
|
|
|
DebugTrace("Error [%#x]: chain object was not initialized.\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
|
|
//
|
|
// Make sure OS is XP and above.
|
|
//
|
|
if (IsWinXPAndAbove())
|
|
{
|
|
//
|
|
// Make sure rgbElement is present.
|
|
//
|
|
if (1 > m_pChainContext->cChain)
|
|
{
|
|
hr = CAPICOM_E_UNKNOWN;
|
|
|
|
DebugTrace("Error [%#x]: m_pChainContext->cChain = %d.\n",
|
|
hr, m_pChainContext->cChain);
|
|
goto ErrorExit;
|
|
}
|
|
|
|
if (1 > m_pChainContext->rgpChain[0]->cElement)
|
|
{
|
|
hr = CAPICOM_E_UNKNOWN;
|
|
|
|
DebugTrace("Error [%#x]: m_pChainContext->rgpChain[0]->cElement = %d.\n",
|
|
hr, m_pChainContext->rgpChain[0]->cElement);
|
|
goto ErrorExit;
|
|
}
|
|
|
|
//
|
|
// Create the OIDs collection for the simple chain.
|
|
//
|
|
if (FAILED(hr = ::CreateOIDsObject(m_pChainContext->rgpChain[0]->rgpElement[0]->pApplicationUsage,
|
|
FALSE, pVal)))
|
|
{
|
|
DebugTrace("Error [%#x]: CreateOIDsObject() failed.\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// $BUGBUG: Not supported (should we return CAPICOM_E_NOT_SUPPORTED?)
|
|
//
|
|
*pVal = NULL;
|
|
}
|
|
}
|
|
|
|
catch(...)
|
|
{
|
|
hr = E_POINTER;
|
|
|
|
DebugTrace("Exception: invalid parameter.\n");
|
|
goto ErrorExit;
|
|
}
|
|
|
|
UnlockExit:
|
|
//
|
|
// Unlock access to this object.
|
|
//
|
|
m_Lock.Unlock();
|
|
|
|
DebugTrace("Leaving CChain::ApplicationPolicies().\n");
|
|
|
|
return hr;
|
|
|
|
ErrorExit:
|
|
//
|
|
// Sanity check.
|
|
//
|
|
ATLASSERT(FAILED(hr));
|
|
|
|
ReportError(hr);
|
|
|
|
goto UnlockExit;
|
|
}
|
|
|
|
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
|
|
Function : CChain::ExtendedErrorInfo
|
|
|
|
Synopsis : Return the extended error information description string.
|
|
|
|
Parameter: long Index - Index of the chain (one based).
|
|
|
|
BSTR * pVal - Pointer to BSTR to receive the string.
|
|
|
|
Remark :
|
|
|
|
------------------------------------------------------------------------------*/
|
|
|
|
STDMETHODIMP CChain::ExtendedErrorInfo (long Index, BSTR * pVal)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
DebugTrace("Entering CChain::ExtendedErrorInfo().\n");
|
|
|
|
try
|
|
{
|
|
//
|
|
// Lock access to this object.
|
|
//
|
|
m_Lock.Lock();
|
|
|
|
//
|
|
// Check parameters.
|
|
//
|
|
if (NULL == pVal)
|
|
{
|
|
hr = E_INVALIDARG;
|
|
|
|
DebugTrace("Error [%#x]: Parameter pVal is NULL.\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
|
|
//
|
|
// Make sure chain has been built.
|
|
//
|
|
if (NULL == m_pChainContext)
|
|
{
|
|
hr = CAPICOM_E_CHAIN_NOT_BUILT;
|
|
|
|
DebugTrace("Error [%#x]: chain object was not initialized.\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
|
|
DebugTrace("m_pChainContext = %#x.\n", m_pChainContext);
|
|
|
|
//
|
|
// Make sure OS is XP and above.
|
|
//
|
|
if (IsWinXPAndAbove())
|
|
{
|
|
CComBSTR bstrErrorInfo;
|
|
|
|
//
|
|
// Make sure rgbElement is present.
|
|
//
|
|
if (1 > m_pChainContext->cChain)
|
|
{
|
|
hr = CAPICOM_E_UNKNOWN;
|
|
|
|
DebugTrace("Error [%#x]: m_pChainContext->cChain = %d.\n",
|
|
hr, m_pChainContext->cChain);
|
|
goto ErrorExit;
|
|
}
|
|
|
|
if (Index < 1 || (DWORD) Index > m_pChainContext->rgpChain[0]->cElement)
|
|
{
|
|
hr = E_INVALIDARG;
|
|
|
|
DebugTrace("Error [%#x]: Index out of range, Index = %d, m_pChainContext->rgpChain[0]->cElement = %u.\n",
|
|
hr, Index, m_pChainContext->rgpChain[0]->cElement);
|
|
goto ErrorExit;
|
|
}
|
|
|
|
//
|
|
// Convert string to BSTR.
|
|
//
|
|
if (m_pChainContext->rgpChain[0]->rgpElement[Index - 1]->pwszExtendedErrorInfo &&
|
|
!(bstrErrorInfo = m_pChainContext->rgpChain[0]->rgpElement[Index - 1]->pwszExtendedErrorInfo))
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
|
|
DebugTrace("Error [%#x]: bstrErrorInfo = pwszExtendedErrorInfo failed.\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
|
|
//
|
|
// Return string to caller.
|
|
//
|
|
*pVal = bstrErrorInfo.Detach();
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// $BUGBUG: Not supported (should we return CAPICOM_E_NOT_SUPPORTED?)
|
|
//
|
|
*pVal = NULL;
|
|
}
|
|
}
|
|
|
|
catch(...)
|
|
{
|
|
hr = E_POINTER;
|
|
|
|
DebugTrace("Exception: invalid parameter.\n");
|
|
goto ErrorExit;
|
|
}
|
|
|
|
UnlockExit:
|
|
//
|
|
// Unlock access to this object.
|
|
//
|
|
m_Lock.Unlock();
|
|
|
|
DebugTrace("Leaving CChain::ExtendedErrorInfo().\n");
|
|
|
|
return hr;
|
|
|
|
ErrorExit:
|
|
//
|
|
// Sanity check.
|
|
//
|
|
ATLASSERT(FAILED(hr));
|
|
|
|
ReportError(hr);
|
|
|
|
goto UnlockExit;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Custom interfaces.
|
|
//
|
|
|
|
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
|
|
Function : CChain::get_ChainContext
|
|
|
|
Synopsis : Return the chains's PCCERT_CHAIN_CONTEXT.
|
|
|
|
Parameter: long * ppChainContext - Pointer to PCCERT_CHAIN_CONTEXT disguished
|
|
in a long.
|
|
|
|
Remark : We need to use long instead of PCCERT_CHAIN_CONTEXT because VB
|
|
can't handle double indirection (i.e. vb would bark on this
|
|
PCCERT_CHAIN_CONTEXT * ppChainContext).
|
|
|
|
------------------------------------------------------------------------------*/
|
|
|
|
STDMETHODIMP CChain::get_ChainContext (long * ppChainContext)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
DebugTrace("Entering CChain::get_ChainContext().\n");
|
|
|
|
try
|
|
{
|
|
//
|
|
// Lock access to this object.
|
|
//
|
|
m_Lock.Lock();
|
|
|
|
//
|
|
// Check parameters.
|
|
//
|
|
if (NULL == ppChainContext)
|
|
{
|
|
hr = E_INVALIDARG;
|
|
|
|
DebugTrace("Error [%#x]: Parameter ppChainContext is NULL.\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
|
|
//
|
|
// Return chain context to caller.
|
|
//
|
|
if (FAILED(hr = GetContext((PCCERT_CHAIN_CONTEXT *) ppChainContext)))
|
|
{
|
|
DebugTrace("Error [%#x]: CChain::GetContext() failed.\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
}
|
|
|
|
catch(...)
|
|
{
|
|
hr = E_POINTER;
|
|
|
|
DebugTrace("Exception: invalid parameter.\n");
|
|
goto ErrorExit;
|
|
}
|
|
|
|
UnlockExit:
|
|
//
|
|
// Unlock access to this object.
|
|
//
|
|
m_Lock.Unlock();
|
|
|
|
DebugTrace("Leaving CChain::get_ChainContext().\n");
|
|
|
|
return hr;
|
|
|
|
ErrorExit:
|
|
//
|
|
// Sanity check.
|
|
//
|
|
ATLASSERT(FAILED(hr));
|
|
|
|
ReportError(hr);
|
|
|
|
goto UnlockExit;
|
|
}
|
|
|
|
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
|
|
Function : CChain::put_ChainContext
|
|
|
|
Synopsis : Initialize the object with a CERT_CHAIN_CONTEXT.
|
|
|
|
Parameter: long pChainContext - Poiner to CERT_CHAIN_CONTEXT, disguised in a
|
|
long, used to initialize this object.
|
|
|
|
Remark : Note that this is NOT 64-bit compatiable. Plese see remark of
|
|
get_ChainContext for more detail.
|
|
|
|
------------------------------------------------------------------------------*/
|
|
|
|
STDMETHODIMP CChain::put_ChainContext (long pChainContext)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
DebugTrace("Entering CChain::put_ChainContext().\n");
|
|
|
|
try
|
|
{
|
|
//
|
|
// Lock access to this object.
|
|
//
|
|
m_Lock.Lock();
|
|
|
|
//
|
|
// Check parameters.
|
|
//
|
|
if (NULL == pChainContext)
|
|
{
|
|
hr = E_INVALIDARG;
|
|
|
|
DebugTrace("Error [%#x]: Parameter pChainContext is NULL.\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
|
|
//
|
|
// Reset the object with this context.
|
|
//
|
|
if (FAILED(hr = PutContext((PCCERT_CHAIN_CONTEXT) pChainContext)))
|
|
{
|
|
DebugTrace("Error [%#x]: CChain::PutContext() failed.\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
}
|
|
|
|
catch(...)
|
|
{
|
|
hr = E_POINTER;
|
|
|
|
DebugTrace("Exception: invalid parameter.\n");
|
|
goto ErrorExit;
|
|
}
|
|
|
|
UnlockExit:
|
|
//
|
|
// Unlock access to this object.
|
|
//
|
|
m_Lock.Unlock();
|
|
|
|
DebugTrace("Leaving CChain::put_CertContext().\n");
|
|
|
|
return hr;
|
|
|
|
ErrorExit:
|
|
//
|
|
// Sanity check.
|
|
//
|
|
ATLASSERT(FAILED(hr));
|
|
|
|
ReportError(hr);
|
|
|
|
goto UnlockExit;
|
|
}
|
|
|
|
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
|
|
Function : CChain::FreeContext
|
|
|
|
Synopsis : Free a CERT_CHAIN_CONTEXT.
|
|
|
|
Parameter: long pChainContext - Poiner to CERT_CHAIN_CONTEXT, disguised in a
|
|
long, to be freed.
|
|
|
|
Remark : Note that this is NOT 64-bit compatiable. Plese see remark of
|
|
get_ChainContext for more detail.
|
|
|
|
------------------------------------------------------------------------------*/
|
|
|
|
STDMETHODIMP CChain::FreeContext (long pChainContext)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
DebugTrace("Entering CChain::FreeContext().\n");
|
|
|
|
try
|
|
{
|
|
//
|
|
// Lock access to this object.
|
|
//
|
|
m_Lock.Lock();
|
|
|
|
//
|
|
// Check parameters.
|
|
//
|
|
if (NULL == pChainContext)
|
|
{
|
|
hr = E_INVALIDARG;
|
|
|
|
DebugTrace("Error [%#x]: Parameter pChainContext is NULL.\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
|
|
//
|
|
// Free the context.
|
|
//
|
|
::CertFreeCertificateChain((PCCERT_CHAIN_CONTEXT) pChainContext);
|
|
}
|
|
|
|
catch(...)
|
|
{
|
|
hr = E_POINTER;
|
|
|
|
DebugTrace("Exception: invalid parameter.\n");
|
|
goto ErrorExit;
|
|
}
|
|
|
|
UnlockExit:
|
|
//
|
|
// Unlock access to this object.
|
|
//
|
|
m_Lock.Unlock();
|
|
|
|
DebugTrace("Leaving CChain::FreeContext().\n");
|
|
|
|
return hr;
|
|
|
|
ErrorExit:
|
|
//
|
|
// Sanity check.
|
|
//
|
|
ATLASSERT(FAILED(hr));
|
|
|
|
ReportError(hr);
|
|
|
|
goto UnlockExit;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Private methods.
|
|
//
|
|
|
|
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
|
|
Function : CChain::Init
|
|
|
|
Synopsis : Initialize the object.
|
|
|
|
Parameter: PCCERT_CONTEXT pCertContext - Pointer to CERT_CONTEXT.
|
|
|
|
ICertificateStatus * pIStatus - Pointer to ICertificateStus object
|
|
used to build the chain.
|
|
|
|
HCERTSTORE hAdditionalStore - Additional store handle.
|
|
|
|
VARIANT_BOOL * pVal - Pointer to VARIANT_BOOL to receive chain
|
|
overall validity result.
|
|
|
|
Remark : This method is not part of the COM interface (it is a normal C++
|
|
member function). We need it to initialize the object created
|
|
internally by us with CERT_CONTEXT.
|
|
|
|
Since it is only a normal C++ member function, this function can
|
|
only be called from a C++ class pointer, not an interface pointer.
|
|
|
|
------------------------------------------------------------------------------*/
|
|
|
|
STDMETHODIMP CChain::Init (PCCERT_CONTEXT pCertContext,
|
|
ICertificateStatus * pIStatus,
|
|
HCERTSTORE hAdditionalStore,
|
|
VARIANT_BOOL * pbResult)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
VARIANT_BOOL bResult = VARIANT_FALSE;
|
|
long lIndex = 0;
|
|
long cEkuOid = 0;
|
|
long cIssuanceOid = 0;
|
|
DWORD dwCheckFlags = 0;
|
|
CAPICOM_CHECK_FLAG UserFlags = CAPICOM_CHECK_NONE;
|
|
CComPtr<IEKU> pIEku = NULL;
|
|
LPSTR * rgpEkuOid = NULL;
|
|
LPSTR * rgpIssuanceOid = NULL;
|
|
PCCERT_CHAIN_CONTEXT pChainContext = NULL;
|
|
CComPtr<ICertificateStatus2> pICertificateStatus2 = NULL;
|
|
CComPtr<IOIDs> pIApplicationPolicies = NULL;
|
|
CComPtr<IOIDs> pICertificatePolicies = NULL;
|
|
DATE dtVerificationTime = {0};
|
|
SYSTEMTIME stVerificationTime = {0};
|
|
FILETIME ftVerificationTime = {0};
|
|
FILETIME ftUTCVerificationTime = {0};
|
|
LPFILETIME pftVerificationTime = NULL;
|
|
DWORD dwUrlRetrievalTimeout = 0;
|
|
CAPICOM_CHAIN_STATUS PolicyStatus = CAPICOM_CHAIN_STATUS_OK;
|
|
CERT_CHAIN_PARA ChainPara = {0};
|
|
CComBSTR bstrEkuOid;
|
|
|
|
DebugTrace("Entering CChain::Init().\n");
|
|
|
|
//
|
|
// Sanity check.
|
|
//
|
|
ATLASSERT(pCertContext);
|
|
ATLASSERT(pIStatus);
|
|
ATLASSERT(pbResult);
|
|
|
|
//
|
|
// Is this v2?
|
|
//
|
|
if (FAILED(hr = pIStatus->QueryInterface(IID_ICertificateStatus2,
|
|
(void **) &pICertificateStatus2)))
|
|
{
|
|
DebugTrace("Info [%#x]: pIStatus->QueryInterface(IID_ICertificateStatus2) failed.\n", hr);
|
|
hr = S_OK;
|
|
}
|
|
|
|
//
|
|
// Get the user's requested check flag.
|
|
//
|
|
if (FAILED(hr = pIStatus->get_CheckFlag(&UserFlags)))
|
|
{
|
|
DebugTrace("Error [%#x]: pIStatus->CheckFlag() failed.\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
|
|
//
|
|
// Set revocation flags.
|
|
//
|
|
if ((CAPICOM_CHECK_ONLINE_REVOCATION_STATUS & UserFlags) ||
|
|
(CAPICOM_CHECK_OFFLINE_REVOCATION_STATUS & UserFlags))
|
|
{
|
|
if (UserFlags & CAPICOM_CHECK_REVOCATION_END_CERT_ONLY)
|
|
{
|
|
dwCheckFlags |= CERT_CHAIN_REVOCATION_CHECK_END_CERT;
|
|
}
|
|
else if (UserFlags & CAPICOM_CHECK_REVOCATION_ENTIRE_CHAIN)
|
|
{
|
|
dwCheckFlags |= CERT_CHAIN_REVOCATION_CHECK_CHAIN;
|
|
}
|
|
else // default is chain minus root.
|
|
{
|
|
dwCheckFlags |= CERT_CHAIN_REVOCATION_CHECK_CHAIN_EXCLUDE_ROOT;
|
|
}
|
|
|
|
if (CAPICOM_CHECK_OFFLINE_REVOCATION_STATUS & UserFlags)
|
|
{
|
|
dwCheckFlags |= CERT_CHAIN_REVOCATION_CHECK_CACHE_ONLY;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Is this v2?
|
|
//
|
|
if (pICertificateStatus2)
|
|
{
|
|
//
|
|
// Get verification time.
|
|
//
|
|
if (FAILED(hr = pICertificateStatus2->get_VerificationTime(&dtVerificationTime)))
|
|
{
|
|
DebugTrace("Error [%#x]: pICertificateStatus2->get_VerificationTime() failed.\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
|
|
//
|
|
// Get URL retrieval timeout.
|
|
//
|
|
if (FAILED(hr = pICertificateStatus2->get_UrlRetrievalTimeout((long *) &dwUrlRetrievalTimeout)))
|
|
{
|
|
DebugTrace("Error [%#x]: pICertificateStatus2->get_UrlRetrievalTimeout() failed.\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
|
|
//
|
|
// Try application policies.
|
|
//
|
|
if (FAILED(hr = pICertificateStatus2->ApplicationPolicies(&pIApplicationPolicies)))
|
|
{
|
|
DebugTrace("Error [%#x]: pICertificateStatus2->ApplicationPolicies() failed.\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
|
|
//
|
|
// Get count of OIDs.
|
|
//
|
|
if (FAILED(hr = pIApplicationPolicies->get_Count(&cEkuOid)))
|
|
{
|
|
DebugTrace("Error [%#x]: pIApplicationPolicies->get_Count() failed.\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
|
|
//
|
|
// Do we have any application usage?
|
|
//
|
|
if (0 < cEkuOid)
|
|
{
|
|
//
|
|
// Allocate memory for usage array.
|
|
//
|
|
if (!(rgpEkuOid = (LPTSTR *) ::CoTaskMemAlloc(sizeof(LPSTR) * cEkuOid)))
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
|
|
DebugTrace("Error [%#x]: CoTaskMemAlloc() failed.\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
::ZeroMemory(rgpEkuOid, sizeof(LPSTR) * cEkuOid);
|
|
|
|
//
|
|
// Setup usage array.
|
|
//
|
|
for (lIndex = 0; lIndex < cEkuOid; lIndex++)
|
|
{
|
|
CComBSTR bstrOid;
|
|
CComPtr<IOID> pIOID = NULL;
|
|
CComVariant varOid = NULL;
|
|
CComVariant varIndex = lIndex + 1;
|
|
|
|
if (FAILED(hr = pIApplicationPolicies->get_Item(varIndex, &varOid)))
|
|
{
|
|
DebugTrace("Error [%#x]: pIApplicationPolicies->get_Item() failed.\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
|
|
if (FAILED(hr = varOid.pdispVal->QueryInterface(IID_IOID, (void **) &pIOID)))
|
|
{
|
|
DebugTrace("Error [%#x]: varOid.pdispVal->QueryInterface() failed.\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
|
|
if (FAILED(hr = pIOID->get_Value(&bstrOid)))
|
|
{
|
|
DebugTrace("Error [%#x]: pIOID->get_Value() failed.\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
|
|
if (FAILED(hr = ::UnicodeToAnsi((LPWSTR) bstrOid,
|
|
-1,
|
|
&rgpEkuOid[lIndex],
|
|
NULL)))
|
|
{
|
|
DebugTrace("Error [%#x]:UnicodeToAnsi() failed.\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// OK, try issuance policies.
|
|
//
|
|
if (FAILED(hr = pICertificateStatus2->CertificatePolicies(&pICertificatePolicies)))
|
|
{
|
|
DebugTrace("Error [%#x]: pICertificateStatus2->CertificatePolicies() failed.\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
|
|
//
|
|
// Get count of OIDs.
|
|
//
|
|
if (FAILED(hr = pICertificatePolicies->get_Count(&cIssuanceOid)))
|
|
{
|
|
DebugTrace("Error [%#x]: pICertificatePolicies->get_Count() failed.\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
|
|
//
|
|
// Do we have any usage?
|
|
//
|
|
if (0 < cIssuanceOid)
|
|
{
|
|
//
|
|
// Make sure we have WinXP and above.
|
|
//
|
|
if (!IsWinXPAndAbove())
|
|
{
|
|
hr = CAPICOM_E_NOT_SUPPORTED;
|
|
|
|
DebugTrace("Error [%#x]: building chain with issuance policy is not support.\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
|
|
//
|
|
// Allocate memory for usage array.
|
|
//
|
|
if (!(rgpIssuanceOid = (LPTSTR *) ::CoTaskMemAlloc(sizeof(LPSTR) * cIssuanceOid)))
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
|
|
DebugTrace("Error [%#x]: CoTaskMemAlloc() failed.\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
|
|
//
|
|
// Setup usage array.
|
|
//
|
|
for (lIndex = 0; lIndex < cIssuanceOid; lIndex++)
|
|
{
|
|
CComBSTR bstrOid;
|
|
CComPtr<IOID> pIOID = NULL;
|
|
CComVariant varOid = NULL;
|
|
CComVariant varIndex = lIndex + 1;
|
|
|
|
if (FAILED(hr = pICertificatePolicies->get_Item(varIndex, &varOid)))
|
|
{
|
|
DebugTrace("Error [%#x]: pICertificatePolicies->get_Item() failed.\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
|
|
if (FAILED(hr = varOid.pdispVal->QueryInterface(IID_IOID, (void **) &pIOID)))
|
|
{
|
|
DebugTrace("Error [%#x]: varOid.pdispVal->QueryInterface() failed.\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
|
|
if (FAILED(hr = pIOID->get_Value(&bstrOid)))
|
|
{
|
|
DebugTrace("Error [%#x]: pIOID->get_Value() failed.\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
|
|
if (FAILED(hr = ::UnicodeToAnsi((LPWSTR) bstrOid,
|
|
-1,
|
|
&rgpIssuanceOid[lIndex],
|
|
NULL)))
|
|
{
|
|
DebugTrace("Error [%#x]:UnicodeToAnsi() failed.\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// If we didn't find any application usage, then try the old EKU object.
|
|
//
|
|
if (0 == cEkuOid)
|
|
{
|
|
//
|
|
// Get EKU object.
|
|
//
|
|
if (FAILED(hr = pIStatus->EKU(&pIEku)))
|
|
{
|
|
DebugTrace("Error [%#x]: pIStatus->EKU() failed.\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
|
|
//
|
|
// Get EKU OID value.
|
|
//
|
|
if (FAILED(hr = pIEku->get_OID(&bstrEkuOid)))
|
|
{
|
|
DebugTrace("Error [%#x]: pIEku->get_OID() failed.\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
|
|
//
|
|
// If not empty EKU, then set it.
|
|
//
|
|
if (bstrEkuOid.Length() > 0)
|
|
{
|
|
//
|
|
// Allocate memory for EKU usage array.
|
|
//
|
|
cEkuOid = 1;
|
|
|
|
if (!(rgpEkuOid = (LPTSTR *) ::CoTaskMemAlloc(sizeof(LPSTR))))
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
|
|
DebugTrace("Error [%#x]: CoTaskMemAlloc() failed.\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
::ZeroMemory(rgpEkuOid, sizeof(LPSTR) * cEkuOid);
|
|
|
|
if (FAILED(hr = ::UnicodeToAnsi((LPWSTR) bstrEkuOid,
|
|
-1,
|
|
&rgpEkuOid[0],
|
|
NULL)))
|
|
{
|
|
DebugTrace("Error [%#x]:UnicodeToAnsi() failed.\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// If we found any usage, then force the appropriate policy check flags.
|
|
//
|
|
if (0 < cEkuOid)
|
|
{
|
|
UserFlags = (CAPICOM_CHECK_FLAG) ((DWORD) UserFlags | CAPICOM_CHECK_APPLICATION_USAGE);
|
|
}
|
|
if (0 < cIssuanceOid)
|
|
{
|
|
UserFlags = (CAPICOM_CHECK_FLAG) ((DWORD) UserFlags | CAPICOM_CHECK_CERTIFICATE_POLICY);
|
|
}
|
|
|
|
//
|
|
// Initialize.
|
|
//
|
|
ChainPara.cbSize = sizeof(ChainPara);
|
|
ChainPara.RequestedUsage.dwType = USAGE_MATCH_TYPE_AND;
|
|
ChainPara.RequestedUsage.Usage.cUsageIdentifier = cEkuOid;
|
|
ChainPara.RequestedUsage.Usage.rgpszUsageIdentifier = rgpEkuOid;
|
|
ChainPara.RequestedIssuancePolicy.dwType = USAGE_MATCH_TYPE_AND;
|
|
ChainPara.RequestedIssuancePolicy.Usage.cUsageIdentifier = cIssuanceOid;
|
|
ChainPara.RequestedIssuancePolicy.Usage.rgpszUsageIdentifier = rgpIssuanceOid;
|
|
|
|
//
|
|
// Set verification time, if specified.
|
|
//
|
|
if ((DATE) 0 != dtVerificationTime)
|
|
{
|
|
//
|
|
// Convert to SYSTEMTIME format.
|
|
//
|
|
if (!::VariantTimeToSystemTime(dtVerificationTime, &stVerificationTime))
|
|
{
|
|
hr = E_INVALIDARG;
|
|
|
|
DebugTrace("Error [%#x]: VariantTimeToSystemTime() failed.\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
|
|
//
|
|
// Convert to FILETIME format.
|
|
//
|
|
if (!::SystemTimeToFileTime(&stVerificationTime, &ftVerificationTime))
|
|
{
|
|
hr = HRESULT_FROM_WIN32(::GetLastError());
|
|
|
|
DebugTrace("Error [%#x]: SystemTimeToFileTime() failed.\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
|
|
//
|
|
// Convert to UTC FILETIME.
|
|
//
|
|
if (!::LocalFileTimeToFileTime(&ftVerificationTime, &ftUTCVerificationTime))
|
|
{
|
|
hr = HRESULT_FROM_WIN32(::GetLastError());
|
|
|
|
DebugTrace("Error [%#x]: LocalFileTimeToFileTime() failed.\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
|
|
pftVerificationTime = &ftUTCVerificationTime;
|
|
}
|
|
|
|
//
|
|
// Set URL retrieval timeout, if avaliable.
|
|
//
|
|
// Note: Ignored by CAPI by pre Win2K platforms.
|
|
//
|
|
if (0 != dwUrlRetrievalTimeout)
|
|
{
|
|
ChainPara.dwUrlRetrievalTimeout = dwUrlRetrievalTimeout * 1000;
|
|
}
|
|
|
|
//
|
|
// Build the chain.
|
|
//
|
|
if (!::CertGetCertificateChain(NULL, // in optional
|
|
pCertContext, // in
|
|
pftVerificationTime, // in optional
|
|
hAdditionalStore, // in optional
|
|
&ChainPara, // in
|
|
dwCheckFlags, // in
|
|
NULL, // in
|
|
&pChainContext)) // out
|
|
{
|
|
hr = HRESULT_FROM_WIN32(::GetLastError());
|
|
|
|
DebugTrace("Error [%#x]: CertGetCertificateChain() failed.\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
|
|
//
|
|
// Chain was successfully built, so update states.
|
|
//
|
|
if (m_pChainContext)
|
|
{
|
|
::CertFreeCertificateChain(m_pChainContext);
|
|
}
|
|
|
|
m_pChainContext = pChainContext;
|
|
m_dwStatus = pChainContext->TrustStatus.dwErrorStatus;
|
|
|
|
//
|
|
// Verify the chain using base policy.
|
|
//
|
|
if (FAILED(hr = Verify(UserFlags, &PolicyStatus)))
|
|
{
|
|
DebugTrace("Error [%#x]: Chain::Verify() failed.\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
|
|
//
|
|
// Ignore errors that user specifically requested not to check.
|
|
//
|
|
if (CAPICOM_CHAIN_STATUS_REVOCATION_OFFLINE == PolicyStatus)
|
|
{
|
|
if (CAPICOM_CHECK_OFFLINE_REVOCATION_STATUS & UserFlags)
|
|
{
|
|
bResult = VARIANT_TRUE;
|
|
|
|
DebugTrace("Info: offline revocation when performing offline revocation checking.\n");
|
|
goto CommonExit;
|
|
}
|
|
else if (CAPICOM_CHECK_ONLINE_REVOCATION_STATUS & UserFlags)
|
|
{
|
|
DebugTrace("Info: offline revocation when performing online revocation checking.\n");
|
|
goto CommonExit;
|
|
}
|
|
}
|
|
|
|
if ((CAPICOM_CHECK_TRUSTED_ROOT & UserFlags) &&
|
|
(CAPICOM_CHAIN_STATUS_UNTRUSTEDROOT == PolicyStatus))
|
|
{
|
|
DebugTrace("Info: chain does not verify because of untrusted root.\n");
|
|
goto CommonExit;
|
|
}
|
|
|
|
if ((CAPICOM_CHECK_TIME_VALIDITY & UserFlags) &&
|
|
(CAPICOM_CHAIN_STATUS_EXPIRED == PolicyStatus))
|
|
{
|
|
DebugTrace("Info: chain does not verify because of certificate expiration.\n");
|
|
goto CommonExit;
|
|
}
|
|
|
|
if ((CAPICOM_CHECK_SIGNATURE_VALIDITY & UserFlags) &&
|
|
(CAPICOM_CHAIN_STATUS_INVALID_SIGNATURE == PolicyStatus))
|
|
{
|
|
DebugTrace("Info: chain does not verify because of invalid certificate signature.\n");
|
|
goto CommonExit;
|
|
}
|
|
|
|
if (((CAPICOM_CHECK_ONLINE_REVOCATION_STATUS | CAPICOM_CHECK_OFFLINE_REVOCATION_STATUS) & UserFlags) &&
|
|
(CAPICOM_CHAIN_STATUS_REVOKED == PolicyStatus || CAPICOM_CHAIN_STATUS_REVOCATION_NO_CHECK == PolicyStatus))
|
|
{
|
|
DebugTrace("Info: chain does not verify because a certificate in the chain was revoked or could not be checked most likely due to no CDP in certificate.\n");
|
|
goto CommonExit;
|
|
}
|
|
|
|
if ((CAPICOM_CHECK_COMPLETE_CHAIN & UserFlags) &&
|
|
(CAPICOM_CHAIN_STATUS_PARTIAL_CHAINING == PolicyStatus))
|
|
{
|
|
DebugTrace("Info: chain does not verify because of partial chain.\n");
|
|
goto CommonExit;
|
|
}
|
|
|
|
if (((CAPICOM_CHECK_APPLICATION_USAGE & UserFlags) ||
|
|
(CAPICOM_CHECK_CERTIFICATE_POLICY & UserFlags)) &&
|
|
(CAPICOM_CHAIN_STATUS_INVALID_USAGE == PolicyStatus))
|
|
{
|
|
DebugTrace("Info: chain does not verify because of invalid usage.\n");
|
|
goto CommonExit;
|
|
}
|
|
|
|
if ((CAPICOM_CHECK_NAME_CONSTRAINTS & UserFlags) &&
|
|
(CAPICOM_CHAIN_STATUS_INVALID_NAME == PolicyStatus))
|
|
{
|
|
DebugTrace("Info: chain does not verify because of invalid name constraints.\n");
|
|
goto CommonExit;
|
|
}
|
|
|
|
if ((CAPICOM_CHECK_BASIC_CONSTRAINTS & UserFlags) &&
|
|
(CAPICOM_CHAIN_STATUS_INVALID_BASIC_CONSTRAINTS == PolicyStatus))
|
|
{
|
|
DebugTrace("Info: chain does not verify because of invalid basic constraints.\n");
|
|
goto CommonExit;
|
|
}
|
|
|
|
if ((CAPICOM_CHECK_NESTED_VALIDITY_PERIOD & UserFlags) &&
|
|
(CAPICOM_CHAIN_STATUS_NESTED_VALIDITY_PERIOD == PolicyStatus))
|
|
{
|
|
DebugTrace("Info: chain does not verify because of invalid nested validity period.\n");
|
|
goto CommonExit;
|
|
}
|
|
|
|
//
|
|
// Everything is check out OK.
|
|
//
|
|
bResult = VARIANT_TRUE;
|
|
|
|
CommonExit:
|
|
//
|
|
// Free resources.
|
|
//
|
|
if (rgpEkuOid)
|
|
{
|
|
for (lIndex = 0; lIndex < cEkuOid; lIndex++)
|
|
{
|
|
if (rgpEkuOid[lIndex])
|
|
{
|
|
::CoTaskMemFree(rgpEkuOid[lIndex]);
|
|
}
|
|
}
|
|
|
|
::CoTaskMemFree((LPVOID) rgpEkuOid);
|
|
}
|
|
if (rgpIssuanceOid)
|
|
{
|
|
for (lIndex = 0; lIndex < cIssuanceOid; lIndex++)
|
|
{
|
|
if (rgpIssuanceOid[lIndex])
|
|
{
|
|
::CoTaskMemFree(rgpIssuanceOid[lIndex]);
|
|
}
|
|
}
|
|
|
|
::CoTaskMemFree((LPVOID) rgpIssuanceOid);
|
|
}
|
|
|
|
//
|
|
// Return result.
|
|
//
|
|
*pbResult = bResult;
|
|
|
|
DebugTrace("Leaving CChain::Init().\n");
|
|
|
|
return hr;
|
|
|
|
ErrorExit:
|
|
//
|
|
// Sanity check.
|
|
//
|
|
ATLASSERT(FAILED(hr));
|
|
|
|
//
|
|
// Free resouce.
|
|
//
|
|
if (pChainContext)
|
|
{
|
|
::CertFreeCertificateChain(pChainContext);
|
|
}
|
|
|
|
goto CommonExit;
|
|
}
|
|
|
|
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
|
|
Function : CChain::Verify
|
|
|
|
Synopsis : Verify the chain using base policy.
|
|
|
|
Parameter: CAPICOM_CHECK_FLAG CheckFlag - Check flag.
|
|
|
|
CAPICOM_CHAIN_STATUS * pVal - Pointer to CAPICOM_CHAIN_STATUS to
|
|
receive the chain validity status.
|
|
|
|
Remark :
|
|
|
|
------------------------------------------------------------------------------*/
|
|
|
|
STDMETHODIMP CChain::Verify (CAPICOM_CHECK_FLAG CheckFlag,
|
|
CAPICOM_CHAIN_STATUS * pVal)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
LPCSTR pszPolicy = CERT_CHAIN_POLICY_BASE;
|
|
CERT_CHAIN_POLICY_PARA PolicyPara = {0};
|
|
CERT_CHAIN_POLICY_STATUS PolicyStatus = {0};
|
|
|
|
DebugTrace("Entering CChain::Verify().\n");
|
|
|
|
//
|
|
// Check parameters.
|
|
//
|
|
if (NULL == pVal)
|
|
{
|
|
hr = E_INVALIDARG;
|
|
|
|
DebugTrace("Error [%#x]: Parameter pVal is NULL.\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
|
|
//
|
|
// Make sure chain has been built.
|
|
//
|
|
if (NULL == m_pChainContext)
|
|
{
|
|
hr = CAPICOM_E_CHAIN_NOT_BUILT;
|
|
|
|
DebugTrace("Error [%#x]: chain object was not initialized.\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
|
|
//
|
|
// Initialize.
|
|
//
|
|
PolicyStatus.cbSize = sizeof(PolicyStatus);
|
|
PolicyPara.cbSize = sizeof(PolicyPara);
|
|
|
|
//
|
|
// Setup policy structures.
|
|
//
|
|
if (0 == (CheckFlag & CAPICOM_CHECK_TIME_VALIDITY))
|
|
{
|
|
PolicyPara.dwFlags |= CERT_CHAIN_POLICY_IGNORE_ALL_NOT_TIME_VALID_FLAGS;
|
|
}
|
|
|
|
if (0 == (CheckFlag & CAPICOM_CHECK_APPLICATION_USAGE) &&
|
|
0 == (CheckFlag & CAPICOM_CHECK_CERTIFICATE_POLICY))
|
|
{
|
|
PolicyPara.dwFlags |= CERT_CHAIN_POLICY_IGNORE_WRONG_USAGE_FLAG;
|
|
}
|
|
|
|
if (0 == (CheckFlag & CAPICOM_CHECK_NAME_CONSTRAINTS))
|
|
{
|
|
PolicyPara.dwFlags |= CERT_CHAIN_POLICY_IGNORE_INVALID_NAME_FLAG;
|
|
}
|
|
|
|
if (0 == (CheckFlag & CAPICOM_CHECK_BASIC_CONSTRAINTS))
|
|
{
|
|
PolicyPara.dwFlags |= CERT_CHAIN_POLICY_IGNORE_INVALID_BASIC_CONSTRAINTS_FLAG;
|
|
}
|
|
|
|
if (0 == (CheckFlag & CAPICOM_CHECK_NESTED_VALIDITY_PERIOD))
|
|
{
|
|
PolicyPara.dwFlags |= CERT_CHAIN_POLICY_IGNORE_NOT_TIME_NESTED_FLAG;
|
|
}
|
|
|
|
//
|
|
// Verify the chain policy.
|
|
//
|
|
if (!::CertVerifyCertificateChainPolicy(pszPolicy,
|
|
m_pChainContext,
|
|
&PolicyPara,
|
|
&PolicyStatus))
|
|
{
|
|
hr = HRESULT_FROM_WIN32(::GetLastError());
|
|
|
|
DebugTrace("Error [%#x]: CertVerifyCertificateChainPolicy() failed.\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
|
|
//
|
|
// Return policy status to caller.
|
|
//
|
|
*pVal = (CAPICOM_CHAIN_STATUS) PolicyStatus.dwError;
|
|
|
|
CommonExit:
|
|
|
|
DebugTrace("Leaving CChain::Verify().\n");
|
|
|
|
return hr;
|
|
|
|
ErrorExit:
|
|
//
|
|
// Sanity check.
|
|
//
|
|
ATLASSERT(FAILED(hr));
|
|
|
|
ReportError(hr);
|
|
|
|
goto CommonExit;
|
|
}
|
|
|
|
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
|
|
Function : CChain::GetContext
|
|
|
|
Synopsis : Return the PCCERT_CHAIN_CONTEXT.
|
|
|
|
Parameter: PCCERT_CHAIN_CONTEXT * ppChainContext - Pointer to
|
|
PCCERT_CHAIN_CONTEXT.
|
|
|
|
Remark : This method is not part of the COM interface (it is a normal C++
|
|
member function). We need it to initialize the object created
|
|
internally by us with CERT_CONTEXT.
|
|
|
|
Since it is only a normal C++ member function, this function can
|
|
only be called from a C++ class pointer, not an interface pointer.
|
|
|
|
------------------------------------------------------------------------------*/
|
|
|
|
STDMETHODIMP CChain::GetContext (PCCERT_CHAIN_CONTEXT * ppChainContext)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
DebugTrace("Entering CChain::GetContext().\n");
|
|
|
|
//
|
|
// Sanity check.
|
|
//
|
|
ATLASSERT(ppChainContext);
|
|
|
|
//
|
|
// Make sure chain has been built.
|
|
//
|
|
if (!m_pChainContext)
|
|
{
|
|
hr = CAPICOM_E_CHAIN_NOT_BUILT;
|
|
|
|
DebugTrace("Error: chain object was not initialized.\n");
|
|
goto ErrorExit;
|
|
}
|
|
|
|
//
|
|
// Duplicate the chain context.
|
|
//
|
|
if (!(*ppChainContext = ::CertDuplicateCertificateChain(m_pChainContext)))
|
|
{
|
|
hr = HRESULT_FROM_WIN32(::GetLastError());
|
|
|
|
DebugTrace("Error [%#x]: CertDuplicateCertificateChain() failed.\n");
|
|
goto ErrorExit;
|
|
}
|
|
|
|
|
|
CommonExit:
|
|
|
|
DebugTrace("Leaving CChain::GetContext().\n");
|
|
|
|
return hr;
|
|
|
|
ErrorExit:
|
|
//
|
|
// Sanity check.
|
|
//
|
|
ATLASSERT(FAILED(hr));
|
|
|
|
goto CommonExit;
|
|
}
|
|
|
|
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
|
|
Function : CChain::PutContext
|
|
|
|
Synopsis : Initialize the object.
|
|
|
|
Parameter: PCCERT_CHAIN_CONTEXT pChainContext - Chain context.
|
|
|
|
Remark : This method is not part of the COM interface (it is a normal C++
|
|
member function). We need it to initialize the object created
|
|
internally by us with CERT_CONTEXT.
|
|
|
|
Since it is only a normal C++ member function, this function can
|
|
only be called from a C++ class pointer, not an interface pointer.
|
|
|
|
------------------------------------------------------------------------------*/
|
|
|
|
STDMETHODIMP CChain::PutContext (PCCERT_CHAIN_CONTEXT pChainContext)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
PCCERT_CHAIN_CONTEXT pChainContext2 = NULL;
|
|
|
|
DebugTrace("Entering CChain::PutContext().\n");
|
|
|
|
//
|
|
// Sanity check.
|
|
//
|
|
ATLASSERT(pChainContext);
|
|
|
|
//
|
|
// Dupliacte the context.
|
|
//
|
|
if (!(pChainContext2 = ::CertDuplicateCertificateChain(pChainContext)))
|
|
{
|
|
hr = HRESULT_FROM_WIN32(::GetLastError());
|
|
|
|
DebugTrace("Error [%#x]: CertDuplicateCertificateChain() failed.\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
|
|
//
|
|
// Free ay previous chain context.
|
|
//
|
|
if (m_pChainContext)
|
|
{
|
|
::CertFreeCertificateChain(m_pChainContext);
|
|
}
|
|
|
|
//
|
|
// Update state.
|
|
//
|
|
m_pChainContext = pChainContext2;
|
|
m_dwStatus = pChainContext->TrustStatus.dwErrorStatus;
|
|
|
|
CommonExit:
|
|
|
|
DebugTrace("Leaving CChain::PutContext().\n");
|
|
|
|
return hr;
|
|
|
|
ErrorExit:
|
|
//
|
|
// Sanity check.
|
|
//
|
|
ATLASSERT(FAILED(hr));
|
|
|
|
goto CommonExit;
|
|
}
|