2228 lines
53 KiB
C++
2228 lines
53 KiB
C++
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
|
|
Microsoft Windows, Copyright (C) Microsoft Corporation, 2000
|
|
|
|
File: Certificate.cpp
|
|
|
|
Content: Implementation of CCertificate.
|
|
|
|
History: 11-15-99 dsie created
|
|
|
|
------------------------------------------------------------------------------*/
|
|
|
|
//
|
|
// Turn off:
|
|
//
|
|
// - Unreferenced formal parameter warning.
|
|
// - Assignment within conditional expression warning.
|
|
//
|
|
#pragma warning (disable: 4100)
|
|
#pragma warning (disable: 4706)
|
|
|
|
#include "stdafx.h"
|
|
#include "CAPICOM.h"
|
|
#include "Certificate.h"
|
|
#include "Convert.h"
|
|
|
|
#include "cryptui.h"
|
|
#include <wincrypt.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.
|
|
|
|
ICertificate ** ppICertificate - Pointer to pointer ICertificate
|
|
object.
|
|
|
|
Remark :
|
|
|
|
------------------------------------------------------------------------------*/
|
|
|
|
HRESULT CreateCertificateObject (PCCERT_CONTEXT pCertContext,
|
|
ICertificate ** 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)))
|
|
{
|
|
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;
|
|
PCCERT_CONTEXT pCertContext = NULL;
|
|
CComPtr<ICCertificate> pICCertificate = NULL;
|
|
|
|
DebugTrace("Entering GetCertContext().\n");
|
|
|
|
try
|
|
{
|
|
//
|
|
// Get ICCertificate interface pointer.
|
|
//
|
|
if (FAILED(hr = pICertificate->QueryInterface(IID_ICCertificate, (void **) &pICCertificate)))
|
|
{
|
|
DebugTrace("Error [%#x]: pICertificate->QueryInterface() failed.\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
|
|
//
|
|
// Get the CERT_CONTEXT.
|
|
//
|
|
if (FAILED(hr = pICCertificate->GetContext(&pCertContext)))
|
|
{
|
|
DebugTrace("Error [%#x]: pICCertificate->GetContext() failed.\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
|
|
*ppCertContext = pCertContext;
|
|
}
|
|
|
|
catch(...)
|
|
{
|
|
hr = CAPICOM_E_INTERNAL;
|
|
|
|
DebugTrace("Exception: internal error.\n");
|
|
goto ErrorExit;
|
|
}
|
|
|
|
CommonExit:
|
|
|
|
DebugTrace("Leaving GetCertContext().\n");
|
|
|
|
return hr;
|
|
|
|
ErrorExit:
|
|
//
|
|
// Sanity check.
|
|
//
|
|
ATLASSERT(FAILED(hr));
|
|
|
|
//
|
|
// Free resource.
|
|
//
|
|
if (pCertContext)
|
|
{
|
|
::CertFreeCertificateContext(pCertContext);
|
|
}
|
|
|
|
goto CommonExit;
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Local functions.
|
|
//
|
|
|
|
static ULONG Byte2Hex (BYTE byte)
|
|
{
|
|
ULONG uValue = 0;
|
|
WCHAR * pwsz0 = L"0";
|
|
WCHAR * pwszA = L"A";
|
|
|
|
if(((ULONG) byte) <= 9)
|
|
{
|
|
uValue = ((ULONG) byte) + ULONG (*pwsz0);
|
|
}
|
|
else
|
|
{
|
|
uValue = (ULONG) byte - 10 + ULONG (*pwszA);
|
|
}
|
|
|
|
return uValue;
|
|
}
|
|
|
|
static HRESULT IntegerBlob2BSTR (CRYPT_INTEGER_BLOB * pBlob, BSTR * pbstrHex)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
BSTR bstrWchar = NULL;
|
|
BSTR bstrTemp = NULL;
|
|
DWORD cbData = 0;
|
|
|
|
DebugTrace("Entering IntegerBlob2BSTR().\n");
|
|
|
|
//
|
|
// Sanity check.
|
|
//
|
|
ATLASSERT(pBlob);
|
|
ATLASSERT(pbstrHex);
|
|
|
|
try
|
|
{
|
|
//
|
|
// Make sure parameters are valid.
|
|
//
|
|
if (!pBlob->cbData || !pBlob->pbData)
|
|
{
|
|
hr = E_INVALIDARG;
|
|
|
|
DebugTrace("Error: invalid parameter, empty integer blob.\n");
|
|
goto ErrorExit;
|
|
}
|
|
|
|
//
|
|
// Allocate memory (Need 2 wchars for each byte, plus a NULL character).
|
|
//
|
|
if (!(bstrWchar = ::SysAllocStringLen(NULL, pBlob->cbData * 2 + 1)))
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
|
|
DebugTrace("Error: out of memory.\n");
|
|
goto ErrorExit;
|
|
}
|
|
|
|
//
|
|
// Now convert it to hex string (Remember data is stored in little-endian).
|
|
//
|
|
bstrTemp = bstrWchar;
|
|
cbData = pBlob->cbData;
|
|
|
|
while (cbData--)
|
|
{
|
|
//
|
|
// Get the byte.
|
|
//
|
|
BYTE byte = pBlob->pbData[cbData];
|
|
|
|
//
|
|
// Convert upper nibble.
|
|
//
|
|
*bstrTemp++ = (WCHAR) ::Byte2Hex((BYTE)((byte & 0xf0) >> 4));
|
|
|
|
//
|
|
// Conver lower nibble.
|
|
//
|
|
*bstrTemp++ = (WCHAR) ::Byte2Hex((BYTE) (byte & 0x0f));
|
|
}
|
|
|
|
//
|
|
// Don't forget to NULL terminate it.
|
|
//
|
|
*bstrTemp = L'\0';
|
|
|
|
//
|
|
// Return BSTR to caller.
|
|
//
|
|
*pbstrHex = bstrWchar;
|
|
}
|
|
|
|
catch(...)
|
|
{
|
|
hr = E_POINTER;
|
|
|
|
DebugTrace("Exception: invalid parameter.\n");
|
|
goto ErrorExit;
|
|
}
|
|
|
|
CommonExit:
|
|
|
|
DebugTrace("Leaving IntegerBlob2BSTR().\n");
|
|
|
|
return hr;
|
|
|
|
ErrorExit:
|
|
//
|
|
// Sanity check.
|
|
//
|
|
ATLASSERT(FAILED(hr));
|
|
|
|
//
|
|
// Free resource.
|
|
//
|
|
if (bstrWchar)
|
|
{
|
|
::SysFreeString(bstrWchar);
|
|
}
|
|
|
|
goto CommonExit;
|
|
}
|
|
|
|
static HRESULT Bytes2BSTR (BYTE * pBytes, DWORD cbBytes, BSTR * pBstr)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
BSTR bstrWchar = NULL;
|
|
BSTR bstrTemp = NULL;
|
|
|
|
DebugTrace("Entering Bytes2BSTR().\n");
|
|
|
|
//
|
|
// Sanity check.
|
|
//
|
|
ATLASSERT(pBytes);
|
|
ATLASSERT(pBstr);
|
|
|
|
try
|
|
{
|
|
//
|
|
// Allocate memory. (Need 2 wchars for each byte, plus a NULL character).
|
|
//
|
|
if (!(bstrWchar = ::SysAllocStringLen(NULL, cbBytes * 2 + 1)))
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
|
|
DebugTrace("Error: out of memory.\n");
|
|
goto ErrorExit;
|
|
}
|
|
|
|
//
|
|
// Now convert it to hex string (Remember data is stored in little-endian).
|
|
//
|
|
bstrTemp = bstrWchar;
|
|
|
|
while (cbBytes--)
|
|
{
|
|
//
|
|
// Get the byte.
|
|
//
|
|
BYTE byte = *pBytes++;
|
|
|
|
//
|
|
// Convert upper nibble.
|
|
//
|
|
*bstrTemp++ = (WCHAR) ::Byte2Hex((BYTE) ((byte & 0xf0) >> 4));
|
|
|
|
//
|
|
// Conver lower nibble.
|
|
//
|
|
*bstrTemp++ = (WCHAR) ::Byte2Hex((BYTE) (byte & 0x0f));
|
|
}
|
|
|
|
//
|
|
// NULL terminate it.
|
|
//
|
|
*bstrTemp = L'\0';
|
|
|
|
//
|
|
// Return BSTR to caller.
|
|
//
|
|
*pBstr = bstrWchar;
|
|
}
|
|
|
|
catch(...)
|
|
{
|
|
hr = E_POINTER;
|
|
|
|
DebugTrace("Exception: invalid parameter.\n");
|
|
goto ErrorExit;
|
|
}
|
|
|
|
CommonExit:
|
|
|
|
DebugTrace("Leaving Bytes2BSTR().\n");
|
|
|
|
return hr;
|
|
|
|
ErrorExit:
|
|
//
|
|
// Sanity check.
|
|
//
|
|
ATLASSERT(FAILED(hr));
|
|
|
|
//
|
|
// Free resource.
|
|
//
|
|
if (bstrWchar)
|
|
{
|
|
::SysFreeString(bstrWchar);
|
|
}
|
|
|
|
goto CommonExit;
|
|
}
|
|
|
|
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
|
|
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 - Can be:
|
|
|
|
CERT_NAME_EMAIL_TYPE
|
|
CERT_NAME_RDN_TYPE
|
|
CERT_NAME_SIMPLE_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);
|
|
|
|
try
|
|
{
|
|
//
|
|
// Get the length needed.
|
|
//
|
|
if (!(cbNameLen = ::CertGetNameStringW(pCertContext,
|
|
dwDisplayType,
|
|
dwNameType,
|
|
dwDisplayType == CERT_NAME_RDN_TYPE ? (LPVOID) &dwStrType : NULL,
|
|
NULL,
|
|
0)))
|
|
{
|
|
hr = HRESULT_FROM_WIN32(::GetLastError());
|
|
|
|
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(GetLastError());
|
|
|
|
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;
|
|
}
|
|
}
|
|
|
|
catch(...)
|
|
{
|
|
hr = E_POINTER;
|
|
|
|
DebugTrace("Exception: invalid parameter.\n");
|
|
goto ErrorExit;
|
|
}
|
|
|
|
CommonExit:
|
|
//
|
|
// Free resource.
|
|
//
|
|
if (pwszName)
|
|
{
|
|
::CoTaskMemFree(pwszName);
|
|
}
|
|
|
|
DebugTrace("Leaving GetCertNameInfo().\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();
|
|
|
|
//
|
|
// 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;
|
|
}
|
|
|
|
*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();
|
|
|
|
//
|
|
// 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 = ::IntegerBlob2BSTR(&m_pCertContext->pCertInfo->SerialNumber, pVal)))
|
|
{
|
|
DebugTrace("Error [%#x]: IntegerBlob2BSTR() 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();
|
|
|
|
//
|
|
// 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();
|
|
|
|
//
|
|
// 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();
|
|
|
|
//
|
|
// 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();
|
|
|
|
//
|
|
// 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();
|
|
|
|
//
|
|
// 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 BSTR.
|
|
//
|
|
if (FAILED(hr = ::Bytes2BSTR(pbHash, cbHash, pVal)))
|
|
{
|
|
DebugTrace("Error [%#x]: Bytes2BSTR() 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();
|
|
|
|
//
|
|
// 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;
|
|
|
|
DebugTrace("Entering CCertificate::GetInfo().\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;
|
|
}
|
|
|
|
//
|
|
// 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.
|
|
//
|
|
if (FAILED(hr = ::GetCertNameInfo(m_pCertContext,
|
|
dwFlags,
|
|
CERT_NAME_SIMPLE_DISPLAY_TYPE,
|
|
pVal)))
|
|
{
|
|
DebugTrace("Error [%#x]: GetCertNameInfo() failed for CERT_NAME_SIMPLE_DISPLAY_TYPE.\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
|
|
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.
|
|
//
|
|
if (FAILED(hr = ::GetCertNameInfo(m_pCertContext,
|
|
0,
|
|
CERT_NAME_EMAIL_TYPE,
|
|
pVal)))
|
|
{
|
|
DebugTrace("Error [%#x]: GetCertNameInfo() failed for CERT_NAME_EMAIL_TYPE.\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
default:
|
|
{
|
|
hr = E_INVALIDARG;
|
|
|
|
DebugTrace("Invalid parameter: unknown info type.\n");
|
|
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();
|
|
|
|
//
|
|
// 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(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();
|
|
|
|
//
|
|
// 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(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();
|
|
|
|
//
|
|
// 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(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();
|
|
|
|
//
|
|
// 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(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 which can be:
|
|
|
|
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();
|
|
|
|
//
|
|
// 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};
|
|
PCCERT_CONTEXT pCertContext = NULL;
|
|
|
|
DebugTrace("Entering CCertificate::Import().\n");
|
|
|
|
try
|
|
{
|
|
//
|
|
// Lock access to this object.
|
|
//
|
|
m_Lock.Lock();
|
|
|
|
//
|
|
// Make sure parameters are valid.
|
|
//
|
|
if (0 == ::SysStringByteLen(EncodedCertificate))
|
|
{
|
|
hr = E_INVALIDARG;
|
|
|
|
DebugTrace("Error: invalid parameter, EncodedCertificate is empty.\n");
|
|
goto ErrorExit;
|
|
}
|
|
|
|
//
|
|
// Import the data.
|
|
//
|
|
if (FAILED(hr = ::ImportData(EncodedCertificate, &CertBlob)))
|
|
{
|
|
DebugTrace("Error [%#x]: ImportData() failed.\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
|
|
//
|
|
// Create the CERT_CONTEXT.
|
|
//
|
|
if (!(pCertContext = ::CertCreateCertificateContext(CAPICOM_ASN_ENCODING,
|
|
CertBlob.pbData,
|
|
CertBlob.cbData)))
|
|
{
|
|
hr = HRESULT_FROM_WIN32(::GetLastError());
|
|
|
|
DebugTrace("Error [%#x]: CertCreateCertificateContext() failed.\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
|
|
//
|
|
// Initialize object.
|
|
//
|
|
if (FAILED(hr = PutContext(pCertContext)))
|
|
{
|
|
DebugTrace("Error [%#x]: Certificate::PutContext() failed.\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
}
|
|
|
|
catch(...)
|
|
{
|
|
hr = E_POINTER;
|
|
|
|
DebugTrace("Exception: invalid parameter.\n");
|
|
goto ErrorExit;
|
|
}
|
|
|
|
UnlockExit:
|
|
//
|
|
// Free resource.
|
|
//
|
|
if (CertBlob.pbData)
|
|
{
|
|
::CoTaskMemFree(CertBlob.pbData);
|
|
}
|
|
if (pCertContext)
|
|
{
|
|
::CertFreeCertificateContext(pCertContext);
|
|
}
|
|
|
|
//
|
|
// 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 CryptUIDlgSelectCertificateW() 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;
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Custom interfaces.
|
|
//
|
|
|
|
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
|
|
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;
|
|
PCCERT_CONTEXT pCertContext = NULL;
|
|
|
|
DebugTrace("Entering CCertificate::GetContext().\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;
|
|
}
|
|
|
|
//
|
|
// Duplicate the cert context.
|
|
//
|
|
if (!(pCertContext = ::CertDuplicateCertificateContext(m_pCertContext)))
|
|
{
|
|
hr = HRESULT_FROM_WIN32(::GetLastError());
|
|
|
|
DebugTrace("Error [%#x]: CertDuplicateCertificateContext() failed.\n");
|
|
goto ErrorExit;
|
|
}
|
|
|
|
//
|
|
// and return to caller.
|
|
//
|
|
*ppCertContext = pCertContext;
|
|
}
|
|
|
|
catch(...)
|
|
{
|
|
hr = CAPICOM_E_INTERNAL;
|
|
|
|
DebugTrace("Exception: internal error.\n");
|
|
goto ErrorExit;
|
|
}
|
|
|
|
UnlockExit:
|
|
//
|
|
// Unlock access to this object.
|
|
//
|
|
m_Lock.Unlock();
|
|
|
|
DebugTrace("Leaving CCertificate::GetContext().\n");
|
|
|
|
return hr;
|
|
|
|
ErrorExit:
|
|
//
|
|
// Sanity check.
|
|
//
|
|
ATLASSERT(FAILED(hr));
|
|
|
|
goto UnlockExit;
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Private methods.
|
|
//
|
|
|
|
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
|
|
Function : CCertificate::PutContext
|
|
|
|
Synopsis : Initialize the object with a CERT_CONTEXT.
|
|
|
|
Parameter: PCERT_CONTEXT pCertContext - Poiner to CERT_CONTEXT used to
|
|
initialize this object.
|
|
|
|
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)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
DebugTrace("Entering CCertificate::PutContext().\n");
|
|
|
|
//
|
|
// Lock access to this object.
|
|
//
|
|
m_Lock.Lock();
|
|
|
|
//
|
|
// Sanity check.
|
|
//
|
|
ATLASSERT(pCertContext);
|
|
|
|
//
|
|
// Reset.
|
|
//
|
|
m_pIKeyUsage.Release();
|
|
m_pIExtendedKeyUsage.Release();
|
|
m_pIBasicConstraints.Release();
|
|
m_pICertificateStatus.Release();
|
|
|
|
if (m_pCertContext)
|
|
{
|
|
::CertFreeCertificateContext(m_pCertContext);
|
|
m_pCertContext = NULL;
|
|
}
|
|
|
|
//
|
|
// Create the embeded IKeyUsage object.
|
|
//
|
|
if (FAILED(hr = ::CreateKeyUsageObject(pCertContext, &m_pIKeyUsage)))
|
|
{
|
|
DebugTrace("Error [%#x]: CreateKeyUsageObject() failed.\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
|
|
//
|
|
// Create the embeded IExtendedKeyUsage object.
|
|
//
|
|
if (FAILED(hr = ::CreateExtendedKeyUsageObject(pCertContext, &m_pIExtendedKeyUsage)))
|
|
{
|
|
DebugTrace("Error [%#x]: CreateExtendedKeyUsageObject() failed.\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
|
|
//
|
|
// Create the embeded IBasicConstraints object.
|
|
//
|
|
if (FAILED(hr = ::CreateBasicConstraintsObject(pCertContext, &m_pIBasicConstraints)))
|
|
{
|
|
DebugTrace("Error [%#x]: CreateBasicConstraintsObject() failed.\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
|
|
//
|
|
// Create the embeded ICertificateStatus object.
|
|
//
|
|
if (FAILED(hr = ::CreateCertificateStatusObject(pCertContext, &m_pICertificateStatus)))
|
|
{
|
|
DebugTrace("Error [%#x]: CreateCertificateStatusObject() failed.\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
|
|
//
|
|
// Duplicate the cert context.
|
|
//
|
|
if (!(m_pCertContext = ::CertDuplicateCertificateContext(pCertContext)))
|
|
{
|
|
hr = HRESULT_FROM_WIN32(::GetLastError());
|
|
|
|
DebugTrace("Error [%#x]: CertDupliacteCertificateContext() failed.\n");
|
|
goto ErrorExit;
|
|
}
|
|
|
|
UnlockExit:
|
|
//
|
|
// Unlock access to this object.
|
|
//
|
|
m_Lock.Unlock();
|
|
|
|
DebugTrace("Leaving CCertificate::PutContext().\n");
|
|
|
|
return hr;
|
|
|
|
ErrorExit:
|
|
//
|
|
// Sanity check.
|
|
//
|
|
ATLASSERT(FAILED(hr));
|
|
|
|
goto UnlockExit;
|
|
}
|