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.
2216 lines
62 KiB
2216 lines
62 KiB
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
|
|
Microsoft Windows, Copyright (C) Microsoft Corporation, 2000
|
|
|
|
File: Store.cpp
|
|
|
|
Content: Implementation of CStore.
|
|
|
|
History: 11-15-99 dsie created
|
|
|
|
------------------------------------------------------------------------------*/
|
|
|
|
#include "StdAfx.h"
|
|
#include "CAPICOM.h"
|
|
#include "Store.h"
|
|
|
|
#include "ADHelpers.h"
|
|
#include "Certificate.h"
|
|
#include "Certificates.h"
|
|
#include "Common.h"
|
|
#include "Convert.h"
|
|
#include "PFXHlpr.h"
|
|
#include "Settings.h"
|
|
#include "SmartCard.h"
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Internal functions.
|
|
//
|
|
|
|
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
|
|
Function : IsProtectedStore
|
|
|
|
Synopsis : Determine if the requested store is proctected from update from
|
|
WEB within script.
|
|
|
|
Parameter: CAPICOM_STORE_LOCATION StoreLocation - Store location.
|
|
|
|
LPWSTR pwszStoreName - Store name.
|
|
|
|
Remark : 1) All LM stores are considered protected.
|
|
|
|
2) CU\Root, CU\AuthRoot, CU\TrustedPeople, CU\TrustedPublisher,
|
|
and CU\Disallowed are considered protected.
|
|
|
|
3) All error conditions would be considered as protected.
|
|
|
|
4) Otherwise, it is not considered protected.
|
|
|
|
------------------------------------------------------------------------------*/
|
|
|
|
static BOOL IsProtectedStore (CAPICOM_STORE_LOCATION StoreLocation,
|
|
LPWSTR pwszStoreName)
|
|
{
|
|
BOOL bIsProtected = TRUE;
|
|
|
|
switch (StoreLocation)
|
|
{
|
|
case CAPICOM_LOCAL_MACHINE_STORE:
|
|
{
|
|
//
|
|
// 1) All LM stores are considered protected.
|
|
//
|
|
break;
|
|
}
|
|
|
|
case CAPICOM_CURRENT_USER_STORE:
|
|
{
|
|
//
|
|
// Sanity check.
|
|
//
|
|
ATLASSERT(pwszStoreName);
|
|
|
|
//
|
|
// 2) CU\Root, CU\AuthRoot, CU\TrustedPeople, CU\TrustedPublisher,
|
|
// and CU\Disallowed are considered protected.
|
|
//
|
|
if (0 != _wcsicmp(L"root", pwszStoreName) &&
|
|
0 != _wcsicmp(L"authroot", pwszStoreName) &&
|
|
0 != _wcsicmp(L"trustedpeople", pwszStoreName) &&
|
|
0 != _wcsicmp(L"trustedpublisher", pwszStoreName) &&
|
|
0 != _wcsicmp(L"disallowed", pwszStoreName))
|
|
{
|
|
bIsProtected = FALSE;
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
case CAPICOM_MEMORY_STORE:
|
|
case CAPICOM_ACTIVE_DIRECTORY_USER_STORE:
|
|
case CAPICOM_SMART_CARD_USER_STORE:
|
|
{
|
|
//
|
|
// Memory backed store is not protected.
|
|
//
|
|
bIsProtected = FALSE;
|
|
break;
|
|
}
|
|
|
|
default:
|
|
{
|
|
//
|
|
// 3) All error conditions would be considered as protected.
|
|
//
|
|
break;
|
|
}
|
|
}
|
|
|
|
return bIsProtected;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// CStore
|
|
//
|
|
|
|
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
|
|
Function : CStore::get_Certificates
|
|
|
|
Synopsis : Get the ICertificates collection object.
|
|
|
|
Parameter: ICertificates ** ppCertificates - Pointer to pointer to
|
|
ICertificates to receive the
|
|
interface pointer.
|
|
|
|
Remark : This is the default property which returns an ICertificates
|
|
collection object, which can then be accessed using standard COM
|
|
collection interface.
|
|
|
|
The collection is not ordered, and can be accessed using a 1-based
|
|
numeric index.
|
|
|
|
Note that the collection is a snapshot of all current certificates
|
|
in the store. In other words, the collection will not be affected
|
|
by Add/Remove operations after the collection is obtained.
|
|
|
|
------------------------------------------------------------------------------*/
|
|
|
|
STDMETHODIMP CStore::get_Certificates (ICertificates ** pVal)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
CComPtr<ICertificates2> pICertificates2 = NULL;
|
|
CAPICOM_CERTIFICATES_SOURCE ccs = {CAPICOM_CERTIFICATES_LOAD_FROM_STORE, 0};
|
|
|
|
DebugTrace("Entering CStore::get_Certificates().\n");
|
|
|
|
try
|
|
{
|
|
//
|
|
// Lock access to this object.
|
|
//
|
|
m_Lock.Lock();
|
|
|
|
//
|
|
// Check parameters.
|
|
//
|
|
if (NULL == pVal)
|
|
{
|
|
hr = E_INVALIDARG;
|
|
|
|
DebugTrace("Error [%#x]: Parameter pVal is NULL.\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
|
|
//
|
|
// Is the store object opened?
|
|
//
|
|
if (!m_hCertStore)
|
|
{
|
|
hr = CAPICOM_E_STORE_NOT_OPENED;
|
|
|
|
DebugTrace("Error [%#x]: store has not been opened.\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
|
|
//
|
|
// Create the ICertificates2 collection object.
|
|
//
|
|
ccs.hCertStore = m_hCertStore;
|
|
|
|
if (FAILED(hr = ::CreateCertificatesObject(ccs, m_dwCurrentSafety, TRUE, &pICertificates2)))
|
|
{
|
|
DebugTrace("Error [%#x]: CreateCertificatesObject() failed.\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
|
|
//
|
|
// Return ICertificates to calller.
|
|
//
|
|
if (FAILED(hr = pICertificates2->QueryInterface(__uuidof(ICertificates), (void **) pVal)))
|
|
{
|
|
DebugTrace("Error [%#x]: pICertificates2->QueryInterface() failed.\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
}
|
|
|
|
catch(...)
|
|
{
|
|
hr = E_INVALIDARG;
|
|
|
|
DebugTrace("Exception: invalid parameter.\n");
|
|
goto ErrorExit;
|
|
}
|
|
|
|
UnlockExit:
|
|
//
|
|
// Unlock access to this object.
|
|
//
|
|
m_Lock.Unlock();
|
|
|
|
DebugTrace("Leaving CStore::get_Certificates().\n");
|
|
|
|
return hr;
|
|
|
|
ErrorExit:
|
|
//
|
|
// Sanity check.
|
|
//
|
|
ATLASSERT(FAILED(hr));
|
|
|
|
ReportError(hr);
|
|
|
|
goto UnlockExit;
|
|
}
|
|
|
|
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
|
|
Function : CStore::Open
|
|
|
|
Synopsis : Open a certificate store for read/write. Note that for MEMORY_STORE
|
|
and ACTIVE_DIRECTORY_USER_STORE, the write operation does not
|
|
persist the certificate.
|
|
|
|
Parameter: CAPICOM_STORE_LOCATION StoreLocation - Store location.
|
|
|
|
BSTR StoreName - Store name or NULL.
|
|
|
|
For:
|
|
|
|
MEMORY_STORE - This argument is ignored.
|
|
|
|
LOCAL_MACHINE_STORE - System store name or NULL.
|
|
|
|
If NULL, then "MY" is used.
|
|
|
|
CURRENT_USER_STORE - See explaination for
|
|
LOCAL_MACHINE_STORE.
|
|
|
|
ACTIVE_DIRECTORY_USER_STORE - LDAP filter for user container
|
|
or NULL,.
|
|
|
|
If NULL, then all users in the
|
|
default domain will be
|
|
included, so this can be very
|
|
slow.
|
|
|
|
If not NULL, then it should
|
|
resolve to group of 0 or more
|
|
users.
|
|
|
|
For example,
|
|
|
|
"cn=Daniel Sie"
|
|
"cn=Daniel *"
|
|
"sn=Sie"
|
|
"mailNickname=dsie"
|
|
"[email protected]"
|
|
"distinguishedName=CN=Daniel Sie,OU=Users,OU=ITG,DC=ntdev,DC=microsoft,DC=com"
|
|
"|((cn=Daniel Sie)(sn=Hallin))"
|
|
|
|
SMART_CARD_STORE - This is ignored.
|
|
|
|
CAPICOM_STORE_OPEN_MODE OpenMode - Always force to read only for
|
|
MEMORY_STORE,
|
|
ACTIVE_DIRECTORY_USER_STORE,
|
|
and SMART_CARD_STORE.
|
|
|
|
Remark :
|
|
|
|
------------------------------------------------------------------------------*/
|
|
|
|
STDMETHODIMP CStore::Open (CAPICOM_STORE_LOCATION StoreLocation,
|
|
BSTR StoreName,
|
|
CAPICOM_STORE_OPEN_MODE OpenMode)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
LPWSTR wszName = NULL;
|
|
LPCSTR szProvider = (LPCSTR) CERT_STORE_PROV_SYSTEM;
|
|
DWORD dwModeFlag = 0;
|
|
DWORD dwArchivedFlag = 0;
|
|
DWORD dwOpenExistingFlag = 0;
|
|
DWORD dwLocationFlag = 0;
|
|
HCERTSTORE hCertStore = NULL;
|
|
HMODULE hDSClientDLL = NULL;
|
|
HMODULE hWinSCardDLL = NULL;
|
|
|
|
DebugTrace("Entering CStore::Open().\n");
|
|
|
|
try
|
|
{
|
|
//
|
|
// Lock access to this object.
|
|
//
|
|
m_Lock.Lock();
|
|
|
|
//
|
|
// Can't open remote store if called from WEB script.
|
|
//
|
|
if (m_dwCurrentSafety && wcschr(StoreName, L'\\'))
|
|
{
|
|
hr = CAPICOM_E_NOT_ALLOWED;
|
|
|
|
DebugTrace("Error [%#x]: Openning remote store from WEB script is not allowed.\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
|
|
//
|
|
// Make sure parameters are valid.
|
|
//
|
|
switch (OpenMode & 0x3) // Only the last two bits.
|
|
{
|
|
case CAPICOM_STORE_OPEN_READ_ONLY:
|
|
{
|
|
dwModeFlag = CERT_STORE_READONLY_FLAG;
|
|
break;
|
|
}
|
|
|
|
case CAPICOM_STORE_OPEN_READ_WRITE:
|
|
{
|
|
break;
|
|
}
|
|
|
|
case CAPICOM_STORE_OPEN_MAXIMUM_ALLOWED:
|
|
{
|
|
dwModeFlag = CERT_STORE_MAXIMUM_ALLOWED_FLAG;
|
|
break;
|
|
}
|
|
|
|
default:
|
|
{
|
|
hr = E_INVALIDARG;
|
|
|
|
DebugTrace("Error [%#x]: Unknown store open mode (%#x).\n", hr, OpenMode);
|
|
goto ErrorExit;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Set open existing flag if WEB client or specifically requested.
|
|
//
|
|
if (m_dwCurrentSafety || (OpenMode & CAPICOM_STORE_OPEN_EXISTING_ONLY))
|
|
{
|
|
dwOpenExistingFlag = CERT_STORE_OPEN_EXISTING_FLAG;
|
|
}
|
|
|
|
//
|
|
// Set archive flag if requested.
|
|
//
|
|
if (OpenMode & CAPICOM_STORE_OPEN_INCLUDE_ARCHIVED)
|
|
{
|
|
dwArchivedFlag = CERT_STORE_ENUM_ARCHIVED_FLAG;
|
|
}
|
|
|
|
switch (StoreLocation)
|
|
{
|
|
case CAPICOM_MEMORY_STORE:
|
|
{
|
|
wszName = NULL;
|
|
szProvider = (LPSTR) CERT_STORE_PROV_MEMORY;
|
|
dwModeFlag = CERT_STORE_READONLY_FLAG;
|
|
break;
|
|
}
|
|
|
|
case CAPICOM_LOCAL_MACHINE_STORE:
|
|
{
|
|
wszName = StoreName;
|
|
dwLocationFlag = CERT_SYSTEM_STORE_LOCAL_MACHINE;
|
|
break;
|
|
}
|
|
|
|
case CAPICOM_CURRENT_USER_STORE:
|
|
{
|
|
wszName = StoreName;
|
|
dwLocationFlag = CERT_SYSTEM_STORE_CURRENT_USER;
|
|
break;
|
|
}
|
|
|
|
case CAPICOM_ACTIVE_DIRECTORY_USER_STORE:
|
|
{
|
|
//
|
|
// Make sure DSClient is installed.
|
|
//
|
|
if (!(hDSClientDLL = ::LoadLibrary("ActiveDS.dll")))
|
|
{
|
|
hr = CAPICOM_E_NOT_SUPPORTED;
|
|
|
|
DebugTrace("Error [%#x]: DSClient not installed.\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
|
|
wszName = NULL;
|
|
szProvider = (LPSTR) CERT_STORE_PROV_MEMORY;
|
|
dwModeFlag = CERT_STORE_READONLY_FLAG;
|
|
|
|
break;
|
|
}
|
|
|
|
case CAPICOM_SMART_CARD_USER_STORE:
|
|
{
|
|
//
|
|
// Make sure WIn2K and above.
|
|
//
|
|
if (!IsWin2KAndAbove())
|
|
{
|
|
hr = CAPICOM_E_NOT_SUPPORTED;
|
|
|
|
DebugTrace("Error [%#x]: Smart Card store not supported for pre-W2K platforms.\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
|
|
wszName = NULL;
|
|
szProvider = (LPSTR) CERT_STORE_PROV_MEMORY;
|
|
dwModeFlag = CERT_STORE_READONLY_FLAG;
|
|
|
|
break;
|
|
}
|
|
|
|
default:
|
|
{
|
|
hr = E_INVALIDARG;
|
|
|
|
DebugTrace("Error [%#x]: Unknown store location (%#x).\n", hr, StoreLocation);
|
|
goto ErrorExit;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Prompt user for approval to open store, if called from WEB script.
|
|
//
|
|
if ((m_dwCurrentSafety) &&
|
|
(StoreLocation != CAPICOM_MEMORY_STORE) &&
|
|
(FAILED(hr = OperationApproved(IDD_STORE_OPEN_SECURITY_ALERT_DLG))))
|
|
{
|
|
DebugTrace("Error [%#x]: OperationApproved() failed.\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
|
|
//
|
|
// First close the store.
|
|
//
|
|
if (FAILED(hr = Close()))
|
|
{
|
|
DebugTrace("Error [%#x]: CStore::Close().\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
|
|
//
|
|
// Call CAPI to open the store.
|
|
//
|
|
if (!(hCertStore = ::CertOpenStore(szProvider,
|
|
CAPICOM_ASN_ENCODING,
|
|
NULL,
|
|
dwModeFlag |
|
|
dwLocationFlag |
|
|
dwArchivedFlag |
|
|
dwOpenExistingFlag |
|
|
CERT_STORE_DEFER_CLOSE_UNTIL_LAST_FREE_FLAG,
|
|
(void *) (LPCWSTR) wszName)))
|
|
{
|
|
hr = HRESULT_FROM_WIN32(::GetLastError());
|
|
|
|
DebugTrace("Error [%#x]: CertOpenStore() failed.\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
|
|
//
|
|
// Load certificates from virtual stores, if necessary.
|
|
//
|
|
switch (StoreLocation)
|
|
{
|
|
case CAPICOM_ACTIVE_DIRECTORY_USER_STORE:
|
|
{
|
|
//
|
|
// Load userCertificate from the active directory.
|
|
//
|
|
if (FAILED(hr = ::LoadFromDirectory(hCertStore, StoreName)))
|
|
{
|
|
DebugTrace("Error [%#x]: LoadFromDirectory() failed.\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
break;
|
|
}
|
|
|
|
case CAPICOM_SMART_CARD_USER_STORE:
|
|
{
|
|
//
|
|
// Load certificate(s) from all smart card readers.
|
|
//
|
|
if (FAILED(hr = ::LoadFromSmartCard(hCertStore)))
|
|
{
|
|
DebugTrace("Error [%#x]: LoadFromSmartCard() failed.\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
break;
|
|
}
|
|
|
|
default:
|
|
{
|
|
//
|
|
// Not virtual store, so nothing to load.
|
|
//
|
|
break;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Update member variables.
|
|
//
|
|
m_hCertStore = hCertStore;
|
|
m_StoreLocation = StoreLocation;
|
|
m_bIsProtected = ::IsProtectedStore(StoreLocation, StoreName);
|
|
|
|
DebugTrace("Info: CStore::Open() for %s store.\n", m_bIsProtected ? "protected" : "non-protected");
|
|
}
|
|
|
|
catch(...)
|
|
{
|
|
hr = E_INVALIDARG;
|
|
|
|
DebugTrace("Exception: invalid parameter.\n");
|
|
goto ErrorExit;
|
|
}
|
|
|
|
UnlockExit:
|
|
//
|
|
// Free resource.
|
|
//
|
|
if (hDSClientDLL)
|
|
{
|
|
::FreeLibrary(hDSClientDLL);
|
|
}
|
|
if (hWinSCardDLL)
|
|
{
|
|
::FreeLibrary(hWinSCardDLL);
|
|
}
|
|
|
|
//
|
|
// Unlock access to this object.
|
|
//
|
|
m_Lock.Unlock();
|
|
|
|
DebugTrace("Leaving CStore::Open().\n");
|
|
|
|
return hr;
|
|
|
|
ErrorExit:
|
|
//
|
|
// Sanity check.
|
|
//
|
|
ATLASSERT(FAILED(hr));
|
|
|
|
//
|
|
// Free resource.
|
|
//
|
|
if (hCertStore)
|
|
{
|
|
::CertCloseStore(hCertStore, 0);
|
|
}
|
|
|
|
ReportError(hr);
|
|
|
|
goto UnlockExit;
|
|
}
|
|
|
|
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
|
|
Function : CStore::Add
|
|
|
|
Synopsis : Add a certificate to the store.
|
|
|
|
Parameter: ICertificate * pVal - Pointer to ICertificate to add.
|
|
|
|
Remark : If called from web, UI will be displayed, if has not been
|
|
previuosly disabled, to solicit user's permission to add
|
|
certificate to the system store.
|
|
|
|
Added certificates are not persisted for non-system stores.
|
|
|
|
------------------------------------------------------------------------------*/
|
|
|
|
STDMETHODIMP CStore::Add (ICertificate * pVal)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
PCCERT_CONTEXT pCertContext = NULL;
|
|
CComPtr<ICertificate> pICertificate = NULL;
|
|
|
|
DebugTrace("Entering CStore::Add().\n");
|
|
|
|
try
|
|
{
|
|
//
|
|
// Lock access to this object.
|
|
//
|
|
m_Lock.Lock();
|
|
|
|
//
|
|
// QI for ICertificate pointer (Just to make sure it is indeed
|
|
// an ICertificate object).
|
|
//
|
|
if (!(pICertificate = pVal))
|
|
{
|
|
hr = E_INVALIDARG;
|
|
|
|
DebugTrace("Error [%#x]: Parameter pVal is not an ICertificate interface pointer.\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
|
|
//
|
|
// Is the store object opened?
|
|
//
|
|
if (!m_hCertStore)
|
|
{
|
|
hr = CAPICOM_E_STORE_NOT_OPENED;
|
|
|
|
DebugTrace("Error [%#x]: Store has not been opened.\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
|
|
//
|
|
// Add is not allowed for protected store when called from WEB script.
|
|
//
|
|
if (m_dwCurrentSafety)
|
|
{
|
|
DebugTrace("Info: CStore::Add called from WEB script.\n");
|
|
|
|
if (m_bIsProtected)
|
|
{
|
|
hr = CAPICOM_E_NOT_ALLOWED;
|
|
|
|
DebugTrace("Error [%#x]: Adding to this store is not allowed from WEB script.\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
|
|
if (CAPICOM_CURRENT_USER_STORE != m_StoreLocation &&
|
|
CAPICOM_LOCAL_MACHINE_STORE != m_StoreLocation &&
|
|
FAILED(hr = OperationApproved(IDD_STORE_ADD_SECURITY_ALERT_DLG)))
|
|
{
|
|
DebugTrace("Error [%#x]: OperationApproved() failed.\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Get cert context from certificate object.
|
|
//
|
|
if (FAILED(hr = ::GetCertContext(pICertificate, &pCertContext)))
|
|
{
|
|
DebugTrace("Error [%#x]: GetCertContext() failed.\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
|
|
//
|
|
// Sanity check.
|
|
//
|
|
ATLASSERT(pCertContext);
|
|
|
|
//
|
|
// Add to the store.
|
|
//
|
|
if (!::CertAddCertificateContextToStore(m_hCertStore,
|
|
pCertContext,
|
|
CERT_STORE_ADD_REPLACE_EXISTING_INHERIT_PROPERTIES,
|
|
NULL))
|
|
{
|
|
hr = HRESULT_FROM_WIN32(::GetLastError());
|
|
|
|
DebugTrace("Error [%#x]: CertAddCertificateContextToStore() failed.\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
}
|
|
|
|
catch(...)
|
|
{
|
|
hr = E_INVALIDARG;
|
|
|
|
DebugTrace("Exception: invalid parameter.\n");
|
|
goto ErrorExit;
|
|
}
|
|
|
|
UnlockExit:
|
|
//
|
|
// Free resource.
|
|
//
|
|
if (pCertContext)
|
|
{
|
|
::CertFreeCertificateContext(pCertContext);
|
|
}
|
|
|
|
//
|
|
// Unlock access to this object.
|
|
//
|
|
m_Lock.Unlock();
|
|
|
|
DebugTrace("Leaving CStore::Add().\n");
|
|
|
|
return hr;
|
|
|
|
ErrorExit:
|
|
//
|
|
// Sanity check.
|
|
//
|
|
ATLASSERT(FAILED(hr));
|
|
|
|
ReportError(hr);
|
|
|
|
goto UnlockExit;
|
|
}
|
|
|
|
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
|
|
Function : CStore::Remove
|
|
|
|
Synopsis : Remove a certificate from the store.
|
|
|
|
Parameter: ICertificate * - Pointer to certificate object to remove.
|
|
|
|
Remark : If called from web, UI will be displayed, if has not been
|
|
previuosly disabled, to solicit user's permission to remove
|
|
certificate to the system store.
|
|
|
|
Removed certificates are not persisted for non-system stores.
|
|
|
|
------------------------------------------------------------------------------*/
|
|
|
|
STDMETHODIMP CStore::Remove (ICertificate * pVal)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
PCCERT_CONTEXT pCertContext = NULL;
|
|
PCCERT_CONTEXT pCertContext2 = NULL;
|
|
CComPtr<ICertificate> pICertificate = NULL;
|
|
BOOL bResult = FALSE;
|
|
|
|
DebugTrace("Entering CStore::Remove().\n");
|
|
|
|
try
|
|
{
|
|
//
|
|
// Lock access to this object.
|
|
//
|
|
m_Lock.Lock();
|
|
|
|
//
|
|
// QI for ICertificate pointer (Just to make sure it is indeed
|
|
// an ICertificate object).
|
|
//
|
|
if (!(pICertificate = pVal))
|
|
{
|
|
hr = E_INVALIDARG;
|
|
|
|
DebugTrace("Error [%#x]: Parameter pVal is not an ICertificate interface pointer.\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
|
|
//
|
|
// Is the store object opened?
|
|
//
|
|
if (!m_hCertStore)
|
|
{
|
|
hr = CAPICOM_E_STORE_NOT_OPENED;
|
|
|
|
DebugTrace("Error [%#x]: Store has not been opened.\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
|
|
//
|
|
// Remove is not allowed for protected store when called from WEB script.
|
|
//
|
|
if (m_dwCurrentSafety)
|
|
{
|
|
DebugTrace("Info: CStore::Remove called from WEB script.\n");
|
|
|
|
if (m_bIsProtected)
|
|
{
|
|
hr = CAPICOM_E_NOT_ALLOWED;
|
|
|
|
DebugTrace("Error [%#x]: Removing from this store is not allowed from WEB script.\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
|
|
if (CAPICOM_CURRENT_USER_STORE != m_StoreLocation &&
|
|
CAPICOM_LOCAL_MACHINE_STORE != m_StoreLocation &&
|
|
FAILED(hr = OperationApproved(IDD_STORE_REMOVE_SECURITY_ALERT_DLG)))
|
|
{
|
|
DebugTrace("Error [%#x]: OperationApproved() failed.\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Get cert context from certificate object.
|
|
//
|
|
if (FAILED(hr = ::GetCertContext(pICertificate, &pCertContext)))
|
|
{
|
|
DebugTrace("Error [%#x]: GetCertContext() failed.\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
|
|
//
|
|
// Sanity check.
|
|
//
|
|
ATLASSERT(pCertContext);
|
|
|
|
//
|
|
// Find the cert in store.
|
|
//
|
|
if (!(pCertContext2 = ::CertFindCertificateInStore(m_hCertStore,
|
|
CAPICOM_ASN_ENCODING,
|
|
0,
|
|
CERT_FIND_EXISTING,
|
|
(const void *) pCertContext,
|
|
NULL)))
|
|
{
|
|
DebugTrace("Error [%#x]: CertFindCertificateInStore() failed.\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
|
|
//
|
|
// Sanity check.
|
|
//
|
|
ATLASSERT(pCertContext2);
|
|
|
|
//
|
|
// Remove from the store.
|
|
//
|
|
bResult =::CertDeleteCertificateFromStore(pCertContext2);
|
|
|
|
//
|
|
// Since CertDeleteCertificateFromStore always release the
|
|
// context regardless of success or failure, we must first
|
|
// NULL the CERT_CONTEXT before checking for result.
|
|
//
|
|
pCertContext2 = NULL;
|
|
|
|
if (!bResult)
|
|
{
|
|
hr = HRESULT_FROM_WIN32(::GetLastError());
|
|
|
|
DebugTrace("Error [%#x]: CertDeleteCertificateFromStore() failed.\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
}
|
|
|
|
catch(...)
|
|
{
|
|
hr = E_INVALIDARG;
|
|
|
|
DebugTrace("Exception: invalid parameter.\n");
|
|
goto ErrorExit;
|
|
}
|
|
|
|
UnlockExit:
|
|
//
|
|
// Free resource.
|
|
//
|
|
if (pCertContext2)
|
|
{
|
|
::CertFreeCertificateContext(pCertContext2);
|
|
}
|
|
if (pCertContext)
|
|
{
|
|
::CertFreeCertificateContext(pCertContext);
|
|
}
|
|
|
|
//
|
|
// Unlock access to this object.
|
|
//
|
|
m_Lock.Unlock();
|
|
|
|
DebugTrace("Leaving CStore::Remove().\n");
|
|
|
|
return hr;
|
|
|
|
ErrorExit:
|
|
//
|
|
// Sanity check.
|
|
//
|
|
ATLASSERT(FAILED(hr));
|
|
|
|
ReportError(hr);
|
|
|
|
goto UnlockExit;
|
|
}
|
|
|
|
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
|
|
Function : CStore:Export
|
|
|
|
Synopsis : Export all certificates in the store.
|
|
|
|
Parameter: CAPICOM_STORE_SAVE_AS_TYPE SaveAs - Save as type.
|
|
|
|
CAPICOM_ENCODING_TYPE EncodingType - Encoding type.
|
|
|
|
BSTR * pVal - Pointer to BSTR to receive the store blob.
|
|
|
|
Remark : If called from web, UI will be displayed, if has not been
|
|
previuosly disabled, to solicit user's permission to export
|
|
certificate from the system store.
|
|
|
|
------------------------------------------------------------------------------*/
|
|
|
|
STDMETHODIMP CStore::Export (CAPICOM_STORE_SAVE_AS_TYPE SaveAs,
|
|
CAPICOM_ENCODING_TYPE EncodingType,
|
|
BSTR * pVal)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
DWORD dwSaveAs = 0;
|
|
DATA_BLOB DataBlob = {0, NULL};
|
|
|
|
DebugTrace("Entering CStore::Export().\n");
|
|
|
|
try
|
|
{
|
|
//
|
|
// Lock access to this object.
|
|
//
|
|
m_Lock.Lock();
|
|
|
|
//
|
|
// Check parameters.
|
|
//
|
|
if (NULL == pVal)
|
|
{
|
|
hr = E_INVALIDARG;
|
|
|
|
DebugTrace("Error [%#x]: Parameter pVal is NULL.\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
|
|
//
|
|
// Determine SaveAs type.
|
|
//
|
|
switch (SaveAs)
|
|
{
|
|
case CAPICOM_STORE_SAVE_AS_SERIALIZED:
|
|
{
|
|
dwSaveAs = CERT_STORE_SAVE_AS_STORE;
|
|
break;
|
|
}
|
|
|
|
case CAPICOM_STORE_SAVE_AS_PKCS7:
|
|
{
|
|
dwSaveAs = CERT_STORE_SAVE_AS_PKCS7;
|
|
break;
|
|
}
|
|
|
|
default:
|
|
{
|
|
hr = E_INVALIDARG;
|
|
|
|
DebugTrace("Error: invalid parameter, unknown save as type.\n");
|
|
goto ErrorExit;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Is the store object opened?
|
|
//
|
|
if (!m_hCertStore)
|
|
{
|
|
hr = CAPICOM_E_STORE_NOT_OPENED;
|
|
|
|
DebugTrace("Error [%#x]: store has not been opened.\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
|
|
//
|
|
// Determine required length.
|
|
//
|
|
if (!::CertSaveStore(m_hCertStore, // in
|
|
CAPICOM_ASN_ENCODING, // in
|
|
dwSaveAs, // in
|
|
CERT_STORE_SAVE_TO_MEMORY, // in
|
|
(void *) &DataBlob, // in/out
|
|
0)) // in
|
|
{
|
|
hr = HRESULT_FROM_WIN32(GetLastError());
|
|
|
|
DebugTrace("Error [%#x]: CertSaveStore() failed.\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
|
|
//
|
|
// Allocate memory.
|
|
//
|
|
if (!(DataBlob.pbData = (BYTE *) ::CoTaskMemAlloc(DataBlob.cbData)))
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
|
|
DebugTrace("Error [%#x]: DataBlob.pbData = (BYTE *) ::CoTaskMemAlloc(DataBlob.cbData).\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
|
|
//
|
|
// Now save the store to memory blob.
|
|
//
|
|
if (!::CertSaveStore(m_hCertStore, // in
|
|
CAPICOM_ASN_ENCODING, // in
|
|
dwSaveAs, // in
|
|
CERT_STORE_SAVE_TO_MEMORY, // in
|
|
(void *) &DataBlob, // in/out
|
|
0)) // in
|
|
{
|
|
hr = HRESULT_FROM_WIN32(::GetLastError());
|
|
|
|
DebugTrace("Error [%#x]: CertSaveStore() failed.\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
|
|
//
|
|
// Export store.
|
|
//
|
|
if (FAILED(hr = ::ExportData(DataBlob, EncodingType, pVal)))
|
|
{
|
|
DebugTrace("Error [%#x]: ExportData() failed.\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
}
|
|
|
|
catch(...)
|
|
{
|
|
hr = E_INVALIDARG;
|
|
|
|
DebugTrace("Exception: invalid parameter.\n");
|
|
goto ErrorExit;
|
|
}
|
|
|
|
UnlockExit:
|
|
//
|
|
// Free resource.
|
|
//
|
|
if (DataBlob.pbData)
|
|
{
|
|
::CoTaskMemFree((LPVOID) DataBlob.pbData);
|
|
}
|
|
|
|
//
|
|
// Unlock access to this object.
|
|
//
|
|
m_Lock.Unlock();
|
|
|
|
DebugTrace("Leaving CStore::Export().\n");
|
|
|
|
return hr;
|
|
|
|
ErrorExit:
|
|
//
|
|
// Sanity check.
|
|
//
|
|
ATLASSERT(FAILED(hr));
|
|
|
|
ReportError(hr);
|
|
|
|
goto UnlockExit;
|
|
}
|
|
|
|
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
|
|
Function : CStore::Import
|
|
|
|
Synopsis : Import either a serialized or PKCS #7 certificate store.
|
|
|
|
Parameter: BSTR EncodedStore - Pointer to BSTR containing the encoded
|
|
store blob.
|
|
|
|
Remark : Note that the SaveAs and EncodingType will be determined
|
|
automatically.
|
|
|
|
If called from web, UI will be displayed, if has not been
|
|
previuosly disabled, to solicit user's permission to import
|
|
certificate to the system store.
|
|
|
|
------------------------------------------------------------------------------*/
|
|
|
|
STDMETHODIMP CStore::Import (BSTR EncodedStore)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
DATA_BLOB StoreBlob = {0, NULL};
|
|
|
|
DebugTrace("Entering CStore::Import().\n");
|
|
|
|
try
|
|
{
|
|
//
|
|
// Lock access to this object.
|
|
//
|
|
m_Lock.Lock();
|
|
|
|
//
|
|
// Make sure parameters are valid.
|
|
//
|
|
if ((NULL == (StoreBlob.pbData = (LPBYTE) EncodedStore)) ||
|
|
(0 == (StoreBlob.cbData = ::SysStringByteLen(EncodedStore))))
|
|
{
|
|
hr = E_INVALIDARG;
|
|
|
|
DebugTrace("Error [%#x]: Parameter EncodedStore is NULL or empty.\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
|
|
//
|
|
// Is the store object opened?
|
|
//
|
|
if (!m_hCertStore)
|
|
{
|
|
hr = CAPICOM_E_STORE_NOT_OPENED;
|
|
|
|
DebugTrace("Error [%#x]: store has not been opened.\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
|
|
//
|
|
// Import is not allowed if the store is protected when called from
|
|
// WEB script.
|
|
//
|
|
if (m_dwCurrentSafety)
|
|
{
|
|
DebugTrace("Info: CStore::Import called from WEB script.\n");
|
|
|
|
if (m_bIsProtected)
|
|
{
|
|
hr = CAPICOM_E_NOT_ALLOWED;
|
|
|
|
DebugTrace("Error [%#x]: Importing to this store is not allowed from WEB script.\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
|
|
if (CAPICOM_CURRENT_USER_STORE != m_StoreLocation &&
|
|
CAPICOM_LOCAL_MACHINE_STORE != m_StoreLocation &&
|
|
FAILED(hr = OperationApproved(IDD_STORE_ADD_SECURITY_ALERT_DLG)))
|
|
{
|
|
DebugTrace("Error [%#x]: OperationApproved() failed.\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Now import the blob.
|
|
//
|
|
if (FAILED(hr = ImportCertObject(CERT_QUERY_OBJECT_BLOB,
|
|
(LPVOID) &StoreBlob,
|
|
FALSE,
|
|
NULL,
|
|
(CAPICOM_KEY_STORAGE_FLAG) 0)))
|
|
{
|
|
DebugTrace("Error [%#x]: CStore::ImportCertObject() failed.\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
}
|
|
|
|
catch(...)
|
|
{
|
|
hr = E_INVALIDARG;
|
|
|
|
DebugTrace("Exception: invalid parameter.\n");
|
|
goto ErrorExit;
|
|
}
|
|
|
|
UnlockExit:
|
|
//
|
|
// Unlock access to this object.
|
|
//
|
|
m_Lock.Unlock();
|
|
|
|
DebugTrace("Leaving CStore::Import().\n");
|
|
|
|
return hr;
|
|
|
|
ErrorExit:
|
|
//
|
|
// Sanity check.
|
|
//
|
|
ATLASSERT(FAILED(hr));
|
|
|
|
ReportError(hr);
|
|
|
|
goto UnlockExit;
|
|
}
|
|
|
|
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
|
|
Function : CStore::Load
|
|
|
|
Synopsis : Method to load certificate(s) from a file.
|
|
|
|
Parameter: BSTR FileName - File name.
|
|
|
|
BSTR Password - Password (required for PFX file.)
|
|
|
|
CAPICOM_KEY_STORAGE_FLAG KeyStorageFlag - Key storage flag.
|
|
|
|
Remark :
|
|
|
|
------------------------------------------------------------------------------*/
|
|
|
|
STDMETHODIMP CStore::Load (BSTR FileName,
|
|
BSTR Password,
|
|
CAPICOM_KEY_STORAGE_FLAG KeyStorageFlag)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
DebugTrace("Entering CStore::Load().\n");
|
|
|
|
try
|
|
{
|
|
//
|
|
// Lock access to this object.
|
|
//
|
|
m_Lock.Lock();
|
|
|
|
//
|
|
// Make sure parameters are valid.
|
|
//
|
|
if (0 == ::SysStringLen(FileName))
|
|
{
|
|
hr = E_INVALIDARG;
|
|
|
|
DebugTrace("Error [%#x]: Paremeter FileName is NULL or empty.\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
|
|
//
|
|
// Work around MIDL problem.
|
|
//
|
|
if (0 == ::SysStringLen(Password))
|
|
{
|
|
Password = NULL;
|
|
}
|
|
|
|
//
|
|
// Is the store object opened?
|
|
//
|
|
if (!m_hCertStore)
|
|
{
|
|
hr = CAPICOM_E_STORE_NOT_OPENED;
|
|
|
|
DebugTrace("Error [%#x]: store has not been opened.\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
|
|
//
|
|
// Not allowed if called from WEB script.
|
|
//
|
|
if (m_dwCurrentSafety)
|
|
{
|
|
hr = CAPICOM_E_NOT_ALLOWED;
|
|
|
|
DebugTrace("Error [%#x]: Loading cert file from WEB script is not allowed.\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
|
|
//
|
|
// Make sure it is a disk file.
|
|
//
|
|
if (FAILED(hr = ::IsDiskFile(FileName)))
|
|
{
|
|
DebugTrace("Error [%#x]: CStore::IsDiskFile() failed.\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
|
|
//
|
|
// Now import the blob.
|
|
//
|
|
if (FAILED(hr = ImportCertObject(CERT_QUERY_OBJECT_FILE,
|
|
(LPVOID) FileName,
|
|
TRUE,
|
|
Password,
|
|
KeyStorageFlag)))
|
|
{
|
|
DebugTrace("Error [%#x]: CStore::ImportCertObject() 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 CStore::Load().\n");
|
|
|
|
return hr;
|
|
|
|
ErrorExit:
|
|
//
|
|
// Sanity check.
|
|
//
|
|
ATLASSERT(FAILED(hr));
|
|
|
|
ReportError(hr);
|
|
|
|
goto UnlockExit;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Custom interfaces.
|
|
//
|
|
|
|
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
|
|
Function : CStore::get_StoreHandle
|
|
|
|
Synopsis : Return the store's HCERTSTORE.
|
|
|
|
Parameter: long * pphCertStore - Pointer to HCERTSTORE disguished in a long.
|
|
|
|
Remark : We need to use long instead of HCERTSTORE because VB can't handle
|
|
double indirection (i.e. vb would bark on this HCERTSTORE *
|
|
phCertStore, as HCERTSTORE is defined as void *).
|
|
|
|
------------------------------------------------------------------------------*/
|
|
|
|
STDMETHODIMP CStore::get_StoreHandle (long * phCertStore)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
HCERTSTORE hCertStore = NULL;
|
|
|
|
DebugTrace("Entering CStore::get_StoreHandle().\n");
|
|
|
|
try
|
|
{
|
|
//
|
|
// Lock access to this object.
|
|
//
|
|
m_Lock.Lock();
|
|
|
|
//
|
|
// Check parameters.
|
|
//
|
|
if (NULL == phCertStore)
|
|
{
|
|
hr = E_INVALIDARG;
|
|
|
|
DebugTrace("Error [%#x]: Parameter phCertStore is NULL.\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
|
|
//
|
|
// Is the store object opened?
|
|
//
|
|
if (!m_hCertStore)
|
|
{
|
|
hr = CAPICOM_E_STORE_NOT_OPENED;
|
|
|
|
DebugTrace("Error [%#x]: store has not been opened.\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
|
|
//
|
|
// Duplicate the HCERTSTORE.
|
|
//
|
|
if (!(hCertStore = ::CertDuplicateStore(m_hCertStore)))
|
|
{
|
|
DebugTrace("Error [%#x]: CertDuplicateStore() failed.\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
|
|
//
|
|
// Returen handle to caller.
|
|
//
|
|
*phCertStore = (long) hCertStore;
|
|
}
|
|
|
|
catch(...)
|
|
{
|
|
hr = E_POINTER;
|
|
|
|
DebugTrace("Exception: invalid parameter.\n");
|
|
goto ErrorExit;
|
|
}
|
|
|
|
UnlockExit:
|
|
//
|
|
// Unlock access to this object.
|
|
//
|
|
m_Lock.Unlock();
|
|
|
|
DebugTrace("Leaving CStore::get_StoreHandle().\n");
|
|
|
|
return hr;
|
|
|
|
ErrorExit:
|
|
//
|
|
// Sanity check.
|
|
//
|
|
ATLASSERT(FAILED(hr));
|
|
|
|
ReportError(hr);
|
|
|
|
goto UnlockExit;
|
|
}
|
|
|
|
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
|
|
Function : CStore::put_StoreHandle
|
|
|
|
Synopsis : Initialize the object with a HCERTSTORE.
|
|
|
|
Parameter: long hCertStore - HCERTSTORE, disguised in a long, used to
|
|
initialize this object.
|
|
|
|
Remark : Note that this is NOT 64-bit compatiable. Plese see remark of
|
|
get_hCertStore for more detail.
|
|
|
|
------------------------------------------------------------------------------*/
|
|
|
|
STDMETHODIMP CStore::put_StoreHandle (long hCertStore)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
HCERTSTORE hCertStore2 = NULL;
|
|
|
|
DebugTrace("Entering CStore::put_StoreHandle().\n");
|
|
|
|
try
|
|
{
|
|
//
|
|
// Lock access to this object.
|
|
//
|
|
m_Lock.Lock();
|
|
|
|
//
|
|
// Check parameter.
|
|
//
|
|
if (0 == hCertStore)
|
|
{
|
|
hr = E_INVALIDARG;
|
|
|
|
DebugTrace("Error [%#x]: Parameter hCertStore is NULL.\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
|
|
//
|
|
// Duplicate the HCERTSTORE.
|
|
//
|
|
if (!(hCertStore2 = ::CertDuplicateStore((HCERTSTORE) hCertStore)))
|
|
{
|
|
DebugTrace("Error [%#x]: CertDuplicateStore() failed.\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
|
|
//
|
|
// Close the store.
|
|
//
|
|
if (FAILED(hr = Close()))
|
|
{
|
|
DebugTrace("Error [%#x]: CStore::Close() failed.\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
|
|
//
|
|
// Reset the object with this handle.
|
|
//
|
|
m_hCertStore = hCertStore2;
|
|
}
|
|
|
|
catch(...)
|
|
{
|
|
hr = E_POINTER;
|
|
|
|
DebugTrace("Exception: invalid parameter.\n");
|
|
goto ErrorExit;
|
|
}
|
|
|
|
UnlockExit:
|
|
//
|
|
// Unlock access to this object.
|
|
//
|
|
m_Lock.Unlock();
|
|
|
|
DebugTrace("Leaving CStore::put_StoreHandle().\n");
|
|
|
|
return hr;
|
|
|
|
ErrorExit:
|
|
//
|
|
// Sanity check.
|
|
//
|
|
ATLASSERT(FAILED(hr));
|
|
|
|
//
|
|
// Free resources.
|
|
//
|
|
if (hCertStore2)
|
|
{
|
|
::CertCloseStore(hCertStore2, 0);
|
|
}
|
|
|
|
ReportError(hr);
|
|
|
|
goto UnlockExit;
|
|
}
|
|
|
|
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
|
|
Function : CStore::get_StoreLocation
|
|
|
|
Synopsis : Get the store location property.
|
|
|
|
Parameter: CAPICOM_STORE_LOCATION * pStoreLocation - Pointer to
|
|
CAPICOM_STORE_LOCATION
|
|
to recieve the value.
|
|
|
|
Remark : For custom interface, we only support CU, LM, and Memory store.
|
|
|
|
------------------------------------------------------------------------------*/
|
|
|
|
STDMETHODIMP CStore::get_StoreLocation (CAPICOM_STORE_LOCATION * pStoreLocation)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
DebugTrace("Entering CStore::get_StoreLocation().\n");
|
|
|
|
try
|
|
{
|
|
//
|
|
// Lock access to this object.
|
|
//
|
|
m_Lock.Lock();
|
|
|
|
//
|
|
// Check parameter.
|
|
//
|
|
if (NULL == pStoreLocation)
|
|
{
|
|
hr = E_INVALIDARG;
|
|
|
|
DebugTrace("Error [%#x]: Parameter pStoreLocation is NULL.\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
|
|
//
|
|
// Return value to caller.
|
|
//
|
|
*pStoreLocation = m_StoreLocation;
|
|
}
|
|
|
|
catch(...)
|
|
{
|
|
hr = E_POINTER;
|
|
|
|
DebugTrace("Exception: invalid parameter.\n");
|
|
goto ErrorExit;
|
|
}
|
|
|
|
UnlockExit:
|
|
//
|
|
// Unlock access to this object.
|
|
//
|
|
m_Lock.Unlock();
|
|
|
|
DebugTrace("Leaving CStore::get_StoreLocation().\n");
|
|
|
|
return hr;
|
|
|
|
ErrorExit:
|
|
//
|
|
// Sanity check.
|
|
//
|
|
ATLASSERT(FAILED(hr));
|
|
|
|
ReportError(hr);
|
|
|
|
goto UnlockExit;
|
|
}
|
|
|
|
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
|
|
Function : CStore::put_StoreLocation
|
|
|
|
Synopsis : Set the store location property.
|
|
|
|
Parameter: CAPICOM_STORE_LOCATION StoreLocation - Store location.
|
|
|
|
Remark : For custom interface, we only support CU, LM, and Memory store.
|
|
|
|
------------------------------------------------------------------------------*/
|
|
|
|
STDMETHODIMP CStore::put_StoreLocation (CAPICOM_STORE_LOCATION StoreLocation)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
DebugTrace("Entering CStore::put_StoreLocation().\n");
|
|
|
|
try
|
|
{
|
|
//
|
|
// Lock access to this object.
|
|
//
|
|
m_Lock.Lock();
|
|
|
|
//
|
|
// Make sure it is a CAPI store (CU, LM, or Memory).
|
|
//
|
|
switch (StoreLocation)
|
|
{
|
|
case CAPICOM_MEMORY_STORE:
|
|
case CAPICOM_LOCAL_MACHINE_STORE:
|
|
case CAPICOM_CURRENT_USER_STORE:
|
|
{
|
|
//
|
|
// Set it.
|
|
//
|
|
m_StoreLocation = StoreLocation;
|
|
break;
|
|
}
|
|
|
|
default:
|
|
{
|
|
hr = E_INVALIDARG;
|
|
|
|
DebugTrace("Error [%#x]: invalid store location (%#x).\n", hr, StoreLocation);
|
|
goto ErrorExit;
|
|
}
|
|
}
|
|
}
|
|
|
|
catch(...)
|
|
{
|
|
hr = E_POINTER;
|
|
|
|
DebugTrace("Exception: invalid parameter.\n");
|
|
goto ErrorExit;
|
|
}
|
|
|
|
UnlockExit:
|
|
//
|
|
// Unlock access to this object.
|
|
//
|
|
m_Lock.Unlock();
|
|
|
|
DebugTrace("Leaving CStore::put_StoreLocation().\n");
|
|
|
|
return hr;
|
|
|
|
ErrorExit:
|
|
//
|
|
// Sanity check.
|
|
//
|
|
ATLASSERT(FAILED(hr));
|
|
|
|
ReportError(hr);
|
|
|
|
goto UnlockExit;
|
|
}
|
|
|
|
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
|
|
Function : CStore::CloseHandle
|
|
|
|
Synopsis : Close a HCERTSTORE.
|
|
|
|
Parameter: long hCertStoret - HCERTSTORE, disguised in a long, to be closed.
|
|
|
|
Remark : Note that this is NOT 64-bit compatiable. Plese see remark of
|
|
get_hCertStore for more detail.
|
|
|
|
------------------------------------------------------------------------------*/
|
|
|
|
STDMETHODIMP CStore::CloseHandle (long hCertStore)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
DebugTrace("Entering CStore::CloseHandle().\n");
|
|
|
|
try
|
|
{
|
|
//
|
|
// Lock access to this object.
|
|
//
|
|
m_Lock.Lock();
|
|
|
|
//
|
|
// Check parameter.
|
|
//
|
|
if (0 == hCertStore)
|
|
{
|
|
hr = E_INVALIDARG;
|
|
|
|
DebugTrace("Error [%#x]: Parameter hCertStore is NULL.\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
|
|
//
|
|
// Duplicate the HCERTSTORE.
|
|
//
|
|
if (!::CertCloseStore((HCERTSTORE) hCertStore, 0))
|
|
{
|
|
hr = HRESULT_FROM_WIN32(::GetLastError());
|
|
|
|
DebugTrace("Error [%#x]: CertCloseStore() 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 CStore::CloseHandle().\n");
|
|
|
|
return hr;
|
|
|
|
ErrorExit:
|
|
//
|
|
// Sanity check.
|
|
//
|
|
ATLASSERT(FAILED(hr));
|
|
|
|
ReportError(hr);
|
|
|
|
goto UnlockExit;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Private methods.
|
|
//
|
|
|
|
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
|
|
Function : CStore::ImportCertObject
|
|
|
|
Synopsis : Private function to import from a file.
|
|
|
|
Parameter: DWORD dwObjectType - CERT_QUERY_OBJECT_FILE or
|
|
CERT_QUERY_OBJECT_BLOB.
|
|
|
|
LPVOID pvObject - LPWSTR to file name for file object, and
|
|
DATA_BLOB * for blob object.
|
|
|
|
BOOL bAllowPfx
|
|
|
|
LPWSTR pwszPassword (Optional)
|
|
|
|
CAPICOM_KEY_STORAGE_FLAG KeyStorageFlag (Optional)
|
|
|
|
Remark :
|
|
|
|
------------------------------------------------------------------------------*/
|
|
|
|
STDMETHODIMP CStore::ImportCertObject (DWORD dwObjectType,
|
|
LPVOID pvObject,
|
|
BOOL bAllowPfx,
|
|
LPWSTR pwszPassword,
|
|
CAPICOM_KEY_STORAGE_FLAG KeyStorageFlag)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
HCERTSTORE hCertStore = NULL;
|
|
PCCERT_CONTEXT pEnumContext = NULL;
|
|
PCCERT_CONTEXT pCertContext = NULL;
|
|
DATA_BLOB StoreBlob = {0, NULL};
|
|
DWORD dwContentType = 0;
|
|
DWORD dwExpectedType = CERT_QUERY_CONTENT_FLAG_CERT |
|
|
CERT_QUERY_CONTENT_FLAG_SERIALIZED_STORE |
|
|
CERT_QUERY_CONTENT_FLAG_SERIALIZED_CERT |
|
|
CERT_QUERY_CONTENT_FLAG_PKCS7_UNSIGNED |
|
|
CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED |
|
|
CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED_EMBED;
|
|
|
|
DebugTrace("Entering CStore::ImportCertObject().\n");
|
|
|
|
//
|
|
// Sanity check.
|
|
//
|
|
ATLASSERT(pvObject);
|
|
ATLASSERT(m_hCertStore);
|
|
|
|
//
|
|
// Set PFX flag, if allowed.
|
|
//
|
|
if (bAllowPfx)
|
|
{
|
|
dwExpectedType |= CERT_QUERY_CONTENT_FLAG_PFX;
|
|
}
|
|
|
|
//
|
|
// Crack the blob.
|
|
//
|
|
if (!::CryptQueryObject(dwObjectType,
|
|
(LPCVOID) pvObject,
|
|
dwExpectedType,
|
|
CERT_QUERY_FORMAT_FLAG_ALL,
|
|
0,
|
|
NULL,
|
|
&dwContentType,
|
|
NULL,
|
|
&hCertStore,
|
|
NULL,
|
|
NULL))
|
|
{
|
|
hr = HRESULT_FROM_WIN32(::GetLastError());
|
|
|
|
DebugTrace("Error [%#x]: CryptQueryObject() failed.\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
|
|
DebugTrace("Info: CryptQueryObject() returns dwContentType = %#x.\n", dwContentType);
|
|
|
|
//
|
|
// Need to import it ourselves for PFX.
|
|
//
|
|
if (CERT_QUERY_CONTENT_PFX == dwContentType)
|
|
{
|
|
DWORD dwFlags = 0;
|
|
|
|
//
|
|
// Make sure PFX is allowed.
|
|
//
|
|
if (!bAllowPfx)
|
|
{
|
|
hr = CAPICOM_E_NOT_SUPPORTED;
|
|
|
|
DebugTrace("Error [%#x]: Importing PFX where not supported.\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
|
|
//
|
|
// Read the file if CERT_QUERY_OBJECT_FILE.
|
|
//
|
|
if (CERT_QUERY_OBJECT_FILE == dwObjectType)
|
|
{
|
|
if (FAILED(hr = ::ReadFileContent((LPWSTR) pvObject, &StoreBlob)))
|
|
{
|
|
DebugTrace("Error [%#x]: ReadFileContent() failed.\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
StoreBlob = * (DATA_BLOB *) pvObject;
|
|
}
|
|
|
|
//
|
|
// Setup import flags.
|
|
//
|
|
if (CAPICOM_LOCAL_MACHINE_STORE == m_StoreLocation)
|
|
{
|
|
dwFlags |= CRYPT_MACHINE_KEYSET;
|
|
}
|
|
else if (IsWin2KAndAbove())
|
|
{
|
|
dwFlags |= CRYPT_USER_KEYSET;
|
|
}
|
|
|
|
if (KeyStorageFlag & CAPICOM_KEY_STORAGE_EXPORTABLE)
|
|
{
|
|
dwFlags |= CRYPT_EXPORTABLE;
|
|
}
|
|
|
|
if (KeyStorageFlag & CAPICOM_KEY_STORAGE_USER_PROTECTED)
|
|
{
|
|
dwFlags |= CRYPT_USER_PROTECTED;
|
|
}
|
|
|
|
//
|
|
// Now import the blob to store.
|
|
//
|
|
if (!(hCertStore = ::PFXImportCertStore((CRYPT_DATA_BLOB *) &StoreBlob,
|
|
pwszPassword,
|
|
dwFlags)))
|
|
{
|
|
hr = HRESULT_FROM_WIN32(::GetLastError());
|
|
|
|
DebugTrace("Error [%#x]: PFXImportCertStore() failed, dwFlags = %#x.\n", hr, dwFlags);
|
|
goto ErrorExit;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Sanity check.
|
|
//
|
|
ATLASSERT(hCertStore);
|
|
|
|
//
|
|
// Add all certificates to the current store.
|
|
//
|
|
while (pEnumContext = ::CertEnumCertificatesInStore(hCertStore, pEnumContext))
|
|
{
|
|
//
|
|
// To avoid orphaning key container when importing PFX into system store,
|
|
// we need to find the cert in the target store. If we find the cert in the
|
|
// target store and the eixsitng cert also contain a key, then we will
|
|
// delete the new key container and key prov info before adding, if any.
|
|
//
|
|
if ((CERT_QUERY_CONTENT_PFX == dwContentType) && (CAPICOM_MEMORY_STORE != m_StoreLocation))
|
|
{
|
|
DWORD cbData = 0;
|
|
DWORD cbData2 = 0;
|
|
PCRYPT_KEY_PROV_INFO pKeyProvInfo = NULL;
|
|
PCCERT_CONTEXT pExistingCertContext = NULL;
|
|
|
|
//
|
|
// Delete the new container, iif:
|
|
// 1. The new cert exists in the target store, and
|
|
// 2. The new cert has a key container, and
|
|
// 3. The existing cert also has a key container.
|
|
//
|
|
if ((pExistingCertContext = ::CertFindCertificateInStore(m_hCertStore,
|
|
CAPICOM_ASN_ENCODING,
|
|
0,
|
|
CERT_FIND_EXISTING,
|
|
(PVOID) pEnumContext,
|
|
NULL)) &&
|
|
(::CertGetCertificateContextProperty(pEnumContext,
|
|
CERT_KEY_PROV_INFO_PROP_ID,
|
|
NULL,
|
|
&cbData)) &&
|
|
(::CertGetCertificateContextProperty(pExistingCertContext,
|
|
CERT_KEY_PROV_INFO_PROP_ID,
|
|
NULL,
|
|
&cbData2)))
|
|
|
|
{
|
|
HCRYPTPROV hCryptProv;
|
|
|
|
//
|
|
// Yes, so retrieve the new key prov info.
|
|
//
|
|
if (!(pKeyProvInfo = (PCRYPT_KEY_PROV_INFO) ::CoTaskMemAlloc(cbData)))
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
|
|
::CertFreeCertificateContext(pExistingCertContext);
|
|
|
|
DebugTrace("Error [%#x]: CoTaskMemAlloc() failed.\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
|
|
if (!::CertGetCertificateContextProperty(pEnumContext,
|
|
CERT_KEY_PROV_INFO_PROP_ID,
|
|
pKeyProvInfo,
|
|
&cbData))
|
|
{
|
|
hr = HRESULT_FROM_WIN32(::GetLastError());
|
|
|
|
::CoTaskMemFree(pKeyProvInfo);
|
|
::CertFreeCertificateContext(pExistingCertContext);
|
|
|
|
DebugTrace("Info [%#x]: CertGetCertificateContextProperty() failed.\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
|
|
//
|
|
// Delete the new key container and its key prov info.
|
|
//
|
|
if (!::CertSetCertificateContextProperty(pEnumContext,
|
|
CERT_KEY_PROV_INFO_PROP_ID,
|
|
0,
|
|
NULL))
|
|
{
|
|
hr = HRESULT_FROM_WIN32(::GetLastError());
|
|
|
|
::CoTaskMemFree(pKeyProvInfo);
|
|
::CertFreeCertificateContext(pExistingCertContext);
|
|
|
|
DebugTrace("Error [%#x]: CertSetCertificateContextProperty() failed.\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
|
|
if (FAILED(hr = ::AcquireContext(pKeyProvInfo->pwszProvName,
|
|
pKeyProvInfo->pwszContainerName,
|
|
pKeyProvInfo->dwProvType,
|
|
CRYPT_DELETEKEYSET | (pKeyProvInfo->dwFlags & CRYPT_MACHINE_KEYSET),
|
|
FALSE,
|
|
&hCryptProv)))
|
|
{
|
|
::CoTaskMemFree(pKeyProvInfo);
|
|
::CertFreeCertificateContext(pExistingCertContext);
|
|
|
|
DebugTrace("Error [%#x]: AcquireContext(CRYPT_DELETEKEYSET) failed.\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
|
|
::CoTaskMemFree(pKeyProvInfo);
|
|
::CertFreeCertificateContext(pExistingCertContext);
|
|
}
|
|
}
|
|
|
|
//
|
|
// Add to store.
|
|
//
|
|
if (!::CertAddCertificateContextToStore(m_hCertStore,
|
|
pEnumContext,
|
|
CERT_STORE_ADD_REPLACE_EXISTING_INHERIT_PROPERTIES,
|
|
&pCertContext))
|
|
{
|
|
hr = HRESULT_FROM_WIN32(::GetLastError());
|
|
|
|
DebugTrace("Error [%#x]: CertAddCertificateContextToStore() failed.\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
|
|
//
|
|
// Sanity check.
|
|
//
|
|
ATLASSERT(pCertContext);
|
|
|
|
//
|
|
// If loading a PFX, need to collect the key provider info for memory store
|
|
// so that we know how to delete the key containers when the store is closed.
|
|
//
|
|
if (CERT_QUERY_CONTENT_PFX == dwContentType &&
|
|
CAPICOM_MEMORY_STORE == m_StoreLocation)
|
|
{
|
|
DWORD cbData = 0;
|
|
PCRYPT_KEY_PROV_INFO pKeyProvInfo = NULL;
|
|
PCRYPT_KEY_PROV_INFO * rgpKeyProvInfo = NULL;
|
|
|
|
//
|
|
// Keep info of those with private key.
|
|
//
|
|
if (::CertGetCertificateContextProperty(pCertContext,
|
|
CERT_KEY_PROV_INFO_PROP_ID,
|
|
NULL,
|
|
&cbData))
|
|
{
|
|
if (!(pKeyProvInfo = (PCRYPT_KEY_PROV_INFO) ::CoTaskMemAlloc(cbData)))
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
|
|
DebugTrace("Error [%#x]: CoTaskMemAlloc() failed.\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
|
|
if (!::CertGetCertificateContextProperty(pCertContext,
|
|
CERT_KEY_PROV_INFO_PROP_ID,
|
|
pKeyProvInfo,
|
|
&cbData))
|
|
{
|
|
hr = HRESULT_FROM_WIN32(::GetLastError());
|
|
|
|
::CoTaskMemFree(pKeyProvInfo);
|
|
|
|
DebugTrace("Info [%#x]: CertGetCertificateContextProperty() failed.\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
|
|
//
|
|
// Realloc the array.
|
|
//
|
|
if (!(rgpKeyProvInfo = (PCRYPT_KEY_PROV_INFO *)
|
|
::CoTaskMemRealloc(m_rgpKeyProvInfo,
|
|
(m_cKeyProvInfo + 1) * sizeof(PCRYPT_KEY_PROV_INFO))))
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
|
|
::CoTaskMemFree(pKeyProvInfo);
|
|
|
|
DebugTrace("Error [%#x]: CoTaskMemRealloc() failed.\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
|
|
//
|
|
// Store key info in array.
|
|
//
|
|
m_rgpKeyProvInfo = rgpKeyProvInfo;
|
|
m_rgpKeyProvInfo[m_cKeyProvInfo++] = pKeyProvInfo;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Free context.
|
|
//
|
|
::CertFreeCertificateContext(pCertContext), pCertContext = NULL;
|
|
}
|
|
|
|
//
|
|
// 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:
|
|
//
|
|
// Free resources.
|
|
//
|
|
if (StoreBlob.pbData)
|
|
{
|
|
::UnmapViewOfFile(StoreBlob.pbData);
|
|
}
|
|
if (pCertContext)
|
|
{
|
|
::CertFreeCertificateContext(pCertContext);
|
|
}
|
|
if (pEnumContext)
|
|
{
|
|
::CertFreeCertificateContext(pEnumContext);
|
|
}
|
|
if (hCertStore)
|
|
{
|
|
::CertCloseStore(hCertStore, 0);
|
|
}
|
|
|
|
DebugTrace("Leaving CStore::ImportCertObject().\n");
|
|
|
|
return hr;
|
|
|
|
ErrorExit:
|
|
//
|
|
// Sanity check.
|
|
//
|
|
ATLASSERT(FAILED(hr));
|
|
|
|
goto CommonExit;
|
|
}
|
|
|
|
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
|
|
Function : CStore::Close
|
|
|
|
Synopsis : Private function to close the store.
|
|
|
|
Parameter:
|
|
|
|
Remark : Store is always closed even if error.
|
|
|
|
------------------------------------------------------------------------------*/
|
|
|
|
STDMETHODIMP CStore::Close (void)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
DebugTrace("Entering CStore::Close().\n");
|
|
|
|
//
|
|
// Close it if opened.
|
|
//
|
|
if (m_hCertStore)
|
|
{
|
|
//
|
|
// Delete key containers if necessary.
|
|
//
|
|
while (m_cKeyProvInfo--)
|
|
{
|
|
HCRYPTPROV hCryptProv = NULL;
|
|
|
|
if (FAILED(hr = ::AcquireContext(m_rgpKeyProvInfo[m_cKeyProvInfo]->pwszProvName,
|
|
m_rgpKeyProvInfo[m_cKeyProvInfo]->pwszContainerName,
|
|
m_rgpKeyProvInfo[m_cKeyProvInfo]->dwProvType,
|
|
CRYPT_DELETEKEYSET |
|
|
(m_rgpKeyProvInfo[m_cKeyProvInfo]->dwFlags & CRYPT_MACHINE_KEYSET),
|
|
FALSE,
|
|
&hCryptProv)))
|
|
{
|
|
DebugTrace("Info [%#x]: AcquireContext(CRYPT_DELETEKEYSET) failed.\n", hr);
|
|
}
|
|
|
|
::CoTaskMemFree((LPVOID) m_rgpKeyProvInfo[m_cKeyProvInfo]);
|
|
}
|
|
|
|
//
|
|
// Now free the arrays itself.
|
|
//
|
|
if (m_rgpKeyProvInfo)
|
|
{
|
|
::CoTaskMemFree((LPVOID) m_rgpKeyProvInfo);
|
|
}
|
|
|
|
//
|
|
// Close it.
|
|
//
|
|
::CertCloseStore(m_hCertStore, 0);
|
|
}
|
|
|
|
//
|
|
// Reset.
|
|
//
|
|
m_hCertStore = NULL;
|
|
m_StoreLocation = CAPICOM_CURRENT_USER_STORE;
|
|
m_bIsProtected = TRUE;
|
|
m_cKeyProvInfo = 0;
|
|
m_rgpKeyProvInfo = NULL;
|
|
|
|
DebugTrace("Leaving CStore::Close().\n");
|
|
|
|
return hr;
|
|
}
|