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.
724 lines
22 KiB
724 lines
22 KiB
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
|
|
Microsoft Windows, Copyright (C) Microsoft Corporation, 2000 - 2001.
|
|
|
|
File: SignHlpr.cpp
|
|
|
|
Content: Helper functions for signing.
|
|
|
|
History: 11-15-99 dsie created
|
|
|
|
------------------------------------------------------------------------------*/
|
|
|
|
#include "StdAfx.h"
|
|
#include "CAPICOM.h"
|
|
#include "SignHlpr.h"
|
|
|
|
#include "Common.h"
|
|
#include "CertHlpr.h"
|
|
#include "Certificate.h"
|
|
#include "Signer2.h"
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Local functions.
|
|
//
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Exported functions.
|
|
//
|
|
|
|
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
|
|
Function : FreeAttributes
|
|
|
|
Synopsis : Free elements of an attribute array.
|
|
|
|
Parameter: DWORD cAttr - Number fo attributes
|
|
|
|
PCRYPT_ATTRIBUTE rgAuthAttr - Pointer to CRYPT_ATTRIBUTE array.
|
|
|
|
Remark :
|
|
|
|
------------------------------------------------------------------------------*/
|
|
|
|
void FreeAttributes (DWORD cAttr,
|
|
PCRYPT_ATTRIBUTE rgAttr)
|
|
{
|
|
DebugTrace("Entering FreeAttributes().\n");
|
|
|
|
//
|
|
// Free each element of the array.
|
|
//
|
|
for (DWORD i = 0; i < cAttr; i++)
|
|
{
|
|
//
|
|
// Make sure pointer is valid.
|
|
//
|
|
if (rgAttr[i].rgValue)
|
|
{
|
|
for (DWORD j = 0; j < rgAttr[i].cValue; j++)
|
|
{
|
|
if (rgAttr[i].rgValue[j].pbData)
|
|
{
|
|
::CoTaskMemFree((LPVOID) rgAttr[i].rgValue[j].pbData);
|
|
}
|
|
}
|
|
|
|
::CoTaskMemFree((LPVOID) rgAttr[i].rgValue);
|
|
}
|
|
}
|
|
|
|
DebugTrace("Leaving FreeAttributes().\n");
|
|
|
|
return;
|
|
}
|
|
|
|
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
|
|
Function : FreeAttributes
|
|
|
|
Synopsis : Free memory allocated for all attributes.
|
|
|
|
Parameter: PCRYPT_ATTRIBUTES pAttributes
|
|
|
|
Remark :
|
|
|
|
------------------------------------------------------------------------------*/
|
|
|
|
void FreeAttributes (PCRYPT_ATTRIBUTES pAttributes)
|
|
{
|
|
//
|
|
// Sanity check.
|
|
//
|
|
ATLASSERT(pAttributes);
|
|
|
|
//
|
|
// Do we have any attribute?
|
|
//
|
|
if (pAttributes->rgAttr)
|
|
{
|
|
//
|
|
// First free elements of array.
|
|
//
|
|
FreeAttributes(pAttributes->cAttr, pAttributes->rgAttr);
|
|
|
|
//
|
|
// Then free the array itself.
|
|
//
|
|
::CoTaskMemFree((LPVOID) pAttributes->rgAttr);
|
|
}
|
|
|
|
::ZeroMemory(pAttributes, sizeof(CRYPT_ATTRIBUTES));
|
|
|
|
return;
|
|
}
|
|
|
|
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
|
|
Function : GetAuthenticatedAttributes
|
|
|
|
Synopsis : Encode and return authenticated attributes of the specified signer.
|
|
|
|
Parameter: ISigner * pISigner - Pointer to ISigner.
|
|
|
|
PCRYPT_ATTRIBUTES pAttributes
|
|
|
|
Remark :
|
|
|
|
------------------------------------------------------------------------------*/
|
|
|
|
HRESULT GetAuthenticatedAttributes (ISigner * pISigner,
|
|
PCRYPT_ATTRIBUTES pAttributes)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
long cAttr = 0;
|
|
PCRYPT_ATTRIBUTE rgAttr = NULL;
|
|
CComPtr<IAttributes> pIAttributes = NULL;
|
|
|
|
DebugTrace("Entering GetAuthenticatedAttributes().\n");
|
|
|
|
//
|
|
// Sanity check.
|
|
//
|
|
ATLASSERT(pISigner);
|
|
ATLASSERT(pAttributes);
|
|
|
|
//
|
|
// Initialize.
|
|
//
|
|
::ZeroMemory(pAttributes, sizeof(CRYPT_ATTRIBUTES));
|
|
|
|
//
|
|
// Get authenticated attributes.
|
|
//
|
|
if (FAILED(hr = pISigner->get_AuthenticatedAttributes(&pIAttributes)))
|
|
{
|
|
DebugTrace("Error [%#x]: pISigner->get_AuthenticatedAttributes() failed.\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
|
|
//
|
|
// Get count of attributes.
|
|
//
|
|
if (FAILED(hr = pIAttributes->get_Count(&cAttr)))
|
|
{
|
|
DebugTrace("Error [%#x]: pIAttributes->get_Count() failed.\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
|
|
if (0 < cAttr)
|
|
{
|
|
//
|
|
// Allocate memory for attribute array.
|
|
//
|
|
if (!(rgAttr = (PCRYPT_ATTRIBUTE) ::CoTaskMemAlloc(sizeof(CRYPT_ATTRIBUTE) * cAttr)))
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
|
|
DebugTrace("Error: out of memory.\n");
|
|
goto ErrorExit;
|
|
}
|
|
|
|
::ZeroMemory(rgAttr, sizeof(CRYPT_ATTRIBUTE) * cAttr);
|
|
|
|
//
|
|
// Loop thru each attribute and add to the array.
|
|
//
|
|
for (long i = 0; i < cAttr; i++)
|
|
{
|
|
CAPICOM_ATTRIBUTE AttrName;
|
|
CComVariant varValue;
|
|
CComVariant varIAttribute;
|
|
CComPtr<IAttribute> pIAttribute = NULL;
|
|
|
|
//
|
|
// Get next attribute.
|
|
//
|
|
if (FAILED(hr = pIAttributes->get_Item(i + 1, &varIAttribute)))
|
|
{
|
|
DebugTrace("Error [%#x]: pIAttributes->get_Item() failed.\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
|
|
//
|
|
// Get custom interface.
|
|
//
|
|
if (FAILED(hr = varIAttribute.pdispVal->QueryInterface(IID_IAttribute,
|
|
(void **) &pIAttribute)))
|
|
{
|
|
DebugTrace("Error [%#x]: varIAttribute.pdispVal->QueryInterface() failed.\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
|
|
//
|
|
// Get attribute name.
|
|
//
|
|
if (FAILED(hr = pIAttribute->get_Name(&AttrName)))
|
|
{
|
|
DebugTrace("Error [%#x]: pIAttribute->get_Name() failed.\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
|
|
//
|
|
// Get attribute value.
|
|
//
|
|
if (FAILED(hr = pIAttribute->get_Value(&varValue)))
|
|
{
|
|
DebugTrace("Error [%#x]: pIAttribute->get_Value() failed.\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
|
|
switch (AttrName)
|
|
{
|
|
case CAPICOM_AUTHENTICATED_ATTRIBUTE_SIGNING_TIME:
|
|
{
|
|
FILETIME ft;
|
|
SYSTEMTIME st;
|
|
|
|
//
|
|
// Conver to FILETIME.
|
|
//
|
|
if (!::VariantTimeToSystemTime(varValue.date, &st))
|
|
{
|
|
hr = CAPICOM_E_ATTRIBUTE_INVALID_VALUE;
|
|
|
|
DebugTrace("Error [%#x]: VariantTimeToSystemTime() failed.\n");
|
|
goto ErrorExit;
|
|
}
|
|
|
|
if (!::SystemTimeToFileTime(&st, &ft))
|
|
{
|
|
hr = CAPICOM_E_ATTRIBUTE_INVALID_VALUE;
|
|
|
|
DebugTrace("Error [%#x]: VariantTimeToSystemTime() failed.\n");
|
|
goto ErrorExit;
|
|
}
|
|
|
|
//
|
|
// Now encode it.
|
|
//
|
|
rgAttr[i].cValue = 1;
|
|
rgAttr[i].pszObjId = szOID_RSA_signingTime;
|
|
if (!(rgAttr[i].rgValue = (CRYPT_ATTR_BLOB *) ::CoTaskMemAlloc(sizeof(CRYPT_ATTR_BLOB))))
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
|
|
DebugTrace("Error: out of memory.\n");
|
|
goto ErrorExit;
|
|
}
|
|
|
|
if (FAILED(hr = ::EncodeObject((LPSTR) szOID_RSA_signingTime,
|
|
(LPVOID) &ft,
|
|
rgAttr[i].rgValue)))
|
|
{
|
|
DebugTrace("Error [%#x]: EncodeObject() failed.\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
case CAPICOM_AUTHENTICATED_ATTRIBUTE_DOCUMENT_NAME:
|
|
{
|
|
CRYPT_DATA_BLOB NameBlob = {0, NULL};
|
|
|
|
NameBlob.cbData = ::SysStringByteLen(varValue.bstrVal);
|
|
NameBlob.pbData = (PBYTE) varValue.bstrVal;
|
|
|
|
rgAttr[i].cValue = 1;
|
|
rgAttr[i].pszObjId = szOID_CAPICOM_DOCUMENT_NAME;
|
|
if (!(rgAttr[i].rgValue = (CRYPT_ATTR_BLOB *) ::CoTaskMemAlloc(sizeof(CRYPT_ATTR_BLOB))))
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
|
|
DebugTrace("Error: out of memory.\n");
|
|
goto ErrorExit;
|
|
}
|
|
|
|
if (FAILED(hr = ::EncodeObject((LPSTR) X509_OCTET_STRING,
|
|
(LPVOID) &NameBlob,
|
|
rgAttr[i].rgValue)))
|
|
{
|
|
DebugTrace("Error [%#x]: EncodeObject() failed.\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
case CAPICOM_AUTHENTICATED_ATTRIBUTE_DOCUMENT_DESCRIPTION:
|
|
{
|
|
CRYPT_DATA_BLOB DescBlob = {0, NULL};
|
|
|
|
DescBlob.cbData = ::SysStringByteLen(varValue.bstrVal);
|
|
DescBlob.pbData = (PBYTE) varValue.bstrVal;
|
|
|
|
rgAttr[i].cValue = 1;
|
|
rgAttr[i].pszObjId = szOID_CAPICOM_DOCUMENT_DESCRIPTION;
|
|
if (!(rgAttr[i].rgValue = (CRYPT_ATTR_BLOB *) ::CoTaskMemAlloc(sizeof(CRYPT_ATTR_BLOB))))
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
|
|
DebugTrace("Error: out of memory.\n");
|
|
goto ErrorExit;
|
|
}
|
|
|
|
if (FAILED(hr = ::EncodeObject((LPSTR) X509_OCTET_STRING,
|
|
(LPVOID) &DescBlob,
|
|
rgAttr[i].rgValue)))
|
|
{
|
|
DebugTrace("Error [%#x]: EncodeObject() failed.\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
default:
|
|
{
|
|
hr = CAPICOM_E_ATTRIBUTE_INVALID_NAME;
|
|
|
|
DebugTrace("Error [%#x]: unknown attribute name.\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Return attributes to caller.
|
|
//
|
|
pAttributes->cAttr = cAttr;
|
|
pAttributes->rgAttr = rgAttr;
|
|
}
|
|
|
|
CommonExit:
|
|
|
|
DebugTrace("Leaving GetAuthenticatedAttributes().\n");
|
|
|
|
return hr;
|
|
|
|
ErrorExit:
|
|
//
|
|
// Sanity check.
|
|
//
|
|
ATLASSERT(FAILED(hr));
|
|
|
|
//
|
|
// Free resources.
|
|
//
|
|
if (rgAttr)
|
|
{
|
|
::FreeAttributes(cAttr, rgAttr);
|
|
|
|
::CoTaskMemFree(rgAttr);
|
|
}
|
|
|
|
goto CommonExit;
|
|
}
|
|
|
|
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
|
|
Function : IsValidForSigning
|
|
|
|
Synopsis : Verify if the certificate is valid for signing.
|
|
|
|
Parameter: PCCERT_CONTEXT pCertContext - CERT_CONTEXT of cert to verify.
|
|
|
|
LPCSTR pszPolicy - Policy used to verify the cert (i.e.
|
|
CERT_CHAIN_POLICY_BASE).
|
|
|
|
Remark :
|
|
|
|
------------------------------------------------------------------------------*/
|
|
|
|
HRESULT IsValidForSigning (PCCERT_CONTEXT pCertContext, LPCSTR pszPolicy)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
DWORD cb = 0;
|
|
int nValidity = 0;
|
|
|
|
DebugTrace("Entering IsValidForSigning().\n");
|
|
|
|
//
|
|
// Sanity check.
|
|
//
|
|
ATLASSERT(pCertContext);
|
|
|
|
//
|
|
// Make sure we have a private key.
|
|
//
|
|
if (!::CertGetCertificateContextProperty(pCertContext,
|
|
CERT_KEY_PROV_INFO_PROP_ID,
|
|
NULL,
|
|
&cb))
|
|
{
|
|
hr = CAPICOM_E_CERTIFICATE_NO_PRIVATE_KEY;
|
|
|
|
DebugTrace("Error: signer's private key is not available.\n");
|
|
goto ErrorExit;
|
|
}
|
|
|
|
//
|
|
// Check cert time validity.
|
|
//
|
|
if (0 != (nValidity = ::CertVerifyTimeValidity(NULL, pCertContext->pCertInfo)))
|
|
{
|
|
hr = HRESULT_FROM_WIN32(CERT_E_EXPIRED);
|
|
|
|
DebugTrace("Info: SelectSignerCertCallback() - invalid time (%s).\n",
|
|
nValidity < 0 ? "not yet valid" : "expired");
|
|
goto ErrorExit;
|
|
}
|
|
|
|
#if (0) //DSIE: Flip this if we decide to build chain here.
|
|
//
|
|
// Make sure the cert is valid.
|
|
//
|
|
if (FAILED(hr = ::VerifyCertificate(pCertContext, NULL, pszPolicy)))
|
|
{
|
|
DebugTrace("Error [%#x]: VerifyCertificate() failed.\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
#endif
|
|
|
|
CommonExit:
|
|
|
|
DebugTrace("Leaving IsValidForSigning().\n");
|
|
|
|
return hr;
|
|
|
|
ErrorExit:
|
|
//
|
|
// Sanity check.
|
|
//
|
|
ATLASSERT(FAILED(hr));
|
|
|
|
goto CommonExit;
|
|
}
|
|
|
|
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
|
|
Function : GetSignerCert
|
|
|
|
Synopsis : Retrieve signer's cert from ISigner object. If signer's cert is
|
|
not available in the ISigner object, pop UI to prompt user to
|
|
select a signing cert.
|
|
|
|
Parameter: ISigner2 * pISigner2 - Pointer to ISigner2 or NULL.
|
|
|
|
LPCSTR pszPolicy - Policy used to verify the cert (i.e.
|
|
CERT_CHAIN_POLICY_BASE).
|
|
|
|
CAPICOM_STORE_INFO StoreInfo - Store to select from.
|
|
|
|
PFNCFILTERPROC pfnFilterCallback - Pointer to filter callback
|
|
function.
|
|
|
|
ISigner2 ** ppISigner2 - Pointer to pointer to ISigner2 to receive
|
|
interface pointer.
|
|
|
|
ICertificate ** ppICertificate - Pointer to pointer to ICertificate
|
|
to receive interface pointer.
|
|
|
|
PCCERT_CONTEXT * ppCertContext - Pointer to pointer to CERT_CONTEXT
|
|
to receive cert context.
|
|
Remark :
|
|
|
|
------------------------------------------------------------------------------*/
|
|
|
|
HRESULT GetSignerCert (ISigner2 * pISigner2,
|
|
LPCSTR pszPolicy,
|
|
CAPICOM_STORE_INFO StoreInfo,
|
|
PFNCFILTERPROC pfnFilterCallback,
|
|
ISigner2 ** ppISigner2,
|
|
ICertificate ** ppICertificate,
|
|
PCCERT_CONTEXT * ppCertContext)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
BOOL bVerified = FALSE;
|
|
CComPtr<ISigner2> pISelectedSigner2 = NULL;
|
|
CComPtr<ICertificate> pISelectedCertificate = NULL;
|
|
CComPtr<ICertificate2> pISelectedCertificate2 = NULL;
|
|
PCCERT_CONTEXT pSelectedCertContext = NULL;
|
|
|
|
DebugTrace("Entering GetSignerCert().\n");
|
|
|
|
try
|
|
{
|
|
//
|
|
// Initialize.
|
|
//
|
|
if (ppISigner2)
|
|
{
|
|
*ppISigner2 = NULL;
|
|
}
|
|
if (ppICertificate)
|
|
{
|
|
*ppICertificate = NULL;
|
|
}
|
|
if (ppCertContext)
|
|
{
|
|
*ppCertContext = NULL;
|
|
}
|
|
|
|
//
|
|
// Did user pass us a signer?
|
|
//
|
|
if (pISigner2)
|
|
{
|
|
//
|
|
// Retrieve the signer's cert.
|
|
//
|
|
if (FAILED(hr = pISigner2->get_Certificate((ICertificate **) &pISelectedCertificate)))
|
|
{
|
|
//
|
|
// If signer's cert is not present, pop UI.
|
|
//
|
|
if (CAPICOM_E_SIGNER_NOT_INITIALIZED == hr)
|
|
{
|
|
//
|
|
// Prompt user to select a certificate.
|
|
//
|
|
if (FAILED(hr = ::SelectCertificate(StoreInfo,
|
|
pfnFilterCallback,
|
|
&pISelectedCertificate2)))
|
|
{
|
|
DebugTrace("Error [%#x]: SelectCertificate() failed.\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
|
|
//
|
|
// QI for ICertificate.
|
|
//
|
|
if (FAILED(hr = pISelectedCertificate2->QueryInterface(&pISelectedCertificate)))
|
|
{
|
|
DebugTrace("Internal error [%#x]: pISelectedCertificate2->QueryInterface() failed.\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
|
|
bVerified = TRUE;
|
|
}
|
|
else
|
|
{
|
|
DebugTrace("Error [%#x]: pISigner2->get_Certificate() failed.\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Get cert context.
|
|
//
|
|
if (FAILED(hr = ::GetCertContext(pISelectedCertificate, &pSelectedCertContext)))
|
|
{
|
|
DebugTrace("Error [%#x]: GetCertContext() failed.\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
|
|
//
|
|
// Verify cert, if not already done so.
|
|
//
|
|
if (!bVerified)
|
|
{
|
|
if (pfnFilterCallback && !pfnFilterCallback(pSelectedCertContext, NULL, NULL))
|
|
{
|
|
hr = CAPICOM_E_SIGNER_INVALID_USAGE;
|
|
|
|
DebugTrace("Error [%#x]: Signing certificate is invalid.\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
}
|
|
|
|
//
|
|
// QI for ISigner2.
|
|
//
|
|
if (FAILED(hr = pISigner2->QueryInterface(&pISelectedSigner2)))
|
|
{
|
|
DebugTrace("Unexpected error [%#x]: pISigner2->QueryInterface() failed.\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
CRYPT_ATTRIBUTES attributes = {0, NULL};
|
|
|
|
//
|
|
// No signer specified, so prompt user to select a certificate.
|
|
//
|
|
if (FAILED(hr = ::SelectCertificate(StoreInfo, pfnFilterCallback, &pISelectedCertificate2)))
|
|
{
|
|
DebugTrace("Error [%#x]: SelectCertificate() failed.\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
|
|
//
|
|
// QI for ICertificate.
|
|
//
|
|
if (FAILED(hr = pISelectedCertificate2->QueryInterface(&pISelectedCertificate)))
|
|
{
|
|
DebugTrace("Internal error [%#x]: pISelectedCertificate2->QueryInterface() failed.\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
|
|
//
|
|
// Get cert context.
|
|
//
|
|
if (FAILED(hr = ::GetCertContext(pISelectedCertificate, &pSelectedCertContext)))
|
|
{
|
|
DebugTrace("Error [%#x]: GetCertContext() failed.\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
|
|
//
|
|
// Create the ISigner2 object.
|
|
//
|
|
if (FAILED(hr = ::CreateSignerObject(pSelectedCertContext,
|
|
&attributes,
|
|
NULL,
|
|
INTERFACESAFE_FOR_UNTRUSTED_CALLER |
|
|
INTERFACESAFE_FOR_UNTRUSTED_DATA,
|
|
&pISelectedSigner2)))
|
|
{
|
|
DebugTrace("Error [%#x]: CreateSignerObject() failed.\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Make sure cert is valid for signing.
|
|
//
|
|
if (FAILED(hr = ::IsValidForSigning(pSelectedCertContext, pszPolicy)))
|
|
{
|
|
DebugTrace("Error [%#x]: IsValidForSigning() failed.\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
|
|
//
|
|
// Return values to caller.
|
|
//
|
|
if (ppISigner2)
|
|
{
|
|
if (FAILED(hr = pISelectedSigner2->QueryInterface(ppISigner2)))
|
|
{
|
|
DebugTrace("Unexpected error [%#x]: pISelectedSigner2->QueryInterface() failed.\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
}
|
|
|
|
if (ppICertificate)
|
|
{
|
|
if (FAILED(hr = pISelectedCertificate->QueryInterface(ppICertificate)))
|
|
{
|
|
DebugTrace("Unexpected error [%#x]: pISelectedCertificate->QueryInterface() failed.\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
}
|
|
|
|
if (ppCertContext)
|
|
{
|
|
*ppCertContext = pSelectedCertContext;
|
|
}
|
|
}
|
|
|
|
catch(...)
|
|
{
|
|
hr = E_POINTER;
|
|
|
|
DebugTrace("Exception: invalid parameter.\n");
|
|
goto ErrorExit;
|
|
}
|
|
|
|
CommonExit:
|
|
|
|
DebugTrace("Leaving GetSignerCert().\n");
|
|
|
|
return hr;
|
|
|
|
ErrorExit:
|
|
//
|
|
// Sanity check.
|
|
//
|
|
ATLASSERT(FAILED(hr));
|
|
|
|
//
|
|
// Free resource.
|
|
//
|
|
if (pSelectedCertContext)
|
|
{
|
|
::CertFreeCertificateContext(pSelectedCertContext);
|
|
}
|
|
if (ppICertificate && *ppICertificate)
|
|
{
|
|
(*ppICertificate)->Release();
|
|
*ppICertificate = NULL;
|
|
}
|
|
if (ppISigner2 && *ppISigner2)
|
|
{
|
|
(*ppISigner2)->Release();
|
|
*ppISigner2 = NULL;
|
|
}
|
|
|
|
goto CommonExit;
|
|
}
|