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.
3206 lines
92 KiB
3206 lines
92 KiB
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
|
|
Microsoft Windows, Copyright (C) Microsoft Corporation, 2000
|
|
|
|
File: Certificates.cpp
|
|
|
|
Contents: Implementation of CCertificates class for collection of
|
|
ICertificate objects.
|
|
|
|
Remarks: This object is not creatable by user directly. It can only be
|
|
created via property/method of other CAPICOM objects.
|
|
|
|
The collection container is implemented usign STL::map of
|
|
STL::pair of BSTR and ICertificate..
|
|
|
|
See Chapter 9 of "BEGINNING ATL 3 COM Programming" for algorithm
|
|
adopted in here.
|
|
|
|
History: 11-15-99 dsie created
|
|
|
|
------------------------------------------------------------------------------*/
|
|
|
|
#include "StdAfx.h"
|
|
#include "CAPICOM.h"
|
|
#include "Certificates.h"
|
|
#include "Common.h"
|
|
#include "Convert.h"
|
|
#include "CertHlpr.h"
|
|
#include "MsgHlpr.h"
|
|
#include "PFXHlpr.h"
|
|
#include "Policy.h"
|
|
#include "Settings.h"
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Exported functions.
|
|
//
|
|
|
|
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
|
|
Function : CreateCertificatesObject
|
|
|
|
Synopsis : Create an ICertificates collection object, and load the object with
|
|
certificates from the specified source.
|
|
|
|
Parameter: CAPICOM_CERTIFICATES_SOURCE ccs - Source where to get the
|
|
certificates.
|
|
|
|
DWORD dwCurrentSafety - Current safety setting.
|
|
|
|
BOOL bIndexedByThumbprint - TRUE to index by thumbprint.
|
|
|
|
ICertificates2 ** ppICertificates - Pointer to pointer to
|
|
ICertificates to receive the
|
|
interface pointer.
|
|
Remark :
|
|
|
|
------------------------------------------------------------------------------*/
|
|
|
|
HRESULT CreateCertificatesObject (CAPICOM_CERTIFICATES_SOURCE ccs,
|
|
DWORD dwCurrentSafety,
|
|
BOOL bIndexedByThumbprint,
|
|
ICertificates2 ** ppICertificates)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
CComObject<CCertificates> * pCCertificates = NULL;
|
|
|
|
DebugTrace("Entering CreateCertificatesObject().\n");
|
|
|
|
//
|
|
// Sanity check.
|
|
//
|
|
ATLASSERT(ppICertificates);
|
|
|
|
try
|
|
{
|
|
//
|
|
// Create the object. Note that the ref count will still be 0
|
|
// after the object is created.
|
|
//
|
|
if (FAILED(hr = CComObject<CCertificates>::CreateInstance(&pCCertificates)))
|
|
{
|
|
DebugTrace("Error [%#x]: CComObject<CCertificates>::CreateInstance() failed.\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
|
|
//
|
|
// Initialize object.
|
|
//
|
|
if (FAILED(hr = pCCertificates->Init(ccs, dwCurrentSafety, bIndexedByThumbprint)))
|
|
{
|
|
DebugTrace("Error [%#x]: pCCertificates->Init() failed.\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
|
|
//
|
|
// Return interface pointer to caller.
|
|
//
|
|
if (FAILED(hr = pCCertificates->QueryInterface(ppICertificates)))
|
|
{
|
|
DebugTrace("Error [%#x]: pCCertificates->QueryInterface() failed.\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
}
|
|
|
|
catch(...)
|
|
{
|
|
hr = E_POINTER;
|
|
|
|
DebugTrace("Exception: invalid parameter.\n");
|
|
goto ErrorExit;
|
|
}
|
|
|
|
CommonExit:
|
|
|
|
DebugTrace("Leaving CreateCertificatesObject().\n");
|
|
|
|
return hr;
|
|
|
|
ErrorExit:
|
|
//
|
|
// Sanity check.
|
|
//
|
|
ATLASSERT(FAILED(hr));
|
|
|
|
//
|
|
// Free resource.
|
|
//
|
|
if (pCCertificates)
|
|
{
|
|
delete pCCertificates;
|
|
}
|
|
|
|
goto CommonExit;
|
|
}
|
|
|
|
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
|
|
Function : FindTimeValidCallback
|
|
|
|
Synopsis : Callback for find-time-valid.
|
|
|
|
Parameter: See CryptUI.h.
|
|
|
|
|
|
Remark :
|
|
|
|
------------------------------------------------------------------------------*/
|
|
|
|
static BOOL WINAPI FindTimeValidCallback (PCCERT_CONTEXT pCertContext,
|
|
BOOL * pfInitialSelectedCert,
|
|
LPVOID pvCallbackData)
|
|
{
|
|
LONG lResult = 0;
|
|
BOOL bInclude = TRUE;
|
|
|
|
DebugTrace("Entering FindTimeValidCallback().\n");
|
|
|
|
//
|
|
// Sanity check.
|
|
//
|
|
ATLASSERT(pCertContext);
|
|
ATLASSERT(pvCallbackData);
|
|
|
|
//
|
|
// Skip it if not yet valid or expired.
|
|
//
|
|
if (0 != (lResult = ::CertVerifyTimeValidity((LPFILETIME) pvCallbackData,
|
|
pCertContext->pCertInfo)))
|
|
{
|
|
bInclude = FALSE;
|
|
|
|
DebugTrace("Info: Time is not valid (lResult = %d)\n", lResult);
|
|
DebugTrace(" Time (High = %#x, Low = %#x).\n",
|
|
((LPFILETIME) pvCallbackData)->dwHighDateTime,
|
|
((LPFILETIME) pvCallbackData)->dwLowDateTime);
|
|
DebugTrace(" NotBefore (High = %#x, Low = %#x).\n",
|
|
pCertContext->pCertInfo->NotBefore.dwHighDateTime,
|
|
pCertContext->pCertInfo->NotBefore.dwLowDateTime);
|
|
DebugTrace(" NotAfter (High = %#x, Low = %#x).\n",
|
|
pCertContext->pCertInfo->NotAfter.dwHighDateTime,
|
|
pCertContext->pCertInfo->NotAfter.dwLowDateTime);
|
|
}
|
|
|
|
DebugTrace("Leaving FindTimeValidCallback().\n");
|
|
|
|
return bInclude;
|
|
}
|
|
|
|
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
|
|
Function : FindNotBeforeCallback
|
|
|
|
Synopsis : Callback for find-by-not-before.
|
|
|
|
Parameter: See CryptUI.h.
|
|
|
|
|
|
Remark :
|
|
|
|
------------------------------------------------------------------------------*/
|
|
|
|
static BOOL WINAPI FindNotBeforeCallback (PCCERT_CONTEXT pCertContext,
|
|
BOOL * pfInitialSelectedCert,
|
|
LPVOID pvCallbackData)
|
|
{
|
|
BOOL bInclude = TRUE;
|
|
|
|
DebugTrace("Entering FindNotBeforeCallback().\n");
|
|
|
|
//
|
|
// Sanity check.
|
|
//
|
|
ATLASSERT(pCertContext);
|
|
ATLASSERT(pvCallbackData);
|
|
|
|
//
|
|
// Skip it if time valid or expired.
|
|
//
|
|
if (!(-1 == ::CertVerifyTimeValidity((LPFILETIME) pvCallbackData,
|
|
pCertContext->pCertInfo)))
|
|
{
|
|
bInclude = FALSE;
|
|
|
|
DebugTrace("Info: time (High = %#x, Low = %#x) is either valid or expired.\n",
|
|
((LPFILETIME) pvCallbackData)->dwHighDateTime,
|
|
((LPFILETIME) pvCallbackData)->dwLowDateTime);
|
|
}
|
|
|
|
DebugTrace("Leaving FindNotBeforeCallback().\n");
|
|
|
|
return bInclude;
|
|
}
|
|
|
|
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
|
|
Function : FindNotAfterCallback
|
|
|
|
Synopsis : Callback for find-by-not-after.
|
|
|
|
Parameter: See CryptUI.h.
|
|
|
|
|
|
Remark :
|
|
|
|
------------------------------------------------------------------------------*/
|
|
|
|
static BOOL WINAPI FindNotAfterCallback (PCCERT_CONTEXT pCertContext,
|
|
BOOL * pfInitialSelectedCert,
|
|
LPVOID pvCallbackData)
|
|
{
|
|
BOOL bInclude = TRUE;
|
|
|
|
DebugTrace("Entering FindNotAfterCallback().\n");
|
|
|
|
//
|
|
// Sanity check.
|
|
//
|
|
ATLASSERT(pCertContext);
|
|
ATLASSERT(pvCallbackData);
|
|
|
|
//
|
|
// Skip it if not expired.
|
|
//
|
|
if (!(1 == ::CertVerifyTimeValidity((LPFILETIME) pvCallbackData,
|
|
pCertContext->pCertInfo)))
|
|
{
|
|
bInclude = FALSE;
|
|
|
|
DebugTrace("Info: time (High = %#x, Low = %#x) is not expired.\n",
|
|
((LPFILETIME) pvCallbackData)->dwHighDateTime,
|
|
((LPFILETIME) pvCallbackData)->dwLowDateTime);
|
|
}
|
|
|
|
DebugTrace("Leaving FindNotAfterCallback().\n");
|
|
|
|
return bInclude;
|
|
}
|
|
|
|
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
|
|
Function : FindTemplateCallback
|
|
|
|
Synopsis : Callback for find-by-template.
|
|
|
|
Parameter: See CryptUI.h.
|
|
|
|
Remark :
|
|
|
|
------------------------------------------------------------------------------*/
|
|
|
|
static BOOL WINAPI FindTemplateCallback (PCCERT_CONTEXT pCertContext,
|
|
BOOL * pfInitialSelectedCert,
|
|
LPVOID pvCallbackData)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
BOOL bInclude = FALSE;
|
|
DATA_BLOB CertTypeBlob = {0, NULL};
|
|
DATA_BLOB TemplateBlob = {0, NULL};
|
|
PCERT_EXTENSION pCertType = NULL;
|
|
PCERT_EXTENSION pCertTemp = NULL;
|
|
|
|
DebugTrace("Entering FindTemplateCallback().\n");
|
|
|
|
//
|
|
// Sanity check.
|
|
//
|
|
ATLASSERT(pCertContext);
|
|
ATLASSERT(pvCallbackData);
|
|
|
|
//
|
|
// Skip it if we don't have either szOID_ENROLL_CERTTYPE_EXTENSION or
|
|
// szOID_CERTIFICATE_TEMPLATE extension.
|
|
//
|
|
if (!(pCertType = ::CertFindExtension(szOID_ENROLL_CERTTYPE_EXTENSION,
|
|
pCertContext->pCertInfo->cExtension,
|
|
pCertContext->pCertInfo->rgExtension)) &&
|
|
!(pCertTemp = ::CertFindExtension(szOID_CERTIFICATE_TEMPLATE,
|
|
pCertContext->pCertInfo->cExtension,
|
|
pCertContext->pCertInfo->rgExtension)))
|
|
{
|
|
DebugTrace("Info: could not find both szOID_ENROLL_CERTTYPE_EXTENSION and szOID_CERTIFICATE_TEMPLATE.\n");
|
|
goto CommonExit;
|
|
}
|
|
|
|
//
|
|
// Check cert type template name if found.
|
|
//
|
|
if (pCertType)
|
|
{
|
|
PCERT_NAME_VALUE pNameValue = NULL;
|
|
|
|
//
|
|
// Decode the extension.
|
|
//
|
|
if (FAILED(hr = ::DecodeObject(X509_UNICODE_ANY_STRING,
|
|
pCertType->Value.pbData,
|
|
pCertType->Value.cbData,
|
|
&CertTypeBlob)))
|
|
{
|
|
DebugTrace("Info [%#x]: DecodeObject() failed.\n", hr);
|
|
goto CommonExit;
|
|
}
|
|
|
|
pNameValue = (PCERT_NAME_VALUE) CertTypeBlob.pbData;
|
|
|
|
if (0 == ::_wcsicmp((LPWSTR) pNameValue->Value.pbData, (LPWSTR) pvCallbackData))
|
|
{
|
|
bInclude = TRUE;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Look into cert template extension, if necessary.
|
|
//
|
|
if (!bInclude && pCertTemp)
|
|
{
|
|
PCCRYPT_OID_INFO pOidInfo = NULL;
|
|
PCERT_TEMPLATE_EXT pTemplate = NULL;
|
|
|
|
//
|
|
// Decode the extension.
|
|
//
|
|
if (FAILED(hr = ::DecodeObject(szOID_CERTIFICATE_TEMPLATE,
|
|
pCertTemp->Value.pbData,
|
|
pCertTemp->Value.cbData,
|
|
&TemplateBlob)))
|
|
{
|
|
DebugTrace("Info [%#x]: DecodeObject() failed.\n", hr);
|
|
goto CommonExit;
|
|
}
|
|
|
|
pTemplate = (PCERT_TEMPLATE_EXT) TemplateBlob.pbData;
|
|
|
|
//
|
|
// Convert to OID if user passed in friendly name.
|
|
//
|
|
if (pOidInfo = ::CryptFindOIDInfo(CRYPT_OID_INFO_NAME_KEY,
|
|
pvCallbackData,
|
|
CRYPT_TEMPLATE_OID_GROUP_ID))
|
|
{
|
|
if (0 == ::strcmp(pTemplate->pszObjId, pOidInfo->pszOID))
|
|
{
|
|
bInclude = TRUE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
CComBSTR bstrOID;
|
|
|
|
if (!(bstrOID = pTemplate->pszObjId))
|
|
{
|
|
DebugTrace("Info: bstrOID = pTemplate->pszObjId failed.\n", hr);
|
|
goto CommonExit;
|
|
}
|
|
|
|
if (0 == ::wcscmp(bstrOID, (LPWSTR) pvCallbackData))
|
|
{
|
|
bInclude = TRUE;
|
|
}
|
|
}
|
|
}
|
|
|
|
CommonExit:
|
|
//
|
|
// Free resources.
|
|
//
|
|
if (TemplateBlob.pbData)
|
|
{
|
|
::CoTaskMemFree((LPVOID) TemplateBlob.pbData);
|
|
}
|
|
if (CertTypeBlob.pbData)
|
|
{
|
|
::CoTaskMemFree((LPVOID) CertTypeBlob.pbData);
|
|
}
|
|
|
|
DebugTrace("Leaving FindTemplateCallback().\n");
|
|
|
|
return bInclude;
|
|
}
|
|
|
|
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
|
|
Function : FindExtensionCallback
|
|
|
|
Synopsis : Callback for find-by-extension.
|
|
|
|
Parameter: See CryptUI.h.
|
|
|
|
|
|
Remark :
|
|
|
|
------------------------------------------------------------------------------*/
|
|
|
|
static BOOL WINAPI FindExtensionCallback (PCCERT_CONTEXT pCertContext,
|
|
BOOL * pfInitialSelectedCert,
|
|
LPVOID pvCallbackData)
|
|
{
|
|
BOOL bInclude = TRUE;
|
|
PCERT_EXTENSION pExtension = NULL;
|
|
|
|
DebugTrace("Entering FindExtensionCallback().\n");
|
|
|
|
//
|
|
// Sanity check.
|
|
//
|
|
ATLASSERT(pCertContext);
|
|
ATLASSERT(pvCallbackData);
|
|
|
|
//
|
|
// Skip it if we can't find the specified extension.
|
|
//
|
|
if (!(pExtension = ::CertFindExtension((LPSTR) pvCallbackData,
|
|
pCertContext->pCertInfo->cExtension,
|
|
pCertContext->pCertInfo->rgExtension)))
|
|
{
|
|
bInclude = FALSE;
|
|
|
|
DebugTrace("Info: extension (%s) could not be found.\n", pvCallbackData);
|
|
}
|
|
|
|
DebugTrace("Leaving FindExtensionCallback().\n");
|
|
|
|
return bInclude;
|
|
}
|
|
|
|
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
|
|
Function : FindRootNameCallback
|
|
|
|
Synopsis : Callback for find-by-rootname.
|
|
|
|
Parameter: See CryptUI.h.
|
|
|
|
Remark :
|
|
|
|
------------------------------------------------------------------------------*/
|
|
|
|
static BOOL WINAPI FindRootNameCallback (PCCERT_CHAIN_CONTEXT pChainContext,
|
|
BOOL * pfInitialSelectedChain,
|
|
LPVOID pvCallbackData)
|
|
{
|
|
BOOL bInclude = FALSE;
|
|
HCERTSTORE hCertStore = NULL;
|
|
PCCERT_CONTEXT pRootContext = NULL;
|
|
PCERT_SIMPLE_CHAIN pSimpleChain;
|
|
|
|
DebugTrace("Entering FindRootNameCallback().\n");
|
|
|
|
//
|
|
// Sanity check.
|
|
//
|
|
ATLASSERT(pChainContext);
|
|
ATLASSERT(pvCallbackData);
|
|
|
|
//
|
|
// Skip if we don't have a complete chain (we don't have a root cert).
|
|
//
|
|
if (CERT_TRUST_IS_PARTIAL_CHAIN & pChainContext->TrustStatus.dwErrorStatus)
|
|
{
|
|
DebugTrace("Info: certificate has only partial chain.\n");
|
|
goto CommonExit;
|
|
}
|
|
|
|
//
|
|
// Open a new temporary memory store.
|
|
//
|
|
if (!(hCertStore = ::CertOpenStore(CERT_STORE_PROV_MEMORY,
|
|
CAPICOM_ASN_ENCODING,
|
|
NULL,
|
|
CERT_STORE_CREATE_NEW_FLAG,
|
|
NULL)))
|
|
{
|
|
DebugTrace("Info [%#x]: CertOpenStore() failed.\n",
|
|
HRESULT_FROM_WIN32(::GetLastError()));
|
|
goto CommonExit;
|
|
}
|
|
|
|
//
|
|
// Copy the root cert of simple chain to memory store.
|
|
//
|
|
pSimpleChain = pChainContext->rgpChain[0];
|
|
if (!::CertAddCertificateContextToStore(hCertStore,
|
|
pSimpleChain->rgpElement[pSimpleChain->cElement - 1]->pCertContext,
|
|
CERT_STORE_ADD_ALWAYS,
|
|
NULL))
|
|
{
|
|
DebugTrace("Info [%#x]: CertAddCertificateContextToStore() failed.\n",
|
|
HRESULT_FROM_WIN32(::GetLastError()));
|
|
goto CommonExit;
|
|
}
|
|
|
|
//
|
|
// Does it match?
|
|
//
|
|
if (!(pRootContext = ::CertFindCertificateInStore(hCertStore,
|
|
CAPICOM_ASN_ENCODING,
|
|
0,
|
|
CERT_FIND_SUBJECT_STR,
|
|
pvCallbackData,
|
|
pRootContext)))
|
|
{
|
|
DebugTrace("Info [%#x]: CertFindCertificateInStore() failed.\n",
|
|
HRESULT_FROM_WIN32(::GetLastError()));
|
|
goto CommonExit;
|
|
}
|
|
|
|
//
|
|
// We have a match.
|
|
//
|
|
bInclude = TRUE;
|
|
|
|
CommonExit:
|
|
//
|
|
// Free resources.
|
|
//
|
|
if (pRootContext)
|
|
{
|
|
::CertFreeCertificateContext(pRootContext);
|
|
}
|
|
if (hCertStore)
|
|
{
|
|
::CertCloseStore(hCertStore, 0);
|
|
}
|
|
|
|
DebugTrace("Leaving FindRootNameCallback().\n");
|
|
|
|
return bInclude;
|
|
}
|
|
|
|
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
|
|
Function : FindApplicationPolicyCallback
|
|
|
|
Synopsis : Callback for find-by-application-policy.
|
|
|
|
Parameter: See CryptUI.h.
|
|
|
|
Remark :
|
|
|
|
------------------------------------------------------------------------------*/
|
|
|
|
static BOOL WINAPI FindApplicationPolicyCallback (PCCERT_CONTEXT pCertContext,
|
|
BOOL * pfInitialSelectedChain,
|
|
LPVOID pvCallbackData)
|
|
{
|
|
BOOL bInclude = FALSE;
|
|
int cNumOIDs = 0;
|
|
DWORD cbOIDs = 0;
|
|
LPSTR * rghOIDs = NULL;
|
|
|
|
DebugTrace("Entering FindApplicationPolicyCallback().\n");
|
|
|
|
//
|
|
// Sanity check.
|
|
//
|
|
ATLASSERT(pCertContext);
|
|
ATLASSERT(pvCallbackData);
|
|
|
|
//
|
|
// Get all the valid application usages.
|
|
//
|
|
if (!::CertGetValidUsages(1, &pCertContext, &cNumOIDs, NULL, &cbOIDs))
|
|
{
|
|
DebugTrace("Info [%#x]: CertGetValidUsages() failed.\n",
|
|
HRESULT_FROM_WIN32(::GetLastError()));
|
|
goto CommonExit;
|
|
}
|
|
|
|
if (!(rghOIDs = (LPSTR *) ::CoTaskMemAlloc(cbOIDs)))
|
|
{
|
|
DebugTrace("Info: out of memory..\n");
|
|
goto CommonExit;
|
|
}
|
|
|
|
if (!::CertGetValidUsages(1, &pCertContext, &cNumOIDs, rghOIDs, &cbOIDs))
|
|
{
|
|
DebugTrace("Info [%#x]: CertGetValidUsages() failed.\n",
|
|
HRESULT_FROM_WIN32(::GetLastError()));
|
|
goto CommonExit;
|
|
}
|
|
|
|
//
|
|
// No EKU is consider good for all.
|
|
//
|
|
if (-1 == cNumOIDs)
|
|
{
|
|
bInclude = TRUE;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// See if we can find it in the array.
|
|
//
|
|
while (cNumOIDs--)
|
|
{
|
|
if (0 == ::strcmp((LPSTR) pvCallbackData, rghOIDs[cNumOIDs]))
|
|
{
|
|
bInclude = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
CommonExit:
|
|
//
|
|
// Free resources.
|
|
//
|
|
if (rghOIDs)
|
|
{
|
|
::CoTaskMemFree((LPVOID) rghOIDs);
|
|
}
|
|
|
|
DebugTrace("Leaving FindApplicationPolicyCallback().\n");
|
|
|
|
return bInclude;
|
|
}
|
|
|
|
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
|
|
Function : FindCertificatePolicyCallback
|
|
|
|
Synopsis : Callback for find-by-certificate-policy.
|
|
|
|
Parameter: See CryptUI.h.
|
|
|
|
Remark :
|
|
|
|
------------------------------------------------------------------------------*/
|
|
|
|
static BOOL WINAPI FindCertificatePolicyCallback (PCCERT_CONTEXT pCertContext,
|
|
BOOL * pfInitialSelectedChain,
|
|
LPVOID pvCallbackData)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
BOOL bInclude = FALSE;
|
|
DWORD dwIndex = 0;
|
|
DATA_BLOB DataBlob = {0, NULL};
|
|
PCERT_EXTENSION pExtension = NULL;
|
|
PCERT_POLICIES_INFO pInfo = NULL;
|
|
|
|
DebugTrace("Entering FindCertificatePolicyCallback().\n");
|
|
|
|
//
|
|
// Sanity check.
|
|
//
|
|
ATLASSERT(pCertContext);
|
|
ATLASSERT(pvCallbackData);
|
|
|
|
//
|
|
// Find the szOID_CERT_POLICIES extension.
|
|
//
|
|
if (!(pExtension = ::CertFindExtension(szOID_CERT_POLICIES,
|
|
pCertContext->pCertInfo->cExtension,
|
|
pCertContext->pCertInfo->rgExtension)))
|
|
{
|
|
DebugTrace("Info [%#x]: CertFindExtension() failed.\n",
|
|
HRESULT_FROM_WIN32(::GetLastError()));
|
|
goto CommonExit;
|
|
}
|
|
|
|
//
|
|
// Decode the extension.
|
|
//
|
|
if (FAILED(hr = ::DecodeObject(szOID_CERT_POLICIES,
|
|
pExtension->Value.pbData,
|
|
pExtension->Value.cbData,
|
|
&DataBlob)))
|
|
{
|
|
DebugTrace("Info [%#x]: DecodeObject() failed.\n", hr);
|
|
goto CommonExit;
|
|
}
|
|
|
|
pInfo = (PCERT_POLICIES_INFO) DataBlob.pbData;
|
|
dwIndex = pInfo->cPolicyInfo;
|
|
|
|
//
|
|
// Try to find a match.
|
|
//
|
|
while (dwIndex--)
|
|
{
|
|
if (0 == ::strcmp(pInfo->rgPolicyInfo[dwIndex].pszPolicyIdentifier, (LPSTR) pvCallbackData))
|
|
{
|
|
bInclude = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
|
|
CommonExit:
|
|
//
|
|
// Free resources.
|
|
//
|
|
if (DataBlob.pbData)
|
|
{
|
|
::CoTaskMemFree((LPVOID) DataBlob.pbData);
|
|
}
|
|
|
|
DebugTrace("Leaving FindCertificatePolicyCallback().\n");
|
|
|
|
return bInclude;
|
|
}
|
|
|
|
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
|
|
Function : FindKeyUsageCallback
|
|
|
|
Synopsis : Callback for find-by-key-usage.
|
|
|
|
Parameter: See CryptUI.h.
|
|
|
|
Remark :
|
|
|
|
------------------------------------------------------------------------------*/
|
|
|
|
static BOOL WINAPI FindKeyUsageCallback (PCCERT_CONTEXT pCertContext,
|
|
BOOL * pfInitialSelectedChain,
|
|
LPVOID pvCallbackData)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
BOOL bInclude = FALSE;
|
|
DWORD dwActualUsages = 0;
|
|
DWORD dwCheckUsages = 0;
|
|
|
|
DebugTrace("Entering FindKeyUsageCallback().\n");
|
|
|
|
//
|
|
// Sanity check.
|
|
//
|
|
ATLASSERT(pCertContext);
|
|
ATLASSERT(pvCallbackData);
|
|
|
|
//
|
|
// Check the key usage.
|
|
//
|
|
if (!::CertGetIntendedKeyUsage(CAPICOM_ASN_ENCODING,
|
|
pCertContext->pCertInfo,
|
|
(BYTE *) &dwActualUsages,
|
|
sizeof(dwActualUsages)))
|
|
{
|
|
//
|
|
// Could be extension not present or an error.
|
|
//
|
|
if (FAILED(hr = HRESULT_FROM_WIN32(::GetLastError())))
|
|
{
|
|
DebugTrace("Error [%#x]: CertGetIntendedKeyUsage() failed.\n", hr);
|
|
goto CommonExit;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Check the bit mask.
|
|
//
|
|
dwCheckUsages = *(LPDWORD) pvCallbackData;
|
|
|
|
if ((dwActualUsages & dwCheckUsages) == dwCheckUsages)
|
|
{
|
|
bInclude = TRUE;
|
|
}
|
|
|
|
CommonExit:
|
|
|
|
DebugTrace("Leaving FindKeyUsageCallback().\n");
|
|
|
|
return bInclude;
|
|
}
|
|
|
|
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
|
|
Function : FindByChain
|
|
|
|
Synopsis : Find certificate(s) in store based on chain's criteria and filter
|
|
with a callback.
|
|
|
|
Parameter: HCERTSTORE hCertStore - Store to find certificate(s).
|
|
|
|
DWORD dwFindType - Find type.
|
|
|
|
LPCVOID pvFindPara - Content to be found.
|
|
|
|
VARIANT_BOOL bFindValidOnly - True to find valid certs only.
|
|
|
|
PFNCHAINFILTERPROC pfnFilterCallback - Callback filter.
|
|
|
|
LPVOID pvCallbackData - Callback data.
|
|
|
|
DWORD dwCurrentSafety - Current safety setting.
|
|
|
|
ICertificates2 ** ppICertificates - Pointer to pointer
|
|
ICertificates2 object.
|
|
Remark :
|
|
|
|
------------------------------------------------------------------------------*/
|
|
|
|
static HRESULT FindByChain (HCERTSTORE hCertStore,
|
|
DWORD dwFindType,
|
|
LPCVOID pvFindPara,
|
|
VARIANT_BOOL bFindValidOnly,
|
|
PFNCHAINFILTERPROC pfnFilterCallback,
|
|
LPVOID pvCallbackData,
|
|
DWORD dwCurrentSafety,
|
|
ICertificates2 * pICertificates)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
DWORD dwWin32Error = 0;
|
|
PCCERT_CHAIN_CONTEXT pChainContext = NULL;
|
|
|
|
DebugTrace("Entering FindByChain().\n");
|
|
|
|
//
|
|
// Sanity check.
|
|
//
|
|
ATLASSERT(hCertStore);
|
|
ATLASSERT(pICertificates);
|
|
|
|
//
|
|
// Find all chains in the store, matching the find criteria.
|
|
//
|
|
while (pChainContext = ::CertFindChainInStore(hCertStore,
|
|
CAPICOM_ASN_ENCODING,
|
|
0,
|
|
dwFindType,
|
|
pvFindPara,
|
|
pChainContext))
|
|
{
|
|
CComPtr<ICertificate2> pICertificate = NULL;
|
|
|
|
//
|
|
// Apply filter if available.
|
|
//
|
|
if (pfnFilterCallback && !pfnFilterCallback(pChainContext, NULL, pvCallbackData))
|
|
{
|
|
continue;
|
|
}
|
|
|
|
//
|
|
// Skip it if check is required and the cert is not valid.
|
|
//
|
|
if (bFindValidOnly && (CERT_TRUST_NO_ERROR != pChainContext->TrustStatus.dwErrorStatus))
|
|
{
|
|
continue;
|
|
}
|
|
|
|
//
|
|
// Sanity check.
|
|
//
|
|
ATLASSERT(pChainContext->cChain);
|
|
ATLASSERT(pChainContext->rgpChain);
|
|
ATLASSERT(pChainContext->rgpChain[0]);
|
|
ATLASSERT(pChainContext->rgpChain[0]->cElement);
|
|
ATLASSERT(pChainContext->rgpChain[0]->rgpElement);
|
|
ATLASSERT(pChainContext->rgpChain[0]->rgpElement[0]);
|
|
ATLASSERT(pChainContext->rgpChain[0]->rgpElement[0]->pCertContext);
|
|
|
|
//
|
|
// Create a ICertificate object for the found certificate.
|
|
//
|
|
if (FAILED (hr = ::CreateCertificateObject(
|
|
pChainContext->rgpChain[0]->rgpElement[0]->pCertContext,
|
|
dwCurrentSafety,
|
|
&pICertificate)))
|
|
{
|
|
DebugTrace("Error [%#x]: CreateCertificateObject() failed.\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
|
|
//
|
|
// Add to collection.
|
|
//
|
|
if (FAILED(hr = pICertificates->Add(pICertificate)))
|
|
{
|
|
DebugTrace("Error [%#x]: pICertificates->Add() failed.\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Above loop can exit with normal or error condition.
|
|
//
|
|
if (CRYPT_E_NOT_FOUND != (dwWin32Error = ::GetLastError()))
|
|
{
|
|
hr = HRESULT_FROM_WIN32(dwWin32Error);
|
|
|
|
DebugTrace("Error [%#x]: CertFindChainInStore() failed.\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
|
|
CommonExit:
|
|
//
|
|
// Free resources.
|
|
//
|
|
if (pChainContext)
|
|
{
|
|
::CertFreeCertificateChain(pChainContext);
|
|
}
|
|
|
|
DebugTrace("Leaving FindByChain().\n");
|
|
|
|
return hr;
|
|
|
|
ErrorExit:
|
|
//
|
|
// Sanity check.
|
|
//
|
|
ATLASSERT(FAILED(hr));
|
|
|
|
goto CommonExit;
|
|
}
|
|
|
|
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
|
|
Function : FindByCert
|
|
|
|
Synopsis : Find certificate(s) in store and filter with a callback.
|
|
|
|
Parameter: HCERTSTORE hCertStore - Store to find certificate(s).
|
|
|
|
DWORD dwFindType - Find type.
|
|
|
|
LPCVOID pvFindPara - Content to be found.
|
|
|
|
VARIANT_BOOL bFindValidOnly - True to find valid certs only.
|
|
|
|
PFNCERTFILTERPROC pfnFilterCallback - Callback filter.
|
|
|
|
LPVOID pvCallbackData - Callback data.
|
|
|
|
DWORD dwCurrentSafety - Current safety setting.
|
|
|
|
ICertificates2 ** ppICertificates - Pointer to pointer
|
|
ICertificates2 object.
|
|
Remark :
|
|
|
|
------------------------------------------------------------------------------*/
|
|
|
|
static HRESULT FindByCert (HCERTSTORE hCertStore,
|
|
DWORD dwFindType,
|
|
LPCVOID pvFindPara,
|
|
VARIANT_BOOL bFindValidOnly,
|
|
PFNCFILTERPROC pfnFilterCallback,
|
|
LPVOID pvCallbackData,
|
|
DWORD dwCurrentSafety,
|
|
ICertificates2 * pICertificates)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
DWORD dwWin32Error = 0;
|
|
PCCERT_CONTEXT pCertContext = NULL;
|
|
|
|
DebugTrace("Entering FindByCert().\n");
|
|
|
|
//
|
|
// Sanity check.
|
|
//
|
|
ATLASSERT(hCertStore);
|
|
ATLASSERT(pICertificates);
|
|
|
|
//
|
|
// Find all certificates in the store, matching the find criteria.
|
|
//
|
|
while (pCertContext = ::CertFindCertificateInStore(hCertStore,
|
|
CAPICOM_ASN_ENCODING,
|
|
0,
|
|
dwFindType,
|
|
pvFindPara,
|
|
pCertContext))
|
|
{
|
|
CComPtr<ICertificate2> pICertificate = NULL;
|
|
|
|
//
|
|
// Apply filter if available.
|
|
//
|
|
if (pfnFilterCallback && !pfnFilterCallback(pCertContext, NULL, pvCallbackData))
|
|
{
|
|
continue;
|
|
}
|
|
|
|
//
|
|
// Skip it if check is required and the cert is not valid.
|
|
//
|
|
if (bFindValidOnly)
|
|
{
|
|
if (FAILED(::VerifyCertificate(pCertContext, NULL, CERT_CHAIN_POLICY_BASE)))
|
|
{
|
|
continue;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Create a ICertificate2 object for the found certificate.
|
|
//
|
|
if (FAILED (hr = ::CreateCertificateObject(pCertContext,
|
|
dwCurrentSafety,
|
|
&pICertificate)))
|
|
{
|
|
DebugTrace("Error [%#x]: CreateCertificateObject() failed.\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
|
|
//
|
|
// Add to collection.
|
|
//
|
|
if (FAILED(hr = pICertificates->Add(pICertificate)))
|
|
{
|
|
DebugTrace("Error [%#x]: pICertificates->Add() failed.\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Above loop can exit with normal or error condition.
|
|
//
|
|
if (CRYPT_E_NOT_FOUND != (dwWin32Error = ::GetLastError()))
|
|
{
|
|
hr = HRESULT_FROM_WIN32(dwWin32Error);
|
|
|
|
DebugTrace("Error [%#x]: CertFindCertificateInStore() failed.\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
|
|
CommonExit:
|
|
//
|
|
// Free resources.
|
|
//
|
|
if (pCertContext)
|
|
{
|
|
::CertFreeCertificateContext(pCertContext);
|
|
}
|
|
|
|
DebugTrace("Leaving FindByCert().\n");
|
|
|
|
return hr;
|
|
|
|
ErrorExit:
|
|
//
|
|
// Sanity check.
|
|
//
|
|
ATLASSERT(FAILED(hr));
|
|
|
|
goto CommonExit;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// CCertificates
|
|
//
|
|
|
|
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
|
|
Function : CCertificates::Find
|
|
|
|
Synopsis : Find certificates in the collection that match the find criteria.
|
|
|
|
Parameter: CAPICOM_CERTIFICATE_FIND_TYPE FindType - Find type (see CAPICOM.H
|
|
for all possible values.)
|
|
|
|
VARIANT varCriteria - Data type depends on FindType.
|
|
|
|
VARIANT_BOOL bFindValidOnly - True to find valid certs only.
|
|
|
|
ICertificates2 ** pVal - Pointer to pointer to ICertificates
|
|
to receive the found certificate
|
|
collection.
|
|
|
|
Remark :
|
|
|
|
------------------------------------------------------------------------------*/
|
|
|
|
STDMETHODIMP CCertificates::Find (CAPICOM_CERTIFICATE_FIND_TYPE FindType,
|
|
VARIANT varCriteria,
|
|
VARIANT_BOOL bFindValidOnly,
|
|
ICertificates2 ** pVal)
|
|
{
|
|
USES_CONVERSION;
|
|
|
|
HRESULT hr = S_OK;
|
|
VARIANT * pvarCriteria = NULL;
|
|
BOOL bFindByChain = FALSE;
|
|
HCERTSTORE hCertStore = NULL;
|
|
DWORD dwFindType = CERT_FIND_ANY;
|
|
LPVOID pvFindPara = NULL;
|
|
LPVOID pvCallbackData = NULL;
|
|
LPSTR pszOid = NULL;
|
|
SYSTEMTIME st = {0};
|
|
FILETIME ftLocal = {0};
|
|
FILETIME ftUTC = {0};
|
|
CRYPT_HASH_BLOB HashBlob = {0, NULL};
|
|
PCCRYPT_OID_INFO pOidInfo = NULL;
|
|
PFNCFILTERPROC pfnCertCallback = NULL;
|
|
PFNCHAINFILTERPROC pfnChainCallback = NULL;
|
|
CComPtr<ICertificates2> pICertificates = NULL;
|
|
CAPICOM_CERTIFICATES_SOURCE ccs = {CAPICOM_CERTIFICATES_LOAD_FROM_STORE, 0};
|
|
CERT_CHAIN_FIND_BY_ISSUER_PARA ChainFindPara;
|
|
|
|
DebugTrace("Entering CCertificates::Find().\n");
|
|
|
|
try
|
|
{
|
|
//
|
|
// Lock access to this object.
|
|
//
|
|
m_Lock.Lock();
|
|
|
|
//
|
|
// Make sure parameters are valid.
|
|
//
|
|
if (NULL == pVal)
|
|
{
|
|
hr = E_INVALIDARG;
|
|
|
|
DebugTrace("Error [%#x]: pVal is NULL.\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
|
|
//
|
|
// Skip over BYREF.
|
|
//
|
|
for (pvarCriteria = &varCriteria;
|
|
pvarCriteria && ((VT_VARIANT | VT_BYREF) == V_VT(pvarCriteria));
|
|
pvarCriteria = V_VARIANTREF(pvarCriteria));
|
|
|
|
//
|
|
// Open a new memory store.
|
|
//
|
|
if (NULL == (hCertStore = ::CertOpenStore(CERT_STORE_PROV_MEMORY,
|
|
CAPICOM_ASN_ENCODING,
|
|
NULL,
|
|
CERT_STORE_CREATE_NEW_FLAG | CERT_STORE_ENUM_ARCHIVED_FLAG,
|
|
NULL)))
|
|
{
|
|
hr = HRESULT_FROM_WIN32(::GetLastError());
|
|
|
|
DebugTrace("Error [%#x]: CertOpenStore() failed.\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
|
|
//
|
|
// Create a new collection.
|
|
//
|
|
ccs.hCertStore = hCertStore;
|
|
|
|
if (FAILED(hr = ::CreateCertificatesObject(ccs, m_dwCurrentSafety, TRUE, &pICertificates)))
|
|
{
|
|
DebugTrace("Error [%#x]: CreateCertificatesObject() failed.\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
|
|
//
|
|
// Export current collection to the new memory store so that we can
|
|
// use it with CAPI's find APIs.
|
|
//
|
|
if (FAILED(hr = _ExportToStore(hCertStore)))
|
|
{
|
|
DebugTrace("Error [%#x]: CCertificates::ExportToStore() failed.\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
|
|
//
|
|
// Setup find parameters.
|
|
//
|
|
switch (FindType)
|
|
{
|
|
//
|
|
// Find by SHA1 hash.
|
|
//
|
|
case CAPICOM_CERTIFICATE_FIND_SHA1_HASH:
|
|
{
|
|
//
|
|
// Make sure data type is OK.
|
|
//
|
|
if (VT_BSTR != pvarCriteria->vt)
|
|
{
|
|
if (FAILED(hr = ::VariantChangeType(pvarCriteria, pvarCriteria, 0, VT_BSTR)))
|
|
{
|
|
DebugTrace("Error [%#x]: invalid data type %d, expect %d.\n", hr, pvarCriteria->vt, VT_BSTR);
|
|
goto ErrorExit;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Convert hash to binary.
|
|
//
|
|
if (FAILED(hr = ::StringToBinary(pvarCriteria->bstrVal,
|
|
::SysStringLen(pvarCriteria->bstrVal),
|
|
CRYPT_STRING_HEX,
|
|
(PBYTE *) &HashBlob.pbData,
|
|
&HashBlob.cbData)))
|
|
{
|
|
DebugTrace("Error [%#x]: StringToBinary() failed.\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
|
|
dwFindType = CERT_FIND_HASH;
|
|
pvFindPara = (LPVOID) &HashBlob;
|
|
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Find by subject name substring-in-string.
|
|
//
|
|
case CAPICOM_CERTIFICATE_FIND_SUBJECT_NAME:
|
|
{
|
|
//
|
|
// Make sure data type is OK.
|
|
//
|
|
if (VT_BSTR != pvarCriteria->vt)
|
|
{
|
|
if (FAILED(hr = ::VariantChangeType(pvarCriteria, pvarCriteria, 0, VT_BSTR)))
|
|
{
|
|
DebugTrace("Error [%#x]: invalid data type %d, expect %d.\n", hr, pvarCriteria->vt, VT_BSTR);
|
|
goto ErrorExit;
|
|
}
|
|
}
|
|
|
|
dwFindType = CERT_FIND_SUBJECT_STR;
|
|
pvFindPara = (LPVOID) pvarCriteria->bstrVal;
|
|
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Find by issuer name substring-in-string.
|
|
//
|
|
case CAPICOM_CERTIFICATE_FIND_ISSUER_NAME:
|
|
{
|
|
//
|
|
// Make sure data type is OK.
|
|
//
|
|
if (VT_BSTR != pvarCriteria->vt)
|
|
{
|
|
if (FAILED(hr = ::VariantChangeType(pvarCriteria, pvarCriteria, 0, VT_BSTR)))
|
|
{
|
|
DebugTrace("Error [%#x]: invalid data type %d, expect %d.\n", hr, pvarCriteria->vt, VT_BSTR);
|
|
goto ErrorExit;
|
|
}
|
|
}
|
|
|
|
dwFindType = CERT_FIND_ISSUER_STR;
|
|
pvFindPara = (LPVOID) pvarCriteria->bstrVal;
|
|
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Find by issuer name of root cert subtring-in-string.
|
|
//
|
|
case CAPICOM_CERTIFICATE_FIND_ROOT_NAME:
|
|
{
|
|
//
|
|
// Make sure data type is OK.
|
|
//
|
|
if (VT_BSTR != pvarCriteria->vt)
|
|
{
|
|
if (FAILED(hr = ::VariantChangeType(pvarCriteria, pvarCriteria, 0, VT_BSTR)))
|
|
{
|
|
DebugTrace("Error [%#x]: invalid data type %d, expect %d.\n", hr, pvarCriteria->vt, VT_BSTR);
|
|
goto ErrorExit;
|
|
}
|
|
}
|
|
|
|
::ZeroMemory(&ChainFindPara, sizeof(ChainFindPara));
|
|
ChainFindPara.cbSize = sizeof(ChainFindPara);
|
|
|
|
dwFindType = CERT_CHAIN_FIND_BY_ISSUER;
|
|
pvFindPara = (LPVOID) &ChainFindPara;
|
|
pfnChainCallback = FindRootNameCallback;
|
|
pvCallbackData = (LPVOID) pvarCriteria->bstrVal;
|
|
|
|
bFindByChain = TRUE;
|
|
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Find by template name or OID.
|
|
//
|
|
case CAPICOM_CERTIFICATE_FIND_TEMPLATE_NAME:
|
|
{
|
|
//
|
|
// Make sure data type is OK.
|
|
//
|
|
if (VT_BSTR != pvarCriteria->vt)
|
|
{
|
|
if (FAILED(hr = ::VariantChangeType(pvarCriteria, pvarCriteria, 0, VT_BSTR)))
|
|
{
|
|
DebugTrace("Error [%#x]: invalid data type %d, expect %d.\n", hr, pvarCriteria->vt, VT_BSTR);
|
|
goto ErrorExit;
|
|
}
|
|
}
|
|
|
|
pfnCertCallback = FindTemplateCallback;
|
|
pvCallbackData = (LPVOID) pvarCriteria->bstrVal;
|
|
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Find by extension.
|
|
//
|
|
case CAPICOM_CERTIFICATE_FIND_EXTENSION:
|
|
{
|
|
//
|
|
// Make sure data type is OK.
|
|
//
|
|
if (VT_BSTR != pvarCriteria->vt)
|
|
{
|
|
if (FAILED(hr = ::VariantChangeType(pvarCriteria, pvarCriteria, 0, VT_BSTR)))
|
|
{
|
|
DebugTrace("Error [%#x]: invalid data type %d, expect %d.\n", hr, pvarCriteria->vt, VT_BSTR);
|
|
goto ErrorExit;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Convert to OID if user passed in friendly name.
|
|
//
|
|
if (pOidInfo = ::CryptFindOIDInfo(CRYPT_OID_INFO_NAME_KEY,
|
|
(LPWSTR) pvarCriteria->bstrVal,
|
|
CRYPT_EXT_OR_ATTR_OID_GROUP_ID))
|
|
{
|
|
pszOid = (LPSTR) pOidInfo->pszOID;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Convert to ASCII.
|
|
//
|
|
if (!(pszOid = W2A(pvarCriteria->bstrVal)))
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
|
|
DebugTrace("Error [%%#x]: pszOid = W2A(pvarCriteria->bstrVal) failed.\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
}
|
|
|
|
pfnCertCallback = FindExtensionCallback;
|
|
pvCallbackData = (LPVOID) pszOid;
|
|
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Find by property ID.
|
|
//
|
|
case CAPICOM_CERTIFICATE_FIND_EXTENDED_PROPERTY:
|
|
{
|
|
//
|
|
// Make sure data type is OK.
|
|
//
|
|
if (VT_I4 != pvarCriteria->vt)
|
|
{
|
|
if (FAILED(hr = ::VariantChangeType(pvarCriteria, pvarCriteria, 0, VT_I4)))
|
|
{
|
|
DebugTrace("Error [%#x]: invalid data type %d, expect %d.\n", hr, pvarCriteria->vt, VT_I4);
|
|
goto ErrorExit;
|
|
}
|
|
}
|
|
|
|
dwFindType = CERT_FIND_PROPERTY;
|
|
pvFindPara = (LPVOID) &pvarCriteria->lVal;
|
|
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Find by application policy (EKU).
|
|
//
|
|
case CAPICOM_CERTIFICATE_FIND_APPLICATION_POLICY:
|
|
{
|
|
//
|
|
// Make sure data type is OK.
|
|
//
|
|
if (VT_BSTR != pvarCriteria->vt)
|
|
{
|
|
if (FAILED(hr = ::VariantChangeType(pvarCriteria, pvarCriteria, 0, VT_BSTR)))
|
|
{
|
|
DebugTrace("Error [%#x]: invalid data type %d, expect %d.\n", hr, pvarCriteria->vt, VT_BSTR);
|
|
goto ErrorExit;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Try to convert to OID if user passed in friendly name.
|
|
//
|
|
if (pOidInfo = ::CryptFindOIDInfo(CRYPT_OID_INFO_NAME_KEY,
|
|
(LPWSTR) pvarCriteria->bstrVal,
|
|
CRYPT_ENHKEY_USAGE_OID_GROUP_ID))
|
|
{
|
|
pszOid = (LPSTR) pOidInfo->pszOID;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Convert to ASCII.
|
|
//
|
|
if (!(pszOid = W2A(pvarCriteria->bstrVal)))
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
|
|
DebugTrace("Error [%#X]: pszOid = W2A(pvarCriteria->bstrVal) failed.\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
}
|
|
|
|
pfnCertCallback = FindApplicationPolicyCallback;
|
|
pvCallbackData = (LPVOID) pszOid;
|
|
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Find by certificate policy.
|
|
//
|
|
case CAPICOM_CERTIFICATE_FIND_CERTIFICATE_POLICY:
|
|
{
|
|
//
|
|
// Make sure data type is OK.
|
|
//
|
|
if (VT_BSTR != pvarCriteria->vt)
|
|
{
|
|
if (FAILED(hr = ::VariantChangeType(pvarCriteria, pvarCriteria, 0, VT_BSTR)))
|
|
{
|
|
DebugTrace("Error [%#x]: invalid data type %d, expect %d.\n", hr, pvarCriteria->vt, VT_BSTR);
|
|
goto ErrorExit;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Convert to OID if user passed in friendly name.
|
|
//
|
|
if (pOidInfo = ::CryptFindOIDInfo(CRYPT_OID_INFO_NAME_KEY,
|
|
(LPWSTR) pvarCriteria->bstrVal,
|
|
CRYPT_POLICY_OID_GROUP_ID))
|
|
{
|
|
pszOid = (LPSTR) pOidInfo->pszOID;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Convert to ASCII.
|
|
//
|
|
if (!(pszOid = W2A(pvarCriteria->bstrVal)))
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
|
|
DebugTrace("Error [%#x]: pszOid = W2A(pvarCriteria->bstrVal) failed.\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
}
|
|
|
|
pfnCertCallback = FindCertificatePolicyCallback;
|
|
pvCallbackData = (LPVOID) pszOid;
|
|
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Find by time valid.
|
|
//
|
|
case CAPICOM_CERTIFICATE_FIND_TIME_VALID:
|
|
{
|
|
//
|
|
// !!! Warning, falling thru. !!!
|
|
//
|
|
}
|
|
|
|
//
|
|
// Find by notBefore time validity.
|
|
//
|
|
case CAPICOM_CERTIFICATE_FIND_TIME_NOT_YET_VALID:
|
|
{
|
|
//
|
|
// !!! Warning, falling thru. !!!
|
|
//
|
|
}
|
|
|
|
// Find by notAfter time validity.
|
|
//
|
|
case CAPICOM_CERTIFICATE_FIND_TIME_EXPIRED:
|
|
{
|
|
//
|
|
// Make sure data type is OK.
|
|
//
|
|
if (VT_DATE != pvarCriteria->vt)
|
|
{
|
|
if (FAILED(hr = ::VariantChangeType(pvarCriteria, pvarCriteria, 0, VT_DATE)))
|
|
{
|
|
DebugTrace("Error [%#x]: invalid data type %d, expect %d.\n", hr, pvarCriteria->vt, VT_DATE);
|
|
goto ErrorExit;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Convert to SYSTEMTIME format.
|
|
//
|
|
if (0 == pvarCriteria->date)
|
|
{
|
|
::GetLocalTime(&st);
|
|
}
|
|
else if (!::VariantTimeToSystemTime(pvarCriteria->date, &st))
|
|
{
|
|
hr = E_INVALIDARG;
|
|
|
|
DebugTrace("Error [%#x]: VariantTimeToSystemTime() failed.\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
|
|
//
|
|
// Convert to FILETIME format.
|
|
//
|
|
if (!::SystemTimeToFileTime(&st, &ftLocal))
|
|
{
|
|
hr = HRESULT_FROM_WIN32(::GetLastError());
|
|
|
|
DebugTrace("Error [%#x]: SystemTimeToFileTime() failed.\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
|
|
//
|
|
// Convert to UTC FILETIME.
|
|
//
|
|
if (!::LocalFileTimeToFileTime(&ftLocal, &ftUTC))
|
|
{
|
|
hr = HRESULT_FROM_WIN32(::GetLastError());
|
|
|
|
DebugTrace("Error [%#x]: LocalFileTimeToFileTime() failed.\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
|
|
if (CAPICOM_CERTIFICATE_FIND_TIME_VALID == FindType)
|
|
{
|
|
pfnCertCallback = FindTimeValidCallback;
|
|
}
|
|
else if (CAPICOM_CERTIFICATE_FIND_TIME_NOT_YET_VALID == FindType)
|
|
{
|
|
pfnCertCallback = FindNotBeforeCallback;
|
|
}
|
|
else
|
|
{
|
|
pfnCertCallback = FindNotAfterCallback;
|
|
}
|
|
pvCallbackData = (LPVOID) &ftUTC;
|
|
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Find by key usage.
|
|
//
|
|
case CAPICOM_CERTIFICATE_FIND_KEY_USAGE:
|
|
{
|
|
//
|
|
// By Key Usage bit flag?
|
|
//
|
|
if (VT_I4 != pvarCriteria->vt)
|
|
{
|
|
//
|
|
// By key usage friendly's name?
|
|
//
|
|
if (VT_BSTR == pvarCriteria->vt)
|
|
{
|
|
typedef struct _KeyUsagesStruct
|
|
{
|
|
LPWSTR pwszKeyUsage;
|
|
DWORD dwKeyUsageBit;
|
|
} KEY_USAGE_STRUCT;
|
|
|
|
KEY_USAGE_STRUCT KeyUsages[] =
|
|
{ {L"DigitalSignature", CERT_DIGITAL_SIGNATURE_KEY_USAGE},
|
|
{L"NonRepudiation", CERT_NON_REPUDIATION_KEY_USAGE},
|
|
{L"KeyEncipherment", CERT_KEY_ENCIPHERMENT_KEY_USAGE},
|
|
{L"DataEncipherment", CERT_DATA_ENCIPHERMENT_KEY_USAGE},
|
|
{L"KeyAgreement", CERT_KEY_AGREEMENT_KEY_USAGE},
|
|
{L"KeyCertSign", CERT_KEY_CERT_SIGN_KEY_USAGE},
|
|
{L"CRLSign", CERT_CRL_SIGN_KEY_USAGE},
|
|
{L"EncipherOnly", CERT_ENCIPHER_ONLY_KEY_USAGE},
|
|
{L"DecipherOnly", CERT_DECIPHER_ONLY_KEY_USAGE}
|
|
};
|
|
|
|
//
|
|
// Find the name.
|
|
//
|
|
for (DWORD i = 0; i < ARRAYSIZE(KeyUsages); i++)
|
|
{
|
|
if (0 == _wcsicmp(KeyUsages[i].pwszKeyUsage, (LPWSTR) pvarCriteria->bstrVal))
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (i == ARRAYSIZE(KeyUsages))
|
|
{
|
|
hr = E_INVALIDARG;
|
|
|
|
DebugTrace("Error [%#x]: Unknown key usage (%ls).\n", hr, (LPWSTR) pvarCriteria->bstrVal);
|
|
goto ErrorExit;
|
|
}
|
|
|
|
//
|
|
// Convert to bit flag.
|
|
//
|
|
::VariantClear(pvarCriteria);
|
|
pvarCriteria->vt = VT_I4;
|
|
pvarCriteria->lVal = KeyUsages[i].dwKeyUsageBit;
|
|
}
|
|
else
|
|
{
|
|
if (FAILED(hr = ::VariantChangeType(pvarCriteria, pvarCriteria, 0, VT_I4)))
|
|
{
|
|
DebugTrace("Error [%#x]: invalid data type %d, expect %d.\n", hr, pvarCriteria->vt, VT_I4);
|
|
goto ErrorExit;
|
|
}
|
|
}
|
|
}
|
|
|
|
pfnCertCallback = FindKeyUsageCallback;
|
|
pvCallbackData = (LPVOID) &pvarCriteria->lVal;
|
|
|
|
break;
|
|
}
|
|
|
|
default:
|
|
{
|
|
hr = CAPICOM_E_FIND_INVALID_TYPE;
|
|
|
|
DebugTrace("Error [%#x]: invalid CAPICOM_CERTIFICATE_FIND_TYPE (%d).\n", hr, FindType);
|
|
goto ErrorExit;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Now find the certs.
|
|
//
|
|
if (bFindByChain)
|
|
{
|
|
if (FAILED(hr = ::FindByChain(hCertStore,
|
|
dwFindType,
|
|
pvFindPara,
|
|
bFindValidOnly,
|
|
pfnChainCallback,
|
|
pvCallbackData,
|
|
m_dwCurrentSafety,
|
|
pICertificates)))
|
|
{
|
|
DebugTrace("Error [%#x]: FindByChain() failed.\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (FAILED(hr = ::FindByCert(hCertStore,
|
|
dwFindType,
|
|
pvFindPara,
|
|
bFindValidOnly,
|
|
pfnCertCallback,
|
|
pvCallbackData,
|
|
m_dwCurrentSafety,
|
|
pICertificates)))
|
|
{
|
|
DebugTrace("Error [%#x]: FindByCert() failed.\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Return collection to caller.
|
|
//
|
|
if (FAILED(hr = pICertificates->QueryInterface(pVal)))
|
|
{
|
|
DebugTrace("Unexpected error [%#x]: pICertificates->QueryInterface() failed.\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
}
|
|
|
|
catch(...)
|
|
{
|
|
hr = E_INVALIDARG;
|
|
|
|
DebugTrace("Exception: invalid parameter.\n");
|
|
goto ErrorExit;
|
|
}
|
|
|
|
UnlockExit:
|
|
//
|
|
// Free reources.
|
|
//
|
|
if (HashBlob.pbData)
|
|
{
|
|
::CoTaskMemFree((LPVOID) HashBlob.pbData);
|
|
}
|
|
if (hCertStore)
|
|
{
|
|
::CertCloseStore(hCertStore, 0);
|
|
}
|
|
|
|
//
|
|
// Unlock access to this object.
|
|
//
|
|
m_Lock.Unlock();
|
|
|
|
DebugTrace("Leaving CCertificates::Find().\n");
|
|
|
|
return hr;
|
|
|
|
ErrorExit:
|
|
//
|
|
// Sanity check.
|
|
//
|
|
ATLASSERT(FAILED(hr));
|
|
|
|
ReportError(hr);
|
|
|
|
goto UnlockExit;
|
|
}
|
|
|
|
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
|
|
Function : CCertificates::Select
|
|
|
|
Synopsis : Display the certificate selection dialog box.
|
|
|
|
Parameter: BSTR Title - Dialog box title.
|
|
|
|
BSTR DisplayString - Display string.
|
|
|
|
VARIANT_BOOL bMultiSelect - True for multi-select.
|
|
|
|
ICertificates2 ** pVal - Pointer to pointer to ICertificates
|
|
to receive the select certificate
|
|
collection.
|
|
|
|
Remark :
|
|
|
|
------------------------------------------------------------------------------*/
|
|
|
|
STDMETHODIMP CCertificates::Select (BSTR Title,
|
|
BSTR DisplayString,
|
|
VARIANT_BOOL bMultiSelect,
|
|
ICertificates2 ** pVal)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
HCERTSTORE hSrcStore = NULL;
|
|
HCERTSTORE hDstStore = NULL;
|
|
PCCERT_CONTEXT pCertContext = NULL;
|
|
CComPtr<ICertificates2> pICertificates = NULL;
|
|
|
|
CAPICOM_CERTIFICATES_SOURCE ccs = {0, NULL};
|
|
|
|
DebugTrace("Entering CCertificates::Select().\n");
|
|
|
|
try
|
|
{
|
|
//
|
|
// Lock access to this object.
|
|
//
|
|
m_Lock.Lock();
|
|
|
|
//
|
|
// Make sure parameters are valid.
|
|
//
|
|
if (NULL == pVal)
|
|
{
|
|
hr = E_INVALIDARG;
|
|
|
|
DebugTrace("Error [%#x]: pVal is NULL.\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
|
|
//
|
|
// Make sure we are allowed to pop UI.
|
|
//
|
|
if (!PromptForCertificateEnabled())
|
|
{
|
|
hr = CAPICOM_E_UI_DISABLED;
|
|
|
|
DebugTrace("Error [%#x]: UI is disabled.\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
|
|
//
|
|
// Work aroung MIDL default BSTR problem.
|
|
//
|
|
if (0 == ::SysStringLen(Title))
|
|
{
|
|
Title = NULL;
|
|
}
|
|
if (0 == ::SysStringLen(DisplayString))
|
|
{
|
|
DisplayString = NULL;
|
|
}
|
|
|
|
//
|
|
// Open a new memory source store.
|
|
//
|
|
if (NULL == (hSrcStore = ::CertOpenStore(CERT_STORE_PROV_MEMORY,
|
|
CAPICOM_ASN_ENCODING,
|
|
NULL,
|
|
CERT_STORE_CREATE_NEW_FLAG,
|
|
NULL)))
|
|
{
|
|
hr = HRESULT_FROM_WIN32(::GetLastError());
|
|
|
|
DebugTrace("Error [%#x]: CertOpenStore() failed.\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
|
|
//
|
|
// Export collections to the new memory source store.
|
|
//
|
|
if (FAILED(hr = _ExportToStore(hSrcStore)))
|
|
{
|
|
DebugTrace("Error [%#x]: CCertificates::_ExportToStore() failed.\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
|
|
//
|
|
// Open a new memory destination store for multi-select.
|
|
//
|
|
if (bMultiSelect)
|
|
{
|
|
if (!(hDstStore = ::CertOpenStore(CERT_STORE_PROV_MEMORY,
|
|
CAPICOM_ASN_ENCODING,
|
|
NULL,
|
|
CERT_STORE_CREATE_NEW_FLAG,
|
|
NULL)))
|
|
{
|
|
hr = HRESULT_FROM_WIN32(::GetLastError());
|
|
|
|
DebugTrace("Error [%#x]: CertOpenStore() failed.\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Display the cert selection dialog box.
|
|
//
|
|
if (FAILED(hr = ::SelectCertificateContext(hSrcStore,
|
|
Title,
|
|
DisplayString,
|
|
(BOOL) bMultiSelect,
|
|
NULL,
|
|
hDstStore,
|
|
&pCertContext)))
|
|
{
|
|
DebugTrace("Error [%#x]: SelectCertificateContext() failed.\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
|
|
//
|
|
// Create the collection object.
|
|
//
|
|
if (bMultiSelect)
|
|
{
|
|
//
|
|
// Create a new collection from the destination store.
|
|
//
|
|
ccs.dwSource = CAPICOM_CERTIFICATES_LOAD_FROM_STORE;
|
|
ccs.hCertStore = hDstStore;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Create a new collection from the cert context.
|
|
//
|
|
ccs.dwSource = CAPICOM_CERTIFICATES_LOAD_FROM_CERT;
|
|
ccs.pCertContext = pCertContext;
|
|
}
|
|
|
|
if (FAILED(hr = ::CreateCertificatesObject(ccs, m_dwCurrentSafety, TRUE, &pICertificates)))
|
|
{
|
|
DebugTrace("Error [%#x]: CreateCertificatesObject() failed.\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
|
|
//
|
|
// Return collection to caller.
|
|
//
|
|
if (FAILED(hr = pICertificates->QueryInterface(pVal)))
|
|
{
|
|
DebugTrace("Unexpected error [%#x]: pICertificates->QueryInterface() failed.\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
}
|
|
|
|
catch(...)
|
|
{
|
|
hr = E_INVALIDARG;
|
|
|
|
DebugTrace("Exception: invalid parameter.\n");
|
|
goto ErrorExit;
|
|
}
|
|
|
|
UnlockExit:
|
|
//
|
|
// Free reources.
|
|
//
|
|
if (pCertContext)
|
|
{
|
|
::CertFreeCertificateContext(pCertContext);
|
|
}
|
|
if (hDstStore)
|
|
{
|
|
::CertCloseStore(hDstStore, 0);
|
|
}
|
|
if (hSrcStore)
|
|
{
|
|
::CertCloseStore(hSrcStore, 0);
|
|
}
|
|
|
|
//
|
|
// Unlock access to this object.
|
|
//
|
|
m_Lock.Unlock();
|
|
|
|
DebugTrace("Leaving CCertificates::Select().\n");
|
|
|
|
return hr;
|
|
|
|
ErrorExit:
|
|
//
|
|
// Sanity check.
|
|
//
|
|
ATLASSERT(FAILED(hr));
|
|
|
|
ReportError(hr);
|
|
|
|
goto UnlockExit;
|
|
}
|
|
|
|
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
|
|
Function : CCertificates::Add
|
|
|
|
Synopsis : Add a Certificate2 to the collection.
|
|
|
|
Parameter: ICertificate2 * pVal - Certificate2 to be added.
|
|
|
|
Remark :
|
|
|
|
------------------------------------------------------------------------------*/
|
|
|
|
STDMETHODIMP CCertificates::Add (ICertificate2 * pVal)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
char szIndex[33];
|
|
CComBSTR bstrIndex;
|
|
|
|
DebugTrace("Entering CCertificates::Add().\n");
|
|
|
|
try
|
|
{
|
|
//
|
|
// Lock access to this object.
|
|
//
|
|
m_Lock.Lock();
|
|
|
|
//
|
|
// Make sure parameters are valid.
|
|
//
|
|
if (NULL == pVal)
|
|
{
|
|
hr = E_INVALIDARG;
|
|
|
|
DebugTrace("Error [%#x]: pVal is NULL.\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
|
|
#if (0)
|
|
CComPtr<ICertificate2> pICertificate = NULL;
|
|
|
|
//
|
|
// Make sure we have a valid Certificate.
|
|
//
|
|
if (FAILED(hr = pVal->QueryInterface(__uuidof(ICertificate2), (void **) &pICertificate.p)))
|
|
{
|
|
hr = E_NOINTERFACE;
|
|
|
|
DebugTrace("Error [%#x]: pVal is not an Certificate object.\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
#endif
|
|
|
|
DebugTrace("Info: m_dwNextIndex = %#x, m_coll.max_size() = %#x.\n",
|
|
m_dwNextIndex, m_coll.max_size());
|
|
|
|
//
|
|
// If index by number, and the index exceeds our max, then we will
|
|
// force it to be indexed by thumbprint.
|
|
//
|
|
if ((m_bIndexedByThumbprint) || ((m_dwNextIndex + 1) > m_coll.max_size()))
|
|
{
|
|
if (FAILED(hr = pVal->get_Thumbprint(&bstrIndex)))
|
|
{
|
|
DebugTrace("Error [%#x]: pVal->get_Thumbprint() failed.\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
|
|
m_bIndexedByThumbprint = TRUE;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// BSTR index of numeric value.
|
|
//
|
|
wsprintfA(szIndex, "%#08x", ++m_dwNextIndex);
|
|
|
|
if (!(bstrIndex = szIndex))
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
|
|
DebugTrace("Error [%#x]: bstrIndex = szIndex failed.\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Now add object to collection map.
|
|
//
|
|
// Note that the overloaded = operator for CComPtr will
|
|
// automatically AddRef to the object. Also, when the CComPtr
|
|
// is deleted (happens when the Remove or map destructor is called),
|
|
// the CComPtr destructor will automatically Release the object.
|
|
//
|
|
m_coll[bstrIndex] = pVal;
|
|
}
|
|
|
|
catch(...)
|
|
{
|
|
hr = E_POINTER;
|
|
|
|
DebugTrace("Exception: invalid parameter.\n");
|
|
goto ErrorExit;
|
|
}
|
|
|
|
UnlockExit:
|
|
|
|
//
|
|
// Unlock access to this object.
|
|
//
|
|
m_Lock.Unlock();
|
|
|
|
DebugTrace("Leaving CCertificates::Add().\n");
|
|
|
|
return hr;
|
|
|
|
ErrorExit:
|
|
//
|
|
// Sanity check.
|
|
//
|
|
ATLASSERT(FAILED(hr));
|
|
|
|
ReportError(hr);
|
|
|
|
goto UnlockExit;
|
|
}
|
|
|
|
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
|
|
Function : CCertificates::Remove
|
|
|
|
Synopsis : Remove a Certificate2 from the collection.
|
|
|
|
Parameter: VARIANT Index - Can be numeric index (1-based), SHA1 string, or
|
|
Certificate object.
|
|
|
|
Remark :
|
|
|
|
------------------------------------------------------------------------------*/
|
|
|
|
STDMETHODIMP CCertificates::Remove (VARIANT Index)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
VARIANT * pvarIndex = NULL;
|
|
CComBSTR bstrIndex;
|
|
CertificateMap::iterator iter;
|
|
CComPtr<ICertificate2> pICertificate;
|
|
|
|
DebugTrace("Entering CCertificates::Remove().\n");
|
|
|
|
try
|
|
{
|
|
//
|
|
// Lock access to this object.
|
|
//
|
|
m_Lock.Lock();
|
|
|
|
//
|
|
// Skip over BYREF.
|
|
//
|
|
for (pvarIndex = &Index;
|
|
pvarIndex && ((VT_VARIANT | VT_BYREF) == V_VT(pvarIndex));
|
|
pvarIndex = V_VARIANTREF(pvarIndex));
|
|
|
|
//
|
|
// Which form of index?
|
|
//
|
|
switch (pvarIndex->vt)
|
|
{
|
|
case VT_DISPATCH:
|
|
{
|
|
//
|
|
// Get the thumbprint;
|
|
//
|
|
if (FAILED(hr = pvarIndex->pdispVal->QueryInterface(IID_ICertificate2, (void **) &pICertificate)))
|
|
{
|
|
DebugTrace("Error [%#x]: pvarIndex->pdispVal->QueryInterface() failed.\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
|
|
if (FAILED(hr = pICertificate->get_Thumbprint(&bstrIndex)))
|
|
{
|
|
DebugTrace("Error [%#x]: pICertificate->get_Thumbprint() failed.\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
|
|
//
|
|
// !!! WARNING. Falling thru !!!
|
|
//
|
|
}
|
|
|
|
case VT_BSTR:
|
|
{
|
|
//
|
|
// Because we could have felt thru, so need to check again.
|
|
//
|
|
if (VT_BSTR == pvarIndex->vt)
|
|
{
|
|
bstrIndex = pvarIndex->bstrVal;
|
|
}
|
|
|
|
//
|
|
// Find the cert matching this thumbprint.
|
|
//
|
|
for (iter = m_coll.begin(); iter != m_coll.end(); iter++)
|
|
{
|
|
CComBSTR bstrThumbprint;
|
|
|
|
//
|
|
// Point to the object.
|
|
//
|
|
pICertificate = (*iter).second;
|
|
|
|
//
|
|
// Get the thumbprint;
|
|
//
|
|
if (FAILED(hr = pICertificate->get_Thumbprint(&bstrThumbprint)))
|
|
{
|
|
DebugTrace("Error [%#x]: pICertificate->get_Thumbprint() failed.\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
|
|
//
|
|
// Same thumbprint?
|
|
//
|
|
if (0 == ::_wcsicmp(bstrThumbprint, bstrIndex))
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Did we find in the map?
|
|
//
|
|
if (iter == m_coll.end())
|
|
{
|
|
hr = E_INVALIDARG;
|
|
|
|
DebugTrace("Error [%#x]: Requested certificate (sha1 = %ls) is not found in the collection.\n",
|
|
hr, bstrIndex);
|
|
goto ErrorExit;
|
|
}
|
|
|
|
//
|
|
// Now remove from map.
|
|
//
|
|
m_coll.erase(iter);
|
|
|
|
break;
|
|
}
|
|
|
|
default:
|
|
{
|
|
DWORD dwIndex;
|
|
|
|
//
|
|
// Assume numeric index.
|
|
//
|
|
if (VT_I4 != pvarIndex->vt &&
|
|
FAILED(hr = ::VariantChangeType(pvarIndex, pvarIndex, 0, VT_I4)))
|
|
{
|
|
DebugTrace("Error [%#x]: VariantChangeType() failed.\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
|
|
//
|
|
// Make sure index is valid.
|
|
//
|
|
dwIndex = (DWORD) pvarIndex->lVal;
|
|
|
|
if (dwIndex < 1 || dwIndex > m_coll.size())
|
|
{
|
|
hr = E_INVALIDARG;
|
|
|
|
DebugTrace("Error [%#x]: Index %d is out of range.\n", hr, dwIndex);
|
|
goto ErrorExit;
|
|
}
|
|
|
|
//
|
|
// Find object in map.
|
|
//
|
|
dwIndex--;
|
|
iter = m_coll.begin();
|
|
|
|
while (iter != m_coll.end() && dwIndex > 0)
|
|
{
|
|
iter++;
|
|
dwIndex--;
|
|
}
|
|
|
|
//
|
|
// Did we find in the map?
|
|
//
|
|
if (iter == m_coll.end())
|
|
{
|
|
hr = E_INVALIDARG;
|
|
|
|
DebugTrace("Error [%#x]: Requested certificate (Index = %d) is not found in the collection.\n",
|
|
hr, dwIndex);
|
|
goto ErrorExit;
|
|
}
|
|
|
|
//
|
|
// Now remove from map.
|
|
//
|
|
m_coll.erase(iter);
|
|
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
catch(...)
|
|
{
|
|
hr = E_POINTER;
|
|
|
|
DebugTrace("Exception: invalid parameter.\n");
|
|
goto ErrorExit;
|
|
}
|
|
|
|
UnlockExit:
|
|
//
|
|
// Unlock access to this object.
|
|
//
|
|
m_Lock.Unlock();
|
|
|
|
DebugTrace("Leaving CCertificates::Remove().\n");
|
|
|
|
return hr;
|
|
|
|
ErrorExit:
|
|
//
|
|
// Sanity check.
|
|
//
|
|
ATLASSERT(FAILED(hr));
|
|
|
|
ReportError(hr);
|
|
|
|
goto UnlockExit;
|
|
}
|
|
|
|
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
|
|
Function : CCertificates::Clear
|
|
|
|
Synopsis : Remove all Certificate2 from the collection.
|
|
|
|
Parameter: None.
|
|
|
|
Remark :
|
|
|
|
------------------------------------------------------------------------------*/
|
|
|
|
STDMETHODIMP CCertificates::Clear (void)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
DebugTrace("Entering CCertificates::Clear().\n");
|
|
|
|
try
|
|
{
|
|
//
|
|
// Lock access to this object.
|
|
//
|
|
m_Lock.Lock();
|
|
|
|
//
|
|
// Clear it.
|
|
//
|
|
m_coll.clear();
|
|
|
|
//
|
|
// Sanity check.
|
|
//
|
|
ATLASSERT(0 == m_coll.size());
|
|
}
|
|
|
|
catch(...)
|
|
{
|
|
hr = E_POINTER;
|
|
|
|
DebugTrace("Exception: invalid parameter.\n");
|
|
goto ErrorExit;
|
|
}
|
|
|
|
UnlockExit:
|
|
//
|
|
// Unlock access to this object.
|
|
//
|
|
m_Lock.Unlock();
|
|
|
|
DebugTrace("Leaving CCertificates::Clear().\n");
|
|
|
|
return hr;
|
|
|
|
ErrorExit:
|
|
//
|
|
// Sanity check.
|
|
//
|
|
ATLASSERT(FAILED(hr));
|
|
|
|
ReportError(hr);
|
|
|
|
goto UnlockExit;
|
|
}
|
|
|
|
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
|
|
Function : CCertificates::Save
|
|
|
|
Synopsis : Method to save certificate collection to a file.
|
|
|
|
Parameter: BSTR FileName - File name.
|
|
|
|
BSTR Password - Password (required for PFX file.).
|
|
|
|
CAPICOM_CERTIFICATES_SAVE_AS_TYPE SaveAs - SaveAs type.
|
|
|
|
CAPICOM_EXPORT_FLAG ExportFlag - Export flags.
|
|
|
|
|
|
Remark :
|
|
|
|
------------------------------------------------------------------------------*/
|
|
|
|
STDMETHODIMP CCertificates::Save (BSTR FileName,
|
|
BSTR Password,
|
|
CAPICOM_CERTIFICATES_SAVE_AS_TYPE SaveAs,
|
|
CAPICOM_EXPORT_FLAG ExportFlag)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
HCERTSTORE hCertStore = NULL;
|
|
|
|
DebugTrace("Entering CCertificates::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;
|
|
}
|
|
|
|
//
|
|
// Open a new memory store.
|
|
//
|
|
if (NULL == (hCertStore = ::CertOpenStore(CERT_STORE_PROV_MEMORY,
|
|
CAPICOM_ASN_ENCODING,
|
|
NULL,
|
|
CERT_STORE_CREATE_NEW_FLAG | CERT_STORE_ENUM_ARCHIVED_FLAG,
|
|
NULL)))
|
|
{
|
|
hr = HRESULT_FROM_WIN32(::GetLastError());
|
|
|
|
DebugTrace("Error [%#x]: CertOpenStore() failed.\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
|
|
//
|
|
// Export current collection to the new memory store so that we can
|
|
// use it with CAPI's store save APIs.
|
|
//
|
|
if (FAILED(hr = _ExportToStore(hCertStore)))
|
|
{
|
|
DebugTrace("Error [%#x]: CCertificates::ExportToStore() failed.\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
|
|
//
|
|
// Check file type.
|
|
//
|
|
switch (SaveAs)
|
|
{
|
|
case CAPICOM_CERTIFICATES_SAVE_AS_PFX:
|
|
{
|
|
//
|
|
// Save as PFX file.
|
|
//
|
|
if (FAILED(hr = ::PFXSaveStore(hCertStore,
|
|
FileName,
|
|
Password,
|
|
EXPORT_PRIVATE_KEYS |
|
|
(ExportFlag & CAPICOM_EXPORT_IGNORE_PRIVATE_KEY_NOT_EXPORTABLE_ERROR ? 0 : REPORT_NOT_ABLE_TO_EXPORT_PRIVATE_KEY))))
|
|
{
|
|
DebugTrace("Error [%#x]: PFXSaveStore() failed.\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
case CAPICOM_CERTIFICATES_SAVE_AS_SERIALIZED:
|
|
{
|
|
//
|
|
// Save as serialized store file.
|
|
//
|
|
if (!::CertSaveStore(hCertStore,
|
|
0,
|
|
CERT_STORE_SAVE_AS_STORE,
|
|
CERT_STORE_SAVE_TO_FILENAME_W,
|
|
(void *) FileName,
|
|
0))
|
|
{
|
|
hr = HRESULT_FROM_WIN32(::GetLastError());
|
|
|
|
DebugTrace("Error [%#x]: CertSaveStore() failed.\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
case CAPICOM_CERTIFICATES_SAVE_AS_PKCS7:
|
|
{
|
|
//
|
|
// Save as PKCS 7 file.
|
|
//
|
|
if (!::CertSaveStore(hCertStore,
|
|
CAPICOM_ASN_ENCODING,
|
|
CERT_STORE_SAVE_AS_PKCS7,
|
|
CERT_STORE_SAVE_TO_FILENAME_W,
|
|
(void *) FileName,
|
|
0))
|
|
{
|
|
hr = HRESULT_FROM_WIN32(::GetLastError());
|
|
|
|
DebugTrace("Error [%#x]: CertSaveStore() failed.\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
default:
|
|
{
|
|
hr = E_INVALIDARG;
|
|
|
|
DebugTrace("Error [%#x]: Unknown save as type (%#x).\n", hr, SaveAs);
|
|
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 CCertificates::Save().\n");
|
|
|
|
return hr;
|
|
|
|
ErrorExit:
|
|
//
|
|
// Sanity check.
|
|
//
|
|
ATLASSERT(FAILED(hr));
|
|
|
|
ReportError(hr);
|
|
|
|
goto UnlockExit;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Non COM functions.
|
|
//
|
|
|
|
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
|
|
Function : CCertificates::AddContext
|
|
|
|
Synopsis : Add a cert to the collection.
|
|
|
|
Parameter: PCCERT_CONTEXT pCertContext - Cert to be added.
|
|
|
|
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 CCertificates::AddContext (PCCERT_CONTEXT pCertContext)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
CComPtr<ICertificate2> pICertificate = NULL;
|
|
|
|
DebugTrace("Entering CCertificates::AddContext().\n");
|
|
|
|
//
|
|
// Sanity check.
|
|
//
|
|
ATLASSERT(pCertContext);
|
|
|
|
try
|
|
{
|
|
//
|
|
// Create the ICertificate object from CERT_CONTEXT.
|
|
//
|
|
if (FAILED(hr = ::CreateCertificateObject(pCertContext,
|
|
m_dwCurrentSafety,
|
|
&pICertificate)))
|
|
{
|
|
DebugTrace("Error [%#x]: CreateCertificateObject() failed.\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
|
|
//
|
|
// Add to collection.
|
|
//
|
|
if (FAILED(hr = Add(pICertificate)))
|
|
{
|
|
DebugTrace("Error [%#x]: CCertificates::Add() failed.\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
}
|
|
|
|
catch(...)
|
|
{
|
|
hr = E_POINTER;
|
|
|
|
DebugTrace("Exception: invalid parameter.\n");
|
|
goto ErrorExit;
|
|
}
|
|
|
|
CommonExit:
|
|
|
|
DebugTrace("Leaving CCertificates::AddContext().\n");
|
|
|
|
return hr;
|
|
|
|
ErrorExit:
|
|
//
|
|
// Sanity check.
|
|
//
|
|
ATLASSERT(FAILED(hr));
|
|
|
|
goto CommonExit;
|
|
}
|
|
|
|
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
|
|
Function : CCertificate::LoadFromCert
|
|
|
|
Synopsis : Load from the single certificate context.
|
|
|
|
Parameter: PCCERT_CONTEXT pContext - Pointer to a cert context.
|
|
|
|
Remark :
|
|
|
|
------------------------------------------------------------------------------*/
|
|
|
|
STDMETHODIMP CCertificates::LoadFromCert (PCCERT_CONTEXT pCertContext)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
DebugTrace("Entering CCertificates::LoadFromCert().\n");
|
|
|
|
//
|
|
// Sanity check.
|
|
//
|
|
ATLASSERT(pCertContext);
|
|
|
|
//
|
|
// Add the cert.
|
|
//
|
|
if (FAILED(hr = AddContext(pCertContext)))
|
|
{
|
|
DebugTrace("Error [%#x]: CCertificates::AddContext() failed.\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
|
|
CommonExit:
|
|
|
|
DebugTrace("Leaving CCertificates::LoadFromCert().\n");
|
|
|
|
return hr;
|
|
|
|
ErrorExit:
|
|
//
|
|
// Sanity check.
|
|
//
|
|
ATLASSERT(FAILED(hr));
|
|
|
|
//
|
|
// Free resource.
|
|
//
|
|
m_coll.clear();
|
|
|
|
goto CommonExit;
|
|
}
|
|
|
|
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
|
|
Function : CCertificate::LoadFromChain
|
|
|
|
Synopsis : Load all certificates from a chain.
|
|
|
|
Parameter: PCCERT_CHAIN_CONTEXT pChainContext - Pointer to a chain context.
|
|
|
|
Remark :
|
|
|
|
------------------------------------------------------------------------------*/
|
|
|
|
STDMETHODIMP CCertificates::LoadFromChain (PCCERT_CHAIN_CONTEXT pChainContext)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
DebugTrace("Entering CCertificates::LoadFromChain().\n");
|
|
|
|
//
|
|
// Sanity check.
|
|
//
|
|
ATLASSERT(pChainContext);
|
|
|
|
//
|
|
// Process only the simple chain.
|
|
//
|
|
PCERT_SIMPLE_CHAIN pSimpleChain = *pChainContext->rgpChain;
|
|
|
|
//
|
|
// Now loop through all certs in the chain.
|
|
//
|
|
for (DWORD i = 0; i < pSimpleChain->cElement; i++)
|
|
{
|
|
//
|
|
// Add the cert.
|
|
//
|
|
if (FAILED(hr = AddContext(pSimpleChain->rgpElement[i]->pCertContext)))
|
|
{
|
|
DebugTrace("Error [%#x]: CCertificates::AddContext() failed.\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
}
|
|
|
|
CommonExit:
|
|
|
|
DebugTrace("Leaving CCertificates::LoadFromChain().\n");
|
|
|
|
return hr;
|
|
|
|
ErrorExit:
|
|
//
|
|
// Sanity check.
|
|
//
|
|
ATLASSERT(FAILED(hr));
|
|
|
|
//
|
|
// Free resource.
|
|
//
|
|
m_coll.clear();
|
|
|
|
goto CommonExit;
|
|
}
|
|
|
|
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
|
|
Function : CCertificates::LoadFromStore
|
|
|
|
Synopsis : Load all certificates from a store.
|
|
|
|
Parameter: HCERTSTORE hCertStore - Store where all certificates are to be
|
|
loaded from.
|
|
|
|
Remark :
|
|
|
|
------------------------------------------------------------------------------*/
|
|
|
|
STDMETHODIMP CCertificates::LoadFromStore (HCERTSTORE hCertStore)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
PCCERT_CONTEXT pCertContext = NULL;
|
|
|
|
DebugTrace("Entering CCertificates::LoadFromStore().\n");
|
|
|
|
//
|
|
// Sanity check.
|
|
//
|
|
ATLASSERT(hCertStore);
|
|
|
|
//
|
|
// Now transfer all certificates from the store to the collection map.
|
|
//
|
|
while (pCertContext = ::CertEnumCertificatesInStore(hCertStore, pCertContext))
|
|
{
|
|
//
|
|
// Add the cert.
|
|
//
|
|
if (FAILED(hr = AddContext(pCertContext)))
|
|
{
|
|
DebugTrace("Error [%#x]: CCertificates::AddContext() failed.\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
|
|
//
|
|
// Don'f free cert context here, as CertEnumCertificatesInStore()
|
|
// will do that automatically!!!
|
|
//
|
|
}
|
|
|
|
//
|
|
// 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;
|
|
}
|
|
|
|
CommonExit:
|
|
|
|
DebugTrace("Leaving CCertificates::LoadFromStore().\n");
|
|
|
|
return hr;
|
|
|
|
ErrorExit:
|
|
//
|
|
// Sanity check.
|
|
//
|
|
ATLASSERT(FAILED(hr));
|
|
|
|
//
|
|
// Free resource.
|
|
//
|
|
if (pCertContext)
|
|
{
|
|
::CertFreeCertificateContext(pCertContext);
|
|
}
|
|
|
|
if (FAILED(hr))
|
|
{
|
|
m_coll.clear();
|
|
}
|
|
|
|
goto CommonExit;
|
|
}
|
|
|
|
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
|
|
Function : CCertificates::LoadFromMessage
|
|
|
|
Synopsis : Load all certificates from a message.
|
|
|
|
Parameter: HCRYPTMSG hMsg - Message handle.
|
|
|
|
Remark :
|
|
|
|
------------------------------------------------------------------------------*/
|
|
|
|
STDMETHODIMP CCertificates::LoadFromMessage (HCRYPTMSG hMsg)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
DWORD dwCertCount = 0;
|
|
DWORD cbCertCount = sizeof(dwCertCount);
|
|
|
|
DebugTrace("Entering CCertificates::LoadFromMessage().\n");
|
|
|
|
//
|
|
// Sanity check.
|
|
//
|
|
ATLASSERT(hMsg);
|
|
|
|
//
|
|
// Get number of certs in message.
|
|
//
|
|
if (!::CryptMsgGetParam(hMsg,
|
|
CMSG_CERT_COUNT_PARAM,
|
|
0,
|
|
(void **) &dwCertCount,
|
|
&cbCertCount))
|
|
{
|
|
hr = HRESULT_FROM_WIN32(::GetLastError());
|
|
|
|
DebugTrace("Error [%#x]: CryptMsgGetParam() failed.\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
|
|
//
|
|
// Loop thru all certs in the message.
|
|
//
|
|
while (dwCertCount--)
|
|
{
|
|
PCCERT_CONTEXT pCertContext = NULL;
|
|
CRYPT_DATA_BLOB EncodedCertBlob = {0, NULL};
|
|
|
|
//
|
|
// Get a cert from the bag of certs.
|
|
//
|
|
if (FAILED(hr = ::GetMsgParam(hMsg,
|
|
CMSG_CERT_PARAM,
|
|
dwCertCount,
|
|
(void **) &EncodedCertBlob.pbData,
|
|
&EncodedCertBlob.cbData)))
|
|
{
|
|
DebugTrace("Error [%#x]: GetMsgParam() failed.\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
|
|
//
|
|
// Create a context for the cert.
|
|
//
|
|
pCertContext = ::CertCreateCertificateContext(CAPICOM_ASN_ENCODING,
|
|
(const PBYTE) EncodedCertBlob.pbData,
|
|
EncodedCertBlob.cbData);
|
|
|
|
//
|
|
// Free encoded cert blob memory before checking result.
|
|
//
|
|
::CoTaskMemFree((LPVOID) EncodedCertBlob.pbData);
|
|
|
|
if (!pCertContext)
|
|
{
|
|
hr = HRESULT_FROM_WIN32(::GetLastError());
|
|
|
|
DebugTrace("Error [%#x]: CertCreateCertificateContext() failed.\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
|
|
//
|
|
// Add the cert.
|
|
//
|
|
hr = AddContext(pCertContext);
|
|
|
|
//
|
|
// Free cert context before checking result.
|
|
//
|
|
::CertFreeCertificateContext(pCertContext);
|
|
|
|
if (FAILED(hr))
|
|
{
|
|
DebugTrace("Error [%#x]: CCertificates::AddContext() failed.\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
}
|
|
|
|
CommonExit:
|
|
|
|
DebugTrace("Leaving CCertificates::LoadFromMessage().\n");
|
|
|
|
return hr;
|
|
|
|
ErrorExit:
|
|
//
|
|
// Sanity check.
|
|
//
|
|
ATLASSERT(FAILED(hr));
|
|
|
|
//
|
|
// Free resource.
|
|
//
|
|
m_coll.clear();
|
|
|
|
goto CommonExit;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Custom interfaces.
|
|
//
|
|
|
|
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
|
|
Function : CCertificates::_ExportToStore
|
|
|
|
Synopsis : Export all certificates in the collection to a specified store.
|
|
|
|
Parameter: HCERTSTORE hCertStore - HCERSTORE to copy to.
|
|
|
|
Remark :
|
|
|
|
------------------------------------------------------------------------------*/
|
|
|
|
STDMETHODIMP CCertificates::_ExportToStore (HCERTSTORE hCertStore)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
CertificateMap::iterator iter;
|
|
|
|
DebugTrace("Entering CCertificates::_ExportToStore().\n");
|
|
|
|
//
|
|
// Sanity check.
|
|
//
|
|
ATLASSERT(hCertStore);
|
|
|
|
//
|
|
// Now, transfer all the certs in the collection to the store.
|
|
//
|
|
for (iter = m_coll.begin(); iter != m_coll.end(); iter++)
|
|
{
|
|
PCCERT_CONTEXT pCertContext = NULL;
|
|
CComPtr<ICertificate> pICertificate = NULL;
|
|
|
|
//
|
|
// Get to the stored interface pointer.
|
|
//
|
|
if (!(pICertificate = (*iter).second))
|
|
{
|
|
hr = CAPICOM_E_INTERNAL;
|
|
|
|
DebugTrace("Error [%#x]: iterator returns NULL pICertificate pointer.\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
|
|
//
|
|
// Get the CERT_CONTEXT.
|
|
//
|
|
if (FAILED(hr = ::GetCertContext(pICertificate, &pCertContext)))
|
|
{
|
|
DebugTrace("Error [%#x]: pICertificate->GetContext() failed.\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
|
|
//
|
|
// Add the link to store.
|
|
//
|
|
BOOL bResult = ::CertAddCertificateContextToStore(hCertStore,
|
|
pCertContext,
|
|
CERT_STORE_ADD_ALWAYS,
|
|
NULL);
|
|
//
|
|
// First free cert context.
|
|
//
|
|
::CertFreeCertificateContext(pCertContext);
|
|
|
|
//
|
|
// then check result.
|
|
//
|
|
if (!bResult)
|
|
{
|
|
hr = HRESULT_FROM_WIN32(::GetLastError());
|
|
|
|
DebugTrace("Error [%#x]: CertAddCertificateContextToStore() failed.\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
}
|
|
|
|
CommonExit:
|
|
|
|
DebugTrace("Leaving CCertificates::_ExportToStore().\n");
|
|
|
|
return hr;
|
|
|
|
ErrorExit:
|
|
//
|
|
// Sanity check.
|
|
//
|
|
ATLASSERT(FAILED(hr));
|
|
|
|
goto CommonExit;
|
|
}
|
|
|
|
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
|
|
Function : CCertificates::Init
|
|
|
|
Synopsis : Initialize the object.
|
|
|
|
Parameter: CAPICOM_CERTIFICATES_SOURCE ccs - Source where to get the
|
|
certificates.
|
|
|
|
DWORD dwCurrentSafety - Current safety setting.
|
|
|
|
BOOL bIndexedByThumbprint - TRUE to index by thumbprint.
|
|
|
|
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 CCertificates::Init (CAPICOM_CERTIFICATES_SOURCE ccs,
|
|
DWORD dwCurrentSafety,
|
|
BOOL bIndexedByThumbprint)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
DebugTrace("Entering CCertificates::Init().\n");
|
|
|
|
//
|
|
// Set safety setting.
|
|
//
|
|
m_dwCurrentSafety = dwCurrentSafety;
|
|
m_dwNextIndex = 0;
|
|
#if (1) // DSIE: Can turn on index by thumbprint if desired.
|
|
m_bIndexedByThumbprint = FALSE;
|
|
#else
|
|
m_bIndexedByThumbprint = bIndexedByThumbprint;
|
|
#endif
|
|
|
|
//
|
|
// Initialize object.
|
|
//
|
|
switch (ccs.dwSource)
|
|
{
|
|
case CAPICOM_CERTIFICATES_LOAD_FROM_CERT:
|
|
{
|
|
//
|
|
// Sanity check.
|
|
//
|
|
ATLASSERT(ccs.pCertContext);
|
|
|
|
if (FAILED(hr = LoadFromCert(ccs.pCertContext)))
|
|
{
|
|
DebugTrace("Error [%#x]: CCertificates::LoadFromCert() failed.\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
break;
|
|
}
|
|
|
|
case CAPICOM_CERTIFICATES_LOAD_FROM_CHAIN:
|
|
{
|
|
//
|
|
// Sanity check.
|
|
//
|
|
ATLASSERT(ccs.pChainContext);
|
|
|
|
if (FAILED(hr = LoadFromChain(ccs.pChainContext)))
|
|
{
|
|
DebugTrace("Error [%#x]: CCertificates::LoadFromChain() failed.\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
break;
|
|
}
|
|
|
|
case CAPICOM_CERTIFICATES_LOAD_FROM_STORE:
|
|
{
|
|
//
|
|
// Sanity check.
|
|
//
|
|
ATLASSERT(ccs.hCertStore);
|
|
|
|
if (FAILED(hr = LoadFromStore(ccs.hCertStore)))
|
|
{
|
|
DebugTrace("Error [%#x]: CCertificates::LoadFromStore() failed.\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
break;
|
|
}
|
|
|
|
case CAPICOM_CERTIFICATES_LOAD_FROM_MESSAGE:
|
|
{
|
|
//
|
|
// Sanity check.
|
|
//
|
|
ATLASSERT(ccs.hCryptMsg);
|
|
|
|
if (FAILED(hr = LoadFromMessage(ccs.hCryptMsg)))
|
|
{
|
|
DebugTrace("Error [%#x]: CCertificates::LoadFromMessage() failed.\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
break;
|
|
}
|
|
|
|
default:
|
|
{
|
|
//
|
|
// We have a bug.
|
|
//
|
|
ATLASSERT(FALSE);
|
|
|
|
hr = CAPICOM_E_INTERNAL;
|
|
|
|
DebugTrace("Error [%#x]: Unknown store source (ccs.dwSource = %d).\n", hr, ccs.dwSource);
|
|
goto ErrorExit;
|
|
}
|
|
}
|
|
|
|
CommonExit:
|
|
|
|
DebugTrace("Leaving CCertificates::Init().\n");
|
|
|
|
return hr;
|
|
|
|
ErrorExit:
|
|
//
|
|
// Sanity check.
|
|
//
|
|
ATLASSERT(FAILED(hr));
|
|
|
|
goto CommonExit;
|
|
}
|