2025-04-27 07:49:33 -04:00

1528 lines
42 KiB
C++

/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Microsoft Windows, Copyright (C) Microsoft Corporation, 2000
File: Store.cpp
Content: Implementation of CStore.
History: 11-15-99 dsie created
------------------------------------------------------------------------------*/
//
// Turn off:
//
// - Unreferenced formal parameter warning.
// - Assignment within conditional expression warning.
//
#pragma warning (disable: 4100)
#pragma warning (disable: 4706)
#include "stdafx.h"
#include "CAPICOM.h"
#include "Store.h"
#include "Convert.h"
#include "Settings.h"
#include "DialogUI.h"
#include "ADHelpers.h"
////////////////////////////////////////////////////////////////////////////////
//
// Local functions.
//
#if (0)
static BYTE Hex2Byte(BYTE hex)
{
if ('0' <= hex && hex <= '9')
{
return (hex - '0');
}
else
{
hex = toupper(hex);
if ('A' <= hex && hex <= 'F')
{
return (hex - 'A' + 10);
}
}
return 0;
}
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Function : Hex2IntegerBlob
Synopsis : Convert a hex string to CRYPT_INTEGER_BLOB.
Parameter: BSTR bstrHex - Hex string to convert.
CRYPT_INTEGER_BLOB * pBlob - To receive the blob.
Remark :
------------------------------------------------------------------------------*/
static HRESULT Hex2IntegerBlob (BSTR bstrHex,
CRYPT_INTEGER_BLOB * pBlob)
{
LPSTR lpszHex = NULL;
//
// For OLE2A macro.
//
USES_CONVERSION;
//
// Sanity check.
//
ATLASSERT(bstrHex);
ATLASSERT(pBlob);
//
// Conver to LPSTR (string is allocated off the stack by OLE2A
// so no need to explicit free these strings, as they will be poped
// when this function exits.
//
if (!(lpszHex = OLE2A(bstrHex)))
{
DebugTrace("Error: out of memory.\n");
return E_OUTOFMEMORY;
}
//
// Determine length (Need 1 byte for every 2 hex digits).
//
if (0 == (pBlob->cbData = (::lstrlen(lpszHex) + 1) >> 1))
{
pBlob->pbData = NULL;
DebugTrace("Warning: empty serial number.\n");
return S_OK;
}
//
// Allocate memory.
//
if(!(pBlob->pbData = (PBYTE) ::CoTaskMemAlloc(pBlob->cbData)))
{
pBlob->cbData = 0;
DebugTrace("Error: out of memory.\n");
return E_OUTOFMEMORY;
}
//
// Now convert it to integer blob (Remember data must be stored in little-endian).
//
for (LPBYTE pbBlob = (LPBYTE) pBlob->pbData + pBlob->cbData - 1; *lpszHex; pbBlob--)
{
//
// Convert upper nibble.
//
*pbBlob = ::Hex2Byte(*lpszHex++) << 4;
if (*lpszHex)
{
//
// Conver lower nibble.
//
*pbBlob |= ::Hex2Byte(*lpszHex++);
}
}
return S_OK;
}
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Function : Name2NameBlob
Synopsis : Convert a name string to CERT_NAME_BLOB.
Parameter: BSTR bstrName - Name string to convert.
CERT_NAME_BLOB * pBlob - To receive the blob.
Remark :
------------------------------------------------------------------------------*/
static HRESULT Name2NameBlob (BSTR bstrName,
CERT_NAME_BLOB * pBlob)
{
HRESULT hr = S_OK;
LPSTR lpszName = NULL;
//
// For OLE2A macro.
//
USES_CONVERSION;
//
// Sanity check.
//
ATLASSERT(bstrName);
ATLASSERT(pBlob);
//
// Conver to LPSTR (string is allocated off the stack by OLE2A
// so no need to explicit free these strings, as they will be poped
// when this function exits.
//
if (!(lpszName = OLE2A(bstrName)))
{
DebugTrace("Error: out of memory.\n");
return E_OUTOFMEMORY;
}
//
// Determine lenght of name blob.
//
if (!::CertStrToName(CAPICOM_ASN_ENCODING,
lpszName,
CERT_X500_NAME_STR | CERT_NAME_STR_REVERSE_FLAG,
NULL,
NULL,
&pBlob->cbData,
NULL))
{
hr = HRESULT_FROM_WIN32(::GetLastError());
DebugTrace("Error [%#x]: CertStrToName() failed.\n", hr);
return hr;
}
//
// Allocate memory.
//
if (!(pBlob->pbData = (PBYTE) ::CoTaskMemAlloc(pBlob->cbData)))
{
DebugTrace("Error: out of memory.\n");
return E_OUTOFMEMORY;
}
//
// Convert name string to name blob.
//
if (!::CertStrToName(CAPICOM_ASN_ENCODING,
lpszName,
CERT_X500_NAME_STR | CERT_NAME_STR_REVERSE_FLAG,
NULL,
pBlob->pbData,
&pBlob->cbData,
NULL))
{
hr = HRESULT_FROM_WIN32(::GetLastError());
::CoTaskMemFree(pBlob->pbData);
pBlob->cbData = 0;
pBlob->pbData = NULL;
DebugTrace("Error [%#x]: CertStrToName() failed.\n", hr);
}
return hr;
}
#endif
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Function : FindCertInStore
Synopsis : Find the specified certificate in the specified store by SHA1
match.
Parameter: HCERTSTORE hStore - Store handle of store to search.
PCCERT_CONTEXT pCertContext - Pointer to CERT_CONTEXT of cert
to be located.
PCCERT_CONTEXT * ppCertContext - Pointer to pointer to CERT_CONTEXT
to receiev the found cert or NULL
if the cert is not found.
Remark :
------------------------------------------------------------------------------*/
static HRESULT FindCertInStore (HCERTSTORE hStore,
PCCERT_CONTEXT pCertContext,
PCCERT_CONTEXT * ppCertContext)
{
HRESULT hr = S_OK;
CRYPT_HASH_BLOB HashBlob = {0, NULL};
DebugTrace("Entering FindCertInStore().\n");
//
// Sanity check.
//
ATLASSERT(hStore);
ATLASSERT(pCertContext);
ATLASSERT(ppCertContext);
//
// Determine hash buffer size.
//
if (!::CryptHashCertificate(NULL,
CALG_SHA1,
0,
pCertContext->pbCertEncoded,
pCertContext->cbCertEncoded,
NULL,
&HashBlob.cbData))
{
hr = HRESULT_FROM_WIN32(::GetLastError());
DebugTrace("Error [%#x]: CryptHashCertificate() failed.\n", hr);
goto ErrorExit;
}
//
// Allocate memory.
//
if (!(HashBlob.pbData = (BYTE *) ::CoTaskMemAlloc(HashBlob.cbData)))
{
hr = E_OUTOFMEMORY;
DebugTrace("Error: out of memory.\n");
goto ErrorExit;
}
//
// Create the hash.
//
if (!::CryptHashCertificate(NULL,
CALG_SHA1,
0,
pCertContext->pbCertEncoded,
pCertContext->cbCertEncoded,
HashBlob.pbData,
&HashBlob.cbData))
{
hr = HRESULT_FROM_WIN32(::GetLastError());
DebugTrace("Error [%#x]: CryptHashCertificate() failed.\n", hr);
goto ErrorExit;
}
//
// Now find the cert.
//
if (!(*ppCertContext = ::CertFindCertificateInStore(hStore,
CAPICOM_ASN_ENCODING,
0,
CERT_FIND_HASH,
&HashBlob,
NULL)))
{
hr = HRESULT_FROM_WIN32(::GetLastError());
DebugTrace("Error [%#x]: CertFindCertificateInStore() failed.\n", hr);
goto ErrorExit;
}
CommonExit:
//
// Free resource.
//
if (HashBlob.pbData)
{
::CoTaskMemFree(HashBlob.pbData);
}
DebugTrace("Leaving FindCertInStore().\n");
return hr;
ErrorExit:
//
// Sanity check.
//
ATLASSERT(FAILED(hr));
goto CommonExit;
}
////////////////////////////////////////////////////////////////////////////////
//
// 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;
DebugTrace("Entering CStore::get_Certificates().\n");
//
// Lock access to this object.
//
m_Lock.Lock();
try
{
#if (1)
//
// Is the store object opened?
//
if (!m_hCertStore)
{
hr = CAPICOM_E_STORE_NOT_OPENED;
DebugTrace("Error: store object does not represent an opened certificate store.\n");
goto ErrorExit;
}
//
// Create the ICertificates collection object.
//
if (FAILED(hr = ::CreateCertificatesObject(CAPICOM_CERTIFICATES_LOAD_FROM_STORE,
(LPARAM) m_hCertStore,
pVal)))
{
DebugTrace("Error [%#x]: CreateCertificatesObject() failed.\n", hr);
goto ErrorExit;
}
#else
if (!m_pICertificates)
{
hr = CAPICOM_E_STORE_NOT_OPENED;
DebugTrace("Error: store object does not represent an opened certificate store.\n");
goto ErrorExit;
}
//
// Return interface pointer to caller.
//
if (FAILED(hr = m_pICertificates->QueryInterface(pVal)))
{
DebugTrace("Unexpected error [%#x]: m_pICertificates->QueryInterface() failed.\n", hr);
goto ErrorExit;
}
#endif
}
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 not NULL, then it can be:
MY_STORE = "My"
CA_STORE = "Ca"
ROOT_STORE = "Root"
OTHER_STORE = "AddressBook"
If NULL, then MY_STORE 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"
"userPrincipalName=dsie@ntdev.microsoft.com"
"distinguishedName=CN=Daniel Sie,OU=Users,OU=ITG,DC=ntdev,DC=microsoft,DC=com"
"|((cn=Daniel Sie)(sn=Hallin))"
CAPICOM_STORE_OPEN_MODE OpenMode - Ignored for MEMORY_STORE and
ACTIVE_DIRECTORY_USER_STORE.
Remark : If the system store does not exist, a new system store will be
created, and for memory store, a new memory store is always
created.
------------------------------------------------------------------------------*/
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 dwOpenFlag = 0;
DWORD dwLocation = 0;
HCERTSTORE hCertStore = NULL;
HMODULE hDSClientDLL = NULL;
CComPtr<ICertificates> pICertificates = NULL;
DebugTrace("Entering CStore::Open().\n");
//
// Lock access to this object.
//
m_Lock.Lock();
try
{
//
// Reset.
//
if (m_hCertStore)
{
::CertCloseStore(m_hCertStore, 0);
m_hCertStore = NULL;
}
//
// Make sure parameters are valid.
//
switch (OpenMode)
{
case CAPICOM_STORE_OPEN_READ_ONLY:
{
dwOpenFlag = CERT_STORE_READONLY_FLAG;
break;
}
case CAPICOM_STORE_OPEN_READ_WRITE:
{
break;
}
case CAPICOM_STORE_OPEN_MAXIMUM_ALLOWED:
{
dwOpenFlag = CERT_STORE_MAXIMUM_ALLOWED_FLAG;
break;
}
default:
{
hr = E_INVALIDARG;
DebugTrace("Error: invalid parameter, unknown store open mode.\n");
goto ErrorExit;
}
}
switch (StoreLocation)
{
case CAPICOM_MEMORY_STORE:
{
wszName = NULL;
szProvider = (LPSTR) CERT_STORE_PROV_MEMORY;
break;
}
case CAPICOM_LOCAL_MACHINE_STORE:
{
wszName = StoreName;
dwLocation = CERT_SYSTEM_STORE_LOCAL_MACHINE;
break;
}
case CAPICOM_CURRENT_USER_STORE:
{
wszName = StoreName;
dwLocation = CERT_SYSTEM_STORE_CURRENT_USER;
break;
}
case CAPICOM_ACTIVE_DIRECTORY_USER_STORE:
{
wszName = NULL;
szProvider = (LPSTR) CERT_STORE_PROV_MEMORY;
//
// Make sure DSClient is installed, and is not WRITE mode.
//
if (!(hDSClientDLL = ::LoadLibrary("ActiveDS.DLL")))
{
hr = CAPICOM_E_NOT_SUPPORTED;
DebugTrace("Error [%#x]: DSClient not installed.\n", hr);
goto ErrorExit;
}
if (CAPICOM_STORE_OPEN_READ_WRITE == OpenMode)
{
hr = CAPICOM_E_STORE_INVALID_OPEN_MODE;
DebugTrace("Error [%#x]: Attemp to open AD Store for WRITE.\n", hr);
goto ErrorExit;
}
//
// Always force to read only even if user asked for
// maximum allowed.
//
dwOpenFlag = CERT_STORE_READONLY_FLAG;
break;
}
default:
{
hr = E_INVALIDARG;
DebugTrace("Error: invalid parameter, unknown store location.\n");
goto ErrorExit;
}
}
//
// Call CAPI to open the store.
//
if (!(hCertStore = ::CertOpenStore(szProvider,
CAPICOM_ASN_ENCODING,
NULL,
dwOpenFlag | dwLocation,
(void *) (LPCWSTR) wszName)))
{
hr = HRESULT_FROM_WIN32(::GetLastError());
DebugTrace("Error [%#x]: CertOpenStore() failed.\n", hr);
goto ErrorExit;
}
//
// Load userCertificate from the directory, if necessary.
//
if (CAPICOM_ACTIVE_DIRECTORY_USER_STORE == StoreLocation &&
FAILED(hr = ::LoadFromDirectory(hCertStore, StoreName)))
{
DebugTrace("Error [%#x]: LoadFromDirectory() failed.\n", hr);
goto ErrorExit;
}
#if (0)
//
// Create the ICertificates collection object.
//
if (FAILED(hr = ::CreateCertificatesObject(CAPICOM_CERTIFICATES_LOAD_FROM_STORE,
(LPARAM) hCertStore,
&pICertificates)))
{
DebugTrace("Error [%#x]: CreateCertificatesObject() failed.\n", hr);
goto ErrorExit;
}
#endif
//
// Update member variables.
//
m_hCertStore = hCertStore;
m_pICertificates = pICertificates;
m_StoreLocation = StoreLocation;
}
catch(...)
{
hr = E_INVALIDARG;
DebugTrace("Exception: invalid parameter.\n");
goto ErrorExit;
}
UnlockExit:
//
// Free resource.
//
if (hDSClientDLL)
{
::FreeLibrary(hDSClientDLL);
}
//
// 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;
}
#if (0) //DSIE - Drop this for now.
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Function : CStore::Find
Synopsis : Find a certificate in the store by issuer's name and serial
number.
Parameter: BSTR Issuer - Issuer's mame.
BSTR SerialNumber - Serial number in hex format.
ICertificate ** pVal - Pointer to pointer to ICertificate interface
to receive the found certificate.
Remark :
------------------------------------------------------------------------------*/
STDMETHODIMP CStore::Find (BSTR Issuer, BSTR SerialNumber, ICertificate ** pVal)
{
HRESULT hr = S_OK;
PCCERT_CONTEXT pCertContext = NULL;
CComPtr<ICertificate> pICertificate = NULL;
CERT_INFO CertInfo;
DebugTrace("Entering CStore::Find().\n");
//
// Lock access to this object.
//
m_Lock.Lock();
try
{
//
// Initialize CERT_INFO.
//
::ZeroMemory(&CertInfo, sizeof(CertInfo));
//
// Is the store object opened?
//
if (!m_hCertStore)
{
hr = CAPICOM_E_STORE_NOT_OPENED;
DebugTrace("Error: store object does not represent an opened certificate store.\n");
goto ErrorExit;
}
//
// Convert issuer's name string to name blob.
//
if (FAILED(hr = ::Name2NameBlob(Issuer, &CertInfo.Issuer)))
{
DebugTrace("Error [%#x]: Name2NameBlob() failed.\n", hr);
goto ErrorExit;
}
//
// Convert serial number to integer blob.
//
if (FAILED(hr = ::Hex2IntegerBlob(SerialNumber, &CertInfo.SerialNumber)))
{
DebugTrace("Error [%#x]: Hex2IntegerBlob() failed.\n", hr);
goto ErrorExit;
}
//
// Find the cert.
//
if (!(pCertContext = ::CertFindCertificateInStore(m_hCertStore,
CAPICOM_ASN_ENCODING,
0,
CERT_FIND_SUBJECT_CERT,
(const void *) &CertInfo,
NULL)))
{
hr = HRESULT_FROM_WIN32(::GetLastError());
DebugTrace("Error [%#x]: CertFindCertificateInStore() failed.\n", hr);
goto ErrorExit;
}
//
// Create an ICertificate object for the found cert.
//
if (FAILED(hr = ::CreateCertificateObject(pCertContext, pVal)))
{
DebugTrace("Error [%#x]: CreateCertificateObject() failed.\n", hr);
goto ErrorExit;
}
}
catch(...)
{
hr = E_INVALIDARG;
DebugTrace("Exception: invalid parameter.\n");
goto ErrorExit;
}
UnlockExit:
//
// Free resource.
//
if (pCertContext)
{
::CertFreeCertificateContext(pCertContext);
}
if (CertInfo.Issuer.pbData)
{
::CoTaskMemFree(CertInfo.Issuer.pbData);
}
if (CertInfo.SerialNumber.pbData)
{
::CoTaskMemFree(CertInfo.SerialNumber.pbData);
}
//
// Unlock access to this object.
//
m_Lock.Unlock();
DebugTrace("Leaving CStore::Find().\n");
return hr;
ErrorExit:
//
// Sanity check.
//
ATLASSERT(FAILED(hr));
::ReportError(hr);
goto UnlockExit;
}
#endif
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Function : CStore::Add
Synopsis : Add a certificate to the store.
Parameter: PCERT_CONTEXT pCertContext - Pointer to CERT_CONTEXT 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");
//
// Lock access to this object.
//
m_Lock.Lock();
try
{
//
// QI for ICertificate pointer (Just to make sure it is indeed
// an ICertificate object).
//
if (!(pICertificate = pVal))
{
hr = E_INVALIDARG;
DebugTrace("Error: invalid parameter, not an ICertificate interface pointer.\n");
goto ErrorExit;
}
//
// Is the store object opened?
//
if (!m_hCertStore)
{
hr = CAPICOM_E_STORE_NOT_OPENED;
DebugTrace("Error: store object does not represent an opened certificate store.\n");
goto ErrorExit;
}
//
// If it is a system store and we are called from a web page, then
// we need to pop up UI to get user permission to add certificates
// to the store.
//
if ((m_dwCurrentSafety) &&
(CAPICOM_CURRENT_USER_STORE == m_StoreLocation || CAPICOM_LOCAL_MACHINE_STORE == m_StoreLocation) &&
(PromptForStoreAddRemoveEnabled()))
{
if (FAILED(hr = ::UserApprovedOperation(IDD_STORE_SECURITY_ALERT_DLG)))
{
DebugTrace("Error [%#x]: UserApprovedOperation() failed.\n", hr);
goto ErrorExit;
}
}
//
// Get cert context from certificate object, using the restriced private
// method, ICertificate::_GetContext().
//
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_USE_EXISTING,
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;
DebugTrace("Entering CStore::Remove().\n");
//
// Lock access to this object.
//
m_Lock.Lock();
try
{
BOOL bResult;
//
// QI for ICertificate pointer (Just to make sure it is indeed
// an ICertificate object).
//
if (!(pICertificate = pVal))
{
hr = E_INVALIDARG;
DebugTrace("Error: invalid parameter, not an ICertificate interface pointer.\n");
goto ErrorExit;
}
//
// Is the store object opened?
//
if (!m_hCertStore)
{
hr = CAPICOM_E_STORE_NOT_OPENED;
DebugTrace("Error: store object does not represent an opened certificate store.\n");
goto ErrorExit;
}
//
// If it is a system store and we are called from a web page, then
// we need to pop up UI to get user permission to remove certificates
// to the store.
//
if ((m_dwCurrentSafety) &&
(CAPICOM_CURRENT_USER_STORE == m_StoreLocation || CAPICOM_LOCAL_MACHINE_STORE == m_StoreLocation) &&
(PromptForStoreAddRemoveEnabled()))
{
if (FAILED(hr = ::UserApprovedOperation(IDD_STORE_SECURITY_ALERT_DLG)))
{
DebugTrace("Error [%#x]: UserApprovedOperation() failed.\n", hr);
goto ErrorExit;
}
}
//
// Get cert context from certificate object, using the restriced private
// method, ICertificate::_GetContext().
//
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 (FAILED(hr = ::FindCertInStore(m_hCertStore, pCertContext, &pCertContext2)))
{
DebugTrace("Error [%#x]: FindCertInStore() 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");
//
// Lock access to this object.
//
m_Lock.Lock();
try
{
//
// 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 encoding type.\n");
goto ErrorExit;
}
}
//
// Is the store object opened?
//
if (!m_hCertStore)
{
hr = CAPICOM_E_STORE_NOT_OPENED;
DebugTrace("Error: store object does not represent an opened certificate store.\n");
goto ErrorExit;
}
//
// If it is a system store and we are called from a web page, then
// we need to pop up UI to get user permission to export certificates
// from the store.
//
if (m_dwCurrentSafety && PromptForStoreAddRemoveEnabled())
{
if (FAILED(hr = ::UserApprovedOperation(IDD_STORE_SECURITY_ALERT_DLG)))
{
DebugTrace("Error [%#x]: UserApprovedOperation() failed.\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: out of memory.\n");
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 DataBlob = {0, NULL};
HCERTSTORE hCertStore = NULL;
PCCERT_CONTEXT pCertContext = NULL;
DebugTrace("Entering CStore::Import().\n");
//
// Lock access to this object.
//
m_Lock.Lock();
try
{
//
// Make sure parameters are valid.
//
if (0 == ::SysStringByteLen(EncodedStore))
{
hr = E_INVALIDARG;
DebugTrace("Error: invalid parameter, EncodedStore is empty.\n");
goto ErrorExit;
}
//
// Is the store object opened?
//
if (!m_hCertStore)
{
hr = CAPICOM_E_STORE_NOT_OPENED;
DebugTrace("Error: store object does not represent an opened certificate store.\n");
goto ErrorExit;
}
//
// If it is a system store and we are called from a web page, then
// we need to pop up UI to get user permission to import certificates
// to the store.
//
if ((m_dwCurrentSafety) &&
(CAPICOM_CURRENT_USER_STORE == m_StoreLocation || CAPICOM_LOCAL_MACHINE_STORE == m_StoreLocation) &&
(PromptForStoreAddRemoveEnabled()))
{
if (FAILED(hr = ::UserApprovedOperation(IDD_STORE_SECURITY_ALERT_DLG)))
{
DebugTrace("Error [%#x]: UserApprovedOperation() failed.\n", hr);
goto ErrorExit;
}
}
//
// Decode store.
//
if (FAILED(hr = ::ImportData(EncodedStore, &DataBlob)))
{
DebugTrace("Error [%#x]: ImportData() failed.\n");
goto ErrorExit;
}
//
// Open the store.
//
if (!(hCertStore = ::CertOpenStore(CERT_STORE_PROV_SERIALIZED,
CAPICOM_ASN_ENCODING,
NULL,
CERT_STORE_OPEN_EXISTING_FLAG,
(void *) &DataBlob)) &&
!(hCertStore = ::CertOpenStore(CERT_STORE_PROV_PKCS7,
CAPICOM_ASN_ENCODING,
NULL,
CERT_STORE_OPEN_EXISTING_FLAG,
(void *) &DataBlob)))
{
hr = HRESULT_FROM_WIN32(::GetLastError());
DebugTrace("Error [%#x]: CertOpenStore() failed.\n", hr);
goto ErrorExit;
}
//
// Now add all certificates to the current store.
//
while (pCertContext = ::CertEnumCertificatesInStore(hCertStore, pCertContext))
{
//
// Add to the store.
//
if (!::CertAddCertificateContextToStore(m_hCertStore,
pCertContext,
CERT_STORE_ADD_USE_EXISTING,
NULL))
{
hr = HRESULT_FROM_WIN32(::GetLastError());
::CertFreeCertificateContext(pCertContext);
DebugTrace("Error [%#x]: CertAddCertificateContextToStore() failed.\n", hr);
goto ErrorExit;
}
}
}
catch(...)
{
hr = E_INVALIDARG;
DebugTrace("Exception: invalid parameter.\n");
goto ErrorExit;
}
UnlockExit:
//
// Free resource.
//
if (hCertStore)
{
::CertCloseStore(hCertStore, 0);
}
if (DataBlob.pbData)
{
::CoTaskMemFree(DataBlob.pbData);
}
//
// 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;
}