|
|
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
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; }
|