|
|
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Microsoft Windows, Copyright (C) Microsoft Corporation, 2000
File: PrivateKey.cpp
Content: Implementation of CPrivateKey.
History: 06-15-2001 dsie created
------------------------------------------------------------------------------*/
#include "StdAfx.h"
#include "CAPICOM.h"
#include "PrivateKey.h"
#include "Common.h"
#include "CertHlpr.h"
#include "Settings.h"
////////////////////////////////////////////////////////////////////////////////
//
// Exported functions.
//
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Function : CreatePrivateKeyObject
Synopsis : Create and initialize an CPrivateKey object.
Parameter: PCCERT_CONTEXT pCertContext - Pointer to CERT_CONTEXT to be used to initialize the IPrivateKey object.
BOOL bReadOnly - TRUE if read-only, else FALSE.
IPrivateKey ** ppIPrivateKey - Pointer to receive IPrivateKey. Remark :
------------------------------------------------------------------------------*/
HRESULT CreatePrivateKeyObject (PCCERT_CONTEXT pCertContext, BOOL bReadOnly, IPrivateKey ** ppIPrivateKey) { HRESULT hr = S_OK; CComObject<CPrivateKey> * pCPrivateKey = NULL;
DebugTrace("Entering CreatePrivateKeyObject().\n");
//
// Sanity check.
//
ATLASSERT(pCertContext); ATLASSERT(ppIPrivateKey);
try { //
// Create the object. Note that the ref count will still be 0
// after the object is created.
//
if (FAILED(hr = CComObject<CPrivateKey>::CreateInstance(&pCPrivateKey))) { DebugTrace("Error [%#x]: CComObject<CPrivateKey>::CreateInstance() failed.\n", hr); goto ErrorExit; }
//
// Initialize object.
//
if (FAILED(hr = pCPrivateKey->Init(pCertContext, bReadOnly))) { DebugTrace("Error [%#x]: pCPrivateKey->Init() failed.\n", hr); goto ErrorExit; }
//
// Return interface pointer to caller.
//
if (FAILED(hr = pCPrivateKey->QueryInterface(ppIPrivateKey))) { DebugTrace("Error [%#x]: pCPrivateKey->QueryInterface() failed.\n", hr); goto ErrorExit; } }
catch(...) { hr = E_POINTER;
DebugTrace("Exception: invalid parameter.\n"); goto ErrorExit; }
CommonExit:
DebugTrace("Leaving CreatePrivateKeyObject().\n");
return hr;
ErrorExit: //
// Sanity check.
//
ATLASSERT(FAILED(hr));
if (pCPrivateKey) { delete pCPrivateKey; }
goto CommonExit; }
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Function : GetKeyProvInfo
Synopsis : Return pointer to key prov info of a private key object.
Parameter: IPrivateKey * pIPrivateKey - Pointer to private key object. PCRYPT_KEY_PROV_INFO * ppKeyProvInfo - Pointer to PCRYPT_KEY_PROV_INFO.
Remark : Caller must NOT free the structure. ------------------------------------------------------------------------------*/
HRESULT GetKeyProvInfo (IPrivateKey * pIPrivateKey, PCRYPT_KEY_PROV_INFO * ppKeyProvInfo) { HRESULT hr = S_OK; PCRYPT_KEY_PROV_INFO pKeyProvInfo = NULL; CComPtr<ICPrivateKey> pICPrivateKey = NULL;
DebugTrace("Entering GetKeyProvInfo().\n");
//
// Sanity check.
//
ATLASSERT(pIPrivateKey); ATLASSERT(ppKeyProvInfo);
//
// Get ICPrivateKey interface pointer.
//
if (FAILED(hr = pIPrivateKey->QueryInterface(IID_ICPrivateKey, (void **) &pICPrivateKey))) { DebugTrace("Error [%#x]: pIPrivateKey->QueryInterface() failed.\n", hr); goto ErrorExit; }
//
// Get the PCRYPT_KEY_PROV_INFO.
//
if (FAILED(hr = pICPrivateKey->_GetKeyProvInfo(&pKeyProvInfo))) { DebugTrace("Error [%#x]: pICPrivateKey->_GetKeyProvInfo() failed.\n", hr); goto ErrorExit; }
*ppKeyProvInfo = pKeyProvInfo;
CommonExit:
DebugTrace("Leaving GetKeyProvInfo().\n");
return hr;
ErrorExit: //
// Sanity check.
//
ATLASSERT(FAILED(hr));
goto CommonExit; }
////////////////////////////////////////////////////////////////////////////////
//
// CPrivateKey
//
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Function : CPrivateKey::get_ContainerName
Synopsis : Return the key container name.
Parameter: BSTR * pVal - Pointer to BSTR to receive the value.
Remark : ------------------------------------------------------------------------------*/
STDMETHODIMP CPrivateKey::get_ContainerName (BSTR * pVal) { HRESULT hr = S_OK;
DebugTrace("Entering CPrivateKey::get_ContainerName().\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; }
//
// Make sure we do have private key.
//
if (!m_pKeyProvInfo) { hr = CAPICOM_E_PRIVATE_KEY_NOT_INITIALIZED;
DebugTrace("Error [%#x]: private key object has not been initialized.\n", hr); goto ErrorExit; }
//
// Return data to caller.
//
if (!(*pVal = ::SysAllocString(m_pKeyProvInfo->pwszContainerName))) { hr = E_OUTOFMEMORY;
DebugTrace("Error [%#x]: SysAllocString() 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 CPrivateKey::get_ContainerName().\n");
return hr;
ErrorExit: //
// Sanity check.
//
ATLASSERT(FAILED(hr));
ReportError(hr);
goto UnlockExit; }
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Function : CPrivateKey::get_UniqueContainerName
Synopsis : Return the unique key container name.
Parameter: BSTR * pVal - Pointer to BSTR to receive the value.
Remark : ------------------------------------------------------------------------------*/
STDMETHODIMP CPrivateKey::get_UniqueContainerName (BSTR * pVal) { HRESULT hr = S_OK; DWORD dwFlags = 0; DWORD cbData = 0; LPBYTE pbData = NULL; HCRYPTPROV hCryptProv = NULL; CComBSTR bstrName;
DebugTrace("Entering CPrivateKey::get_UniqueContainerName().\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; }
//
// Make sure we do have private key.
//
if (!m_pKeyProvInfo) { hr = CAPICOM_E_PRIVATE_KEY_NOT_INITIALIZED;
DebugTrace("Error [%#x]: private key object has not been initialized.\n", hr); goto ErrorExit; }
//
// Set dwFlags for machine keyset.
//
dwFlags = m_pKeyProvInfo->dwFlags & CRYPT_MACHINE_KEYSET;
//
// Get the provider context.
//
if (FAILED(hr = ::AcquireContext(m_pKeyProvInfo->pwszProvName, m_pKeyProvInfo->pwszContainerName, m_pKeyProvInfo->dwProvType, dwFlags, FALSE, &hCryptProv))) { DebugTrace("Error [%#x]: AcquireContext() failed.\n", hr); goto ErrorExit; }
//
// Get the unique container name.
//
if (!::CryptGetProvParam(hCryptProv, PP_UNIQUE_CONTAINER, NULL, &cbData, 0)) { hr = HRESULT_FROM_WIN32(::GetLastError());
DebugTrace("Error [%#x]: CryptGetProvParam() failed.\n", hr); goto ErrorExit; }
if (NULL == (pbData = (LPBYTE) ::CoTaskMemAlloc(cbData))) { hr = E_OUTOFMEMORY;
DebugTrace("Error [%#x]: CoTaskMemAlloc() failed.\n", hr); goto ErrorExit; }
if (!::CryptGetProvParam(hCryptProv, PP_UNIQUE_CONTAINER, pbData, &cbData, 0)) { hr = HRESULT_FROM_WIN32(::GetLastError());
DebugTrace("Error [%#x]: CryptGetProvParam() failed.\n", hr); goto ErrorExit; }
//
// Return data to caller.
//
if (!(bstrName = (LPSTR) pbData)) { hr = E_OUTOFMEMORY;
DebugTrace("Error [%#x]: bstrName = pbData failed.\n", hr); goto ErrorExit; }
*pVal = bstrName.Detach(); }
catch(...) { hr = E_POINTER;
DebugTrace("Exception: invalid parameter.\n"); goto ErrorExit; }
UnlockExit: //
// Unlock access to this object.
//
m_Lock.Unlock();
//
// Free resources.
//
if (hCryptProv) { ::CryptReleaseContext(hCryptProv, 0); }
DebugTrace("Leaving CPrivateKey::get_UniqueContainerName().\n");
return hr;
ErrorExit: //
// Sanity check.
//
ATLASSERT(FAILED(hr));
ReportError(hr);
goto UnlockExit; }
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Function : CPrivateKey::get_ProviderName
Synopsis : Return the provider name.
Parameter: BSTR * pVal - Pointer to BSTR to receive the value.
Remark : ------------------------------------------------------------------------------*/
STDMETHODIMP CPrivateKey::get_ProviderName (BSTR * pVal) { HRESULT hr = S_OK;
DebugTrace("Entering CPrivateKey::get_ProviderName().\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; }
//
// Make sure we do have private key.
//
if (!m_pKeyProvInfo) { hr = CAPICOM_E_PRIVATE_KEY_NOT_INITIALIZED;
DebugTrace("Error [%#x]: private key object has not been initialized.\n", hr); goto ErrorExit; }
//
// Return data to caller.
//
if (!(*pVal = ::SysAllocString(m_pKeyProvInfo->pwszProvName))) { hr = E_OUTOFMEMORY;
DebugTrace("Error [%#x]: SysAllocString() 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 CPrivateKey::get_ProviderName().\n");
return hr;
ErrorExit: //
// Sanity check.
//
ATLASSERT(FAILED(hr));
ReportError(hr);
goto UnlockExit; }
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Function : CPrivateKey::get_ProviderType
Synopsis : Return the provider type.
Parameter: CAPICOM_PROV_TYPE * pVal - Pointer to CAPICOM_PROV_TYPE to receive the value. Remark : ------------------------------------------------------------------------------*/
STDMETHODIMP CPrivateKey::get_ProviderType (CAPICOM_PROV_TYPE * pVal) { HRESULT hr = S_OK;
DebugTrace("Entering CPrivateKey::get_ProviderType().\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; }
//
// Make sure we do have private key.
//
if (!m_pKeyProvInfo) { hr = CAPICOM_E_PRIVATE_KEY_NOT_INITIALIZED;
DebugTrace("Error [%#x]: private key object has not been initialized.\n", hr); goto ErrorExit; }
//
// Return data to caller.
//
*pVal = (CAPICOM_PROV_TYPE) m_pKeyProvInfo->dwProvType; }
catch(...) { hr = E_POINTER;
DebugTrace("Exception: invalid parameter.\n"); goto ErrorExit; }
UnlockExit: //
// Unlock access to this object.
//
m_Lock.Unlock();
DebugTrace("Leaving CPrivateKey::get_ProviderType().\n");
return hr;
ErrorExit: //
// Sanity check.
//
ATLASSERT(FAILED(hr));
ReportError(hr);
goto UnlockExit; }
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Function : CPrivateKey::get_KeySpec
Synopsis : Return the Key spec.
Parameter: CAPICOM_KEY_SPEC * pVal - Pointer to CAPICOM_KEY_SPEC to receive the value. Remark : ------------------------------------------------------------------------------*/
STDMETHODIMP CPrivateKey::get_KeySpec (CAPICOM_KEY_SPEC * pVal) { HRESULT hr = S_OK;
DebugTrace("Entering CPrivateKey::get_KeySpec().\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; }
//
// Make sure we do have private key.
//
if (!m_pKeyProvInfo) { hr = CAPICOM_E_PRIVATE_KEY_NOT_INITIALIZED;
DebugTrace("Error [%#x]: private key object has not been initialized.\n", hr); goto ErrorExit; }
//
// Return data to caller.
//
*pVal = (CAPICOM_KEY_SPEC) m_pKeyProvInfo->dwKeySpec; }
catch(...) { hr = E_POINTER;
DebugTrace("Exception: invalid parameter.\n"); goto ErrorExit; }
UnlockExit: //
// Unlock access to this object.
//
m_Lock.Unlock();
DebugTrace("Leaving CPrivateKey::get_KeySpec().\n");
return hr;
ErrorExit: //
// Sanity check.
//
ATLASSERT(FAILED(hr));
ReportError(hr);
goto UnlockExit; }
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Function : CPrivateKey::IsAccessible
Synopsis : Check to see if the private key is accessible.
Parameter: VARIANT_BOOL * pVal - Pointer to VARIANT_BOOL to receive the result.
Remark : This may cause UI to be displayed. ------------------------------------------------------------------------------*/
STDMETHODIMP CPrivateKey::IsAccessible (VARIANT_BOOL * pVal) { HRESULT hr = S_OK; DWORD dwFlags = 0; DWORD dwVerifyContextFlag = 0; DWORD cbData = 0; DWORD dwImpType = 0; HCRYPTPROV hCryptProv = NULL;
DebugTrace("Entering CPrivateKey::IsAccessible().\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; }
//
// Initialize.
//
*pVal = VARIANT_FALSE;
//
// Make sure we do have private key.
//
if (!m_pKeyProvInfo) { hr = CAPICOM_E_PRIVATE_KEY_NOT_INITIALIZED;
DebugTrace("Error [%#x]: private key object has not been initialized.\n", hr); goto ErrorExit; }
//
// Set dwFlags for machine keyset.
//
dwFlags = m_pKeyProvInfo->dwFlags & CRYPT_MACHINE_KEYSET;
//
// If Win2K and above, use CRYPT_VERIFYCONTEXT flag.
//
if (IsWin2KAndAbove()) { dwVerifyContextFlag = CRYPT_VERIFYCONTEXT; }
//
// Get the provider context with no key access.
//
if (FAILED(hr = ::AcquireContext(m_pKeyProvInfo->pwszProvName, NULL, m_pKeyProvInfo->dwProvType, dwVerifyContextFlag | dwFlags, FALSE, &hCryptProv))) { DebugTrace("Error [%#x]: AcquireContext(CRYPT_VERIFYCONTEXT) failed.\n", hr); goto ErrorExit; }
//
// Get provider param.
//
cbData = sizeof(dwImpType);
if (!::CryptGetProvParam(hCryptProv, PP_IMPTYPE, (PBYTE) &dwImpType, &cbData, 0)) { hr = HRESULT_FROM_WIN32(::GetLastError());
DebugTrace("Error [%#x]: CryptGetProvParam(PP_IMPTYPE) failed.\n", hr); goto ErrorExit; }
//
// Release verify context.
//
::ReleaseContext(hCryptProv), hCryptProv = NULL;
//
// Check implementation type.
//
if (dwImpType & CRYPT_IMPL_HARDWARE) { //
// We do not support this for hardware key in down level platforms,
// because CRYPT_SILENT flag is not available.
//
if (!IsWin2KAndAbove()) { hr = CAPICOM_E_NOT_SUPPORTED;
DebugTrace("Error [%#x]: IsAccessible() for hardware key is not supported.\n", hr); goto ErrorExit; }
//
// Reacquire context with silent flag.
//
if (FAILED(hr = ::AcquireContext(m_pKeyProvInfo->pwszProvName, m_pKeyProvInfo->pwszContainerName, m_pKeyProvInfo->dwProvType, CRYPT_SILENT | dwFlags, FALSE, &hCryptProv))) { DebugTrace("Info [%#x]: AcquireContext(CRYPT_SILENT) failed, probably smart card not inserted.\n", hr); hr = S_OK; goto UnlockExit; } } else { //
// Reacquire context with private key access.
//
if (FAILED(hr = ::AcquireContext(m_pKeyProvInfo->pwszProvName, m_pKeyProvInfo->pwszContainerName, m_pKeyProvInfo->dwProvType, dwFlags, FALSE, &hCryptProv))) { DebugTrace("Info [%#x]: AcquireContext() failed, probably access denied.\n", hr); hr = S_OK; goto UnlockExit; } }
//
// Return result to caller.
//
*pVal = VARIANT_TRUE; }
catch(...) { hr = E_POINTER;
DebugTrace("Exception: invalid parameter.\n"); goto ErrorExit; }
UnlockExit: //
// Unlock access to this object.
//
m_Lock.Unlock();
//
// Free resources.
//
if (hCryptProv) { ::ReleaseContext(hCryptProv); }
DebugTrace("Leaving CPrivateKey::IsAccessible().\n");
return hr;
ErrorExit: //
// Sanity check.
//
ATLASSERT(FAILED(hr));
ReportError(hr);
goto UnlockExit; }
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Function : CPrivateKey::IsProtected
Synopsis : Check to see if the private key is user protected.
Parameter: VARIANT_BOOL * pVal - Pointer to VARIANT_BOOL to receive the result.
Remark : ------------------------------------------------------------------------------*/
STDMETHODIMP CPrivateKey::IsProtected (VARIANT_BOOL * pVal) { HRESULT hr = S_OK; DWORD dwFlags = 0; DWORD dwVerifyContextFlag = 0; DWORD cbData = 0; DWORD dwImpType = 0; HCRYPTPROV hCryptProv = NULL;
DebugTrace("Entering CPrivateKey::IsProtected().\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; }
//
// Initialize.
//
*pVal = VARIANT_FALSE;
//
// Make sure we do have private key.
//
if (!m_pKeyProvInfo) { hr = CAPICOM_E_PRIVATE_KEY_NOT_INITIALIZED;
DebugTrace("Error [%#x]: private key object has not been initialized.\n", hr); goto ErrorExit; }
//
// Set dwFlags for machine keyset.
//
dwFlags = m_pKeyProvInfo->dwFlags & CRYPT_MACHINE_KEYSET;
//
// If Win2K and above, use CRYPT_VERIFYCONTEXT flag.
//
if (IsWin2KAndAbove()) { dwVerifyContextFlag = CRYPT_VERIFYCONTEXT; }
//
// Get the provider context with no key access.
//
if (FAILED(hr = ::AcquireContext(m_pKeyProvInfo->pwszProvName, NULL, m_pKeyProvInfo->dwProvType, dwVerifyContextFlag | dwFlags, FALSE, &hCryptProv))) { DebugTrace("Error [%#x]: AcquireContext(CRYPT_VERIFYCONTEXT) failed.\n", hr); goto ErrorExit; }
//
// Get provider param.
//
cbData = sizeof(dwImpType);
if (!::CryptGetProvParam(hCryptProv, PP_IMPTYPE, (PBYTE) &dwImpType, &cbData, 0)) { hr = HRESULT_FROM_WIN32(::GetLastError());
DebugTrace("Error [%#x]: CryptGetProvParam(PP_IMPTYPE) failed.\n", hr); goto ErrorExit; }
//
// Assume hardware key is protected.
//
if (dwImpType & CRYPT_IMPL_HARDWARE) { //
// Return result to caller.
//
*pVal = VARIANT_TRUE; } else { //
// We do not support this for software key in down level platforms,
// because CRYPT_SILENT flag is not available.
//
if (!IsWin2KAndAbove()) { hr = CAPICOM_E_NOT_SUPPORTED;
DebugTrace("Error [%#x]: IsProtected() for software key is not supported.\n", hr); goto ErrorExit; }
//
// Reacquire context with key access (to make sure key exists).
//
::ReleaseContext(hCryptProv), hCryptProv = NULL;
if (FAILED(hr = ::AcquireContext(m_pKeyProvInfo->pwszProvName, m_pKeyProvInfo->pwszContainerName, m_pKeyProvInfo->dwProvType, dwFlags, FALSE, &hCryptProv))) { DebugTrace("Error [%#x]: AcquireContext() failed.\n", hr); goto ErrorExit; }
//
// Reacquire context with silent flag.
//
::ReleaseContext(hCryptProv), hCryptProv = NULL;
if (FAILED(hr = ::AcquireContext(m_pKeyProvInfo->pwszProvName, m_pKeyProvInfo->pwszContainerName, m_pKeyProvInfo->dwProvType, CRYPT_SILENT | dwFlags, FALSE, &hCryptProv))) { //
// CSP refuses to open the container, so can assume it is user protected.
//
*pVal = VARIANT_TRUE;
DebugTrace("Info [%#x]: AcquireContext(CRYPT_SILENT) failed, assume user protected.\n", hr);
//
// Successful.
//
hr = S_OK; } } }
catch(...) { hr = E_POINTER;
DebugTrace("Exception: invalid parameter.\n"); goto ErrorExit; }
UnlockExit: //
// Unlock access to this object.
//
m_Lock.Unlock();
//
// Free resources.
//
if (hCryptProv) { ::ReleaseContext(hCryptProv); }
DebugTrace("Leaving CPrivateKey::IsProtected().\n");
return hr;
ErrorExit: //
// Sanity check.
//
ATLASSERT(FAILED(hr));
ReportError(hr);
goto UnlockExit; }
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Function : CPrivateKey::IsExportable
Synopsis : Check to see if the private key is exportable.
Parameter: VARIANT_BOOL * pVal - Pointer to VARIANT_BOOL to receive the result.
Remark : ------------------------------------------------------------------------------*/
STDMETHODIMP CPrivateKey::IsExportable (VARIANT_BOOL * pVal) { HRESULT hr = S_OK; DWORD dwFlags = 0; DWORD dwVerifyContextFlag = 0; DWORD cbData = 0; DWORD dwImpType = 0; DWORD dwPermissions = 0; HCRYPTPROV hCryptProv = NULL; HCRYPTKEY hCryptKey = NULL;
DebugTrace("Entering CPrivateKey::IsExportable().\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; }
//
// Initialize.
//
*pVal = VARIANT_FALSE;
//
// Make sure we do have private key.
//
if (!m_pKeyProvInfo) { hr = CAPICOM_E_PRIVATE_KEY_NOT_INITIALIZED;
DebugTrace("Error [%#x]: private key object has not been initialized.\n", hr); goto ErrorExit; }
//
// Set dwFlags for machine keyset.
//
dwFlags = m_pKeyProvInfo->dwFlags & CRYPT_MACHINE_KEYSET;
//
// If Win2K and above, use CRYPT_VERIFYCONTEXT flag.
//
if (IsWin2KAndAbove()) { dwVerifyContextFlag = CRYPT_VERIFYCONTEXT; }
//
// Get the provider context with no key access.
//
if (FAILED(hr = ::AcquireContext(m_pKeyProvInfo->pwszProvName, NULL, m_pKeyProvInfo->dwProvType, dwVerifyContextFlag | dwFlags, FALSE, &hCryptProv))) { DebugTrace("Error [%#x]: AcquireContext(CRYPT_VERIFYCONTEXT) failed.\n", hr); goto ErrorExit; }
//
// Get provider param.
//
cbData = sizeof(dwImpType);
if (!::CryptGetProvParam(hCryptProv, PP_IMPTYPE, (PBYTE) &dwImpType, &cbData, 0)) { hr = HRESULT_FROM_WIN32(::GetLastError());
DebugTrace("Error [%#x]: CryptGetProvParam(PP_IMPTYPE) failed.\n", hr); goto ErrorExit; }
//
// Assume hardware key is not exportable.
//
if (!(dwImpType & CRYPT_IMPL_HARDWARE)) { //
// We do not support this for software key in down level platforms,
// because KP_PERMISSIONS flag is not available.
//
if (!IsWin2KAndAbove()) { hr = CAPICOM_E_NOT_SUPPORTED;
DebugTrace("Error [%#x]: IsExportabled() for software key is not supported.\n", hr); goto ErrorExit; }
//
// Reacquire context with private key access.
//
::ReleaseContext(hCryptProv), hCryptProv = NULL;
if (FAILED(hr = ::AcquireContext(m_pKeyProvInfo->pwszProvName, m_pKeyProvInfo->pwszContainerName, m_pKeyProvInfo->dwProvType, dwFlags, FALSE, &hCryptProv))) { DebugTrace("Error [%#x]: AcquireContext() failed.\n", hr); goto ErrorExit; }
//
// Get key handle.
//
if (!::CryptGetUserKey(hCryptProv, m_pKeyProvInfo->dwKeySpec, &hCryptKey)) { hr = HRESULT_FROM_WIN32(::GetLastError());
DebugTrace("Error [%#x]: CryptGetUserKey() failed.\n", hr); goto ErrorExit; }
//
// Get key param.
//
cbData = sizeof(dwPermissions);
if (!::CryptGetKeyParam(hCryptKey, KP_PERMISSIONS, (PBYTE) &dwPermissions, &cbData, 0)) { hr = HRESULT_FROM_WIN32(::GetLastError());
DebugTrace("Error [%#x]: CryptGetKeyParam(KP_PERMISSIONS) failed.\n", hr); goto ErrorExit; }
//
// Return result to caller.
//
if (dwPermissions & CRYPT_EXPORT) { *pVal = VARIANT_TRUE; } } }
catch(...) { hr = E_POINTER;
DebugTrace("Exception: invalid parameter.\n"); goto ErrorExit; }
UnlockExit: //
// Unlock access to this object.
//
m_Lock.Unlock();
//
// Free resources.
//
if (hCryptKey) { ::CryptDestroyKey(hCryptKey); } if (hCryptProv) { ::ReleaseContext(hCryptProv); }
DebugTrace("Leaving CPrivateKey::IsExportable().\n");
return hr;
ErrorExit: //
// Sanity check.
//
ATLASSERT(FAILED(hr));
ReportError(hr);
goto UnlockExit; }
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Function : CPrivateKey::IsRemovable
Synopsis : Check to see if the private key is stored in removable device.
Parameter: VARIANT_BOOL * pVal - Pointer to VARIANT_BOOL to receive the result.
Remark : ------------------------------------------------------------------------------*/
STDMETHODIMP CPrivateKey::IsRemovable (VARIANT_BOOL * pVal) { HRESULT hr = S_OK; DWORD dwFlags = 0; DWORD dwVerifyContextFlag = 0; DWORD cbData = 0; DWORD dwImpType = 0; HCRYPTPROV hCryptProv = NULL;
DebugTrace("Entering CPrivateKey::IsRemovable().\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; }
//
// Initialize.
//
*pVal = VARIANT_FALSE;
//
// Make sure we do have private key.
//
if (!m_pKeyProvInfo) { hr = CAPICOM_E_PRIVATE_KEY_NOT_INITIALIZED;
DebugTrace("Error [%#x]: private key object has not been initialized.\n", hr); goto ErrorExit; }
//
// Set dwFlags for machine keyset.
//
dwFlags = m_pKeyProvInfo->dwFlags & CRYPT_MACHINE_KEYSET;
//
// If Win2K and above, use CRYPT_VERIFYCONTEXT flag.
//
if (IsWin2KAndAbove()) { dwVerifyContextFlag = CRYPT_VERIFYCONTEXT; }
//
// Get the provider context with no key access.
//
if (FAILED(hr = ::AcquireContext(m_pKeyProvInfo->pwszProvName, NULL, m_pKeyProvInfo->dwProvType, dwVerifyContextFlag | dwFlags, FALSE, &hCryptProv))) { DebugTrace("Error [%#x]: AcquireContext(CRYPT_VERIFYCONTEXT) failed.\n", hr); goto ErrorExit; }
//
// Get provider param.
//
cbData = sizeof(dwImpType);
if (!::CryptGetProvParam(hCryptProv, PP_IMPTYPE, (PBYTE) &dwImpType, &cbData, 0)) { hr = HRESULT_FROM_WIN32(::GetLastError());
DebugTrace("Error [%#x]: CryptGetProvParam(PP_IMPTYPE) failed.\n", hr); goto ErrorExit; }
//
// Return result to caller.
//
if (dwImpType & CRYPT_IMPL_REMOVABLE) { *pVal = VARIANT_TRUE; } }
catch(...) { hr = E_POINTER;
DebugTrace("Exception: invalid parameter.\n"); goto ErrorExit; }
UnlockExit: //
// Unlock access to this object.
//
m_Lock.Unlock();
//
// Free resources.
//
if (hCryptProv) { ::ReleaseContext(hCryptProv); }
DebugTrace("Leaving CPrivateKey::IsRemovable().\n");
return hr;
ErrorExit: //
// Sanity check.
//
ATLASSERT(FAILED(hr));
ReportError(hr);
goto UnlockExit; }
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Function : CPrivateKey::IsMachineKeyset
Synopsis : Check to see if the private key is stored in machine key container.
Parameter: VARIANT_BOOL * pVal - Pointer to VARIANT_BOOL to receive the result.
Remark : ------------------------------------------------------------------------------*/
STDMETHODIMP CPrivateKey::IsMachineKeyset (VARIANT_BOOL * pVal) { HRESULT hr = S_OK;
DebugTrace("Entering CPrivateKey::IsMachineKeyset().\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; }
//
// Initialize.
//
*pVal = VARIANT_FALSE;
//
// Make sure we do have private key.
//
if (!m_pKeyProvInfo) { hr = CAPICOM_E_PRIVATE_KEY_NOT_INITIALIZED;
DebugTrace("Error [%#x]: private key object has not been initialized.\n", hr); goto ErrorExit; }
//
// Return result to caller.
//
if (m_pKeyProvInfo->dwFlags & CRYPT_MACHINE_KEYSET) { *pVal = VARIANT_TRUE; } }
catch(...) { hr = E_POINTER;
DebugTrace("Exception: invalid parameter.\n"); goto ErrorExit; }
UnlockExit: //
// Unlock access to this object.
//
m_Lock.Unlock();
DebugTrace("Leaving CPrivateKey::IsMachineKeyset().\n");
return hr;
ErrorExit: //
// Sanity check.
//
ATLASSERT(FAILED(hr));
ReportError(hr);
goto UnlockExit; }
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Function : CPrivateKey::IsHardwareDevice
Synopsis : Check to see if the private key is stored in hardware device.
Parameter: VARIANT_BOOL * pVal - Pointer to VARIANT_BOOL to receive the result.
Remark : ------------------------------------------------------------------------------*/
STDMETHODIMP CPrivateKey::IsHardwareDevice (VARIANT_BOOL * pVal) { HRESULT hr = S_OK; DWORD dwFlags = 0; DWORD dwVerifyContextFlag = 0; DWORD cbData = 0; DWORD dwImpType = 0; HCRYPTPROV hCryptProv = NULL;
DebugTrace("Entering CPrivateKey::IsHardwareDevice().\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; }
//
// Initialize.
//
*pVal = VARIANT_FALSE;
//
// Make sure we do have private key.
//
if (!m_pKeyProvInfo) { hr = CAPICOM_E_PRIVATE_KEY_NOT_INITIALIZED;
DebugTrace("Error [%#x]: private key object has not been initialized.\n", hr); goto ErrorExit; }
//
// Set dwFlags for machine keyset.
//
dwFlags = m_pKeyProvInfo->dwFlags & CRYPT_MACHINE_KEYSET;
//
// If Win2K and above, use CRYPT_VERIFYCONTEXT flag.
//
if (IsWin2KAndAbove()) { dwVerifyContextFlag = CRYPT_VERIFYCONTEXT; }
//
// Get the provider context with no key access.
//
if (FAILED(hr = ::AcquireContext(m_pKeyProvInfo->pwszProvName, NULL, m_pKeyProvInfo->dwProvType, dwVerifyContextFlag | dwFlags, FALSE, &hCryptProv))) { DebugTrace("Error [%#x]: AcquireContext(CRYPT_VERIFYCONTEXT) failed.\n", hr); goto ErrorExit; }
//
// Get provider param.
//
cbData = sizeof(dwImpType);
if (!::CryptGetProvParam(hCryptProv, PP_IMPTYPE, (PBYTE) &dwImpType, &cbData, 0)) { hr = HRESULT_FROM_WIN32(::GetLastError());
DebugTrace("Error [%#x]: CryptGetProvParam(PP_IMPTYPE) failed.\n", hr); goto ErrorExit; }
//
// Return result to caller.
//
if (dwImpType & CRYPT_IMPL_HARDWARE) { *pVal = VARIANT_TRUE; } }
catch(...) { hr = E_POINTER;
DebugTrace("Exception: invalid parameter.\n"); goto ErrorExit; }
UnlockExit: //
// Unlock access to this object.
//
m_Lock.Unlock();
//
// Free resources.
//
if (hCryptProv) { ::ReleaseContext(hCryptProv); }
DebugTrace("Leaving CPrivateKey::IsHardwareDevice().\n");
return hr;
ErrorExit: //
// Sanity check.
//
ATLASSERT(FAILED(hr));
ReportError(hr);
goto UnlockExit; }
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Function : CPrivateKey::Open
Synopsis : Open an existing key container.
Parameter: BSTR ContainerName - Container name. BSTR ProviderName - Provider name.
CAPICOM_PROV_TYPE ProviderType - Provider type.
CAPICOM_KEY_SPEC KeySpec - Key spec.
CAPICOM_STORE_LOCATION StoreLocation - Machine or user.
VARIANT_BOOL bCheckExistence - True to check if the specified container and key actually exists.
Remark : ------------------------------------------------------------------------------*/
STDMETHODIMP CPrivateKey::Open (BSTR ContainerName, BSTR ProviderName, CAPICOM_PROV_TYPE ProviderType, CAPICOM_KEY_SPEC KeySpec, CAPICOM_STORE_LOCATION StoreLocation, VARIANT_BOOL bCheckExistence) { HRESULT hr = S_OK; DWORD dwFlags = 0; DWORD dwSerializedLength = 0; HCRYPTPROV hCryptProv = NULL; HCRYPTKEY hCryptKey = NULL; PCRYPT_KEY_PROV_INFO pKeyProvInfo = NULL;;
DebugTrace("Entering CPrivateKey::Open().\n");
try { //
// Lock access to this object.
//
m_Lock.Lock();
//
// Not allowed if read-only.
//
if (m_bReadOnly) { hr = CAPICOM_E_NOT_ALLOWED;
DebugTrace("Error [%#x]: Opening private key from WEB script is not allowed.\n", hr); goto ErrorExit; }
//
// Make sure paremeters are valid.
//
switch (StoreLocation) { case CAPICOM_LOCAL_MACHINE_STORE: { dwFlags = CRYPT_MACHINE_KEYSET; break; }
case CAPICOM_CURRENT_USER_STORE: { break; }
default: { hr = E_INVALIDARG;
DebugTrace("Error: invalid store location (%#x).\n", StoreLocation); goto ErrorExit; } } if (KeySpec != CAPICOM_KEY_SPEC_KEYEXCHANGE && KeySpec != CAPICOM_KEY_SPEC_SIGNATURE) { hr = E_INVALIDARG;
DebugTrace("Error [%#x]: invalid key spec (%#x).\n", hr, KeySpec); goto ErrorExit; } //
// Make sure the container and key exists, if requested.
//
if (bCheckExistence) { if (FAILED(hr = ::AcquireContext((LPWSTR) ProviderName, (LPWSTR) ContainerName, ProviderType, dwFlags, FALSE, &hCryptProv))) { DebugTrace("Error [%#x]: AcquireContext() failed.\n", hr); goto ErrorExit; }
if (!::CryptGetUserKey(hCryptProv, KeySpec, &hCryptKey)) { hr = HRESULT_FROM_WIN32(::GetLastError());
DebugTrace("Error [%#x]: CryptGetUserKey() failed.\n", hr); goto ErrorExit; } }
//
// Allocate memory to serialize the structure.
//
dwSerializedLength = sizeof(CRYPT_KEY_PROV_INFO) + ((::SysStringLen(ContainerName) + 1) * sizeof(WCHAR)) + ((::SysStringLen(ProviderName) + 1) * sizeof(WCHAR));
if (!(pKeyProvInfo = (PCRYPT_KEY_PROV_INFO) ::CoTaskMemAlloc(dwSerializedLength))) { hr = E_OUTOFMEMORY;
DebugTrace("Error [%#x]: CoTaskMemAlloc() failed.\n", hr); goto ErrorExit; }
//
// Now serialize it.
//
::ZeroMemory((LPVOID) pKeyProvInfo, dwSerializedLength); pKeyProvInfo->pwszContainerName = (LPWSTR) ((LPBYTE) pKeyProvInfo + sizeof(CRYPT_KEY_PROV_INFO)); pKeyProvInfo->pwszProvName = (LPWSTR) ((LPBYTE) pKeyProvInfo->pwszContainerName + ((::SysStringLen(ContainerName) + 1) * sizeof(WCHAR))); pKeyProvInfo->dwProvType = ProviderType; pKeyProvInfo->dwKeySpec = KeySpec; pKeyProvInfo->dwFlags = dwFlags;
::wcscpy(pKeyProvInfo->pwszContainerName, ContainerName); ::wcscpy(pKeyProvInfo->pwszProvName, ProviderName);
//
// Update states.
//
if (m_pKeyProvInfo) { ::CoTaskMemFree((LPVOID) m_pKeyProvInfo); } m_cbKeyProvInfo = dwSerializedLength; m_pKeyProvInfo = pKeyProvInfo; }
catch(...) { hr = E_POINTER;
DebugTrace("Exception: invalid parameter.\n"); goto ErrorExit; }
UnlockExit: //
// Free resources.
//
if (hCryptKey) { ::CryptDestroyKey(hCryptKey); } if (hCryptProv) { ::ReleaseContext(hCryptProv); }
//
// Unlock access to this object.
//
m_Lock.Unlock();
DebugTrace("Leaving CPrivateKey::Open().\n");
return hr;
ErrorExit: //
// Sanity check.
//
ATLASSERT(FAILED(hr));
//
// Free resources.
//
if (pKeyProvInfo) { ::CoTaskMemFree(pKeyProvInfo); }
ReportError(hr);
goto UnlockExit; }
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Function : CPrivateKey::Delete
Synopsis : Delete the existing key container.
Parameter: None.
Remark : ------------------------------------------------------------------------------*/
STDMETHODIMP CPrivateKey::Delete () { HRESULT hr = S_OK; HCRYPTPROV hCryptProv = NULL;
DebugTrace("Entering CPrivateKey::Delete().\n");
try { //
// Lock access to this object.
//
m_Lock.Lock();
//
// Not allowed if read-only.
//
if (m_bReadOnly) { hr = CAPICOM_E_NOT_ALLOWED;
DebugTrace("Error [%#x]: Deleting private key from WEB script is not allowed.\n", hr); goto ErrorExit; }
//
// Make sure we do have private key.
//
if (!m_pKeyProvInfo) { hr = CAPICOM_E_PRIVATE_KEY_NOT_INITIALIZED;
DebugTrace("Error [%#x]: private key object has not been initialized.\n", hr); goto ErrorExit; }
//
// Delete it!
//
if (FAILED(hr = ::AcquireContext(m_pKeyProvInfo->pwszProvName, m_pKeyProvInfo->pwszContainerName, m_pKeyProvInfo->dwProvType, CRYPT_DELETEKEYSET | (m_pKeyProvInfo->dwFlags & CRYPT_MACHINE_KEYSET), FALSE, &hCryptProv))) { DebugTrace("Error [%#x]: AcquireContext(CRYPT_DELETEKEYSET) failed.\n", hr); goto ErrorExit; } //
// Update states.
//
::CoTaskMemFree((LPVOID) m_pKeyProvInfo);
m_cbKeyProvInfo = 0; m_pKeyProvInfo = NULL; }
catch(...) { hr = E_POINTER;
DebugTrace("Exception: invalid parameter.\n"); goto ErrorExit; }
UnlockExit: //
// Unlock access to this object.
//
m_Lock.Unlock();
DebugTrace("Leaving CPrivateKey::Delete().\n");
return hr;
ErrorExit: //
// Sanity check.
//
ATLASSERT(FAILED(hr));
ReportError(hr);
goto UnlockExit; }
////////////////////////////////////////////////////////////////////////////////
//
// Custom interfaces.
//
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Function : CPrivateKey::_GetKeyProvInfo
Synopsis : Return pointer to key prov info of a private key object.
Parameter: PCRYPT_KEY_PROV_INFO * ppKeyProvInfo - Pointer to PCRYPT_KEY_PROV_INFO.
Remark : Caller must free the structure with CoTaskMemFree(). ------------------------------------------------------------------------------*/
STDMETHODIMP CPrivateKey::_GetKeyProvInfo (PCRYPT_KEY_PROV_INFO * ppKeyProvInfo) { HRESULT hr = S_OK; PCRYPT_KEY_PROV_INFO pKeyProvInfo = NULL;
DebugTrace("Entering CPrivateKey::_GetKeyProvInfo().\n");
try { //
// Lock access to this object.
//
m_Lock.Lock();
//
// Make sure we do have private key.
//
if (!m_pKeyProvInfo) { hr = CAPICOM_E_PRIVATE_KEY_NOT_INITIALIZED;
DebugTrace("Error [%#x]: private key object has not been initialized.\n", hr); goto ErrorExit; }
//
// Allocate memory.
//
if (!(pKeyProvInfo = (PCRYPT_KEY_PROV_INFO) ::CoTaskMemAlloc(m_cbKeyProvInfo))) { hr = E_OUTOFMEMORY;
DebugTrace("Error [%#x]: CoTaskMemAlloc() failed.\n", hr); goto ErrorExit; }
//
// copy structure over.
//
::CopyMemory((LPVOID) pKeyProvInfo, (LPVOID) m_pKeyProvInfo, (SIZE_T) m_cbKeyProvInfo);
//
// and return the structure to caller.
//
*ppKeyProvInfo = pKeyProvInfo; }
catch(...) { hr = E_POINTER;
DebugTrace("Exception: invalid parameter.\n"); goto ErrorExit; }
UnlockExit: //
// Unlock access to this object.
//
m_Lock.Unlock();
DebugTrace("Leaving CPrivateKey::_GetKeyProvInfo().\n");
return hr;
ErrorExit: //
// Sanity check.
//
ATLASSERT(FAILED(hr));
//
// Free resources.
//
if (pKeyProvInfo) { ::CoTaskMemFree((LPVOID) pKeyProvInfo); }
ReportError(hr);
goto UnlockExit; }
////////////////////////////////////////////////////////////////////////////////
//
// Private methods.
//
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Function : CPrivateKey::Init
Synopsis : Initialize the object.
Parameter: PCCERT_CONTEXT pCertContext - Pointer to PCCERT_CONTEXT to be used to initialize the object.
BOOL bReadOnly - TRUE if read-only, else FALSE. Remark : This method is not part of the COM interface (it is a normal C++ member function). We need it to initialize the object created internally by us.
Since it is only a normal C++ member function, this function can only be called from a C++ class pointer, not an interface pointer. ------------------------------------------------------------------------------*/
STDMETHODIMP CPrivateKey::Init (PCCERT_CONTEXT pCertContext, BOOL bReadOnly) { HRESULT hr = S_OK; DWORD cbData = 0; PCRYPT_KEY_PROV_INFO pKeyProvInfo = NULL;
DebugTrace("Entering CPrivateKey::Init().\n");
//
// Sanity check.
//
ATLASSERT(pCertContext);
//
// Get key provider info property.
//
if (!::CertGetCertificateContextProperty(pCertContext, CERT_KEY_PROV_INFO_PROP_ID, NULL, &cbData)) { hr = HRESULT_FROM_WIN32(::GetLastError());
DebugTrace("Info [%#x]: CertGetCertificateContextProperty() failed.\n", hr); goto ErrorExit; }
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());
DebugTrace("Info [%#x]: CertGetCertificateContextProperty() failed.\n", hr); goto ErrorExit; }
//
// Update states.
//
if (m_pKeyProvInfo) { ::CoTaskMemFree((LPVOID) m_pKeyProvInfo); } m_bReadOnly = bReadOnly; m_cbKeyProvInfo = cbData; m_pKeyProvInfo = pKeyProvInfo;
CommonExit:
DebugTrace("Leaving CPrivateKey::Init().\n");
return hr;
ErrorExit: //
// Sanity check.
//
ATLASSERT(FAILED(hr));
//
// Free resources.
//
if (pKeyProvInfo) { ::CoTaskMemFree((LPVOID) pKeyProvInfo); }
goto CommonExit; }
|