Leaked source code of windows server 2003
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.
 
 
 
 
 
 

3902 lines
96 KiB

/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Microsoft Windows, Copyright (C) Microsoft Corporation, 2000
File: Certificate.cpp
Content: Implementation of CCertificate.
History: 11-15-99 dsie created
------------------------------------------------------------------------------*/
#include "StdAfx.h"
#include "CAPICOM.h"
#include "Certificate.h"
#include "CertHlpr.h"
#include "Convert.h"
#include "Common.h"
#include "PFXHlpr.h"
#include "PrivateKey.h"
#include "Settings.h"
////////////////////////////////////////////////////////////////////////////////
//
// typedefs.
//
typedef BOOL (WINAPI * PCRYPTUIDLGVIEWCERTIFICATEW)
(IN PCCRYPTUI_VIEWCERTIFICATE_STRUCTW pCertViewInfo,
OUT BOOL *pfPropertiesChanged);
////////////////////////////////////////////////////////////////////////////////
//
// Exported functions.
//
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Function : CreateCertificateObject
Synopsis : Create an ICertificate object.
Parameter: PCCERT_CONTEXT pCertContext - Pointer to CERT_CONTEXT to be used
to initialize the ICertificate
object.
DWORD dwCurrentSafety - Current safety setting.
ICertificate2 ** ppICertificate - Pointer to pointer ICertificate
object.
Remark :
------------------------------------------------------------------------------*/
HRESULT CreateCertificateObject (PCCERT_CONTEXT pCertContext,
DWORD dwCurrentSafety,
ICertificate2 ** ppICertificate)
{
HRESULT hr = S_OK;
CComObject<CCertificate> * pCCertificate = NULL;
DebugTrace("Entering CreateCertificateObject().\n", hr);
//
// Sanity check.
//
ATLASSERT(pCertContext);
ATLASSERT(ppICertificate);
try
{
//
// Create the object. Note that the ref count will still be 0
// after the object is created.
//
if (FAILED(hr = CComObject<CCertificate>::CreateInstance(&pCCertificate)))
{
DebugTrace("Error [%#x]: CComObject<CCertificate>::CreateInstance() failed.\n", hr);
goto ErrorExit;
}
//
// Initialize object.
//
if (FAILED(hr = pCCertificate->PutContext(pCertContext, dwCurrentSafety)))
{
DebugTrace("Error [%#x]: pCCertificate->PutContext() failed.\n", hr);
goto ErrorExit;
}
//
// Return interface pointer to caller.
//
if (FAILED(hr = pCCertificate->QueryInterface(ppICertificate)))
{
DebugTrace("Error [%#x]: pCCertificate->QueryInterface() failed.\n", hr);
goto ErrorExit;
}
}
catch(...)
{
hr = E_POINTER;
DebugTrace("Exception: invalid parameter.\n");
goto ErrorExit;
}
CommonExit:
DebugTrace("Leaving CreateCertificateObject().\n");
return hr;
ErrorExit:
//
// Sanity check.
//
ATLASSERT(FAILED(hr));
if (pCCertificate)
{
delete pCCertificate;
}
goto CommonExit;
}
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Function : GetCertContext
Synopsis : Return the certificate's PCERT_CONTEXT.
Parameter: ICertificate * pICertificate - Pointer to ICertificate for which
the PCERT_CONTEXT is to be returned.
PCCERT_CONTEXT * ppCertContext - Pointer to PCERT_CONTEXT.
Remark :
------------------------------------------------------------------------------*/
HRESULT GetCertContext (ICertificate * pICertificate,
PCCERT_CONTEXT * ppCertContext)
{
HRESULT hr = S_OK;
CComPtr<ICertContext> pICertContext = NULL;
DebugTrace("Entering GetCertContext().\n");
//
// Sanity check.
//
ATLASSERT(pICertificate);
ATLASSERT(ppCertContext);
//
// Get ICCertificate interface pointer.
//
if (FAILED(hr = pICertificate->QueryInterface(IID_ICertContext, (void **) &pICertContext)))
{
DebugTrace("Error [%#x]: pICertificate->QueryInterface() failed.\n", hr);
goto ErrorExit;
}
//
// Get the CERT_CONTEXT.
//
if (FAILED(hr = pICertContext->get_CertContext((long *) ppCertContext)))
{
DebugTrace("Error [%#x]: pICertContext->get_CertContext() failed.\n", hr);
goto ErrorExit;
}
CommonExit:
DebugTrace("Leaving GetCertContext().\n");
return hr;
ErrorExit:
//
// Sanity check.
//
ATLASSERT(FAILED(hr));
goto CommonExit;
}
////////////////////////////////////////////////////////////////////////////////
//
// Local functions.
//
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Function : GetCertNameInfo
Synopsis : Return the name for the subject or issuer field.
Parameter: PCCERT_CONTEXT pCertContext - Pointer to CERT_CONTEXT.
DWORD dwNameType - 0 for subject name or CERT_NAME_ISSUER_FLAG
for issuer name.
DWORD dwDisplayType - Display type.
BSTR * pbstrName - Pointer to BSTR to receive resulting name
string.
Remark : It is the caller's responsibility to free the BSTR.
No checking of any of the flags is done, so be sure to call
with the right flags.
------------------------------------------------------------------------------*/
static HRESULT GetCertNameInfo (PCCERT_CONTEXT pCertContext,
DWORD dwNameType,
DWORD dwDisplayType,
BSTR * pbstrName)
{
HRESULT hr = S_OK;
DWORD cbNameLen = 0;
LPWSTR pwszName = NULL;
DWORD dwStrType = CERT_X500_NAME_STR | CERT_NAME_STR_REVERSE_FLAG;
DebugTrace("Entering GetCertNameInfo().\n");
//
// Sanity check.
//
ATLASSERT(pCertContext);
ATLASSERT(pbstrName);
//
// Get the length needed.
//
if (!(cbNameLen = ::CertGetNameStringW(pCertContext,
dwDisplayType,
dwNameType,
dwDisplayType == CERT_NAME_RDN_TYPE ? (LPVOID) &dwStrType : NULL,
NULL,
0)))
{
hr = HRESULT_FROM_WIN32(CRYPT_E_NOT_FOUND);
DebugTrace("Error [%#x]: CertGetNameStringW() failed.\n", hr);
goto ErrorExit;
}
//
// Create returned BSTR.
//
if (!(pwszName = (LPWSTR) ::CoTaskMemAlloc(cbNameLen * sizeof(WCHAR))))
{
hr = E_OUTOFMEMORY;
DebugTrace("Error: out of memory.\n");
goto ErrorExit;
}
//
// Now actually get the name string.
//
if (!::CertGetNameStringW(pCertContext,
dwDisplayType,
dwNameType,
dwDisplayType == CERT_NAME_RDN_TYPE ? (LPVOID) &dwStrType : NULL,
(LPWSTR) pwszName,
cbNameLen))
{
hr = HRESULT_FROM_WIN32(CRYPT_E_NOT_FOUND);
DebugTrace("Error [%#x]: CertGetNameStringW() failed.\n", hr);
goto ErrorExit;
}
//
// Return BSTR to caller.
//
if (!(*pbstrName = ::SysAllocString(pwszName)))
{
hr = E_OUTOFMEMORY;
DebugTrace("Error: out of memory.\n");
goto ErrorExit;
}
CommonExit:
//
// Free resource.
//
if (pwszName)
{
::CoTaskMemFree(pwszName);
}
DebugTrace("Leaving GetCertNameInfo().\n");
return hr;
ErrorExit:
//
// Sanity check.
//
ATLASSERT(FAILED(hr));
goto CommonExit;
}
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Function : CertToStore
Synopsis : Add the cert, optionally with the chain, to the store.
Parameter: PCCERT_CONTEXT pCertContext - Pointer to CERT_CONTEXT.
CAPICOM_CERTIFICATE_INCLUDE_OPTION IncludeOption - Include option.
HCERTSTORE hCertStore - Store to add to.
Remark :
------------------------------------------------------------------------------*/
static HRESULT CertToStore(PCCERT_CONTEXT pCertContext,
CAPICOM_CERTIFICATE_INCLUDE_OPTION IncludeOption,
HCERTSTORE hCertStore)
{
HRESULT hr = S_OK;
PCCERT_CHAIN_CONTEXT pChainContext = NULL;
DebugTrace("Entering CertToStore().\n");
//
// Sanity check.
//
ATLASSERT(pCertContext);
ATLASSERT(hCertStore);
//
// No need to build chain if only including end cert.
//
if (CAPICOM_CERTIFICATE_INCLUDE_END_ENTITY_ONLY == IncludeOption)
{
//
// Add the only cert to store.
//
if (!::CertAddCertificateContextToStore(hCertStore,
pCertContext,
CERT_STORE_ADD_REPLACE_EXISTING_INHERIT_PROPERTIES,
NULL))
{
hr = HRESULT_FROM_WIN32(::GetLastError());
DebugTrace("Error [%#x]: CertAddCertificateContextToStore() failed.\n", hr);
goto ErrorExit;
}
}
else
{
DWORD i;
BOOL bAddRoot;
CERT_CHAIN_PARA ChainPara = {0};
//
// Initialize.
//
ChainPara.cbSize = sizeof(ChainPara);
switch (IncludeOption)
{
case CAPICOM_CERTIFICATE_INCLUDE_WHOLE_CHAIN:
{
bAddRoot = TRUE;
break;
}
case CAPICOM_CERTIFICATE_INCLUDE_CHAIN_EXCEPT_ROOT:
//
// Fall thru to default.
//
default:
{
bAddRoot = FALSE;
break;
}
}
//
// Build the chain.
//
if (!::CertGetCertificateChain(NULL,
pCertContext,
NULL,
NULL,
&ChainPara,
0,
NULL,
&pChainContext))
{
hr = HRESULT_FROM_WIN32(::GetLastError());
DebugTrace("Error [%#x]: CertGetCertificateChain() failed.\n", hr);
goto ErrorExit;
}
//
// Sanity check.
//
ATLASSERT(pChainContext->cChain);
//
// Now add the chain to store and skip root cert if requested.
//
for (i = 0; i < pChainContext->rgpChain[0]->cElement; i++)
{
//
// Skip the root cert, if requested.
//
if (!bAddRoot &&
(pChainContext->rgpChain[0]->rgpElement[i]->TrustStatus.dwInfoStatus & CERT_TRUST_IS_SELF_SIGNED))
{
continue;
}
//
// Add to store.
//
if (!::CertAddCertificateContextToStore(hCertStore,
pChainContext->rgpChain[0]->rgpElement[i]->pCertContext,
CERT_STORE_ADD_REPLACE_EXISTING_INHERIT_PROPERTIES,
NULL))
{
hr = HRESULT_FROM_WIN32(::GetLastError());
DebugTrace("Error [%#x]: CertAddCertificateContextToStore() failed.\n", hr);
goto ErrorExit;
}
}
}
CommonExit:
//
// Free resource.
//
if (pChainContext)
{
::CertFreeCertificateChain(pChainContext);
}
DebugTrace("Leaving CertToStore().\n");
return hr;
ErrorExit:
//
// Sanity check.
//
ATLASSERT(FAILED(hr));
goto CommonExit;
}
////////////////////////////////////////////////////////////////////////////////
//
// CCertificate
//
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Function : CCertificate::get_Version
Synopsis : Return the cert version number.
Parameter: long * pVersion - Pointer to long to receive version number.
Remark : The returned value is 1 for V1, 2 for V2, 3 for V3, and so on.
------------------------------------------------------------------------------*/
STDMETHODIMP CCertificate::get_Version (long * pVal)
{
HRESULT hr = S_OK;
DebugTrace("Entering CCertificate::get_Version().\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 cert is already initialized.
//
if (!m_pCertContext)
{
hr = CAPICOM_E_CERTIFICATE_NOT_INITIALIZED;
DebugTrace("Error [%#x]: Certificate object has not been initalized.\n", hr);
goto ErrorExit;
}
*pVal = (long) m_pCertContext->pCertInfo->dwVersion + 1;
}
catch(...)
{
hr = E_POINTER;
DebugTrace("Exception: invalid parameter.\n");
goto ErrorExit;
}
UnlockExit:
//
// Unlock access to this object.
//
m_Lock.Unlock();
DebugTrace("Leaving CCertificate::get_Version().\n");
return hr;
ErrorExit:
//
// Sanity check.
//
ATLASSERT(FAILED(hr));
ReportError(hr);
goto UnlockExit;
}
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Function : CCertificate::get_SerialNumber
Synopsis : Return the Serial Number field as HEX string in BSTR.
Parameter: BSTR * pVal - Pointer to BSTR to receive the serial number.
Remark : Upper case 'A' - 'F' is used for the returned HEX string with
no embeded space (i.e. 46A2FC01).
------------------------------------------------------------------------------*/
STDMETHODIMP CCertificate::get_SerialNumber (BSTR * pVal)
{
HRESULT hr = S_OK;
DebugTrace("Entering CCertificate::get_SerialNumber().\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 cert is already initialized.
//
if (!m_pCertContext)
{
hr = CAPICOM_E_CERTIFICATE_NOT_INITIALIZED;
DebugTrace("Error [%#x]: object does not represent an initialized certificate.\n", hr);
goto ErrorExit;
}
//
// Convert integer blob to BSTR.
//
if (FAILED(hr = ::IntBlobToHexString(&m_pCertContext->pCertInfo->SerialNumber, pVal)))
{
DebugTrace("Error [%#x]: IntBlobToHexString() 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 CCertificate::get_SerialNumber().\n");
return hr;
ErrorExit:
//
// Sanity check.
//
ATLASSERT(FAILED(hr));
ReportError(hr);
goto UnlockExit;
}
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Function : CCertificate::get_SubjectName
Synopsis : Return the Subject field.
Parameter: BSTR * pVal - Pointer to BSTR to receive the subject's name.
Remark : This method returns the full DN in the SubjectName field in the
form of "CN = Daniel Sie OU = Outlook O = Microsoft L = Redmond
S = WA C = US"
The returned name has the same format as specifying
CERT_NAME_RDN_TYPE for the CertGetNameString() API..
------------------------------------------------------------------------------*/
STDMETHODIMP CCertificate::get_SubjectName (BSTR * pVal)
{
HRESULT hr = S_OK;
DebugTrace("Entering CCertificate::get_SubjectName().\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 cert is already initialized.
//
if (!m_pCertContext)
{
hr = CAPICOM_E_CERTIFICATE_NOT_INITIALIZED;
DebugTrace("Error [%#x]: object does not represent an initialized certificate.\n", hr);
goto ErrorExit;
}
//
// Return requested name string.
//
if (FAILED(hr = ::GetCertNameInfo(m_pCertContext,
0,
CERT_NAME_RDN_TYPE,
pVal)))
{
DebugTrace("Error [%#x]: GetCertNameInfo() 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 CCertificate::get_SubjectName().\n");
return hr;
ErrorExit:
//
// Sanity check.
//
ATLASSERT(FAILED(hr));
ReportError(hr);
goto UnlockExit;
}
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Function : CCertificate::get_IssuerName
Synopsis : Return the Issuer field.
Parameter: BSTR * pVal - Pointer to BSTR to receive the issuer's name.
Remark : This method returns the full DN in the IssuerName field in the
form of "CN = Daniel Sie OU = Outlook O = Microsoft L = Redmond
S = WA C = US"
The returned name has the same format as specifying
CERT_NAME_RDN_TYPE for the CertGetNameString() API.
------------------------------------------------------------------------------*/
STDMETHODIMP CCertificate::get_IssuerName (BSTR * pVal)
{
HRESULT hr = S_OK;
DebugTrace("Entering CCertificate::get_IssuerName().\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 cert is already initialized.
//
if (!m_pCertContext)
{
hr = CAPICOM_E_CERTIFICATE_NOT_INITIALIZED;
DebugTrace("Error [%#x]: object does not represent an initialized certificate.\n", hr);
goto ErrorExit;
}
//
// Return requested name string.
//
if (FAILED(hr = ::GetCertNameInfo(m_pCertContext,
CERT_NAME_ISSUER_FLAG,
CERT_NAME_RDN_TYPE,
pVal)))
{
DebugTrace("Error [%#x]: GetCertNameInfo() 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 CCertificate::get_IssuerName().\n");
return hr;
ErrorExit:
//
// Sanity check.
//
ATLASSERT(FAILED(hr));
ReportError(hr);
goto UnlockExit;
}
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Function : CCertificate::get_ValidFromDate
Synopsis : Return the NotBefore field.
Parameter: DATE * pDate - Pointer to DATE to receive the valid from date.
Remark :
------------------------------------------------------------------------------*/
STDMETHODIMP CCertificate::get_ValidFromDate (DATE * pVal)
{
HRESULT hr = S_OK;
FILETIME ftLocal;
SYSTEMTIME stLocal;
DebugTrace("Entering CCertificate::get_ValidFromDate().\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 cert is already initialized.
//
if (!m_pCertContext)
{
hr = CAPICOM_E_CERTIFICATE_NOT_INITIALIZED;
DebugTrace("Error [%#x]: object does not represent an initialized certificate.\n", hr);
goto ErrorExit;
}
//
// Convert to local time.
//
if (!(::FileTimeToLocalFileTime(&m_pCertContext->pCertInfo->NotBefore, &ftLocal) &&
::FileTimeToSystemTime(&ftLocal, &stLocal) &&
::SystemTimeToVariantTime(&stLocal, pVal)))
{
hr = HRESULT_FROM_WIN32(::GetLastError());
DebugTrace("Error [%#x]: unable to convert FILETIME to DATE.\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 CCertificate::get_ValidFromDate().\n");
return hr;
ErrorExit:
//
// Sanity check.
//
ATLASSERT(FAILED(hr));
ReportError(hr);
goto UnlockExit;
}
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Function : CCertificate::get_ValidToDate
Synopsis : Return the NotAfter field.
Parameter: DATE * pDate - Pointer to DATE to receive valid to date.
Remark :
------------------------------------------------------------------------------*/
STDMETHODIMP CCertificate::get_ValidToDate (DATE * pVal)
{
HRESULT hr = S_OK;
FILETIME ftLocal;
SYSTEMTIME stLocal;
DebugTrace("Entering CCertificate::get_ValidToDate().\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 cert is already initialized.
//
if (!m_pCertContext)
{
hr = CAPICOM_E_CERTIFICATE_NOT_INITIALIZED;
DebugTrace("Error [%#x]: object does not represent an initialized certificate.\n", hr);
goto ErrorExit;
}
//
// Convert to local time.
//
if (!(::FileTimeToLocalFileTime(&m_pCertContext->pCertInfo->NotAfter, &ftLocal) &&
::FileTimeToSystemTime(&ftLocal, &stLocal) &&
::SystemTimeToVariantTime(&stLocal, pVal)))
{
hr = HRESULT_FROM_WIN32(::GetLastError());
DebugTrace("Error [%#x]: unable to convert FILETIME to DATE.\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 CCertificate::get_ValidToDate().\n");
return hr;
ErrorExit:
//
// Sanity check.
//
ATLASSERT(FAILED(hr));
ReportError(hr);
goto UnlockExit;
}
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Function : CCertificate::get_Thumbprint
Synopsis : Return the SHA1 hash as HEX string.
Parameter: BSTR * pVal - Pointer to BSTR to receive hash.
Remark :
------------------------------------------------------------------------------*/
STDMETHODIMP CCertificate::get_Thumbprint (BSTR * pVal)
{
HRESULT hr = S_OK;
BYTE * pbHash = NULL;
DWORD cbHash = 0;
DebugTrace("Entering CCertificate::get_Thumbprint().\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 cert is already initialized.
//
if (!m_pCertContext)
{
hr = CAPICOM_E_CERTIFICATE_NOT_INITIALIZED;
DebugTrace("Error [%#x]: object does not represent an initialized certificate.\n", hr);
goto ErrorExit;
}
//
// Calculate length needed.
//
if (!::CertGetCertificateContextProperty(m_pCertContext,
CERT_SHA1_HASH_PROP_ID,
NULL,
&cbHash))
{
hr = HRESULT_FROM_WIN32(::GetLastError());
DebugTrace("Error [%#x]: CertGetCertificateContextProperty() failed.\n", hr);
goto ErrorExit;
}
//
// Allocate memory.
//
if (!(pbHash = (BYTE *) ::CoTaskMemAlloc(cbHash)))
{
hr = E_OUTOFMEMORY;
DebugTrace("Error: out of memory.\n");
goto ErrorExit;
}
//
// Now get the hash.
//
if (!::CertGetCertificateContextProperty(m_pCertContext,
CERT_SHA1_HASH_PROP_ID,
(LPVOID) pbHash,
&cbHash))
{
hr = HRESULT_FROM_WIN32(GetLastError());
DebugTrace("Error [%#x]: CertGetCertificateContextProperty() failed.\n", hr);
goto ErrorExit;
}
//
// Conver to HEX BSTR.
//
if (FAILED(hr = ::BinaryToHexString(pbHash, cbHash, pVal)))
{
DebugTrace("Error [%#x]: BinaryToHexString() failed.\n", hr);
goto ErrorExit;
}
}
catch(...)
{
hr = E_POINTER;
DebugTrace("Exception: invalid parameter.\n");
goto ErrorExit;
}
UnlockExit:
//
// Free resource.
//
if (pbHash)
{
::CoTaskMemFree((LPVOID) pbHash);
}
//
// Unlock access to this object.
//
m_Lock.Unlock();
DebugTrace("Leaving CCertificate::get_Thumbprint().\n");
return hr;
ErrorExit:
//
// Sanity check.
//
ATLASSERT(FAILED(hr));
ReportError(hr);
goto UnlockExit;
}
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Function : CCertificate::HasPrivateKey
Synopsis : Check to see if the cert has the associated private key.
Parameter: VARIANT_BOOL * pVal - Pointer to BOOL to receive result.
Remark :
------------------------------------------------------------------------------*/
STDMETHODIMP CCertificate::HasPrivateKey (VARIANT_BOOL * pVal)
{
HRESULT hr = S_OK;
DWORD cb = 0;
DebugTrace("Entering CCertificate::HasPrivateKey().\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 cert is already initialized.
//
if (!m_pCertContext)
{
hr = CAPICOM_E_CERTIFICATE_NOT_INITIALIZED;
DebugTrace("Error [%#x]: object does not represent an initialized certificate.\n", hr);
goto ErrorExit;
}
//
// Return result.
//
*pVal = ::CertGetCertificateContextProperty(m_pCertContext,
CERT_KEY_PROV_INFO_PROP_ID,
NULL,
&cb) ? VARIANT_TRUE : VARIANT_FALSE;
}
catch(...)
{
hr = E_POINTER;
DebugTrace("Exception: invalid parameter.\n");
goto ErrorExit;
}
UnlockExit:
//
// Unlock access to this object.
//
m_Lock.Unlock();
DebugTrace("Leaving CCertificate::HasPrivateKey().\n");
return hr;
ErrorExit:
//
// Sanity check.
//
ATLASSERT(FAILED(hr));
ReportError(hr);
goto UnlockExit;
}
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Function : CCertificate::GetInfo
Synopsis : Get other simple info from the certificate.
Parameter: CAPICOM_CERT_INFO_TYPE InfoType - Info type
BSTR * pVal - Pointer to BSTR to receive the result.
Remark : Note that an empty string "" is returned if the requested info is
not available in the certificate.
------------------------------------------------------------------------------*/
STDMETHODIMP CCertificate::GetInfo (CAPICOM_CERT_INFO_TYPE InfoType,
BSTR * pVal)
{
HRESULT hr = S_OK;
DWORD dwFlags = 0;
DWORD dwDisplayType = 0;
DebugTrace("Entering CCertificate::GetInfo().\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 cert is already initialized.
//
if (!m_pCertContext)
{
hr = CAPICOM_E_CERTIFICATE_NOT_INITIALIZED;
DebugTrace("Error [%#x]: object does not represent an initialized certificate.\n", hr);
goto ErrorExit;
}
//
// Process request.
//
switch (InfoType)
{
case CAPICOM_CERT_INFO_ISSUER_SIMPLE_NAME:
{
dwFlags = CERT_NAME_ISSUER_FLAG;
//
// Warning: dropping thru.
//
}
case CAPICOM_CERT_INFO_SUBJECT_SIMPLE_NAME:
{
//
// Get requested simple name string.
//
dwDisplayType = CERT_NAME_SIMPLE_DISPLAY_TYPE;
break;
}
case CAPICOM_CERT_INFO_ISSUER_EMAIL_NAME:
{
dwFlags = CERT_NAME_ISSUER_FLAG;
//
// Warning: dropping thru.
//
}
case CAPICOM_CERT_INFO_SUBJECT_EMAIL_NAME:
{
//
// Get requested email name string.
//
dwDisplayType = CERT_NAME_EMAIL_TYPE;
break;
}
case CAPICOM_CERT_INFO_ISSUER_UPN:
{
dwFlags = CERT_NAME_ISSUER_FLAG;
//
// Warning: dropping thru.
//
}
case CAPICOM_CERT_INFO_SUBJECT_UPN:
{
//
// Get requested UPN name string.
//
dwDisplayType = CERT_NAME_UPN_TYPE;
break;
}
case CAPICOM_CERT_INFO_ISSUER_DNS_NAME:
{
dwFlags = CERT_NAME_ISSUER_FLAG;
//
// Warning: dropping thru.
//
}
case CAPICOM_CERT_INFO_SUBJECT_DNS_NAME:
{
//
// Get requested DNS name string.
//
dwDisplayType = CERT_NAME_DNS_TYPE;
break;
}
default:
{
hr = E_INVALIDARG;
DebugTrace("Error [%#x]: Unknown cert info type (%#x).\n", hr, InfoType);
goto ErrorExit;
}
}
if (FAILED(hr = ::GetCertNameInfo(m_pCertContext,
dwFlags,
dwDisplayType,
pVal)))
{
DebugTrace("Error [%#x]: GetCertNameInfo() failed for display type = %d.\n", hr, dwDisplayType);
goto ErrorExit;
}
}
catch(...)
{
hr = E_POINTER;
DebugTrace("Exception: invalid parameter.\n");
goto ErrorExit;
}
UnlockExit:
//
// Unlock access to this object.
//
m_Lock.Unlock();
DebugTrace("Leaving CCertificate::GetInfo().\n");
return hr;
ErrorExit:
//
// Sanity check.
//
ATLASSERT(FAILED(hr));
ReportError(hr);
goto UnlockExit;
}
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Function : CCertificate::IsValid
Synopsis : Return an ICertificateStatus object for certificate validity check.
Parameter: ICertificateStatus ** pVal - Pointer to pointer to
ICertificateStatus object to receive
the interface pointer.
Remark :
------------------------------------------------------------------------------*/
STDMETHODIMP CCertificate::IsValid (ICertificateStatus ** pVal)
{
HRESULT hr = S_OK;
DebugTrace("Entering CCertificate::IsValid().\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 cert is already initialized.
//
if (!m_pCertContext)
{
hr = CAPICOM_E_CERTIFICATE_NOT_INITIALIZED;
DebugTrace("Error [%#x]: object does not represent an initialized certificate.\n", hr);
goto ErrorExit;
}
//
// Create the embeded ICertificateStatus object, if not already done so.
//
if (!m_pICertificateStatus)
{
if (FAILED(hr = ::CreateCertificateStatusObject(m_pCertContext, &m_pICertificateStatus)))
{
DebugTrace("Error [%#x]: CreateCertificateStatusObject() failed.\n", hr);
goto ErrorExit;
}
}
//
// Sanity check.
//
ATLASSERT(m_pICertificateStatus);
//
// Return interface pointer to user.
//
if (FAILED(hr = m_pICertificateStatus->QueryInterface(pVal)))
{
DebugTrace("Error [%#x]: m_pICertificateStatus->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 CCertificate::IsValid().\n");
return hr;
ErrorExit:
//
// Sanity check.
//
ATLASSERT(FAILED(hr));
ReportError(hr);
goto UnlockExit;
}
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Function : CCertificate::KeyUsage
Synopsis : Return the Key Usage extension as an IKeyUsage object.
Parameter: IKeyUsage ** pVal - Pointer to pointer to IKeyUsage to receive the
interface pointer.
Remark :
------------------------------------------------------------------------------*/
STDMETHODIMP CCertificate::KeyUsage (IKeyUsage ** pVal)
{
HRESULT hr = S_OK;
DebugTrace("Entering CCertificate::KeyUsage().\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 cert is already initialized.
//
if (!m_pCertContext)
{
hr = CAPICOM_E_CERTIFICATE_NOT_INITIALIZED;
DebugTrace("Error [%#x]: object does not represent an initialized certificate.\n", hr);
goto ErrorExit;
}
//
// Create the embeded IKeyUsage object, if not already done so.
//
if (!m_pIKeyUsage)
{
if (FAILED(hr = ::CreateKeyUsageObject(m_pCertContext, &m_pIKeyUsage)))
{
DebugTrace("Error [%#x]: CreateKeyUsageObject() failed.\n", hr);
goto ErrorExit;
}
}
//
// Sanity check.
//
ATLASSERT(m_pIKeyUsage);
//
// Return interface pointer to user.
//
if (FAILED(hr = m_pIKeyUsage->QueryInterface(pVal)))
{
DebugTrace("Error [%#x]: m_pIKeyUsage->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 CCertificate::KeyUsage().\n");
return hr;
ErrorExit:
//
// Sanity check.
//
ATLASSERT(FAILED(hr));
ReportError(hr);
goto UnlockExit;
}
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Function : CCertificate::ExtendedKeyUsage
Synopsis : Return the EKU extension as an IExtendedKeyUsage object.
Parameter: IExtendedKeyUsage ** pVal - Pointer to pointer to IExtendedKeyUsage
to receive the interface pointer.
Remark :
------------------------------------------------------------------------------*/
STDMETHODIMP CCertificate::ExtendedKeyUsage (IExtendedKeyUsage ** pVal)
{
HRESULT hr = S_OK;
DebugTrace("Entering CCertificate::ExtendedKeyUsage().\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 cert is already initialized.
//
if (!m_pCertContext)
{
hr = CAPICOM_E_CERTIFICATE_NOT_INITIALIZED;
DebugTrace("Error [%#x]: object does not represent an initialized certificate.\n", hr);
goto ErrorExit;
}
//
// Create the embeded IExtendedKeyUsage object, if not already done so.
//
if (!m_pIExtendedKeyUsage)
{
if (FAILED(hr = ::CreateExtendedKeyUsageObject(m_pCertContext, &m_pIExtendedKeyUsage)))
{
DebugTrace("Error [%#x]: CreateExtendedKeyUsageObject() failed.\n", hr);
goto ErrorExit;
}
}
//
// Sanity check.
//
ATLASSERT(m_pIExtendedKeyUsage);
//
// Return interface pointer to user.
//
if (FAILED(hr = m_pIExtendedKeyUsage->QueryInterface(pVal)))
{
DebugTrace("Error [%#x]: m_pIExtendedKeyUsage->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 CCertificate::ExtendedKeyUsage().\n");
return hr;
ErrorExit:
//
// Sanity check.
//
ATLASSERT(FAILED(hr));
ReportError(hr);
goto UnlockExit;
}
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Function : CCertificate::BasicConstraints
Synopsis : Return the BasicConstraints extension as an IBasicConstraints
object.
Parameter: IBasicConstraints ** pVal - Pointer to pointer to IBasicConstraints
to receive the interface pointer.
Remark :
------------------------------------------------------------------------------*/
STDMETHODIMP CCertificate::BasicConstraints (IBasicConstraints ** pVal)
{
HRESULT hr = S_OK;
DebugTrace("Entering CCertificate::BasicConstraints().\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 cert is already initialized.
//
if (!m_pCertContext)
{
hr = CAPICOM_E_CERTIFICATE_NOT_INITIALIZED;
DebugTrace("Error [%#x]: object does not represent an initialized certificate.\n", hr);
goto ErrorExit;
}
//
// Create the embeded IBasicConstraints object, if not already done so.
//
if (!m_pIBasicConstraints)
{
if (FAILED(hr = ::CreateBasicConstraintsObject(m_pCertContext, &m_pIBasicConstraints)))
{
DebugTrace("Error [%#x]: CreateBasicConstraintsObject() failed.\n", hr);
goto ErrorExit;
}
}
//
// Sanity check.
//
ATLASSERT(m_pIBasicConstraints);
//
// Return interface pointer to user.
//
if (FAILED(hr = m_pIBasicConstraints->QueryInterface(pVal)))
{
DebugTrace("Error [%#x]: m_pIBasicConstraints->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 CCertificate::BasicConstraints().\n");
return hr;
ErrorExit:
//
// Sanity check.
//
ATLASSERT(FAILED(hr));
ReportError(hr);
goto UnlockExit;
}
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Function : CCertificate::Export
Synopsis : Export the certificate.
Parameter: CAPICOM_ENCODING_TYPE EncodingType - Encoding type.
BSTR * pVal - Pointer to BSTR to receive the certificate blob.
Remark :
------------------------------------------------------------------------------*/
STDMETHODIMP CCertificate::Export (CAPICOM_ENCODING_TYPE EncodingType,
BSTR * pVal)
{
HRESULT hr = S_OK;
DATA_BLOB CertBlob = {0, NULL};
DebugTrace("Entering CCertificate::Export().\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 cert is already initialized.
//
if (!m_pCertContext)
{
hr = CAPICOM_E_CERTIFICATE_NOT_INITIALIZED;
DebugTrace("Error [%#x]: object does not represent an initialized certificate.\n", hr);
goto ErrorExit;
}
//
// Determine encoding type.
//
CertBlob.cbData = m_pCertContext->cbCertEncoded;
CertBlob.pbData = m_pCertContext->pbCertEncoded;
//
// Export certificate.
//
if (FAILED(hr = ::ExportData(CertBlob, EncodingType, pVal)))
{
DebugTrace("Error [%#x]: ExportData() 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 CCertificate::Export().\n");
return hr;
ErrorExit:
//
// Sanity check.
//
ATLASSERT(FAILED(hr));
ReportError(hr);
goto UnlockExit;
}
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Function : CCertificate::Import
Synopsis : Imoprt a certificate.
Parameter: BSTR EncodedCertificate - BSTR containing the encoded certificate
blob.
Remark :
------------------------------------------------------------------------------*/
STDMETHODIMP CCertificate::Import (BSTR EncodedCertificate)
{
HRESULT hr = S_OK;
DATA_BLOB CertBlob = {0, NULL};
DebugTrace("Entering CCertificate::Import().\n");
try
{
//
// Lock access to this object.
//
m_Lock.Lock();
//
// Make sure parameter is valid.
//
if ((NULL == (CertBlob.pbData = (LPBYTE) EncodedCertificate)) ||
(0 == (CertBlob.cbData = ::SysStringByteLen(EncodedCertificate))))
{
hr = E_INVALIDARG;
DebugTrace("Error [%#x]: EncodedCertificate = %#x, SysStringByteLen(EncodedCertificate) = %d.\n",
hr, EncodedCertificate, EncodedCertificate);
goto ErrorExit;
}
//
// Now import the blob.
//
if (FAILED(hr = ImportBlob(&CertBlob,
FALSE,
(CAPICOM_KEY_LOCATION) 0,
NULL,
(CAPICOM_KEY_STORAGE_FLAG) 0)))
{
DebugTrace("Error [%#x]: CCertificate::ImportBlob() 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("Entering CCertificate::Import().\n");
return hr;
ErrorExit:
//
// Sanity check.
//
ATLASSERT(FAILED(hr));
ReportError(hr);
goto UnlockExit;
}
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Function : CCertificate::Display
Synopsis : Display the certificate using CryptUIDlgViewCertificateW() API.
Parameter: None
Remark :
------------------------------------------------------------------------------*/
STDMETHODIMP CCertificate::Display()
{
HRESULT hr = S_OK;
HINSTANCE hDLL = NULL;
PCRYPTUIDLGVIEWCERTIFICATEW pCryptUIDlgViewCertificateW = NULL;
CRYPTUI_VIEWCERTIFICATE_STRUCTW ViewInfo;
DebugTrace("Entering CCertificate::Display().\n");
//
// Lock access to this object.
//
m_Lock.Lock();
//
// Make sure cert is already initialized.
//
if (!m_pCertContext)
{
hr = CAPICOM_E_CERTIFICATE_NOT_INITIALIZED;
DebugTrace("Error [%#x]: object does not represent an initialized certificate.\n", hr);
goto ErrorExit;
}
//
// Get pointer to CryptUIDlgViewCertificateW().
//
if (hDLL = ::LoadLibrary("CryptUI.dll"))
{
pCryptUIDlgViewCertificateW = (PCRYPTUIDLGVIEWCERTIFICATEW) ::GetProcAddress(hDLL, "CryptUIDlgViewCertificateW");
}
//
// Is CryptUIDlgViewCertificateW() available?
//
if (!pCryptUIDlgViewCertificateW)
{
hr = CAPICOM_E_NOT_SUPPORTED;
DebugTrace("Error: CryptUIDlgViewCertificateW() API not available.\n");
goto ErrorExit;
}
//
// Initialize view structure.
//
::ZeroMemory((void *) &ViewInfo, sizeof(ViewInfo));
ViewInfo.dwSize = sizeof(ViewInfo);
ViewInfo.pCertContext = m_pCertContext;
//
// View it.
//
if (!pCryptUIDlgViewCertificateW(&ViewInfo, 0))
{
//
// CryptUIDlgViewCertificateW() returns ERROR_CANCELLED if user closed
// the window through the x button!!!
//
DWORD dwWinError = ::GetLastError();
if (ERROR_CANCELLED != dwWinError)
{
hr = HRESULT_FROM_WIN32(dwWinError);
DebugTrace("Error [%#x]: CryptUIDlgViewCertificateW() failed.\n", hr);
goto ErrorExit;
}
}
UnlockExit:
//
// Release resources.
//
if (hDLL)
{
::FreeLibrary(hDLL);
}
//
// Unlock access to this object.
//
m_Lock.Unlock();
DebugTrace("Leaving CCertificate::Display().\n");
return hr;
ErrorExit:
//
// Sanity check.
//
ATLASSERT(FAILED(hr));
ReportError(hr);
goto UnlockExit;
}
////////////////////////////////////////////////////////////////////////////////
//
// Certificate2
//
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Function : CCertificate::get_Archived
Synopsis : Return the archived status.
Parameter: VARIANT_BOOL * pVal - Pointer to BOOL to receive result.
Remark :
------------------------------------------------------------------------------*/
STDMETHODIMP CCertificate::get_Archived (VARIANT_BOOL * pVal)
{
HRESULT hr = S_OK;
DWORD cb = 0;
DebugTrace("Entering CCertificate::get_Archived().\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 cert is already initialized.
//
if (!m_pCertContext)
{
hr = CAPICOM_E_CERTIFICATE_NOT_INITIALIZED;
DebugTrace("Error [%#x]: object does not represent an initialized certificate.\n", hr);
goto ErrorExit;
}
//
// Return result.
//
*pVal = ::CertGetCertificateContextProperty(m_pCertContext,
CERT_ARCHIVED_PROP_ID,
NULL,
&cb) ? VARIANT_TRUE : VARIANT_FALSE;
}
catch(...)
{
hr = E_POINTER;
DebugTrace("Exception: invalid parameter.\n");
goto ErrorExit;
}
UnlockExit:
//
// Unlock access to this object.
//
m_Lock.Unlock();
DebugTrace("Leaving CCertificate::get_Archived().\n");
return hr;
ErrorExit:
//
// Sanity check.
//
ATLASSERT(FAILED(hr));
ReportError(hr);
goto UnlockExit;
}
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Function : CCertificate::put_Archived
Synopsis : Set the archived status.
Parameter: VARIANT_BOOL newVal - Pointer to BOOL to receive result.
Remark :
------------------------------------------------------------------------------*/
STDMETHODIMP CCertificate::put_Archived (VARIANT_BOOL newVal)
{
HRESULT hr = S_OK;
LPVOID pvData = NULL;
DATA_BLOB DataBlob = {0, NULL};
DebugTrace("Entering CCertificate::put_Archived().\n");
try
{
//
// Lock access to this object.
//
m_Lock.Lock();
//
// Make sure cert is already initialized.
//
if (!m_pCertContext)
{
hr = CAPICOM_E_CERTIFICATE_NOT_INITIALIZED;
DebugTrace("Error [%#x]: object does not represent an initialized certificate.\n", hr);
goto ErrorExit;
}
//
// Not allowed if called from WEB script.
//
if (m_dwCurrentSafety)
{
hr = CAPICOM_E_NOT_ALLOWED;
DebugTrace("Error [%#x]: Changing archived bit from within WEB script is not allowed.\n", hr);
goto ErrorExit;
}
//
// Set/Reset archive property.
//
if (newVal)
{
pvData = (LPVOID) &DataBlob;
}
if (!::CertSetCertificateContextProperty(m_pCertContext,
CERT_ARCHIVED_PROP_ID,
0,
pvData))
{
hr = HRESULT_FROM_WIN32(::GetLastError());
DebugTrace("Error [%#x]: CertSetCertificateContextProperty() 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 CCertificate::put_Archived().\n");
return hr;
ErrorExit:
//
// Sanity check.
//
ATLASSERT(FAILED(hr));
ReportError(hr);
goto UnlockExit;
}
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Function : CCertificate::Template
Synopsis : Return the ITemplate object.
Parameter: ITemplate ** pVal - Pointer to pointer to ITemplate
to receive the interface pointer.
Remark :
------------------------------------------------------------------------------*/
STDMETHODIMP CCertificate::Template (ITemplate ** pVal)
{
HRESULT hr = S_OK;
DebugTrace("Entering CCertificate::Template().\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 cert is already initialized.
//
if (!m_pCertContext)
{
hr = CAPICOM_E_CERTIFICATE_NOT_INITIALIZED;
DebugTrace("Error [%#x]: object does not represent an initialized certificate.\n", hr);
goto ErrorExit;
}
//
// Create the embeded ITemplate object, if not already done so.
//
if (!m_pITemplate)
{
if (FAILED(hr = ::CreateTemplateObject(m_pCertContext, &m_pITemplate)))
{
DebugTrace("Error [%#x]: CreateTemplateObject() failed.\n", hr);
goto ErrorExit;
}
}
//
// Sanity check.
//
ATLASSERT(m_pITemplate);
//
// Return interface pointer to user.
//
if (FAILED(hr = m_pITemplate->QueryInterface(pVal)))
{
DebugTrace("Error [%#x]: m_pITemplate->QueryInterface() failed.\n", hr);
goto ErrorExit;
}
ATLASSERT(*pVal);
DebugTrace("Info: ITemplate vtable value = %#x\n", (PVOID) *pVal);
}
catch(...)
{
hr = E_POINTER;
DebugTrace("Exception: invalid parameter.\n");
goto ErrorExit;
}
UnlockExit:
//
// Unlock access to this object.
//
m_Lock.Unlock();
DebugTrace("Leaving CCertificate::Template().\n");
return hr;
ErrorExit:
//
// Sanity check.
//
ATLASSERT(FAILED(hr));
ReportError(hr);
goto UnlockExit;
}
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Function : CCertificate::PublicKey
Synopsis : Return the IPublicKey object.
Parameter: IPublicKey ** pVal - Pointer to pointer to IPublicKey
to receive the interface pointer.
Remark :
------------------------------------------------------------------------------*/
STDMETHODIMP CCertificate::PublicKey (IPublicKey ** pVal)
{
HRESULT hr = S_OK;
DebugTrace("Entering CCertificate::PublicKey().\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 cert is already initialized.
//
if (!m_pCertContext)
{
hr = CAPICOM_E_CERTIFICATE_NOT_INITIALIZED;
DebugTrace("Error [%#x]: object does not represent an initialized certificate.\n", hr);
goto ErrorExit;
}
//
// Create the embeded IPublicKey object, if not already done so.
//
if (!m_pIPublicKey)
{
if (FAILED(hr = ::CreatePublicKeyObject(m_pCertContext, &m_pIPublicKey)))
{
DebugTrace("Error [%#x]: CreatePublicKeybject() failed.\n", hr);
goto ErrorExit;
}
}
//
// Sanity check.
//
ATLASSERT(m_pIPublicKey);
//
// Return interface pointer to user.
//
if (FAILED(hr = m_pIPublicKey->QueryInterface(pVal)))
{
DebugTrace("Error [%#x]: m_pIPublicKey->QueryInterface() failed.\n", hr);
goto ErrorExit;
}
ATLASSERT(*pVal);
DebugTrace("Info: IPublicKey vtable value = %#x\n", (PVOID) *pVal);
}
catch(...)
{
hr = E_POINTER;
DebugTrace("Exception: invalid parameter.\n");
goto ErrorExit;
}
UnlockExit:
//
// Unlock access to this object.
//
m_Lock.Unlock();
DebugTrace("Leaving CCertificate::PublicKey().\n");
return hr;
ErrorExit:
//
// Sanity check.
//
ATLASSERT(FAILED(hr));
ReportError(hr);
goto UnlockExit;
}
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Function : CCertificate::get_PrivateKey
Synopsis : Return the IPrivateKey object.
Parameter: IPrivateKey ** pVal - Pointer to pointer to IPrivateKey
to receive the interface pointer.
Remark :
------------------------------------------------------------------------------*/
STDMETHODIMP CCertificate::get_PrivateKey (IPrivateKey ** pVal)
{
HRESULT hr = S_OK;
CComPtr<IPrivateKey> pIPrivateKey = NULL;
DebugTrace("Entering CCertificate::get_PrivateKey().\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 cert is already initialized.
//
if (!m_pCertContext)
{
hr = CAPICOM_E_CERTIFICATE_NOT_INITIALIZED;
DebugTrace("Error [%#x]: object does not represent an initialized certificate.\n", hr);
goto ErrorExit;
}
//
// Create the object on the fly (read-only if called from WEB script).
//
if (FAILED(hr = ::CreatePrivateKeyObject(m_pCertContext, m_dwCurrentSafety ? TRUE : FALSE, &pIPrivateKey)))
{
DebugTrace("Error [%#x]: CreatePrivateKeybject() failed.\n", hr);
goto ErrorExit;
}
//
// Return interface pointer to user.
//
if (FAILED(hr = pIPrivateKey->QueryInterface(pVal)))
{
DebugTrace("Error [%#x]: pIPrivateKey->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 CCertificate::get_PrivateKey().\n");
return hr;
ErrorExit:
//
// Sanity check.
//
ATLASSERT(FAILED(hr));
ReportError(hr);
goto UnlockExit;
}
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Function : CCertificate::put_PrivateKey
Synopsis : Set the IPrivateKey object.
Parameter: IPrivateKey * newVal - Pointer to IPrivateKey.
Remark :
------------------------------------------------------------------------------*/
STDMETHODIMP CCertificate::put_PrivateKey (IPrivateKey * newVal)
{
HRESULT hr = S_OK;
PCRYPT_KEY_PROV_INFO pKeyProvInfo = NULL;
DebugTrace("Entering CCertificate::put_PrivateKey().\n");
try
{
//
// Lock access to this object.
//
m_Lock.Lock();
//
// Not allowed if called from WEB script.
//
if (m_dwCurrentSafety)
{
hr = CAPICOM_E_NOT_ALLOWED;
DebugTrace("Error [%#x]: Changing PrivateKey from within WEB script is not allowed.\n", hr);
goto ErrorExit;
}
//
// Check parameters.
//
if (NULL == newVal)
{
hr = E_INVALIDARG;
DebugTrace("Error [%#x]: Parameter newVal is NULL.\n", hr);
goto ErrorExit;
}
//
// Make sure cert is already initialized.
//
if (!m_pCertContext)
{
hr = CAPICOM_E_CERTIFICATE_NOT_INITIALIZED;
DebugTrace("Error [%#x]: object does not represent an initialized certificate.\n", hr);
goto ErrorExit;
}
//
// NULL to disassociate.
//
if (newVal)
{
//
// Get copy of key prov info.
//
if (FAILED(hr = ::GetKeyProvInfo(newVal, &pKeyProvInfo)))
{
DebugTrace("Error [%#x]: GetKeyProvInfo() failed.\n", hr);
goto ErrorExit;
}
//
// Make sure public keys match.
//
if (FAILED(hr = ::CompareCertAndContainerPublicKey(m_pCertContext,
pKeyProvInfo->pwszContainerName,
pKeyProvInfo->pwszProvName,
pKeyProvInfo->dwProvType,
pKeyProvInfo->dwKeySpec,
pKeyProvInfo->dwFlags & CRYPT_MACHINE_KEYSET)))
{
DebugTrace("Error [%#x]: CompareCertAndContainerPublicKey() failed.\n", hr);
goto ErrorExit;
}
}
//
// Set the association.
//
if (!::CertSetCertificateContextProperty(m_pCertContext,
CERT_KEY_PROV_INFO_PROP_ID,
0,
pKeyProvInfo))
{
hr = HRESULT_FROM_WIN32(::GetLastError());
DebugTrace("Error [%#x]: CertSetCertificateContextProperty() failed.\n", hr);
goto ErrorExit;
}
}
catch(...)
{
hr = E_POINTER;
DebugTrace("Exception: invalid parameter.\n");
goto ErrorExit;
}
UnlockExit:
//
// Free resources.
//
if (pKeyProvInfo)
{
::CoTaskMemFree(pKeyProvInfo);
}
//
// Unlock access to this object.
//
m_Lock.Unlock();
DebugTrace("Leaving CCertificate::put_PrivateKey().\n");
return hr;
ErrorExit:
//
// Sanity check.
//
ATLASSERT(FAILED(hr));
ReportError(hr);
goto UnlockExit;
}
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Function : CCertificate::Extensions
Synopsis : Return the IExtensions collection object.
Parameter: IExtensions ** pVal - Pointer to pointer to IExtensions
to receive the interface pointer.
Remark :
------------------------------------------------------------------------------*/
STDMETHODIMP CCertificate::Extensions (IExtensions ** pVal)
{
HRESULT hr = S_OK;
DebugTrace("Entering CCertificate::Extensions().\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 cert is already initialized.
//
if (!m_pCertContext)
{
hr = CAPICOM_E_CERTIFICATE_NOT_INITIALIZED;
DebugTrace("Error [%#x]: object does not represent an initialized certificate.\n", hr);
goto ErrorExit;
}
//
// Create the embeded IExtensions object, if not already done so.
//
if (!m_pIExtensions)
{
if (FAILED(hr = ::CreateExtensionsObject(m_pCertContext, &m_pIExtensions)))
{
DebugTrace("Error [%#x]: CreateExtensionsObject() failed.\n", hr);
goto ErrorExit;
}
}
//
// Sanity check.
//
ATLASSERT(m_pIExtensions);
//
// Return interface pointer to user.
//
if (FAILED(hr = m_pIExtensions->QueryInterface(pVal)))
{
DebugTrace("Error [%#x]: m_pIExtensions->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 CCertificate::Extensions().\n");
return hr;
ErrorExit:
//
// Sanity check.
//
ATLASSERT(FAILED(hr));
ReportError(hr);
goto UnlockExit;
}
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Function : CCertificate::ExtendedProperties
Synopsis : Return the IExtendedProperties collection object.
Parameter: IExtendedProperties ** pVal - Pointer to pointer to
IExtendedProperties to receive the
interface pointer.
Remark :
------------------------------------------------------------------------------*/
STDMETHODIMP CCertificate::ExtendedProperties (IExtendedProperties ** pVal)
{
HRESULT hr = S_OK;
DebugTrace("Entering CCertificate::ExtendedProperties().\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 cert is already initialized.
//
if (!m_pCertContext)
{
hr = CAPICOM_E_CERTIFICATE_NOT_INITIALIZED;
DebugTrace("Error [%#x]: object does not represent an initialized certificate.\n", hr);
goto ErrorExit;
}
//
// Create the dynamic IExtendedProperties object.
//
if (FAILED(hr = ::CreateExtendedPropertiesObject(m_pCertContext,
m_dwCurrentSafety ? TRUE : FALSE,
pVal)))
{
DebugTrace("Error [%#x]: CreateExtendedPropertiesObject() 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 CCertificate::ExtendedProperties().\n");
return hr;
ErrorExit:
//
// Sanity check.
//
ATLASSERT(FAILED(hr));
ReportError(hr);
goto UnlockExit;
}
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Function : CCertificate::Load
Synopsis : Method to load certificate(s) from a file.
Parameter: BSTR FileName - File name.
BSTR Password - Password (required for PFX file.)
CAPICOM_KEY_STORAGE_FLAG KeyStorageFlag - Key storage flag.
CAPICOM_KEY_LOCATION KeyLocation - Key location.
Remark :
------------------------------------------------------------------------------*/
STDMETHODIMP CCertificate::Load (BSTR FileName,
BSTR Password,
CAPICOM_KEY_STORAGE_FLAG KeyStorageFlag,
CAPICOM_KEY_LOCATION KeyLocation)
{
HRESULT hr = S_OK;
DATA_BLOB CertBlob = {0, NULL};
DebugTrace("Entering CCertificate::Load().\n");
try
{
//
// Lock access to this object.
//
m_Lock.Lock();
//
// Not allowed if called from WEB script.
//
if (m_dwCurrentSafety)
{
hr = CAPICOM_E_NOT_ALLOWED;
DebugTrace("Error [%#x]: Loading cert file from WEB script is not allowed.\n", hr);
goto ErrorExit;
}
//
// Check parameters.
//
if (0 == ::SysStringLen(FileName))
{
hr = E_INVALIDARG;
DebugTrace("Error [%#x]: Parameter FileName is NULL or empty.\n", hr);
goto ErrorExit;
}
//
// Work around MIDL problem.
//
if (0 == ::SysStringLen(Password))
{
Password = NULL;
}
//
// Read entire file in.
//
if (FAILED(hr = ::ReadFileContent((LPWSTR) FileName, &CertBlob)))
{
DebugTrace("Error [%#x]: ReadFileContent() failed.\n", hr);
goto ErrorExit;
}
//
// Now import the blob.
//
if (FAILED(hr = ImportBlob(&CertBlob, TRUE, KeyLocation, Password, KeyStorageFlag)))
{
DebugTrace("Error [%#x]: CCertificate::ImportBlob() failed.\n", hr);
goto ErrorExit;
}
}
catch(...)
{
hr = E_POINTER;
DebugTrace("Exception: invalid parameter.\n");
goto ErrorExit;
}
UnlockExit:
//
// Free resource.
//
if (CertBlob.pbData)
{
::UnmapViewOfFile(CertBlob.pbData);
}
//
// Unlock access to this object.
//
m_Lock.Unlock();
DebugTrace("Leaving CCertificate::Load().\n");
return hr;
ErrorExit:
//
// Sanity check.
//
ATLASSERT(FAILED(hr));
ReportError(hr);
goto UnlockExit;
}
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Function : CCertificate::Save
Synopsis : Method to save certificate(s) to a file.
Parameter: BSTR FileName - File name.
BSTR Password - Password (required for PFX file.)
CAPICOM_CERTIFICATE_SAVE_AS_TYPE FileType - SaveAs type.
CAPICOM_CERTIFICATE_INCLUDE_OPTION IncludeOption - Include option.
Remark :
------------------------------------------------------------------------------*/
STDMETHODIMP CCertificate::Save (BSTR FileName,
BSTR Password,
CAPICOM_CERTIFICATE_SAVE_AS_TYPE SaveAs,
CAPICOM_CERTIFICATE_INCLUDE_OPTION IncludeOption)
{
HRESULT hr = S_OK;
HCERTSTORE hCertStore = NULL;
DebugTrace("Entering CCertificate::Save().\n");
try
{
//
// Lock access to this object.
//
m_Lock.Lock();
//
// Not allowed if called from WEB script.
//
if (m_dwCurrentSafety)
{
hr = CAPICOM_E_NOT_ALLOWED;
DebugTrace("Error [%#x]: Saving cert file from WEB script is not allowed.\n", hr);
goto ErrorExit;
}
//
// Check parameters.
//
if (0 == ::SysStringLen(FileName))
{
hr = E_INVALIDARG;
DebugTrace("Error [%#x]: Parameter FileName is NULL or empty.\n", hr);
goto ErrorExit;
}
//
// Work around MIDL problem.
//
if (0 == ::SysStringLen(Password))
{
Password = NULL;
}
//
// Make sure cert is already initialized.
//
if (!m_pCertContext)
{
hr = CAPICOM_E_CERTIFICATE_NOT_INITIALIZED;
DebugTrace("Error [%#x]: object does not represent an initialized certificate.\n", hr);
goto ErrorExit;
}
//
// Check file type.
//
switch (SaveAs)
{
case CAPICOM_CERTIFICATE_SAVE_AS_CER:
{
DATA_BLOB DataBlob;
//
// Simply write the encoded cert blob to file.
//
DataBlob.cbData = m_pCertContext->cbCertEncoded;
DataBlob.pbData = m_pCertContext->pbCertEncoded;
if (FAILED(hr = ::WriteFileContent(FileName, DataBlob)))
{
DebugTrace("Error [%#x]: WriteFileContent() failed.\n", hr);
goto ErrorExit;
}
break;
}
case CAPICOM_CERTIFICATE_SAVE_AS_PFX:
{
//
// Create a memory store.
//
if (!(hCertStore = ::CertOpenStore(CERT_STORE_PROV_MEMORY,
CAPICOM_ASN_ENCODING,
0,
0,
NULL)))
{
hr = HRESULT_FROM_WIN32(::GetLastError());
DebugTrace("Error [%#x]: CertOpenStore() failed.\n", hr);
goto ErrorExit;
}
//
// Add all requested certs to the store.
//
if (FAILED(hr = ::CertToStore(m_pCertContext, IncludeOption, hCertStore)))
{
DebugTrace("Error [%#x]: CertToStore() failed.\n", hr);
goto ErrorExit;
}
//
// Save as PFX file.
//
if (FAILED(hr = ::PFXSaveStore(hCertStore,
FileName,
Password,
EXPORT_PRIVATE_KEYS | REPORT_NOT_ABLE_TO_EXPORT_PRIVATE_KEY)))
{
DebugTrace("Error [%#x]: PFXSaveStore() failed.\n", hr);
goto ErrorExit;
}
break;
}
default:
{
hr = E_INVALIDARG;
DebugTrace("Error: invalid parameter, unknown save as type.\n");
goto ErrorExit;
}
}
}
catch(...)
{
hr = E_POINTER;
DebugTrace("Exception: invalid parameter.\n");
goto ErrorExit;
}
UnlockExit:
//
// Free resources.
//
if (hCertStore)
{
::CertCloseStore(hCertStore, 0);
}
//
// Unlock access to this object.
//
m_Lock.Unlock();
DebugTrace("Leaving CCertificate::Save().\n");
return hr;
ErrorExit:
//
// Sanity check.
//
ATLASSERT(FAILED(hr));
ReportError(hr);
goto UnlockExit;
}
////////////////////////////////////////////////////////////////////////////////
//
// Custom interfaces.
//
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Function : CCertificate::get_CertContext
Synopsis : Return the certificate's PCCERT_CONTEXT.
Parameter: long * ppCertContext - Pointer to PCCERT_CONTEXT disguished in a
long.
Remark : We need to use long instead of PCCERT_CONTEXT because VB can't
handle double indirection (i.e. vb would bark on this
PCCERT_CONTEXT * ppCertContext).
------------------------------------------------------------------------------*/
STDMETHODIMP CCertificate::get_CertContext (long * ppCertContext)
{
HRESULT hr = S_OK;
DebugTrace("Entering CCertificate::get_CertContext().\n");
try
{
//
// Lock access to this object.
//
m_Lock.Lock();
//
// Return cert context to caller.
//
if (FAILED(hr = GetContext((PCCERT_CONTEXT *) ppCertContext)))
{
DebugTrace("Error [%#x]: CCertificate::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 CCertificate::get_CertContext().\n");
return hr;
ErrorExit:
//
// Sanity check.
//
ATLASSERT(FAILED(hr));
ReportError(hr);
goto UnlockExit;
}
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Function : CCertificate::put_CertContext
Synopsis : Initialize the object with a CERT_CONTEXT.
Parameter: long pCertContext - Poiner to CERT_CONTEXT, disguised in a long,
used to initialize this object.
Remark : Note that this is NOT 64-bit compatiable. Plese see remark of
get_CertContext for more detail.
------------------------------------------------------------------------------*/
STDMETHODIMP CCertificate::put_CertContext (long pCertContext)
{
HRESULT hr = S_OK;
DebugTrace("Entering CCertificate::put_CertContext().\n");
try
{
//
// Lock access to this object.
//
m_Lock.Lock();
//
// Reset the object with this context.
//
if (FAILED(hr = PutContext((PCCERT_CONTEXT) pCertContext, m_dwCurrentSafety)))
{
DebugTrace("Error [%#x]: CCertificate::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 CCertificate::put_CertContext().\n");
return hr;
ErrorExit:
//
// Sanity check.
//
ATLASSERT(FAILED(hr));
ReportError(hr);
goto UnlockExit;
}
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Function : CCertificate::FreeContext
Synopsis : Free a CERT_CONTEXT.
Parameter: long pCertContext - Poiner to CERT_CONTEXT, disguised in a long,
to be freed.
Remark : Note that this is NOT 64-bit compatiable. Plese see remark of
get_CertContext for more detail.
------------------------------------------------------------------------------*/
STDMETHODIMP CCertificate::FreeContext (long pCertContext)
{
HRESULT hr = S_OK;
DebugTrace("Entering CCertificate::FreeContext().\n");
try
{
//
// Lock access to this object.
//
m_Lock.Lock();
//
// Free the context.
//
if (!::CertFreeCertificateContext((PCCERT_CONTEXT) pCertContext))
{
hr = HRESULT_FROM_WIN32(::GetLastError());
DebugTrace("Error [%#x]: CertFreeCertificateContext() 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 CCertificate::FreeContext().\n");
return hr;
ErrorExit:
//
// Sanity check.
//
ATLASSERT(FAILED(hr));
ReportError(hr);
goto UnlockExit;
}
////////////////////////////////////////////////////////////////////////////////
//
// Private methods.
//
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Function : CCertificate::ImportBlob
Synopsis : Private function to load a certificate from blob.
Parameter: DATA_BLOB * pCertBlob
BOOL bAllowPfx
CAPICOM_KEY_LOCATION KeyLocation - Key location.
BSTR pwszPassword - Password (required for PFX file.)
CAPICOM_KEY_STORAGE_FLAG KeyStorageFlag - Key storage flag.
Remark :
------------------------------------------------------------------------------*/
STDMETHODIMP CCertificate::ImportBlob (DATA_BLOB * pCertBlob,
BOOL bAllowPfx,
CAPICOM_KEY_LOCATION KeyLocation,
BSTR pwszPassword,
CAPICOM_KEY_STORAGE_FLAG KeyStorageFlag)
{
HRESULT hr = S_OK;
HCERTSTORE hCertStore = NULL;
PCCERT_CONTEXT pEnumContext = NULL;
PCCERT_CONTEXT pCertContext = NULL;
DWORD dwContentType = 0;
DWORD cb = 0;
DWORD dwFlags = 0;
DWORD dwExpectedType = CERT_QUERY_CONTENT_FLAG_CERT |
CERT_QUERY_CONTENT_FLAG_SERIALIZED_CERT;
DebugTrace("Entering CCertificate::ImportBlob().\n");
//
// Sanity check.
//
ATLASSERT(pCertBlob);
//
// Set PFX flag, if allowed.
//
if (bAllowPfx)
{
dwExpectedType |= CERT_QUERY_CONTENT_FLAG_PFX;
}
//
// Crack the blob.
//
if (!::CryptQueryObject(CERT_QUERY_OBJECT_BLOB,
(LPCVOID) pCertBlob,
dwExpectedType,
CERT_QUERY_FORMAT_FLAG_ALL,
0,
NULL,
&dwContentType,
NULL,
&hCertStore,
NULL,
NULL))
{
hr = HRESULT_FROM_WIN32(::GetLastError());
DebugTrace("Error [%#x]: CryptQueryObject() failed.\n", hr);
goto ErrorExit;
}
DebugTrace("Info: CryptQueryObject() returns dwContentType = %#x.\n", dwContentType);
//
// Need to import it ourselves for PFX file.
//
if (CERT_QUERY_CONTENT_PFX == dwContentType)
{
//
// Make sure PFX is allowed.
//
if (!bAllowPfx)
{
hr = CAPICOM_E_NOT_SUPPORTED;
DebugTrace("Error [%#x]: Importing PFX where not supported.\n", hr);
goto ErrorExit;
}
//
// Setup import flags.
//
if (CAPICOM_LOCAL_MACHINE_KEY == KeyLocation)
{
dwFlags |= CRYPT_MACHINE_KEYSET;
}
else if (IsWin2KAndAbove())
{
dwFlags |= CRYPT_USER_KEYSET;
}
if (KeyStorageFlag & CAPICOM_KEY_STORAGE_EXPORTABLE)
{
dwFlags |= CRYPT_EXPORTABLE;
}
if (KeyStorageFlag & CAPICOM_KEY_STORAGE_USER_PROTECTED)
{
dwFlags |= CRYPT_USER_PROTECTED;
}
DebugTrace("Info: dwFlags = %#x.", dwFlags);
//
// Now import the blob to store.
//
if (!(hCertStore = ::PFXImportCertStore((CRYPT_DATA_BLOB *) pCertBlob,
pwszPassword,
dwFlags)))
{
hr = HRESULT_FROM_WIN32(::GetLastError());
DebugTrace("Error [%#x]: PFXImportCertStore() failed.\n", hr);
goto ErrorExit;
}
//
// Sanity check.
//
ATLASSERT(hCertStore);
//
// Find the first cert with private key, if none, then simply take
// the very first cert.
//
while (pEnumContext = ::CertEnumCertificatesInStore(hCertStore, pEnumContext))
{
//
// Does this cert has a private key?
//
if (::CertGetCertificateContextProperty(pEnumContext,
CERT_KEY_PROV_INFO_PROP_ID,
NULL,
&cb))
{
//
// Yes, so free the one without private key, had we found one previously.
//
if (pCertContext)
{
if (!::CertFreeCertificateContext(pCertContext))
{
hr = HRESULT_FROM_WIN32(::GetLastError());
DebugTrace("Error [%#x]: CertFreeCertificateContext() failed.\n", hr);
goto ErrorExit;
}
}
if (!(pCertContext = ::CertDuplicateCertificateContext(pEnumContext)))
{
hr = HRESULT_FROM_WIN32(::GetLastError());
DebugTrace("Error [%#x]: CertDuplicateCertificateContext() failed.\n", hr);
goto ErrorExit;
}
//
// Set last error before we break out of loop.
//
::SetLastError((DWORD) CRYPT_E_NOT_FOUND);
break;
}
else
{
//
// Keep the first one.
//
if (!pCertContext)
{
if (!(pCertContext = ::CertDuplicateCertificateContext(pEnumContext)))
{
hr = HRESULT_FROM_WIN32(::GetLastError());
DebugTrace("Error [%#x]: CertDuplicateCertificateContext() failed.\n", hr);
goto ErrorExit;
}
}
}
}
//
// Above loop can exit either because there is no more certificate in
// the store or an error. Need to check last error to be certain.
//
if (CRYPT_E_NOT_FOUND != ::GetLastError())
{
hr = HRESULT_FROM_WIN32(::GetLastError());
DebugTrace("Error [%#x]: CertEnumCertificatesInStore() failed.\n", hr);
goto ErrorExit;
}
}
else
{
//
// It is a CER file, so it must have only 1 cert.
//
if (!(pCertContext = ::CertEnumCertificatesInStore(hCertStore, NULL)))
{
hr = HRESULT_FROM_WIN32(::GetLastError());
DebugTrace("Error [%#x]: CertEnumCertificatesInStore() failed.\n", hr);
goto ErrorExit;
}
}
//
// Sanity check.
//
ATLASSERT(pCertContext);
//
// Now initialize the object with the found cert.
//
if (FAILED(hr = PutContext(pCertContext, m_dwCurrentSafety)))
{
DebugTrace("Error [%#x]: CCertificate::PutContext() failed.\n", hr);
goto ErrorExit;
}
CommonExit:
//
// Free resource.
//
if (pCertContext)
{
::CertFreeCertificateContext(pCertContext);
}
if (pEnumContext)
{
::CertFreeCertificateContext(pEnumContext);
}
if (hCertStore)
{
::CertCloseStore(hCertStore, 0);
}
DebugTrace("Leaving CCertificate::ImportBlob().\n");
return hr;
ErrorExit:
//
// Sanity check.
//
ATLASSERT(FAILED(hr));
goto CommonExit;
}
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Function : CCertificate::GetContext
Synopsis : Return the certificate's PCCERT_CONTEXT.
Parameter: PCCERT_CONTEXT * ppCertContext - Pointer to PCCERT_CONTEXT.
Remark : This method is designed for internal use only, and therefore,
should not be exposed to user.
Note that this is a custom interface, not a dispinterface.
Note that the cert context ref count is incremented by
CertDuplicateCertificateContext(), so it is the caller's
responsibility to free the context.
------------------------------------------------------------------------------*/
STDMETHODIMP CCertificate::GetContext (PCCERT_CONTEXT * ppCertContext)
{
HRESULT hr = S_OK;
DebugTrace("Entering CCertificate::GetContext().\n");
//
// Make sure cert is already initialized.
//
if (!m_pCertContext)
{
hr = CAPICOM_E_CERTIFICATE_NOT_INITIALIZED;
DebugTrace("Error [%#x]: object does not represent an initialized certificate.\n", hr);
goto ErrorExit;
}
//
// Sanity check.
//
ATLASSERT(ppCertContext);
//
// Duplicate the cert context.
//
if (!(*ppCertContext = ::CertDuplicateCertificateContext(m_pCertContext)))
{
hr = HRESULT_FROM_WIN32(::GetLastError());
DebugTrace("Error [%#x]: CertDuplicateCertificateContext() failed.\n");
goto ErrorExit;
}
CommonExit:
DebugTrace("Leaving CCertificate::GetContext().\n");
return hr;
ErrorExit:
//
// Sanity check.
//
ATLASSERT(FAILED(hr));
goto CommonExit;
}
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Function : CCertificate::PutContext
Synopsis : Initialize the object with a CERT_CONTEXT.
Parameter: PCERT_CONTEXT pCertContext - Poiner to CERT_CONTEXT used to
initialize this object.
DWORD dwCurrentSafety - Current safety setting.
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.
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 CCertificate::PutContext (PCCERT_CONTEXT pCertContext,
DWORD dwCurrentSafety)
{
HRESULT hr = S_OK;
PCCERT_CONTEXT pCertContext2 = NULL;
DebugTrace("Entering CCertificate::PutContext().\n");
//
// Sanity check.
//
ATLASSERT(pCertContext);
//
// Duplicate the cert context.
//
if (!(pCertContext2 = ::CertDuplicateCertificateContext(pCertContext)))
{
hr = HRESULT_FROM_WIN32(::GetLastError());
DebugTrace("Error [%#x]: CertDupliacteCertificateContext() failed.\n");
goto ErrorExit;
}
//
// Free previous context, if any.
//
if (m_pCertContext)
{
if (!::CertFreeCertificateContext(m_pCertContext))
{
hr = HRESULT_FROM_WIN32(::GetLastError());
DebugTrace("Error [%#x]: CertFreeCertificateContext() failed.\n");
goto ErrorExit;
}
}
//
// Reset.
//
m_pCertContext = pCertContext2;
m_pIKeyUsage.Release();
m_pIExtendedKeyUsage.Release();
m_pIBasicConstraints.Release();
m_pICertificateStatus.Release();
m_pITemplate.Release();
m_pIPublicKey.Release();
m_pIExtensions.Release();
m_dwCurrentSafety = dwCurrentSafety;
CommonExit:
DebugTrace("Leaving CCertificate::PutContext().\n");
return hr;
ErrorExit:
//
// Sanity check.
//
ATLASSERT(FAILED(hr));
//
// Free resources.
//
if (pCertContext2)
{
::CertFreeCertificateContext(pCertContext2);
}
goto CommonExit;
}